- debug handler file not closed - (thanks to oyvind harboe for the patch)
[openocd.git] / src / jtag / jtag.c
index d43fafb9dbabd67aa45ef9cfde4f6d20686d700d..3ef5735eb05276a70f959a54d514c278c8c8c1de 100644 (file)
@@ -58,6 +58,8 @@ static cmd_queue_page_t *cmd_queue_pages = NULL;
  * 3: Pause-DR
  * 4: Shift-IR
  * 5: Pause-IR
+ * 
+ * SD->SD and SI->SI have to be caught in interface specific code
  */
 u8 tap_move[6][6] =
 {
@@ -95,6 +97,14 @@ tap_transition_t tap_transitions[16] =
        {TAP_SDS, TAP_RTI}              /* UI  */
 };
 
+char* jtag_event_strings[] =
+{
+       "SRST asserted",
+       "TRST asserted",
+       "SRST released",
+       "TRST released"
+};
+
 enum tap_state end_state = TAP_TLR;
 enum tap_state cur_state = TAP_TLR;
 int jtag_trst = 0;
@@ -111,6 +121,14 @@ enum tap_state cmd_queue_cur_state = TAP_TLR;
 
 int jtag_verify_capture_ir = 1;
 
+/* how long the OpenOCD should wait before attempting JTAG communication after reset lines deasserted (in ms) */
+int jtag_nsrst_delay = 0; /* default to no nSRST delay */
+int jtag_ntrst_delay = 0; /* default to no nTRST delay */ 
+
+/* maximum number of JTAG devices expected in the chain
+ */
+#define JTAG_MAX_CHAIN_SIZE 20 
+
 /* callbacks to inform high-level handlers about JTAG state changes */
 jtag_event_callback_t *jtag_event_callbacks;
 
@@ -120,12 +138,12 @@ jtag_event_callback_t *jtag_event_callbacks;
        extern jtag_interface_t parport_interface;
 #endif
 
-#if BUILD_FTDI2232 == 1
-       extern jtag_interface_t ftdi2232_interface;
+#if BUILD_FT2232_FTD2XX == 1
+       extern jtag_interface_t ft2232_interface;
 #endif
 
-#if BUILD_FTD2XX == 1
-       extern jtag_interface_t ftd2xx_interface;
+#if BUILD_FT2232_LIBFTDI == 1
+       extern jtag_interface_t ft2232_interface;
 #endif
 
 #if BUILD_AMTJTAGACCEL == 1
@@ -136,21 +154,49 @@ jtag_event_callback_t *jtag_event_callbacks;
        extern jtag_interface_t ep93xx_interface;
 #endif
 
+#if BUILD_AT91RM9200 == 1
+       extern jtag_interface_t at91rm9200_interface;
+#endif
+
+#if BUILD_GW16012 == 1
+       extern jtag_interface_t gw16012_interface;
+#endif
+
+#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1
+       extern jtag_interface_t presto_interface;
+#endif
+
+#if BUILD_USBPROG == 1
+       extern jtag_interface_t usbprog_interface;
+#endif
+
 jtag_interface_t *jtag_interfaces[] = {
 #if BUILD_PARPORT == 1
        &parport_interface,
 #endif
-#if BUILD_FTDI2232 == 1
-       &ftdi2232_interface,
+#if BUILD_FT2232_FTD2XX == 1
+       &ft2232_interface,
 #endif
-#if BUILD_FTD2XX == 1
-       &ftd2xx_interface,
+#if BUILD_FT2232_LIBFTDI == 1
+       &ft2232_interface,
 #endif
 #if BUILD_AMTJTAGACCEL == 1
        &amt_jtagaccel_interface,
 #endif
 #if BUILD_EP93XX == 1
        &ep93xx_interface,
+#endif
+#if BUILD_AT91RM9200 == 1
+       &at91rm9200_interface,
+#endif
+#if BUILD_GW16012 == 1
+       &gw16012_interface,
+#endif
+#if BUILD_PRESTO_LIBFTDI == 1 || BUILD_PRESTO_FTD2XX == 1
+       &presto_interface,
+#endif
+#if BUILD_USBPROG == 1
+       &usbprog_interface,
 #endif
        NULL,
 };
@@ -161,13 +207,24 @@ jtag_interface_t *jtag = NULL;
 char* jtag_interface = NULL;
 int jtag_speed = -1;
 
+
 /* forward declarations */
+int jtag_add_statemove(enum tap_state endstate);
+int jtag_add_pathmove(int num_states, enum tap_state *path);
+int jtag_add_runtest(int num_cycles, enum tap_state endstate);
+int jtag_add_reset(int trst, int srst);
+int jtag_add_end_state(enum tap_state endstate);
+int jtag_add_sleep(u32 us);
+int jtag_execute_queue(void);
+int jtag_cancel_queue(void);
 
 /* jtag commands */
 int handle_interface_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_jtag_device_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
