added jtag_add_statemove() helper fn(actual fn written by Dick Hollonbeck, I just...
[fw/openocd] / src / jtag / jtag.c
index a974cad832f012052f364143b3cc6e8fa75d9fbe..4ed08971a47ae91737e8ddce79e60c84ddfc99e7 100644 (file)
@@ -37,7 +37,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 +227,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 +531,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 +568,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 +580,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 +613,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;
+       size_t num_taps = jtag_NumEnabledTaps();
 
-       int 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 +631,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 */
+
+       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 */
 
-               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 */
+               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,46 +703,34 @@ 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)
 {
-       /* 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 ir scan command */
-       cmd->cmd.scan = cmd_queue_alloc(sizeof(scan_command_t));
-       cmd->cmd.scan->ir_scan = true;
-       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                   = true;
+       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_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);
@@ -725,7 +740,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++)
@@ -786,192 +801,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_prelude(state);
+
+       retval=interface_jtag_add_dr_scan(in_num_fields, in_fields, cmd_queue_end_state);
+       if (retval!=ERROR_OK)
+               jtag_error=retval;
+}
 
-       jtag_tap_t *tap;
 
+/**
+ * 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;
 
@@ -982,35 +1009,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);
@@ -1038,7 +1064,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;
@@ -1076,7 +1102,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));
@@ -1227,6 +1253,7 @@ void jtag_add_reset(int req_tlr_or_trst, int req_srst)
                jtag_error=retval;
                return;
        }
+       jtag_execute_queue();
 
        if (jtag_srst)
        {
@@ -1254,7 +1281,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
@@ -1313,7 +1340,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;
@@ -1327,7 +1354,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;
@@ -1371,7 +1398,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;
@@ -1409,7 +1436,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;
 }
@@ -1481,7 +1508,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;
@@ -2288,9 +2315,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 <ir_length> <ir_expected> <ir_mask>");
        register_command(cmd_ctx, NULL, "reset_config", handle_reset_config_command,
@@ -2379,6 +2407,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;
@@ -2623,77 +2665,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;
 }
 
@@ -3336,10 +3412,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 */
 
@@ -3643,3 +3719,90 @@ static int handle_tms_sequence_command(struct command_context_s *cmd_ctx, char *
 }
 
 /*-----</Cable Helper API>--------------------------------------*/
+
+
+/**
+ * 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<tms_count;   i++, tms_bits>>=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;
+}
+