- renamed M5960 USB JTAG to "flyswatter"
[fw/openocd] / src / jtag / jtag.c
index a3e8cff8dba11eb9703b0995979e7d69935dfc15..bac1b39eeb07dd1d20fb3a82b633da3a13536536 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] =
 {
@@ -160,6 +162,14 @@ jtag_event_callback_t *jtag_event_callbacks;
        extern jtag_interface_t gw16012_interface;
 #endif
 
+#if BUILD_PRESTO == 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,
@@ -181,6 +191,12 @@ jtag_interface_t *jtag_interfaces[] = {
 #endif
 #if BUILD_GW16012 == 1
        &gw16012_interface,
+#endif
+#if BUILD_PRESTO == 1
+       &presto_interface,
+#endif
+#if BUILD_USBPROG == 1
+       &usbprog_interface,
 #endif
        NULL,
 };
@@ -191,11 +207,12 @@ jtag_interface_t *jtag = NULL;
 char* jtag_interface = NULL;
 int jtag_speed = -1;
 
+
 /* forward declarations */
-int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
-int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
-int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
-int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate);
+int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate, error_handler_t *error_handler);
+int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate, error_handler_t *error_handler);
+int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state endstate, error_handler_t *error_handler);
+int jtag_add_plain_dr_scan(int num_fields, scan_field_t *fields, enum tap_state endstate, error_handler_t *error_handler);
 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);