@@ -231,7 +288,7 @@ int jtag_call_event_callbacks(enum jtag_event event)
 {
        jtag_event_callback_t *callback = jtag_event_callbacks;
        
-       DEBUG("jtag event: %i", event);
+       DEBUG("jtag event: %s", jtag_event_strings[event]);
        
        while (callback)
        {
@@ -320,13 +377,12 @@ void cmd_queue_free()
        cmd_queue_pages = NULL;
 }
 
-int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
+int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state, void *dummy_anachronism)
 {
        jtag_command_t **last_cmd;
        jtag_device_t *device;
        int i, j;
        int scan_size = 0;
-       /*      int changed = 0; */
 
        if (jtag_trst == 1)
        {
@@ -334,26 +390,6 @@ int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
                return ERROR_JTAG_TRST_ASSERTED;
        }
 
-       /*
-       for (i=0; i<num_fields; i++)
-       {
-               device = jtag_get_device(fields[i].device);
-               if (device)
-               {
-                       if (buf_cmp(device->cur_instr, fields[i].out_value, device->ir_length))
-                               changed = 1;
-               }
-               else
-               {
-                       ERROR("inexistant device specified for ir scan");
-                       return ERROR_INVALID_ARGUMENTS;
-               }
-       }
-
-       if (!changed)
-               return ERROR_OK;
-       */
-       
        last_cmd = jtag_get_last_command_p();
        
        /* allocate memory for a new list member */
@@ -368,7 +404,7 @@ int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
        (*last_cmd)->cmd.scan->num_fields = jtag_num_devices;   /* one field per device */
        (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(jtag_num_devices * sizeof(scan_field_t));
        (*last_cmd)->cmd.scan->end_state = state;
-       
+               
        if (state != -1)
                cmd_queue_end_state = state;
 
@@ -380,7 +416,7 @@ int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
        
        cmd_queue_cur_state = cmd_queue_end_state;
                
-       for (i=0; i < jtag_num_devices; i++)
+       for (i = 0; i < jtag_num_devices; i++)
        {
                int found = 0;
                device = jtag_get_device(i);
@@ -388,21 +424,15 @@ int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
                (*last_cmd)->cmd.scan->fields[i].device = i;
                (*last_cmd)->cmd.scan->fields[i].num_bits = scan_size;
                (*last_cmd)->cmd.scan->fields[i].in_value = NULL;
+               (*last_cmd)->cmd.scan->fields[i].in_handler = NULL;
+               (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL;
                if (jtag_verify_capture_ir)
                {
-                       (*last_cmd)->cmd.scan->fields[i].in_check_value = buf_cpy(device->expected, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
-                       (*last_cmd)->cmd.scan->fields[i].in_check_mask = buf_cpy(device->expected_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+                       jtag_set_check_value((*last_cmd)->cmd.scan->fields+i, device->expected, device->expected_mask, NULL);
                }
-               else
-               {
-                       (*last_cmd)->cmd.scan->fields[i].in_check_value = NULL;
-                       (*last_cmd)->cmd.scan->fields[i].in_check_mask = NULL;
-               }                       
-               (*last_cmd)->cmd.scan->fields[i].in_handler = NULL;
-               (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL;
 
                /* search the list */
-               for (j=0; j < num_fields; j++)
+               for (j = 0; j < num_fields; j++)
                {
                        if (i == fields[j].device)
                        {
@@ -431,7 +461,7 @@ int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
        return ERROR_OK;
 }
 
-int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
+int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state, void *dummy_anachronism)
 {
        jtag_command_t **last_cmd;
        int i;
@@ -477,15 +507,15 @@ int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state
                (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits);
                (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits);
                (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value;
-               (*last_cmd)->cmd.scan->fields[i].in_check_value = buf_cpy(fields[i].in_check_value, cmd_queue_alloc(num_bytes), num_bits);
-               (*last_cmd)->cmd.scan->fields[i].in_check_mask = buf_cpy(fields[i].in_check_mask, cmd_queue_alloc(num_bytes), num_bits);
+               (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value;
+               (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask;
                (*last_cmd)->cmd.scan->fields[i].in_handler = NULL;
                (*last_cmd)->cmd.scan->fields[i].in_handler_priv = NULL;
        }
        return ERROR_OK;
 }
 
-int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
+int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state, void *dummy_anachronism)
 {
        int i, j;
        int bypass_devices = 0;
@@ -520,7 +550,7 @@ int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
        (*last_cmd)->cmd.scan->num_fields = num_fields + bypass_devices;
        (*last_cmd)->cmd.scan->fields = cmd_queue_alloc((num_fields + bypass_devices) * sizeof(scan_field_t));
        (*last_cmd)->cmd.scan->end_state = state;
-
+       
        if (state != -1)
                cmd_queue_end_state = state;
 
@@ -532,12 +562,12 @@ int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
                        
        cmd_queue_cur_state = cmd_queue_end_state;
        
-       for (i=0; i < jtag_num_devices; i++)
+       for (i = 0; i < jtag_num_devices; i++)
        {
                int found = 0;
                (*last_cmd)->cmd.scan->fields[field_count].device = i;
        
-               for (j=0; j < num_fields; j++)
+               for (j = 0; j < num_fields; j++)
                {
                        if (i == fields[j].device)
                        {
@@ -547,8 +577,8 @@ int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
                                (*last_cmd)->cmd.scan->fields[field_count].out_value = buf_cpy(fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
                                (*last_cmd)->cmd.scan->fields[field_count].out_mask = buf_cpy(fields[j].out_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
                                (*last_cmd)->cmd.scan->fields[field_count].in_value = fields[j].in_value;
-                               (*last_cmd)->cmd.scan->fields[field_count].in_check_value = buf_cpy(fields[j].in_check_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
-                               (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = buf_cpy(fields[j].in_check_mask, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size);
+                               (*last_cmd)->cmd.scan->fields[field_count].in_check_value = fields[j].in_check_value;
+                               (*last_cmd)->cmd.scan->fields[field_count].in_check_mask = fields[j].in_check_mask;
                                (*last_cmd)->cmd.scan->fields[field_count].in_handler = fields[j].in_handler;
                                (*last_cmd)->cmd.scan->fields[field_count++].in_handler_priv = fields[j].in_handler_priv;
                        }
@@ -577,15 +607,14 @@ int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
                        /* if a device is listed, the BYPASS register must not be selected */
                        if (jtag_get_device(i)->bypass)
                        {
-                               ERROR("BUG: scan data for a device in BYPASS");
-                               exit(-1);
+                               WARNING("scan data for a device in BYPASS");
                        }
                }
        }
        return ERROR_OK;
 }
 
-int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
+int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state, void *dummy_anachronism)
 {
        int i;
        jtag_command_t **last_cmd = jtag_get_last_command_p();
@@ -608,7 +637,7 @@ int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state
        (*last_cmd)->cmd.scan->num_fields = num_fields;
        (*last_cmd)->cmd.scan->fields = cmd_queue_alloc(num_fields * sizeof(scan_field_t));
        (*last_cmd)->cmd.scan->end_state = state;
-       
+               
        if (state != -1)
                cmd_queue_end_state = state;
 
@@ -629,8 +658,8 @@ int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state
                (*last_cmd)->cmd.scan->fields[i].out_value = buf_cpy(fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits);
                (*last_cmd)->cmd.scan->fields[i].out_mask = buf_cpy(fields[i].out_mask, cmd_queue_alloc(num_bytes), num_bits);
                (*last_cmd)->cmd.scan->fields[i].in_value = fields[i].in_value;
-               (*last_cmd)->cmd.scan->fields[i].in_check_value = buf_cpy(fields[i].in_check_value, cmd_queue_alloc(num_bytes), num_bits);
-               (*last_cmd)->cmd.scan->fields[i].in_check_mask = buf_cpy(fields[i].in_check_mask, cmd_queue_alloc(num_bytes), num_bits);
+               (*last_cmd)->cmd.scan->fields[i].in_check_value = fields[i].in_check_value;
+               (*last_cmd)->cmd.scan->fields[i].in_check_mask = fields[i].in_check_mask;
                (*last_cmd)->cmd.scan->fields[i].in_handler = fields[i].in_handler;
                (*last_cmd)->cmd.scan->fields[i].in_handler_priv = fields[i].in_handler_priv;
        }
@@ -688,13 +717,13 @@ int jtag_add_pathmove(int num_states, enum tap_state *path)
                return ERROR_JTAG_NOT_IMPLEMENTED;
        }
        
-       if (jtag->support_statemove)
+       if (jtag->support_pathmove)
        {
                /* allocate memory for a new list member */
                *last_cmd = cmd_queue_alloc(sizeof(jtag_command_t));
                last_comand_pointer = &((*last_cmd)->next);
                (*last_cmd)->next = NULL;
-               (*last_cmd)->type = JTAG_RUNTEST;
+               (*last_cmd)->type = JTAG_PATHMOVE;
        
                (*last_cmd)->cmd.pathmove = cmd_queue_alloc(sizeof(pathmove_command_t));
                (*last_cmd)->cmd.pathmove->num_states = num_states;
@@ -805,7 +834,10 @@ int jtag_add_reset(int req_trst, int req_srst)
        }
        
        if (req_srst && !(jtag_reset_config & RESET_HAS_SRST))
+       {
+               ERROR("requested nSRST assertion, but the current configuration doesn't support this");
                return ERROR_JTAG_RESET_CANT_SRST;
+       }
        
        if (req_trst && !(jtag_reset_config & RESET_HAS_TRST))
        {
@@ -827,9 +859,15 @@ int jtag_add_reset(int req_trst, int req_srst)
        jtag_srst = req_srst;
 
        if (jtag_srst)
+       {
                jtag_call_event_callbacks(JTAG_SRST_ASSERTED);
+       }
        else
+       {
                jtag_call_event_callbacks(JTAG_SRST_RELEASED);
+               if (jtag_nsrst_delay)
+                       jtag_add_sleep(jtag_nsrst_delay * 1000);
+       }
        
        if (trst_with_tms)
        {
@@ -854,9 +892,20 @@ int jtag_add_reset(int req_trst, int req_srst)
        {
                if (jtag_trst)
                {
+                       /* we just asserted nTRST, so we're now in Test-Logic-Reset,
+                        * and inform possible listeners about this
+                        */
                        cmd_queue_cur_state = TAP_TLR;
                        jtag_call_event_callbacks(JTAG_TRST_ASSERTED);
                }
+               else
+               {
+                       /* the nTRST line got deasserted, so we're still in Test-Logic-Reset,
+                        * but we might want to add a delay to give the TAP time to settle
+                        */
+                       if (jtag_ntrst_delay)
+                               jtag_add_sleep(jtag_ntrst_delay * 1000);
+               }
        }
 
        return ERROR_OK;
@@ -903,7 +952,7 @@ int jtag_scan_size(scan_command_t *cmd)
        int i;
 
        /* count bits in scan command */
-       for (i=0; i<cmd->num_fields; i++)
+       for (i = 0; i < cmd->num_fields; i++)
        {
                bit_count += cmd->fields[i].num_bits;
        }
@@ -925,12 +974,14 @@ int jtag_build_buffer(scan_command_t *cmd, u8 **buffer)
        {
                if (cmd->fields[i].out_value)
                {
-                       char* char_buf = buf_to_char(cmd->fields[i].out_value, cmd->fields[i].num_bits);
-                       buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits);
 #ifdef _DEBUG_JTAG_IO_
-                       DEBUG("fields[%i].out_value: %s", i, char_buf);
+                       char* char_buf = buf_to_str(cmd->fields[i].out_value, (cmd->fields[i].num_bits > 64) ? 64 : cmd->fields[i].num_bits, 16);
 #endif
+                       buf_set_buf(cmd->fields[i].out_value, 0, *buffer, bit_count, cmd->fields[i].num_bits);
+#ifdef _DEBUG_JTAG_IO_
+                       DEBUG("fields[%i].out_value: 0x%s", i, char_buf);
                        free(char_buf);
+#endif
                }
                
                bit_count += cmd->fields[i].num_bits;
@@ -940,57 +991,80 @@ int jtag_build_buffer(scan_command_t *cmd, u8 **buffer)
 
 }
 
+extern int jtag_check_value(u8 *captured, void *priv);
+
 int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
 {
        int i;
        int bit_count = 0;
-       int retval = ERROR_OK;
-
-       for (i=0; i < cmd->num_fields; i++)
+       int retval;
+       
+       /* we return ERROR_OK, unless a check fails, or a handler reports a problem */
+       retval = ERROR_OK;
+       
+       for (i = 0; i < cmd->num_fields; i++)
        {
-               /* if neither in_value nor in_check_value are specified we don't have to examine this field */
-               if (cmd->fields[i].in_value || cmd->fields[i].in_check_value)
+               /* if neither in_value nor in_handler
+                * are specified we don't have to examine this field
+                */
+               if (cmd->fields[i].in_value || cmd->fields[i].in_handler)
                {
                        int num_bits = cmd->fields[i].num_bits;
+                       u8 *captured = buf_set_buf(buffer, bit_count, malloc(CEIL(num_bits, 8)), 0, num_bits);
+                       
+#ifdef _DEBUG_JTAG_IO_
+                       char *char_buf;
 
+                       char_buf = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16);
+                       DEBUG("fields[%i].in_value: 0x%s", i, char_buf);
+                       free(char_buf);
+#endif
+                       
+                       void *priv = cmd->fields[i].in_handler_priv;
+                       if (cmd->fields[i].in_handler == &jtag_check_value)
+                       {
+                               /* Yuk! we want to pass in the pointer to cmd->fields[i] which is not known
+                                * when jtag_check_value is invoked
+                                * 
+                                * Not pretty, but this is part of synthesizing check_mask via in_handler
+                                * with a minimum of code impact.
+                                * 
+                                * A cleaner change would be to modify the in_handler to always take field 
+                                * as an argument. Perhaps later...
+                                * 
+                                * Change in_handler to be varargs and have fields+i as the first vararg?
+                                * 
+                                */
+                               priv = cmd->fields + i;
+                       }
                        if (cmd->fields[i].in_value)
                        {
-                               char *char_buf;
-                               buf_set_buf(buffer, bit_count, cmd->fields[i].in_value, 0, num_bits);
-                               char_buf = buf_to_char(cmd->fields[i].in_value, num_bits);
-#ifdef _DEBUG_JTAG_IO_
-                               DEBUG("fields[%i].in_value: %s", i, char_buf);
-#endif
-                               free(char_buf);
+                               buf_cpy(captured, cmd->fields[i].in_value, num_bits);
+                               
                                if (cmd->fields[i].in_handler)
                                {
-                                       if (cmd->fields[i].in_handler(cmd->fields[i].in_value, cmd->fields[i].in_handler_priv) != ERROR_OK)
+                                       if (cmd->fields[i].in_handler(cmd->fields[i].in_value, priv) != ERROR_OK)
                                        {
-                                               /* TODO: error reporting */
                                                WARNING("in_handler reported a failed check");
                                                retval = ERROR_JTAG_QUEUE_FAILED;
                                        }
                                }
                        }
-
-                       if (cmd->fields[i].in_check_value)
+                       
+                       /* no in_value specified, but a handler takes care of the scanned data */
+                       if (cmd->fields[i].in_handler && (!cmd->fields[i].in_value))
                        {
-                               u8 *captured = buf_set_buf(buffer, bit_count, malloc(CEIL(num_bits, 8)), 0, num_bits);
-                               if ((cmd->fields[i].in_check_mask && buf_cmp_mask(captured, cmd->fields[i].in_check_value, cmd->fields[i].in_check_mask, num_bits))
-                                       || (!cmd->fields[i].in_check_mask && buf_cmp(captured, cmd->fields[i].in_check_mask, num_bits)))
+                               if (cmd->fields[i].in_handler(captured, priv) != ERROR_OK)
                                {
-                                       char *captured_char = buf_to_char(captured, num_bits);
-                                       char *in_check_value_char = buf_to_char(cmd->fields[i].in_check_value, num_bits);
-                                       char *in_check_mask_char = buf_to_char(cmd->fields[i].in_check_mask, num_bits);
-                                       /* TODO: error reporting */
-                                       WARNING("value captured during scan didn't pass the requested check: captured: %s check_value: %s check_mask: %s", captured_char, in_check_value_char, in_check_mask_char);
+                                       /* We're going to call the error:handler later, but if the in_handler
+                                        * reported an error we report this failure upstream
+                                        */
+                                       WARNING("in_handler reported a failed check");
                                        retval = ERROR_JTAG_QUEUE_FAILED;
-                                       free(captured_char);
-                                       free(in_check_value_char);
-                                       free(in_check_mask_char);
                                }
-                               free(captured);
                        }
+
+                       free(captured);
                }
                bit_count += cmd->fields[i].num_bits;
        }
@@ -998,14 +1072,91 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
        return retval;
 }
 
+int jtag_check_value(u8 *captured, void *priv)
+{
+       int retval = ERROR_OK;
+       scan_field_t *field=(scan_field_t *)priv;
+       int num_bits = field->num_bits;
+       
+       int compare_failed = 0;
+       
+       if (field->in_check_mask)
+               compare_failed = buf_cmp_mask(captured, field->in_check_value, field->in_check_mask, num_bits);
+       else
+               compare_failed = buf_cmp(captured, field->in_check_value, num_bits);
+       
+       if (compare_failed)
+       {
+               if (field->in_handler_error_handler.error_handler)
+               {
+                       /* ask the error handler if once has been specified if this is a real problem */ 
+                       if (field->in_handler_error_handler.error_handler(captured, field->in_handler_error_handler.error_handler_priv) != ERROR_OK)
+                               retval = ERROR_JTAG_QUEUE_FAILED;
+                       else
+                               compare_failed = 0;
+               }
+               else
+               {
+                       /* if there wasn't a handler specified, we report a failure */
+                       retval = ERROR_JTAG_QUEUE_FAILED;
+               }
+               
+               /* An error handler could have caught the failing check
+                * only report a problem when there wasn't a handler, or if the handler
+                * acknowledged the error
+                */ 
+               if (compare_failed)
+               {
+                       char *captured_char = buf_to_str(captured, (num_bits > 64) ? 64 : num_bits, 16);
+                       char *in_check_value_char = buf_to_str(field->in_check_value, (num_bits > 64) ? 64 : num_bits, 16);
+
+                       if (field->in_check_mask)
+                       {
+                               char *in_check_mask_char;
+                               in_check_mask_char = buf_to_str(field->in_check_mask, (num_bits > 64) ? 64 : num_bits, 16);
+                               WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s check_mask: 0x%s", captured_char, in_check_value_char, in_check_mask_char);
+                               free(in_check_mask_char);
+                       }
+                       else
+                       {
+                               WARNING("value captured during scan didn't pass the requested check: captured: 0x%s check_value: 0x%s", captured_char, in_check_value_char);
+                       }
+
+                       free(captured_char);
+                       free(in_check_value_char);
+               }
+               
+       }
+       return retval;
+}
+
+/* 
+  set up checking of this field using the in_handler. The values passed in must be valid until
+  after jtag_execute() has completed.
+ */
+void jtag_set_check_value(scan_field_t *field, u8 *value, u8 *mask, error_handler_t *in_error_handler)
+{
+       if (value)
+               field->in_handler = jtag_check_value;
+       else
+               field->in_handler = NULL;       /* No check, e.g. embeddedice uses value==NULL to indicate no check */
+       field->in_handler_priv = NULL;  /* this will be filled in at the invocation site to point to the field duplicate */ 
+       field->in_check_value = value;
+       field->in_check_mask = mask;
+       if (in_error_handler)
+               field->in_handler_error_handler = *in_error_handler;
+       else
+               field->in_handler_error_handler.error_handler = NULL;
+}
+
 enum scan_type jtag_scan_type(scan_command_t *cmd)
 {
        int i;
        int type = 0;
        
-       for (i=0; i < cmd->num_fields; i++)
+       for (i = 0; i < cmd->num_fields; i++)
        {
-               if (cmd->fields[i].in_check_value || cmd->fields[i].in_value)
+               if (cmd->fields[i].in_value || cmd->fields[i].in_handler)
                        type |= SCAN_IN;
                if (cmd->fields[i].out_value)
                        type |= SCAN_OUT;
@@ -1041,7 +1192,7 @@ int jtag_reset_callback(enum jtag_event event, void *priv)
 {
        jtag_device_t *device = priv;
 
-       DEBUG("");
+       DEBUG("-");
        
        if (event == JTAG_TRST_ASSERTED)
        {
@@ -1057,6 +1208,102 @@ void jtag_sleep(u32 us)
        usleep(us);
 }
 
+/* Try to examine chain layout according to IEEE 1149.1 ยง12
+ */
+int jtag_examine_chain()
+{
+       jtag_device_t *device = jtag_devices;
+       scan_field_t field;
+       u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
+       int i;
+       int bit_count;
+       int device_count = 0;
+       u8 zero_check = 0x0;
+       u8 one_check = 0xff;
+       
+       field.device = 0;
+       field.num_bits = sizeof(idcode_buffer) * 8;
+       field.out_value = idcode_buffer;
+       field.out_mask = NULL;
+       field.in_value = idcode_buffer;
+       field.in_check_value = NULL;
+       field.in_check_mask = NULL;
+       field.in_handler = NULL;
+       field.in_handler_priv = NULL;
+       
+       for (i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
+       {
+               buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF);
+       }
+       
+       jtag_add_plain_dr_scan(1, &field, TAP_TLR, NULL);
+       jtag_execute_queue();
+       
+       for (i = 0; i < JTAG_MAX_CHAIN_SIZE * 4; i++)
+       {
+               zero_check |= idcode_buffer[i];
+               one_check &= idcode_buffer[i];
+       }
+       
+       /* if there wasn't a single non-zero bit or if all bits were one, the scan isn't valid */
+       if ((zero_check == 0x00) || (one_check == 0xff))
+       {
+               ERROR("JTAG communication failure, check connection, JTAG interface, target power etc.");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       for (bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
+       {
+               u32 idcode = buf_get_u32(idcode_buffer, bit_count, 32);
+               if ((idcode & 1) == 0)
+               {
+                       /* LSB must not be 0, this indicates a device in bypass */
+                       device_count++;
+                       
+                       bit_count += 1;
+               }
+               else
+               {
+                       u32 manufacturer;
+                       u32 part;
+                       u32 version;
+                       
+                       if (idcode == 0x000000FF)
+                       {
+                               /* End of chain (invalid manufacturer ID) */
+                               break;
+                       }
+                       
+                       if (device)
+                       {
+                               device->idcode = idcode;
+                               device = device->next;
+                       }
+                       device_count++;
+                       
+                       manufacturer = (idcode & 0xffe) >> 1;
+                       part = (idcode & 0xffff000) >> 12;
+                       version = (idcode & 0xf0000000) >> 28;
+
+                       INFO("JTAG device found: 0x%8.8x (Manufacturer: 0x%3.3x, Part: 0x%4.4x, Version: 0x%1.1x)", 
+                               idcode, manufacturer, part, version);
+                       
+                       bit_count += 32;
+               }
+       }
+       
+       /* see if number of discovered devices matches configuration */
+       if (device_count != jtag_num_devices)
+       {
+               ERROR("number of discovered devices in JTAG chain (%i) doesn't match configuration (%i)", 
+                       device_count, jtag_num_devices);
+               ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)");
+               return ERROR_JTAG_INIT_FAILED;
+       }
+       
+       return ERROR_OK;
+}
+
 int jtag_validate_chain()
 {
        jtag_device_t *device = jtag_devices;
@@ -1085,7 +1332,7 @@ int jtag_validate_chain()
        field.in_handler = NULL;
        field.in_handler_priv = NULL;
        
-       jtag_add_plain_ir_scan(1, &field, TAP_TLR);
+       jtag_add_plain_ir_scan(1, &field, TAP_TLR, NULL);
        jtag_execute_queue();
        
        device = jtag_devices;
@@ -1093,8 +1340,11 @@ int jtag_validate_chain()
        {
                if (buf_get_u32(ir_test, chain_pos, 2) != 0x1)
                {
-                       ERROR("Error validating JTAG scan chain, IR mismatch");
-                       exit(-1);
+                       char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
+                       ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf);
+                       free(cbuf);
+                       free(ir_test);
+                       return ERROR_JTAG_INIT_FAILED;
                }
                chain_pos += device->ir_length;
                device = device->next;
@@ -1102,8 +1352,11 @@ int jtag_validate_chain()
        
        if (buf_get_u32(ir_test, chain_pos, 2) != 0x3)
        {
-               ERROR("Error validating JTAG scan chain, IR mismatch");
-               exit(-1);
+               char *cbuf = buf_to_str(ir_test, total_ir_length, 16);
+               ERROR("Error validating JTAG scan chain, IR mismatch, scan returned 0x%s", cbuf);
+               free(cbuf);
+               free(ir_test);
+               return ERROR_JTAG_INIT_FAILED;
        }
        
        free(ir_test);
@@ -1121,7 +1374,11 @@ int jtag_register_commands(struct command_context_s *cmd_ctx)
                COMMAND_CONFIG, NULL);
        register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command,
                COMMAND_CONFIG, NULL);
-
+       register_command(cmd_ctx, NULL, "jtag_nsrst_delay", handle_jtag_nsrst_delay_command,
+               COMMAND_CONFIG, NULL);
+       register_command(cmd_ctx, NULL, "jtag_ntrst_delay", handle_jtag_ntrst_delay_command,
+               COMMAND_CONFIG, NULL);
+               
        register_command(cmd_ctx, NULL, "scan_chain", handle_scan_chain_command,
                COMMAND_EXEC, "print current scan chain configuration");
 
@@ -1145,9 +1402,9 @@ int jtag_register_commands(struct command_context_s *cmd_ctx)
 
 int jtag_init(struct command_context_s *cmd_ctx)
 {
-       int i;
+       int i, validate_tries = 0;
        
-       DEBUG("");
+       DEBUG("-");
 
        if (jtag_speed == -1)
                jtag_speed = 0;
@@ -1176,9 +1433,25 @@ int jtag_init(struct command_context_s *cmd_ctx)
                                
                                jtag_add_statemove(TAP_TLR);
                                jtag_execute_queue();
+
+                               /* examine chain first, as this could discover the real chain layout */
+                               if (jtag_examine_chain() != ERROR_OK)
+                               {
+                                       ERROR("trying to validate configured JTAG chain anyway...");
+                               }
                                
-                               jtag_validate_chain();
-                               
+                               while (jtag_validate_chain() != ERROR_OK)
+                               {
+                                       validate_tries++;
+                                       if (validate_tries > 5)
+                                       {
+                                               ERROR("Could not validate JTAG chain, exit");
+                                               jtag = NULL;
+                                               return ERROR_JTAG_INVALID_INTERFACE;
+                                       }
+                                       usleep(10000);
+                               }
+
                                return ERROR_OK;
                        }
                }
@@ -1187,6 +1460,12 @@ int jtag_init(struct command_context_s *cmd_ctx)
         * didn't match one of the compiled-in interfaces
         */
        ERROR("No valid jtag interface found (%s)", jtag_interface);
+       ERROR("compiled-in jtag interfaces:");
+       for (i = 0; jtag_interfaces[i]; i++)
+       {
+               ERROR("%i: %s", i, jtag_interfaces[i]->name);
+       }
+       
        jtag = NULL;
        return ERROR_JTAG_INVALID_INTERFACE;
 }
@@ -1290,8 +1569,9 @@ int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, ch
                        jtag_reset_config = RESET_TRST_AND_SRST;
                else
                {
-                       ERROR("invalid reset_config argument");
-                       exit(-1);
+                       ERROR("invalid reset_config argument, defaulting to none");
+                       jtag_reset_config = RESET_NONE;
+                       return ERROR_INVALID_ARGUMENTS;
                }
        }
        
@@ -1307,8 +1587,9 @@ int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, ch
                        jtag_reset_config &= ~(RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST);
                else
                {
-                       ERROR("invalid reset_config argument");
-                       exit(-1);
+                       ERROR("invalid reset_config argument, defaulting to none");
+                       jtag_reset_config = RESET_NONE;
+                       return ERROR_INVALID_ARGUMENTS;
                }
        }
        
@@ -1320,8 +1601,9 @@ int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, ch
                        jtag_reset_config &= ~RESET_TRST_OPEN_DRAIN;
                else
                {
-                       ERROR("invalid reset_config argument");
-                       exit(-1);
+                       ERROR("invalid reset_config argument, defaulting to none");
+                       jtag_reset_config = RESET_NONE;
+                       return ERROR_INVALID_ARGUMENTS;
                }
        }
 
@@ -1333,14 +1615,45 @@ int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, ch
                        jtag_reset_config &= ~RESET_SRST_PUSH_PULL;
                else
                {
-                       ERROR("invalid reset_config argument");
-                       exit(-1);
+                       ERROR("invalid reset_config argument, defaulting to none");
+                       jtag_reset_config = RESET_NONE;
+                       return ERROR_INVALID_ARGUMENTS;
                }
        }
        
        return ERROR_OK;
 }
 
+int handle_jtag_nsrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       if (argc < 1)
+       {
+               ERROR("jtag_nsrst_delay <ms> command takes one required argument");
+               exit(-1);
+       }
+       else
+       {
+               jtag_nsrst_delay = strtoul(args[0], NULL, 0);
+       }
+       
+       return ERROR_OK;
+}
+
+int handle_jtag_ntrst_delay_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       if (argc < 1)
+       {
+               ERROR("jtag_ntrst_delay <ms> command takes one required argument");
+               exit(-1);
+       }
+       else
+       {
+               jtag_ntrst_delay = strtoul(args[0], NULL, 0);
+       }
+       
+       return ERROR_OK;
+}
+
 int handle_jtag_speed_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
 {
        if (argc == 0)
@@ -1366,17 +1679,19 @@ int handle_endstate_command(struct command_context_s *cmd_ctx, char *cmd, char *
        if (argc < 1)
        {
                command_print(cmd_ctx, "usage: endstate <tap_state>");
-               return ERROR_OK;
        }
-
-       for (state = 0; state < 16; state++)
+       else
        {
-               if (strcmp(args[0], tap_state_strings[state]) == 0)
+               for (state = 0; state < 16; state++)
                {
-                       jtag_add_end_state(state);
-                       jtag_execute_queue();
+                       if (strcmp(args[0], tap_state_strings[state]) == 0)
+                       {
+                               jtag_add_end_state(state);
+                               jtag_execute_queue();
+                       }
                }
        }
+       command_print(cmd_ctx, "current endstate: %s", tap_state_strings[end_state]);
        
        return ERROR_OK;
 }
@@ -1498,7 +1813,7 @@ int handle_irscan_command(struct command_context_s *cmd_ctx, char *cmd, char **a
                fields[i].in_handler_priv = NULL;
        }
 
-       jtag_add_ir_scan(argc / 2, fields, -1);
+       jtag_add_ir_scan(argc / 2, fields, -1, NULL);
        jtag_execute_queue();
 
        for (i = 0; i < argc / 2; i++)
@@ -1558,7 +1873,7 @@ int handle_drscan_command(struct command_context_s *cmd_ctx, char *cmd, char **a
                }
        }
 
-       jtag_add_dr_scan(num_fields, fields, -1);
+       jtag_add_dr_scan(num_fields, fields, -1, NULL);
        jtag_execute_queue();
        
        for (i = 0; i < argc / 2; i++)

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)