• 【简介】OpenOCD 由jtag操作到parport driver流程


    1. 定义 jtag_command_type

    在 OpenOCD 中,JTag 命令在枚举 jtag_command_type 中定义,定义如下:

     1 /**
     2  * The type of the @c jtag_command_container contained by a
     3  * @c jtag_command_s structure.
     4  */
     5 enum jtag_command_type {
     6     JTAG_SCAN         = 1, // 数据扫描,IR_SCAN 或 DR_SCAN
     7     /* JTAG_TLR_RESET's non-minidriver implementation is a
     8      * vestige from a statemove cmd. The statemove command
     9      * is obsolete and replaced by pathmove.
    10      *
    11      * pathmove does not support reset as one of it's states,
    12      * hence the need for an explicit statemove command.
    13      */
    14     JTAG_TLR_RESET    = 2, // TAP 状态机转到 RESET 状态
    15     JTAG_RUNTEST      = 3, // 状态机在 IDEL 态下进行自循环
    16     JTAG_RESET        = 4, // 进行 srst 或 trst
    17     JTAG_PATHMOVE     = 6, // 进行状态切换,手动控制状态机轮转
    18     JTAG_SLEEP        = 7, // sleep 一段时间
    19     JTAG_STABLECLOCKS = 8, // 发送 N 次 TMS,TMS 的值取决于 TAP 当前状态
    20     JTAG_TMS          = 9, // 发送指定的 TMS
    21 };

    2. 使用 jtag_command_type 创建 cmd 序列

    jtag_command_type 在 IR/DR 等命令创建时创建,在 execute_queue 中使用。例如,在创建 IR_SCAN 时,会构建 jtag_command 结构体,并赋 予cmd->type 为 JTAG_SCAN。

     1 /**
     2  * see jtag_add_ir_scan()
     3  *
     4  */
     5 int interface_jtag_add_ir_scan(struct jtag_tap *active,                                                
     6         const struct scan_field *in_fields, tap_state_t state)                                         
     7 {
     8     size_t num_taps = jtag_tap_count_enabled();
     9 
    10     struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));                           
    11     struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command));                          
    12     struct scan_field *out_fields = cmd_queue_alloc(num_taps  * sizeof(struct scan_field));            
    13 
    14     jtag_queue_command(cmd);
    15 
    16     cmd->type = JTAG_SCAN;                                                                             
    17     cmd->cmd.scan = scan;
    18 
    19     scan->ir_scan = true;                                                                              
    20     scan->num_fields = num_taps;    /* one field per device */
    21     scan->fields = out_fields;
    22     scan->end_state = state;                                                                           
    23 
    24     struct scan_field *field = out_fields;  /* keep track where we insert data */                      
    25 
    26     /* loop over all enabled TAPs */
    27 
    28     for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) {
    29         /* search the input field list for fields for the current TAP */
    30 
    31         if (tap == active) {
    32             /* if TAP is listed in input fields, copy the value */                                     
    33             tap->bypass = 0;
    34 
    35             jtag_scan_field_clone(field, in_fields);                                                   
    36         } else {
    37             /* if a TAP isn't listed in input fields, set it to BYPASS */                              
    38 
    39             tap->bypass = 1;
    40 
    41             field->num_bits = tap->ir_length;                                                          
    42             field->out_value = buf_set_ones(cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)), tap->ir_length);      
    43             field->in_value = NULL; /* do not collect input for tap's in bypass */                     
    44         }                                                                                              
    45 
    46         /* update device information */                                                                
    47         buf_cpy(field->out_value, tap->cur_instr, tap->ir_length);                                     
    48 
    49         field++;
    50     }
    51     /* paranoia: jtag_tap_count_enabled() and jtag_tap_next_enabled() not in sync */
    52     assert(field == out_fields + num_taps);
    53 
    54     return ERROR_OK;
    55 }

    在上面的代码中,定义了本次操作的 cmd 是 JTAG_SCAN,操作数据在 scan 变量中进行定义。

    jtag_queue_command 用于将本次新建的命令序列加入命令列表中,在执行jtag_execute_queue的时候执行。

    上述代码中的 for 循环,遍历全部的 TAP,并将 bypass 的TAP的 IR 设置为全1,并把数据加入到操作的数据列表中。

    与 interface_jtag_add_ir_scan 函数类似,能够构建cmd的函数如下:

     1 // cmd->type = JTAG_SCAN;
     2 int interface_jtag_add_ir_scan(struct jtag_tap *active,
     3         const struct scan_field *in_fields, tap_state_t state)
     4 
     5 // cmd->type = JTAG_SCAN;
     6 int interface_jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields,                             
     7         const struct scan_field *in_fields, tap_state_t state) 
     8 
     9 // cmd->type = JTAG_SCAN;
    10 static int jtag_add_plain_scan(int num_bits, const uint8_t *out_bits,
    11         uint8_t *in_bits, tap_state_t state, bool ir_scan)
    12 
    13 // cmd->type = JTAG_TLR_RESET;
    14 int interface_jtag_add_tlr(void)
    15 
    16 // cmd->type = JTAG_TMS;
    17 int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state)
    18 
    19 // cmd->type = JTAG_PATHMOVE;
    20 int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
    21 
    22 // cmd->type = JTAG_RUNTEST;
    23 int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
    24 
    25 // cmd->type = JTAG_STABLECLOCKS;
    26 int interface_jtag_add_clocks(int num_cycles)
    27 
    28 // cmd->type = JTAG_RESET;
    29 int interface_jtag_add_reset(int req_trst, int req_srst)
    30 
    31 // cmd->type = JTAG_SLEEP;
    32 int interface_jtag_add_sleep(uint32_t us)

    3. 根据 cmd->type 进行操作

    在cmd类型定义完成后,在执行 jtag_execute_queue 时使用 cmd->type 来处理具体的工作。 以 parport 驱动为例,jtag_execute_queue 最终会调用到  bitbang_execute_queue,函数代码如下:

      1 int bitbang_execute_queue(void)
      2 {
      3     struct jtag_command *cmd = jtag_command_queue;  /* currently processed command */
      4     int scan_size;
      5     enum scan_type type;
      6     uint8_t *buffer;
      7     int retval;
      8 
      9     if (!bitbang_interface) {
     10         LOG_ERROR("BUG: Bitbang interface called, but not yet initialized");
     11         exit(-1);
     12     }
     13 
     14     /* return ERROR_OK, unless a jtag_read_buffer returns a failed check
     15      * that wasn't handled by a caller-provided error handler
     16      */
     17     retval = ERROR_OK;
     18 
     19     if (bitbang_interface->blink) {
     20         if (bitbang_interface->blink(1) != ERROR_OK)
     21             return ERROR_FAIL;
     22     }
     23 
     24     while (cmd) {
     25         switch (cmd->type) {
     26             case JTAG_RESET:
     27                 LOG_DEBUG_IO("reset trst: %i srst %i",
     28                         cmd->cmd.reset->trst,
     29                         cmd->cmd.reset->srst);
     30                 if ((cmd->cmd.reset->trst == 1) ||
     31                         (cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
     32                     tap_set_state(TAP_RESET);
     33                 if (bitbang_interface->reset(cmd->cmd.reset->trst,
     34                             cmd->cmd.reset->srst) != ERROR_OK)
     35                     return ERROR_FAIL;
     36                 break;
     37             case JTAG_RUNTEST:
     38                 LOG_DEBUG_IO("runtest %i cycles, end in %s",
     39                         cmd->cmd.runtest->num_cycles,
     40                         tap_state_name(cmd->cmd.runtest->end_state));
     41                 bitbang_end_state(cmd->cmd.runtest->end_state);
     42                 if (bitbang_runtest(cmd->cmd.runtest->num_cycles) != ERROR_OK)
     43                     return ERROR_FAIL;
     44                 break;
     45 
     46             case JTAG_STABLECLOCKS:
     47                 /* this is only allowed while in a stable state.  A check for a stable
     48                  * state was done in jtag_add_clocks()
     49                  */
     50                 if (bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles) != ERROR_OK)
     51                     return ERROR_FAIL;
     52                 break;
     53 
     54             case JTAG_TLR_RESET:
     55                 LOG_DEBUG_IO("statemove end in %s",
     56                         tap_state_name(cmd->cmd.statemove->end_state));
     57                 bitbang_end_state(cmd->cmd.statemove->end_state);
     58                 if (bitbang_state_move(0) != ERROR_OK)
     59                     return ERROR_FAIL;
     60                 break;
     61             case JTAG_PATHMOVE:
     62                 LOG_DEBUG_IO("pathmove: %i states, end in %s",
     63                         cmd->cmd.pathmove->num_states,
     64                         tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]));
     65                 if (bitbang_path_move(cmd->cmd.pathmove) != ERROR_OK)
     66                     return ERROR_FAIL;
     67                 break;
     68             case JTAG_SCAN:
     69                 bitbang_end_state(cmd->cmd.scan->end_state);
     70                 scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
     71                 LOG_DEBUG_IO("%s scan %d bits; end in %s",
     72                         (cmd->cmd.scan->ir_scan) ? "IR" : "DR",
     73                         scan_size,
     74                     tap_state_name(cmd->cmd.scan->end_state));
     75                 type = jtag_scan_type(cmd->cmd.scan);
     76                 if (bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer,
     77                             scan_size) != ERROR_OK)
     78                     return ERROR_FAIL;
     79                 if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
     80                     retval = ERROR_JTAG_QUEUE_FAILED;
     81                 if (buffer)
     82                     free(buffer);
     83                 break;
     84             case JTAG_SLEEP:
     85                 LOG_DEBUG_IO("sleep %" PRIi32, cmd->cmd.sleep->us);
     86                 jtag_sleep(cmd->cmd.sleep->us);
     87                 break;
     88             case JTAG_TMS:
     89                 retval = bitbang_execute_tms(cmd);
     90                 break;
     91             default:
     92                 LOG_ERROR("BUG: unknown JTAG command type encountered");
     93                 exit(-1);
     94         }
     95         cmd = cmd->next;
     96     }
     97     if (bitbang_interface->blink) {
     98         if (bitbang_interface->blink(0) != ERROR_OK)
     99             return ERROR_FAIL;
    100     }
    101 
    102     return retval;
    103 }

    在 bitbang_execute_queue 函数中,通过 switch 语句对各种不同类型的 cmd->type 进行解析处理。

    在 bitbang_execute_queue 中,变量 bitbang_interface 在 parport 驱动初始化时定义,定义如下:

    1 static struct bitbang_interface parport_bitbang = { 
    2         .read = &parport_read,
    3         .write = &parport_write,
    4         .reset = &parport_reset,
    5         .blink = &parport_led,
    6     };  

    4. JTAG_SCAN

     接下来的内容将着重讲解 JTAG_SCAN 功能。JTAG_SCAN 是进行 IR_SCAN 和 DR_SCCAN 的 command,是上位机与被调试处理器进行数据交互的接口。在 bitbang_execute_queue 函数中可以看到,JTAG_SCAN 命令相关代码如下:

     1             case JTAG_SCAN:
     2                 bitbang_end_state(cmd->cmd.scan->end_state);
     3                 scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
     4                 LOG_DEBUG_IO("%s scan %d bits; end in %s",
     5                         (cmd->cmd.scan->ir_scan) ? "IR" : "DR",
     6                         scan_size,
     7                     tap_state_name(cmd->cmd.scan->end_state));
     8                 type = jtag_scan_type(cmd->cmd.scan);
     9                 if (bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer,
    10                             scan_size) != ERROR_OK)
    11                     return ERROR_FAIL;
    12                 if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
    13                     retval = ERROR_JTAG_QUEUE_FAILED;
    14                 if (buffer)
    15                     free(buffer);
    16                 break;

    在函数开始时,首先将状态机结束状态设置成 cmd 命令预设的状态,然后通过 jtag_build_buffer 函数拼接 scan 数据。

    4.1 jtag_build_buffer

    jtag_build_buffer 函数如下:

     1 int jtag_build_buffer(const struct scan_command *cmd, uint8_t **buffer)
     2 {
     3     int bit_count = 0;
     4     int i;
     5 
     6     bit_count = jtag_scan_size(cmd);
     7     *buffer = calloc(1, DIV_ROUND_UP(bit_count, 8));
     8 
     9     bit_count = 0;
    10 
    11     LOG_DEBUG_IO("%s num_fields: %i",
    12             cmd->ir_scan ? "IRSCAN" : "DRSCAN",
    13             cmd->num_fields);
    14 
    15     for (i = 0; i < cmd->num_fields; i++) {
    16         if (cmd->fields[i].out_value) {
    17             if (LOG_LEVEL_IS(LOG_LVL_DEBUG_IO)) {
    18                 char *char_buf = buf_to_str(cmd->fields[i].out_value,
    19                         (cmd->fields[i].num_bits > DEBUG_JTAG_IOZ)
    20                         ? DEBUG_JTAG_IOZ
    21                                 : cmd->fields[i].num_bits, 16);
    22 
    23                 LOG_DEBUG("fields[%i].out_value[%i]: 0x%s", i,
    24                         cmd->fields[i].num_bits, char_buf);
    25                 free(char_buf);
    26             }   
    27             buf_set_buf(cmd->fields[i].out_value, 0, *buffer,
    28                     bit_count, cmd->fields[i].num_bits);
    29         } else {
    30             LOG_DEBUG_IO("fields[%i].out_value[%i]: NULL",
    31                     i, cmd->fields[i].num_bits);
    32         }   
    33 
    34         bit_count += cmd->fields[i].num_bits;
    35     }   
    36 
    37     /*LOG_DEBUG_IO("bit_count totalling: %i",  bit_count); */
    38 
    39     return bit_count;
    40 }

    在函数开始时,首先统计 scan 数据长度,构建数据 buffer。然后将 cmd 中相应的数据复制到 buffer 中,最后函数将拼接数据的总长度作为返回值返回。

    在获取操作的数据后,接下来通过 bitbang_scan 函数实现数据交互,将发送的数据通过 TDI 发送出去,同时接收 TDO 的返回数据。

    4.2 bitbang_scan

    bitbang_scan 函数的定义如下:

     1 static int bitbang_scan(bool ir_scan, enum scan_type type, uint8_t *buffer,                            
     2         unsigned scan_size)
     3 {                       
     4     tap_state_t saved_end_state = tap_get_end_state();                                                 
     5     unsigned bit_cnt;
     6                 
     7     if (!((!ir_scan &&
     8             (tap_get_state() == TAP_DRSHIFT)) ||
     9             (ir_scan && (tap_get_state() == TAP_IRSHIFT)))) {                                          
    10         if (ir_scan)
    11             bitbang_end_state(TAP_IRSHIFT); // 状态机状态设置为 IR_SHIFT
    12         else    
    13             bitbang_end_state(TAP_DRSHIFT); // 状态机状态设置为 DR_SHIFT                                                           
    14                 
    15         if (bitbang_state_move(0) != ERROR_OK) // 执行状态转换                                                        
    16             return ERROR_FAIL;
    17         bitbang_end_state(saved_end_state); // 恢复结束状态
    18     }           
    19             
    20     size_t buffered = 0; 
    21     for (bit_cnt = 0; bit_cnt < scan_size; bit_cnt++) {                                                
    22         int tms = (bit_cnt == scan_size-1) ? 1 : 0;                                                    
    23         int tdi;
    24         int bytec = bit_cnt/8;                                                                         
    25         int bcval = 1 << (bit_cnt % 8);                                                                
    26         
    27         /* if we're just reading the scan, but don't care about the output                             
    28          * default to outputting 'low', this also makes valgrind traces more readable,                 
    29          * as it removes the dependency on an uninitialised value                                      
    30          */
    31         tdi = 0;
    32         if ((type != SCAN_IN) && (buffer[bytec] & bcval)) // 如果需要输出数据,且数据为 1,则 tdi 置 1
    33             tdi = 1;
    34 
    35         if (bitbang_interface->write(0, tms, tdi) != ERROR_OK) // 发送 tck,tms,tdi,下降沿
    36             return ERROR_FAIL;
    37 
    38         if (type != SCAN_OUT) {
    39             if (bitbang_interface->buf_size) {
    40                 if (bitbang_interface->sample() != ERROR_OK)
    41                     return ERROR_FAIL;
    42                 buffered++;
    43             } else {
    44                 switch (bitbang_interface->read()) { // 接收 TDO 数据
    45                     case BB_LOW:
    46                         buffer[bytec] &= ~bcval;
    47                         break;
    48                     case BB_HIGH:
    49                         buffer[bytec] |= bcval;
    50                         break;
    51                     default:
    52                         return ERROR_FAIL;
    53                 }
    54             }
    55         }
    56 
    57         if (bitbang_interface->write(1, tms, tdi) != ERROR_OK) // 发送 tck,tms,tdi,上升沿
    58             return ERROR_FAIL;
    59 
    60         if (type != SCAN_OUT && bitbang_interface->buf_size &&
    61                 (buffered == bitbang_interface->buf_size ||
    62                  bit_cnt == scan_size - 1)) { // 采用 sample 形式的数据读取
    63             for (unsigned i = bit_cnt + 1 - buffered; i <= bit_cnt; i++) {
    64                 switch (bitbang_interface->read_sample()) {
    65                     case BB_LOW:
    66                         buffer[i/8] &= ~(1 << (i % 8));
    67                         break;
    68                     case BB_HIGH:
    69                         buffer[i/8] |= 1 << (i % 8);
    70                         break;
    71                     default:
    72                         return ERROR_FAIL;
    73                 }
    74             }
    75             buffered = 0;
    76         }
    77     }
    78 
    79     if (tap_get_state() != tap_get_end_state()) { // 进行状态切换,切换到 cmd 要求的结束状态
    80         /* we *KNOW* the above loop transitioned out of
    81          * the shift state, so we skip the first state
    82          * and move directly to the end state.
    83          */
    84         if (bitbang_state_move(1) != ERROR_OK) // 当前状态为 IR/DR SHIFT,所以要跳过当前状态,传参为 1
    85             return ERROR_FAIL;
    86     }
    87     return ERROR_OK;
    88 }

    5. bitbang_interface 解析

    bitbang_interface 在 parport.c 中的定义为 parport_bitbang。结构体定义入下:

    static struct bitbang_interface parport_bitbang = {
            .read = &parport_read,
            .write = &parport_write,
            .reset = &parport_reset,
            .blink = &parport_led,
        };

    在结构体中,包含 read、write、reset 和 blink 函数。其中,read 操作用于读取 tdo;write 操作用于输出 tck、tms 和 tdi;reset操作用于进行 trst 或 srst 对 JTag 进行复位;blink 用于点亮或熄灭指示灯。

    5.1 parport_read

    parport_read 函数用于读取并口的输入数据,其中包含 TDO 数据。代码如下:

     1 static bb_value_t parport_read(void)
     2 {       
     3     int data = 0;
     4         
     5 #if PARPORT_USE_PPDEV == 1
     6     ioctl(device_handle, PPRSTATUS, &data); // 读取数据
     7 #else
     8     data = inb(statusport); // 读取数据
     9 #endif
    10 
    11     if ((data ^ cable->INPUT_INVERT) & cable->TDO_MASK) // 分析读取到的 TDO 数据读取数据
    12         return BB_HIGH;
    13     else
    14         return BB_LOW;
    15 }

    5.2 parport_write

    parport_write 函数用于构建并口的输出数据,并执行数据输出。代码如下:

     1 static int parport_write(int tck, int tms, int tdi)
     2 {
     3     int i = wait_states + 1;
     4 
     5     if (tck) // 设置 TCK 数据
     6         dataport_value |= cable->TCK_MASK;
     7     else
     8         dataport_value &= ~cable->TCK_MASK;
     9 
    10     if (tms) // 设置 TMS 数据
    11         dataport_value |= cable->TMS_MASK;
    12     else
    13         dataport_value &= ~cable->TMS_MASK;
    14 
    15     if (tdi) // 设置 TDI 数据
    16         dataport_value |= cable->TDI_MASK;
    17     else
    18         dataport_value &= ~cable->TDI_MASK;
    19 
    20     while (i-- > 0)
    21         parport_write_data(); // 输出数据
    22 
    23     return ERROR_OK;
    24 }

    parport_write_data 函数为实际的数据输出函数,代码如下:

     1 static inline void parport_write_data(void)
     2 {   
     3     uint8_t output;
     4     output = dataport_value ^ cable->OUTPUT_INVERT; // 构建输出数据
     5     
     6 #if PARPORT_USE_PPDEV == 1
     7     ioctl(device_handle, PPWDATA, &output);
     8 #else   
     9 #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
    10     outb(dataport, output); // 数据输出
    11 #else   
    12     outb(output, dataport); // 数据输出
    13 #endif
    14 #endif
    15 }

    5.3 parport_reset

    parport_reset 函数用于 trst 或 srst,代码如下:

     1 /* (1) assert or (0) deassert reset lines */
     2 static int parport_reset(int trst, int srst)
     3 {
     4     LOG_DEBUG("trst: %i, srst: %i", trst, srst);
     5 
     6     if (trst == 0) // 设置 trst
     7         dataport_value |= cable->TRST_MASK;
     8     else if (trst == 1)
     9         dataport_value &= ~cable->TRST_MASK;
    10 
    11     if (srst == 0) // 设置 srst
    12         dataport_value |= cable->SRST_MASK;
    13     else if (srst == 1)
    14         dataport_value &= ~cable->SRST_MASK;
    15 
    16     parport_write_data(); // 发送数据
    17 
    18     return ERROR_OK;
    19 }

    5.4 parport_led

    parport_led 函数用于点亮和关闭调试器上的指示灯。代码如下:

     1 /* turn LED on parport adapter on (1) or off (0) */
     2 static int parport_led(int on)
     3 {
     4     if (on) // 是否点亮指示灯
     5         dataport_value |= cable->LED_MASK;
     6     else
     7         dataport_value &= ~cable->LED_MASK;
     8 
     9     parport_write_data(); // 发送数据
    10 
    11     return ERROR_OK;
    12 }
    
    
    
  • 相关阅读:
    HBASE学习笔记(一)
    模板:循环数据库表
    where(泛型类型约束)
    如何很好的使用Linq的Distinct方法
    Sql自定义表类型批量导入数据
    Linq select 语法
    JTemplate学习(四)
    JTemplate学习(三)
    JTemplate学习(二)
    正则表达式学习
  • 原文地址:https://www.cnblogs.com/elta/p/12559827.html
Copyright © 2020-2023  润新知