@@ -364,13 +381,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, error_handler_t *error_handler)
 {
        jtag_command_t **last_cmd;
        jtag_device_t *device;
        int i, j;
        int scan_size = 0;
-       /*      int changed = 0; */
 
        if (jtag_trst == 1)
        {
@@ -378,26 +394,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 */
@@ -412,7 +408,16 @@ 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 (error_handler)
+       {
+               (*last_cmd)->cmd.scan->error_handler = cmd_queue_alloc(sizeof(error_handler_t));
+               *(*last_cmd)->cmd.scan->error_handler = *error_handler;
+       }
+       else
+       {
+               (*last_cmd)->cmd.scan->error_handler = NULL;
+       }
+               
        if (state != -1)
                cmd_queue_end_state = state;
 
@@ -441,7 +446,7 @@ int jtag_add_ir_scan(int num_fields, scan_field_t *fields, enum tap_state state)
                {
                        (*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;
 
@@ -475,7 +480,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, error_handler_t *error_handler)
 {
        jtag_command_t **last_cmd;
        int i;
@@ -500,6 +505,15 @@ int jtag_add_plain_ir_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 (error_handler)
+       {
+               (*last_cmd)->cmd.scan->error_handler = cmd_queue_alloc(sizeof(error_handler_t));
+               *(*last_cmd)->cmd.scan->error_handler = *error_handler;
+       }
+       else
+       {
+               (*last_cmd)->cmd.scan->error_handler = NULL;
+       }
 
        if (state != -1)
                cmd_queue_end_state = state;
@@ -529,7 +543,7 @@ int jtag_add_plain_ir_scan(int num_fields, scan_field_t *fields, enum tap_state
        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, error_handler_t *error_handler)
 {
        int i, j;
        int bypass_devices = 0;
@@ -564,7 +578,16 @@ 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 (error_handler)
+       {
+               (*last_cmd)->cmd.scan->error_handler = cmd_queue_alloc(sizeof(error_handler_t));
+               *(*last_cmd)->cmd.scan->error_handler = *error_handler;
+       }
+       else
+       {
+               (*last_cmd)->cmd.scan->error_handler = NULL;
+       }
+       
        if (state != -1)
                cmd_queue_end_state = state;
 
@@ -628,7 +651,7 @@ int jtag_add_dr_scan(int num_fields, scan_field_t *fields, enum tap_state state)
        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, error_handler_t *error_handler)
 {
        int i;
        jtag_command_t **last_cmd = jtag_get_last_command_p();
@@ -651,7 +674,16 @@ 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 (error_handler)
+       {
+               (*last_cmd)->cmd.scan->error_handler = cmd_queue_alloc(sizeof(error_handler_t));
+               *(*last_cmd)->cmd.scan->error_handler = *error_handler;
+       }
+       else
+       {
+               (*last_cmd)->cmd.scan->error_handler = NULL;
+       }
+               
        if (state != -1)
                cmd_queue_end_state = state;
 
@@ -1009,8 +1041,11 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
 {
        int i;
        int bit_count = 0;
-       int retval = ERROR_OK;
-
+       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, in_check_value nor in_handler
@@ -1020,6 +1055,7 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
                {
                        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;
 
@@ -1027,7 +1063,6 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
                                DEBUG("fields[%i].in_value: 0x%s", i, char_buf);
                                free(char_buf);
                        #endif
-
                        
                        if (cmd->fields[i].in_value)
                        {
@@ -1037,7 +1072,6 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
                                {
                                        if (cmd->fields[i].in_handler(cmd->fields[i].in_value, cmd->fields[i].in_handler_priv) != ERROR_OK)
                                        {
-                                               /* TODO: error reporting */
                                                WARNING("in_handler reported a failed check");
                                                retval = ERROR_JTAG_QUEUE_FAILED;
                                        }
@@ -1049,27 +1083,64 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd)
                        {
                                if (cmd->fields[i].in_handler(captured, cmd->fields[i].in_handler_priv) != ERROR_OK)
                                {
-                                       /* TODO: error reporting */
+                                       /* 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;
                                }
-                               
                        }
 
                        if (cmd->fields[i].in_check_value)
                        {
-                               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)))
+                               int compare_failed = 0;
+                               
+                               if (cmd->fields[i].in_check_mask)
+                                       compare_failed = buf_cmp_mask(captured, cmd->fields[i].in_check_value, cmd->fields[i].in_check_mask, num_bits);
+                               else
+                                       compare_failed = buf_cmp(captured, cmd->fields[i].in_check_value, num_bits);
+                               
+                               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(cmd->fields[i].in_check_value, (num_bits > 64) ? 64 : num_bits, 16);
-                                       char *in_check_mask_char = buf_to_str(cmd->fields[i].in_check_mask, (num_bits > 64) ? 64 : num_bits, 16);
-                                       /* TODO: error reporting */
-                                       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);
-                                       retval = ERROR_JTAG_QUEUE_FAILED;
-                                       free(captured_char);
-                                       free(in_check_value_char);
-                                       free(in_check_mask_char);
+                                       if (cmd->error_handler)
+                                       {
+                                               /* ask the error handler if once has been specified if this is a real problem */ 
+                                               if (cmd->error_handler->error_handler(captured, cmd->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(cmd->fields[i].in_check_value, (num_bits > 64) ? 64 : num_bits, 16);
+
+                                               if (cmd->fields[i].in_check_mask)
+                                               {
+                                                       char *in_check_mask_char;
+                                                       in_check_mask_char = buf_to_str(cmd->fields[i].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);
+                                       }
+                                       
                                }
                        }
                        free(captured);
@@ -1123,7 +1194,7 @@ int jtag_reset_callback(enum jtag_event event, void *priv)
 {
        jtag_device_t *device = priv;
 
-       DEBUG("");
+       DEBUG("-");
        
        if (event == JTAG_TRST_ASSERTED)
        {
@@ -1143,6 +1214,7 @@ void jtag_sleep(u32 us)
  */
 int jtag_examine_chain()
 {
+       jtag_device_t *device = jtag_devices;
        scan_field_t field;
        u8 idcode_buffer[JTAG_MAX_CHAIN_SIZE * 4];
        int i;
@@ -1163,10 +1235,10 @@ int jtag_examine_chain()
        
        for (i = 0; i < JTAG_MAX_CHAIN_SIZE; i++)
        {
-               buf_set_u32(idcode_buffer, 0, 32, 0x000000FF);
+               buf_set_u32(idcode_buffer, i * 32, 32, 0x000000FF);
        }
        
-       jtag_add_plain_dr_scan(1, &field, TAP_TLR);
+       jtag_add_plain_dr_scan(1, &field, TAP_TLR, NULL);
        jtag_execute_queue();
        
        for (i = 0; i < JTAG_MAX_CHAIN_SIZE * 4; i++)
@@ -1179,7 +1251,7 @@ int jtag_examine_chain()
        if ((zero_check == 0x00) || (one_check == 0xff))
        {
                ERROR("JTAG communication failure, check connection, JTAG interface, target power etc.");
-               exit(-1);
+               return ERROR_JTAG_INIT_FAILED;
        }
        
        for (bit_count = 0; bit_count < (JTAG_MAX_CHAIN_SIZE * 32) - 31;)
@@ -1204,6 +1276,11 @@ int jtag_examine_chain()
                                break;
                        }
                        
+                       if (device)
+                       {
+                               device->idcode = idcode;
+                               device = device->next;
+                       }
                        device_count++;
                        
                        manufacturer = (idcode & 0xffe) >> 1;
@@ -1222,7 +1299,8 @@ int jtag_examine_chain()
        {
                ERROR("number of discovered devices in JTAG chain (%i) doesn't match configuration (%i)", 
                        device_count, jtag_num_devices);
-               exit(-1);
+               ERROR("check the config file and ensure proper JTAG communication (connections, speed, ...)");
+               return ERROR_JTAG_INIT_FAILED;
        }
        
        return ERROR_OK;
@@ -1256,7 +1334,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;
@@ -1267,7 +1345,7 @@ int jtag_validate_chain()
                        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);
-                       exit(-1);
+                       return ERROR_JTAG_INIT_FAILED;
                }
                chain_pos += device->ir_length;
                device = device->next;
@@ -1278,7 +1356,7 @@ int jtag_validate_chain()
                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);
-               exit(-1);
+               return ERROR_JTAG_INIT_FAILED;
        }
        
        free(ir_test);
@@ -1324,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;
@@ -1355,11 +1433,24 @@ 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_examine_chain();
-                               
-                               jtag_validate_chain();
-                               
+                               while (jtag_validate_chain() != ERROR_OK)
+                               {
+                                       validate_tries++;
+                                       if (validate_tries > 5)
+                                       {
+                                               ERROR("Could not validate JTAG chain, exit");
+                                               exit(-1);
+                                       }
+                                       usleep(10000);
+                               }
+
                                return ERROR_OK;
                        }
                }
@@ -1583,17 +1674,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;
 }
@@ -1715,7 +1808,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++)
@@ -1775,7 +1868,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++)