X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Fjtag%2Fjtag.c;h=303b43416629b1fdd349cac40c1d7ce73243c70c;hb=35082f788b457b8f5fde9943d9b4246592f29c1d;hp=33205bd81a1bbf4fd7a0d35a0714b422d3877e74;hpb=044e3a4904c75f95819303190845511beb16ee90;p=openocd.git diff --git a/src/jtag/jtag.c b/src/jtag/jtag.c index 33205bd81a..303b434166 100644 --- a/src/jtag/jtag.c +++ b/src/jtag/jtag.c @@ -28,6 +28,7 @@ #include "config.h" #endif +#define INCLUDE_JTAG_MINIDRIVER_H #include "jtag.h" #ifdef HAVE_STRINGS_H @@ -37,7 +38,7 @@ int jtag_flush_queue_count; /* count # of flushes for profiling / debugging purposes */ -static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, scan_field_t *in_fields, tap_state_t state), +static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const scan_field_t *in_fields, tap_state_t state), int in_num_fields, scan_field_t *in_fields, tap_state_t state); /* note that this is not marked as static as it must be available from outside jtag.c for those @@ -227,7 +228,7 @@ jtag_interface_t *jtag_interfaces[] = { NULL, }; -jtag_interface_t *jtag = NULL; +static jtag_interface_t *jtag = NULL; /* configuration */ static jtag_interface_t *jtag_interface = NULL; @@ -531,6 +532,20 @@ void cmd_queue_free(void) cmd_queue_pages = NULL; } +/** + * Copy a scan_field_t for insertion into the queue. + * + * This allocates a new copy of out_value using cmd_queue_alloc. + */ +static void cmd_queue_scan_field_clone(scan_field_t * dst, const scan_field_t * src) +{ + dst->tap = src->tap; + dst->num_bits = src->num_bits; + dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(CEIL(src->num_bits, 8)), src->num_bits); + dst->in_value = src->in_value; +} + + static void jtag_prelude1(void) { if (jtag_trst == 1) @@ -554,7 +569,7 @@ static void jtag_prelude(tap_state_t state) cmd_queue_cur_state = cmd_queue_end_state; } -void jtag_add_ir_scan_noverify(int in_num_fields, scan_field_t *in_fields, tap_state_t state) +void jtag_add_ir_scan_noverify(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) { int retval; jtag_prelude(state); @@ -566,6 +581,15 @@ void jtag_add_ir_scan_noverify(int in_num_fields, scan_field_t *in_fields, tap_s } +/** + * Generate an IR SCAN with a list of scan fields with one entry for each enabled TAP. + * + * If the input field list contains an instruction value for a TAP then that is used + * otherwise the TAP is set to bypass. + * + * TAPs for which no fields are passed are marked as bypassed for subsequent DR SCANs. + * + */ void jtag_add_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t state) { if (jtag_verify&&jtag_verify_capture_ir) @@ -590,21 +614,16 @@ void jtag_add_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t st } /** - * Generate a list of scan fields with one entry for each TAP. - * - * If the input field list contains an instruction value for a TAP then that is used - * otherwise the TAP is set to bypass. + * see jtag_add_ir_scan() * */ -int MINIDRIVER(interface_jtag_add_ir_scan)(int in_num_fields, scan_field_t *in_fields, tap_state_t state) +int MINIDRIVER(interface_jtag_add_ir_scan)(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) { - jtag_tap_t *tap; - int nth_tap; - - int num_taps = jtag_NumEnabledTaps(); + size_t num_taps = jtag_NumEnabledTaps(); - jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - scan_command_t * scan = cmd_queue_alloc(sizeof(scan_command_t)); + jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + scan_command_t * scan = cmd_queue_alloc(sizeof(scan_command_t)); + scan_field_t * out_fields = cmd_queue_alloc(num_taps * sizeof(scan_field_t)); jtag_queue_command(cmd); @@ -613,59 +632,68 @@ int MINIDRIVER(interface_jtag_add_ir_scan)(int in_num_fields, scan_field_t *in_f scan->ir_scan = true; scan->num_fields = num_taps; /* one field per device */ - scan->fields = cmd_queue_alloc(num_taps * sizeof(scan_field_t)); + scan->fields = out_fields; scan->end_state = state; - nth_tap = -1; - tap = NULL; - for(;;){ - int found = 0; - /* do this here so it is not forgotten */ - tap = jtag_NextEnabledTap(tap); - if( tap == NULL ){ - break; - } - nth_tap++; + scan_field_t * field = out_fields; /* keep track where we insert data */ - assert(nth_tap < num_taps); + /* loop over all enabled TAPs */ - size_t scan_size = tap->ir_length; - scan->fields[nth_tap].tap = tap; - scan->fields[nth_tap].num_bits = scan_size; - scan->fields[nth_tap].in_value = NULL; /* do not collect input for tap's in bypass */ + for (jtag_tap_t * tap = jtag_NextEnabledTap(NULL); tap != NULL; tap = jtag_NextEnabledTap(tap)) + { + /* search the input field list for fields for the current TAP */ + + bool found = false; - /* search the list */ for (int j = 0; j < in_num_fields; j++) { - if (tap == in_fields[j].tap) - { - found = 1; - scan->fields[nth_tap].in_value = in_fields[j].in_value; - scan->fields[nth_tap].out_value = buf_cpy(in_fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + if (tap != in_fields[j].tap) + continue; - tap->bypass = 0; - break; - } + /* if TAP is listed in input fields, copy the value */ + + found = true; + + tap->bypass = 0; + + assert(in_fields[j].num_bits == tap->ir_length); /* input fields must have the same length as the TAP's IR */ + + cmd_queue_scan_field_clone(field, in_fields + j); + + break; } if (!found) { - /* if a tap isn't listed, set it to BYPASS */ - scan->fields[nth_tap].out_value = buf_set_ones(cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + /* if a TAP isn't listed in input fields, set it to BYPASS */ + tap->bypass = 1; + + field->tap = tap; + field->num_bits = tap->ir_length; + field->out_value = buf_set_ones(cmd_queue_alloc(CEIL(tap->ir_length, 8)), tap->ir_length); + field->in_value = NULL; /* do not collect input for tap's in bypass */ } /* update device information */ - buf_cpy(scan->fields[nth_tap].out_value, tap->cur_instr, scan_size); + buf_cpy(field->out_value, tap->cur_instr, tap->ir_length); + + field++; } - assert(nth_tap == (num_taps - 1)); + assert(field == out_fields + num_taps); /* paranoia: jtag_NumEnabledTaps() and jtag_NextEnabledTap() not in sync */ return ERROR_OK; } -void jtag_add_plain_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t state) +/** + * Duplicate the scan fields passed into the function into an IR SCAN command + * + * This function assumes that the caller handles extra fields for bypassed TAPs + * + */ +void jtag_add_plain_ir_scan(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) { int retval; @@ -676,11 +704,17 @@ void jtag_add_plain_ir_scan(int in_num_fields, scan_field_t *in_fields, tap_stat jtag_error=retval; } -int MINIDRIVER(interface_jtag_add_plain_ir_scan)(int in_num_fields, scan_field_t *in_fields, tap_state_t state) + +/** + * see jtag_add_plain_ir_scan() + * + */ +int MINIDRIVER(interface_jtag_add_plain_ir_scan)(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) { - jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); - scan_command_t * scan = cmd_queue_alloc(sizeof(scan_command_t)); + jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + scan_command_t * scan = cmd_queue_alloc(sizeof(scan_command_t)); + scan_field_t * out_fields = cmd_queue_alloc(in_num_fields * sizeof(scan_field_t)); jtag_queue_command(cmd); @@ -689,32 +723,15 @@ int MINIDRIVER(interface_jtag_add_plain_ir_scan)(int in_num_fields, scan_field_t scan->ir_scan = true; scan->num_fields = in_num_fields; - scan->fields = cmd_queue_alloc(in_num_fields * sizeof(scan_field_t)); + scan->fields = out_fields; scan->end_state = state; for (int i = 0; i < in_num_fields; i++) - { - int num_bits = in_fields[i].num_bits; - int num_bytes = CEIL(in_fields[i].num_bits, 8); - scan->fields[i].tap = in_fields[i].tap; - scan->fields[i].num_bits = num_bits; - scan->fields[i].out_value = buf_cpy(in_fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits); - scan->fields[i].in_value = in_fields[i].in_value; - } + cmd_queue_scan_field_clone(out_fields + i, in_fields + i); return ERROR_OK; } -void jtag_add_dr_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t state) -{ - int retval; - - jtag_prelude(state); - - retval=interface_jtag_add_dr_scan(in_num_fields, in_fields, cmd_queue_end_state); - if (retval!=ERROR_OK) - jtag_error=retval; -} int jtag_check_value_inner(u8 *captured, u8 *in_check_value, u8 *in_check_mask, int num_bits); @@ -724,7 +741,7 @@ static int jtag_check_value_mask_callback(u8 *in, jtag_callback_data_t data1, jt return jtag_check_value_inner(in, (u8 *)data1, (u8 *)data2, (int)data3); } -static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, scan_field_t *in_fields, tap_state_t state), +static void jtag_add_scan_check(void (*jtag_add_scan)(int in_num_fields, const scan_field_t *in_fields, tap_state_t state), int in_num_fields, scan_field_t *in_fields, tap_state_t state) { for (int i = 0; i < in_num_fields; i++) @@ -785,192 +802,204 @@ void jtag_add_dr_scan_check(int in_num_fields, scan_field_t *in_fields, tap_stat } } -int MINIDRIVER(interface_jtag_add_dr_scan)(int in_num_fields, scan_field_t *in_fields, tap_state_t state) + +/** + * Generate a DR SCAN using the fields passed to the function + * + * For not bypassed TAPs the function checks in_fields and uses fields specified there. + * For bypassed TAPs the function generates a dummy 1bit field. + * + * The bypass status of TAPs is set by jtag_add_ir_scan(). + * + */ +void jtag_add_dr_scan(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) { - int j; - int nth_tap; - int bypass_devices = 0; - int field_count = 0; - int scan_size; + int retval; - jtag_tap_t *tap; + jtag_prelude(state); + retval=interface_jtag_add_dr_scan(in_num_fields, in_fields, cmd_queue_end_state); + if (retval!=ERROR_OK) + jtag_error=retval; +} + + +/** + * see jtag_add_dr_scan() + * + */ +int MINIDRIVER(interface_jtag_add_dr_scan)(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) +{ /* count devices in bypass */ - tap = NULL; - bypass_devices = 0; - for(;;){ - tap = jtag_NextEnabledTap(tap); - if( tap == NULL ){ - break; - } - if( tap->bypass ){ + + size_t bypass_devices = 0; + + for (jtag_tap_t * tap = jtag_NextEnabledTap(NULL); tap != NULL; tap = jtag_NextEnabledTap(tap)) + { + if (tap->bypass) bypass_devices++; - } } - /* allocate memory for a new list member */ - - jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + scan_command_t * scan = cmd_queue_alloc(sizeof(scan_command_t)); + scan_field_t * out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(scan_field_t)); jtag_queue_command(cmd); - cmd->type = JTAG_SCAN; + cmd->type = JTAG_SCAN; + cmd->cmd.scan = scan; - /* allocate memory for dr scan command */ - cmd->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); - cmd->cmd.scan->ir_scan = false; - cmd->cmd.scan->num_fields = in_num_fields + bypass_devices; - cmd->cmd.scan->fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(scan_field_t)); - cmd->cmd.scan->end_state = state; + scan->ir_scan = false; + scan->num_fields = in_num_fields + bypass_devices; + scan->fields = out_fields; + scan->end_state = state; - tap = NULL; - nth_tap = -1; - for(;;){ - nth_tap++; - tap = jtag_NextEnabledTap(tap); - if( tap == NULL ){ - break; - } - int found = 0; - cmd->cmd.scan->fields[field_count].tap = tap; - for (j = 0; j < in_num_fields; j++) - { - if (tap == in_fields[j].tap) - { - found = 1; - scan_size = in_fields[j].num_bits; - cmd->cmd.scan->fields[field_count].num_bits = scan_size; - cmd->cmd.scan->fields[field_count].out_value = buf_cpy(in_fields[j].out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); - cmd->cmd.scan->fields[field_count].in_value = in_fields[j].in_value; - field_count++; - } - } - if (!found) + scan_field_t * field = out_fields; /* keep track where we insert data */ + + /* loop over all enabled TAPs */ + + for (jtag_tap_t * tap = jtag_NextEnabledTap(NULL); tap != NULL; tap = jtag_NextEnabledTap(tap)) + { + /* if TAP is not bypassed insert matching input fields */ + + if (!tap->bypass) { -#ifdef _DEBUG_JTAG_IO_ - /* if a device isn't listed, the BYPASS register should be selected */ - if (! tap->bypass) + scan_field_t * start_field = field; /* keep initial position for assert() */ + + for (int j = 0; j < in_num_fields; j++) { - LOG_ERROR("BUG: no scan data for a device not in BYPASS"); - exit(-1); + if (tap != in_fields[j].tap) + continue; + + cmd_queue_scan_field_clone(field, in_fields + j); + + field++; } -#endif - /* program the scan field to 1 bit length, and ignore it's value */ - cmd->cmd.scan->fields[field_count].num_bits = 1; - cmd->cmd.scan->fields[field_count].out_value = NULL; - cmd->cmd.scan->fields[field_count].in_value = NULL; - field_count++; + + assert(field > start_field); /* must have at least one input field per not bypassed TAP */ } + + /* if a TAP is bypassed, generated a dummy bit*/ else { -#ifdef _DEBUG_JTAG_IO_ - /* if a device is listed, the BYPASS register must not be selected */ - if (tap->bypass) - { - LOG_ERROR("BUG: scan data for a device in BYPASS"); - exit(-1); - } -#endif + field->tap = tap; + field->num_bits = 1; + field->out_value = NULL; + field->in_value = NULL; + + field++; } } - /* field_count represents the true number of fields setup*/ - cmd->cmd.scan->num_fields = field_count; + assert(field == out_fields + scan->num_fields); /* no superfluous input fields permitted */ + return ERROR_OK; } + + +/** + * Generate a DR SCAN using the array of output values passed to the function + * + * This function assumes that the parameter target_tap specifies the one TAP + * that is not bypassed. All other TAPs must be bypassed and the function will + * generate a dummy 1bit field for them. + * + * For the target_tap a sequence of output-only fields will be generated where + * each field has the size num_bits and the field's values are taken from + * the array value. + * + * The bypass status of TAPs is set by jtag_add_ir_scan(). + * + */ void MINIDRIVER(interface_jtag_add_dr_out)(jtag_tap_t *target_tap, int in_num_fields, const int *num_bits, const u32 *value, tap_state_t end_state) { - int nth_tap; - int field_count = 0; - int scan_size; - int bypass_devices = 0; + /* count devices in bypass */ - jtag_tap_t *tap; + size_t bypass_devices = 0; - /* count devices in bypass */ - tap = NULL; - bypass_devices = 0; - for(;;){ - tap = jtag_NextEnabledTap(tap); - if( tap == NULL ){ - break; - } - if( tap->bypass ){ + for (jtag_tap_t * tap = jtag_NextEnabledTap(NULL); tap != NULL; tap = jtag_NextEnabledTap(tap)) + { + if (tap->bypass) bypass_devices++; - } } - /* allocate memory for a new list member */ - jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + + jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + scan_command_t * scan = cmd_queue_alloc(sizeof(scan_command_t)); + scan_field_t * out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(scan_field_t)); jtag_queue_command(cmd); - cmd->type = JTAG_SCAN; + cmd->type = JTAG_SCAN; + cmd->cmd.scan = scan; - /* allocate memory for dr scan command */ - cmd->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); - cmd->cmd.scan->ir_scan = false; - cmd->cmd.scan->num_fields = in_num_fields + bypass_devices; - cmd->cmd.scan->fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(scan_field_t)); - cmd->cmd.scan->end_state = end_state; + scan->ir_scan = false; + scan->num_fields = in_num_fields + bypass_devices; + scan->fields = out_fields; + scan->end_state = end_state; - tap = NULL; - nth_tap = -1; - for(;;){ - tap = jtag_NextEnabledTap(tap); - if( tap == NULL ){ - break; - } - nth_tap++; - cmd->cmd.scan->fields[field_count].tap = tap; - if (tap == target_tap) + bool target_tap_match = false; + + scan_field_t * field = out_fields; /* keep track where we insert data */ + + /* loop over all enabled TAPs */ + + for (jtag_tap_t * tap = jtag_NextEnabledTap(NULL); tap != NULL; tap = jtag_NextEnabledTap(tap)) + { + /* if TAP is not bypassed insert matching input fields */ + + if (!tap->bypass) { - int j; -#ifdef _DEBUG_JTAG_IO_ - /* if a device is listed, the BYPASS register must not be selected */ - if (tap->bypass) - { - LOG_ERROR("BUG: scan data for a device in BYPASS"); - exit(-1); - } -#endif - for (j = 0; j < in_num_fields; j++) + assert(tap == target_tap); /* target_tap must match the one not bypassed TAP */ + + target_tap_match = true; + + for (int j = 0; j < in_num_fields; j++) { u8 out_value[4]; - scan_size = num_bits[j]; + size_t scan_size = num_bits[j]; buf_set_u32(out_value, 0, scan_size, value[j]); - cmd->cmd.scan->fields[field_count].num_bits = scan_size; - cmd->cmd.scan->fields[field_count].out_value = buf_cpy(out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); - cmd->cmd.scan->fields[field_count].in_value = NULL; - field_count++; + + field->tap = tap; + field->num_bits = scan_size; + field->out_value = buf_cpy(out_value, cmd_queue_alloc(CEIL(scan_size, 8)), scan_size); + field->in_value = NULL; + + field++; } - } else + } + + /* if a TAP is bypassed, generated a dummy bit*/ + else { -#ifdef _DEBUG_JTAG_IO_ - /* if a device isn't listed, the BYPASS register should be selected */ - if (! tap->bypass) - { - LOG_ERROR("BUG: no scan data for a device not in BYPASS"); - exit(-1); - } -#endif - /* program the scan field to 1 bit length, and ignore it's value */ - cmd->cmd.scan->fields[field_count].num_bits = 1; - cmd->cmd.scan->fields[field_count].out_value = NULL; - cmd->cmd.scan->fields[field_count].in_value = NULL; - field_count++; + + field->tap = tap; + field->num_bits = 1; + field->out_value = NULL; + field->in_value = NULL; + + field++; } } + + assert(target_tap_match); /* target_tap should be enabled and not bypassed */ } -void jtag_add_plain_dr_scan(int in_num_fields, scan_field_t *in_fields, tap_state_t state) + +/** + * Duplicate the scan fields passed into the function into a DR SCAN command + * + * This function assumes that the caller handles extra fields for bypassed TAPs + * + */ +void jtag_add_plain_dr_scan(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) { int retval; @@ -981,35 +1010,34 @@ void jtag_add_plain_dr_scan(int in_num_fields, scan_field_t *in_fields, tap_stat jtag_error=retval; } -int MINIDRIVER(interface_jtag_add_plain_dr_scan)(int in_num_fields, scan_field_t *in_fields, tap_state_t state) + +/** + * see jtag_add_plain_dr_scan() + * + */ +int MINIDRIVER(interface_jtag_add_plain_dr_scan)(int in_num_fields, const scan_field_t *in_fields, tap_state_t state) { - /* allocate memory for a new list member */ - jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); + scan_command_t * scan = cmd_queue_alloc(sizeof(scan_command_t)); + scan_field_t * out_fields = cmd_queue_alloc(in_num_fields * sizeof(scan_field_t)); jtag_queue_command(cmd); - cmd->type = JTAG_SCAN; + cmd->type = JTAG_SCAN; + cmd->cmd.scan = scan; - /* allocate memory for scan command */ - cmd->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t)); - cmd->cmd.scan->ir_scan = false; - cmd->cmd.scan->num_fields = in_num_fields; - cmd->cmd.scan->fields = cmd_queue_alloc(in_num_fields * sizeof(scan_field_t)); - cmd->cmd.scan->end_state = state; + scan->ir_scan = false; + scan->num_fields = in_num_fields; + scan->fields = out_fields; + scan->end_state = state; for (int i = 0; i < in_num_fields; i++) - { - int num_bits = in_fields[i].num_bits; - int num_bytes = CEIL(in_fields[i].num_bits, 8); - cmd->cmd.scan->fields[i].tap = in_fields[i].tap; - cmd->cmd.scan->fields[i].num_bits = num_bits; - cmd->cmd.scan->fields[i].out_value = buf_cpy(in_fields[i].out_value, cmd_queue_alloc(num_bytes), num_bits); - cmd->cmd.scan->fields[i].in_value = in_fields[i].in_value; - } + cmd_queue_scan_field_clone(out_fields + i, in_fields + i); return ERROR_OK; } + void jtag_add_tlr(void) { jtag_prelude(TAP_RESET); @@ -1037,7 +1065,7 @@ int MINIDRIVER(interface_jtag_add_tlr)(void) return ERROR_OK; } -void jtag_add_pathmove(int num_states, tap_state_t *path) +void jtag_add_pathmove(int num_states, const tap_state_t *path) { tap_state_t cur_state = cmd_queue_cur_state; int i; @@ -1075,7 +1103,7 @@ void jtag_add_pathmove(int num_states, tap_state_t *path) jtag_error=retval; } -int MINIDRIVER(interface_jtag_add_pathmove)(int num_states, tap_state_t *path) +int MINIDRIVER(interface_jtag_add_pathmove)(int num_states, const tap_state_t *path) { /* allocate memory for a new list member */ jtag_command_t * cmd = cmd_queue_alloc(sizeof(jtag_command_t)); @@ -1226,6 +1254,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) jtag_error=retval; return; } + jtag_execute_queue(); if (jtag_srst) { @@ -1253,7 +1282,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst) * and inform possible listeners about this */ LOG_DEBUG("TRST line asserted"); - cmd_queue_cur_state = TAP_RESET; + tap_set_state(TAP_RESET); jtag_call_event_callbacks(JTAG_TRST_ASSERTED); } else @@ -1312,7 +1341,7 @@ void jtag_add_sleep(u32 us) return; } -int jtag_scan_size(scan_command_t *cmd) +int jtag_scan_size(const scan_command_t *cmd) { int bit_count = 0; int i; @@ -1326,7 +1355,7 @@ int jtag_scan_size(scan_command_t *cmd) return bit_count; } -int jtag_build_buffer(scan_command_t *cmd, u8 **buffer) +int jtag_build_buffer(const scan_command_t *cmd, u8 **buffer) { int bit_count = 0; int i; @@ -1370,7 +1399,7 @@ int jtag_build_buffer(scan_command_t *cmd, u8 **buffer) return bit_count; } -int jtag_read_buffer(u8 *buffer, scan_command_t *cmd) +int jtag_read_buffer(u8 *buffer, const scan_command_t *cmd) { int i; int bit_count = 0; @@ -1408,7 +1437,7 @@ int jtag_read_buffer(u8 *buffer, scan_command_t *cmd) return retval; } -static const char *jtag_tap_name(jtag_tap_t *tap) +static const char *jtag_tap_name(const jtag_tap_t *tap) { return (tap == NULL) ? "(unknown)" : tap->dotted_name; } @@ -1480,7 +1509,7 @@ void jtag_check_value_mask(scan_field_t *field, u8 *value, u8 *mask) -enum scan_type jtag_scan_type(scan_command_t *cmd) +enum scan_type jtag_scan_type(const scan_command_t *cmd) { int i; int type = 0; @@ -2287,9 +2316,10 @@ int jtag_register_commands(struct command_context_s *cmd_ctx) register_command(cmd_ctx, NULL, "interface", handle_interface_command, COMMAND_CONFIG, "try to configure interface"); register_command(cmd_ctx, NULL, "jtag_speed", handle_jtag_speed_command, - COMMAND_ANY, "set jtag speed (if supported)"); + COMMAND_ANY, "(DEPRECATED) set jtag speed (if supported)"); register_command(cmd_ctx, NULL, "jtag_khz", handle_jtag_khz_command, - COMMAND_ANY, "same as jtag_speed, except it takes maximum khz as arguments. 0 KHz = RTCK."); + COMMAND_ANY, "set maximum jtag speed (if supported); " + "parameter is maximum khz, or 0 for adaptive clocking (RTCK)."); register_command(cmd_ctx, NULL, "jtag_device", handle_jtag_device_command, COMMAND_CONFIG, "jtag_device "); register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command, @@ -2378,6 +2408,20 @@ static int jtag_init_inner(struct command_context_s *cmd_ctx) return ERROR_OK; } +int jtag_interface_quit(void) +{ + if (!jtag || !jtag->quit) + return ERROR_OK; + + // close the JTAG interface + int result = jtag->quit(); + if (ERROR_OK != result) + LOG_ERROR("failed: %d", result); + + return ERROR_OK; +} + + int jtag_init_reset(struct command_context_s *cmd_ctx) { int retval; @@ -2622,77 +2666,111 @@ static int handle_scan_chain_command(struct command_context_s *cmd_ctx, char *cm static int handle_reset_config_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) { + int new_cfg = 0; + int mask = 0; + if (argc < 1) return ERROR_COMMAND_SYNTAX_ERROR; - if (argc >= 1) - { - if (strcmp(args[0], "none") == 0) - jtag_reset_config = RESET_NONE; - else if (strcmp(args[0], "trst_only") == 0) - jtag_reset_config = RESET_HAS_TRST; - else if (strcmp(args[0], "srst_only") == 0) - jtag_reset_config = RESET_HAS_SRST; - else if (strcmp(args[0], "trst_and_srst") == 0) - jtag_reset_config = RESET_TRST_AND_SRST; + /* Original versions cared about the order of these tokens: + * reset_config signals [combination [trst_type [srst_type]]] + * They also clobbered the previous configuration even on error. + * + * Here we don't care about the order, and only change values + * which have been explicitly specified. + */ + for (; argc; argc--, args++) { + int tmp = 0; + int m; + + /* signals */ + m = RESET_HAS_TRST | RESET_HAS_SRST; + if (strcmp(*args, "none") == 0) + tmp = RESET_NONE; + else if (strcmp(*args, "trst_only") == 0) + tmp = RESET_HAS_TRST; + else if (strcmp(*args, "srst_only") == 0) + tmp = RESET_HAS_SRST; + else if (strcmp(*args, "trst_and_srst") == 0) + tmp = RESET_HAS_TRST | RESET_HAS_SRST; else - { - LOG_ERROR("(1) invalid reset_config argument (%s), defaulting to none", args[0]); - jtag_reset_config = RESET_NONE; + m = 0; + if (mask & m) { + LOG_ERROR("extra reset_config %s spec (%s)", + "signal", *args); return ERROR_INVALID_ARGUMENTS; } - } - - if (argc >= 2) - { - if (strcmp(args[1], "separate") == 0) - { - /* seperate reset lines - default */ - } else - { - if (strcmp(args[1], "srst_pulls_trst") == 0) - jtag_reset_config |= RESET_SRST_PULLS_TRST; - else if (strcmp(args[1], "trst_pulls_srst") == 0) - jtag_reset_config |= RESET_TRST_PULLS_SRST; - else if (strcmp(args[1], "combined") == 0) - jtag_reset_config |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; - else - { - LOG_ERROR("(2) invalid reset_config argument (%s), defaulting to none", args[1]); - jtag_reset_config = RESET_NONE; - return ERROR_INVALID_ARGUMENTS; - } + if (m) + goto next; + + /* combination (options for broken wiring) */ + m = RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; + if (strcmp(*args, "separate") == 0) + /* separate reset lines - default */; + else if (strcmp(*args, "srst_pulls_trst") == 0) + tmp |= RESET_SRST_PULLS_TRST; + else if (strcmp(*args, "trst_pulls_srst") == 0) + tmp |= RESET_TRST_PULLS_SRST; + else if (strcmp(*args, "combined") == 0) + tmp |= RESET_SRST_PULLS_TRST | RESET_TRST_PULLS_SRST; + else + m = 0; + if (mask & m) { + LOG_ERROR("extra reset_config %s spec (%s)", + "combination", *args); + return ERROR_INVALID_ARGUMENTS; } - } + if (m) + goto next; - if (argc >= 3) - { - if (strcmp(args[2], "trst_open_drain") == 0) - jtag_reset_config |= RESET_TRST_OPEN_DRAIN; - else if (strcmp(args[2], "trst_push_pull") == 0) - jtag_reset_config &= ~RESET_TRST_OPEN_DRAIN; + /* trst_type (NOP without HAS_TRST) */ + m = RESET_TRST_OPEN_DRAIN; + if (strcmp(*args, "trst_open_drain") == 0) + tmp |= RESET_TRST_OPEN_DRAIN; + else if (strcmp(*args, "trst_push_pull") == 0) + /* push/pull from adapter - default */; else - { - LOG_ERROR("(3) invalid reset_config argument (%s) defaulting to none", args[2] ); - jtag_reset_config = RESET_NONE; + m = 0; + if (mask & m) { + LOG_ERROR("extra reset_config %s spec (%s)", + "trst_type", *args); return ERROR_INVALID_ARGUMENTS; } - } + if (m) + goto next; - if (argc >= 4) - { - if (strcmp(args[3], "srst_push_pull") == 0) - jtag_reset_config |= RESET_SRST_PUSH_PULL; - else if (strcmp(args[3], "srst_open_drain") == 0) - jtag_reset_config &= ~RESET_SRST_PUSH_PULL; + /* srst_type (NOP without HAS_SRST) */ + m |= RESET_SRST_PUSH_PULL; + if (strcmp(*args, "srst_push_pull") == 0) + tmp |= RESET_SRST_PUSH_PULL; + else if (strcmp(*args, "srst_open_drain") == 0) + /* open drain from adapter - default */; else - { - LOG_ERROR("(4) invalid reset_config argument (%s), defaulting to none", args[3]); - jtag_reset_config = RESET_NONE; + m = 0; + if (mask & m) { + LOG_ERROR("extra reset_config %s spec (%s)", + "srst_type", *args); return ERROR_INVALID_ARGUMENTS; } + if (m) + goto next; + + /* caller provided nonsense; fail */ + LOG_ERROR("unknown reset_config flag (%s)", *args); + return ERROR_INVALID_ARGUMENTS; + +next: + /* Remember the bits which were specified (mask) + * and their new values (new_cfg). + */ + mask |= m; + new_cfg |= tmp; } + /* clear previous values of those bits, save new values */ + jtag_reset_config &= ~mask; + jtag_reset_config |= new_cfg; + return ERROR_OK; } @@ -3335,10 +3413,10 @@ static const struct tms_sequences short_tms_seqs[6][6] = /* [from_state_ndx][t /* to state: */ /* RESET IDLE DRSHIFT DRPAUSE IRSHIFT IRPAUSE */ /* from state: */ - { B8(1111111,7), B8(0000000,7), B8(00101,5), B8(01010,5), B8(001101,6), B8(010110,6) }, /* RESET */ + { B8(1111111,7), B8(0000000,7), B8(0010111,7), B8(0001010,7), B8(0011011,7), B8(0010110,7) }, /* RESET */ { B8(1111111,7), B8(0000000,7), B8(001,3), B8(0101,4), B8(0011,4), B8(01011,5) }, /* IDLE */ - { B8(1111111,7), B8(011,3), B8(00111,5), B8(01,2), B8(001111,6), B8(0101111,7) }, /* DRSHIFT */ - { B8(1111111,7), B8(011,3), B8(01,2), B8(0,1), B8(001111,6), B8(0101111,7) }, /* DRPAUSE */ + { B8(1111111,7), B8(011,3), B8(00111,5), B8(01,2), B8(001111,6), B8(0101111,7) }, /* DRSHIFT */ + { B8(1111111,7), B8(011,3), B8(01,2), B8(0,1), B8(001111,6), B8(0101111,7) }, /* DRPAUSE */ { B8(1111111,7), B8(011,3), B8(00111,5), B8(010111,6), B8(001111,6), B8(01,2) }, /* IRSHIFT */ { B8(1111111,7), B8(011,3), B8(00111,5), B8(010111,6), B8(01,2), B8(0,1) } /* IRPAUSE */ @@ -3642,3 +3720,90 @@ static int handle_tms_sequence_command(struct command_context_s *cmd_ctx, char * } /*-------------------------------------------*/ + + +/** + * Function jtag_add_statemove + * moves from the current state to the goal \a state. This needs + * to be handled according to the xsvf spec, see the XSTATE command + * description. + */ +int jtag_add_statemove(tap_state_t goal_state) +{ + int retval = ERROR_OK; + + tap_state_t moves[8]; + tap_state_t cur_state = cmd_queue_cur_state; + int i; + int tms_bits; + int tms_count; + + LOG_DEBUG( "cur_state=%s goal_state=%s", + tap_state_name(cur_state), + tap_state_name(goal_state) ); + + + /* From the XSVF spec, pertaining to XSTATE: + + For special states known as stable states (Test-Logic-Reset, + Run-Test/Idle, Pause-DR, Pause- IR), an XSVF interpreter follows + predefined TAP state paths when the starting state is a stable state and + when the XSTATE specifies a new stable state (see the STATE command in + the [Ref 5] for the TAP state paths between stable states). For + non-stable states, XSTATE should specify a state that is only one TAP + state transition distance from the current TAP state to avoid undefined + TAP state paths. A sequence of multiple XSTATE commands can be issued to + transition the TAP through a specific state path. + */ + + if (goal_state==cur_state ) + ; /* nothing to do */ + + else if( goal_state==TAP_RESET ) + { + jtag_add_tlr(); + } + + else if( tap_is_state_stable(cur_state) && tap_is_state_stable(goal_state) ) + { + /* note: unless tms_bits holds a path that agrees with [Ref 5] in above + spec, then this code is not fully conformant to the xsvf spec. This + puts a burden on tap_get_tms_path() function from the xsvf spec. + If in doubt, you should confirm that that burden is being met. + */ + + tms_bits = tap_get_tms_path(cur_state, goal_state); + tms_count = tap_get_tms_path_len(cur_state, goal_state); + + assert( (unsigned) tms_count < DIM(moves) ); + + for (i=0; i>=1) + { + bool bit = tms_bits & 1; + + cur_state = tap_state_transition(cur_state, bit); + moves[i] = cur_state; + } + + jtag_add_pathmove(tms_count, moves); + } + + /* else state must be immediately reachable in one clock cycle, and does not + need to be a stable state. + */ + else if( tap_state_transition(cur_state, true) == goal_state + || tap_state_transition(cur_state, false) == goal_state ) + { + /* move a single state */ + moves[0] = goal_state; + jtag_add_pathmove( 1, moves ); + } + + else + { + retval = ERROR_FAIL; + } + + return retval; +} +