75ec115edbbfdb4c48f61439db10e84053bf9bd7
[openocd.git] / src / jtag / drivers / driver.c
1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
4 * *
5 * Copyright (C) 2007-2010 Øyvind Harboe *
6 * oyvind.harboe@zylin.com *
7 * *
8 * Copyright (C) 2009 SoftPLC Corporation *
9 * http://softplc.com *
10 * dick@softplc.com *
11 * *
12 * Copyright (C) 2009 Zachary T Welch *
13 * zw@superlucidity.net *
14 * *
15 * This program is free software; you can redistribute it and/or modify *
16 * it under the terms of the GNU General Public License as published by *
17 * the Free Software Foundation; either version 2 of the License, or *
18 * (at your option) any later version. *
19 * *
20 * This program is distributed in the hope that it will be useful, *
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
23 * GNU General Public License for more details. *
24 * *
25 * You should have received a copy of the GNU General Public License *
26 * along with this program; if not, write to the *
27 * Free Software Foundation, Inc., *
28 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
29 ***************************************************************************/
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <jtag/jtag.h>
36 #include <jtag/interface.h>
37 #include <jtag/commands.h>
38 #include <jtag/minidriver.h>
39 #include <helper/command.h>
40
41 struct jtag_callback_entry {
42 struct jtag_callback_entry *next;
43
44 jtag_callback_t callback;
45 jtag_callback_data_t data0;
46 jtag_callback_data_t data1;
47 jtag_callback_data_t data2;
48 jtag_callback_data_t data3;
49 };
50
51 static struct jtag_callback_entry *jtag_callback_queue_head;
52 static struct jtag_callback_entry *jtag_callback_queue_tail;
53
54 static void jtag_callback_queue_reset(void)
55 {
56 jtag_callback_queue_head = NULL;
57 jtag_callback_queue_tail = NULL;
58 }
59
60 /**
61 * Copy a struct scan_field for insertion into the queue.
62 *
63 * This allocates a new copy of out_value using cmd_queue_alloc.
64 */
65 static void cmd_queue_scan_field_clone(struct scan_field *dst, const struct scan_field *src)
66 {
67 dst->num_bits = src->num_bits;
68 dst->out_value = buf_cpy(src->out_value, cmd_queue_alloc(DIV_ROUND_UP(src->num_bits, 8)), src->num_bits);
69 dst->in_value = src->in_value;
70 }
71
72 /**
73 * see jtag_add_ir_scan()
74 *
75 */
76 int interface_jtag_add_ir_scan(struct jtag_tap *active,
77 const struct scan_field *in_fields, tap_state_t state)
78 {
79 size_t num_taps = jtag_tap_count_enabled();
80
81 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
82 struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command));
83 struct scan_field *out_fields = cmd_queue_alloc(num_taps * sizeof(struct scan_field));
84
85 jtag_queue_command(cmd);
86
87 cmd->type = JTAG_SCAN;
88 cmd->cmd.scan = scan;
89
90 scan->ir_scan = true;
91 scan->num_fields = num_taps; /* one field per device */
92 scan->fields = out_fields;
93 scan->end_state = state;
94
95 struct scan_field *field = out_fields; /* keep track where we insert data */
96
97 /* loop over all enabled TAPs */
98
99 for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) {
100 /* search the input field list for fields for the current TAP */
101
102 if (tap == active) {
103 /* if TAP is listed in input fields, copy the value */
104 tap->bypass = 0;
105
106 cmd_queue_scan_field_clone(field, in_fields);
107 } else {
108 /* if a TAP isn't listed in input fields, set it to BYPASS */
109
110 tap->bypass = 1;
111
112 field->num_bits = tap->ir_length;
113 field->out_value = buf_set_ones(cmd_queue_alloc(DIV_ROUND_UP(tap->ir_length, 8)), tap->ir_length);
114 field->in_value = NULL; /* do not collect input for tap's in bypass */
115 }
116
117 /* update device information */
118 buf_cpy(field->out_value, tap->cur_instr, tap->ir_length);
119
120 field++;
121 }
122 /* paranoia: jtag_tap_count_enabled() and jtag_tap_next_enabled() not in sync */
123 assert(field == out_fields + num_taps);
124
125 return ERROR_OK;
126 }
127
128 /**
129 * see jtag_add_dr_scan()
130 *
131 */
132 int interface_jtag_add_dr_scan(struct jtag_tap *active, int in_num_fields,
133 const struct scan_field *in_fields, tap_state_t state)
134 {
135 /* count devices in bypass */
136
137 size_t bypass_devices = 0;
138
139 for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) {
140 if (tap->bypass)
141 bypass_devices++;
142 }
143
144 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
145 struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command));
146 struct scan_field *out_fields = cmd_queue_alloc((in_num_fields + bypass_devices) * sizeof(struct scan_field));
147
148 jtag_queue_command(cmd);
149
150 cmd->type = JTAG_SCAN;
151 cmd->cmd.scan = scan;
152
153 scan->ir_scan = false;
154 scan->num_fields = in_num_fields + bypass_devices;
155 scan->fields = out_fields;
156 scan->end_state = state;
157
158 struct scan_field *field = out_fields; /* keep track where we insert data */
159
160 /* loop over all enabled TAPs */
161
162 for (struct jtag_tap *tap = jtag_tap_next_enabled(NULL); tap != NULL; tap = jtag_tap_next_enabled(tap)) {
163 /* if TAP is not bypassed insert matching input fields */
164
165 if (!tap->bypass) {
166 assert(active == tap);
167 #ifndef NDEBUG
168 /* remember initial position for assert() */
169 struct scan_field *start_field = field;
170 #endif /* NDEBUG */
171
172 for (int j = 0; j < in_num_fields; j++) {
173 cmd_queue_scan_field_clone(field, in_fields + j);
174
175 field++;
176 }
177
178 assert(field > start_field); /* must have at least one input field per not bypassed TAP */
179 }
180
181 /* if a TAP is bypassed, generated a dummy bit*/
182 else {
183 field->num_bits = 1;
184 field->out_value = NULL;
185 field->in_value = NULL;
186
187 field++;
188 }
189 }
190
191 assert(field == out_fields + scan->num_fields); /* no superfluous input fields permitted */
192
193 return ERROR_OK;
194 }
195
196 static int jtag_add_plain_scan(int num_bits, const uint8_t *out_bits,
197 uint8_t *in_bits, tap_state_t state, bool ir_scan)
198 {
199 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
200 struct scan_command *scan = cmd_queue_alloc(sizeof(struct scan_command));
201 struct scan_field *out_fields = cmd_queue_alloc(sizeof(struct scan_field));
202
203 jtag_queue_command(cmd);
204
205 cmd->type = JTAG_SCAN;
206 cmd->cmd.scan = scan;
207
208 scan->ir_scan = ir_scan;
209 scan->num_fields = 1;
210 scan->fields = out_fields;
211 scan->end_state = state;
212
213 out_fields->num_bits = num_bits;
214 out_fields->out_value = buf_cpy(out_bits, cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits);
215 out_fields->in_value = in_bits;
216
217 return ERROR_OK;
218 }
219
220 int interface_jtag_add_plain_dr_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state)
221 {
222 return jtag_add_plain_scan(num_bits, out_bits, in_bits, state, false);
223 }
224
225 int interface_jtag_add_plain_ir_scan(int num_bits, const uint8_t *out_bits, uint8_t *in_bits, tap_state_t state)
226 {
227 return jtag_add_plain_scan(num_bits, out_bits, in_bits, state, true);
228 }
229
230 int interface_jtag_add_tlr(void)
231 {
232 tap_state_t state = TAP_RESET;
233
234 /* allocate memory for a new list member */
235 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
236
237 jtag_queue_command(cmd);
238
239 cmd->type = JTAG_TLR_RESET;
240
241 cmd->cmd.statemove = cmd_queue_alloc(sizeof(struct statemove_command));
242 cmd->cmd.statemove->end_state = state;
243
244 return ERROR_OK;
245 }
246
247 int interface_add_tms_seq(unsigned num_bits, const uint8_t *seq, enum tap_state state)
248 {
249 struct jtag_command *cmd;
250
251 cmd = cmd_queue_alloc(sizeof(struct jtag_command));
252 if (cmd == NULL)
253 return ERROR_FAIL;
254
255 cmd->type = JTAG_TMS;
256 cmd->cmd.tms = cmd_queue_alloc(sizeof(*cmd->cmd.tms));
257 if (!cmd->cmd.tms)
258 return ERROR_FAIL;
259
260 /* copy the bits; our caller doesn't guarantee they'll persist */
261 cmd->cmd.tms->num_bits = num_bits;
262 cmd->cmd.tms->bits = buf_cpy(seq,
263 cmd_queue_alloc(DIV_ROUND_UP(num_bits, 8)), num_bits);
264 if (!cmd->cmd.tms->bits)
265 return ERROR_FAIL;
266
267 jtag_queue_command(cmd);
268
269 return ERROR_OK;
270 }
271
272 int interface_jtag_add_pathmove(int num_states, const tap_state_t *path)
273 {
274 /* allocate memory for a new list member */
275 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
276
277 jtag_queue_command(cmd);
278
279 cmd->type = JTAG_PATHMOVE;
280
281 cmd->cmd.pathmove = cmd_queue_alloc(sizeof(struct pathmove_command));
282 cmd->cmd.pathmove->num_states = num_states;
283 cmd->cmd.pathmove->path = cmd_queue_alloc(sizeof(tap_state_t) * num_states);
284
285 for (int i = 0; i < num_states; i++)
286 cmd->cmd.pathmove->path[i] = path[i];
287
288 return ERROR_OK;
289 }
290
291 int interface_jtag_add_runtest(int num_cycles, tap_state_t state)
292 {
293 /* allocate memory for a new list member */
294 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
295
296 jtag_queue_command(cmd);
297
298 cmd->type = JTAG_RUNTEST;
299
300 cmd->cmd.runtest = cmd_queue_alloc(sizeof(struct runtest_command));
301 cmd->cmd.runtest->num_cycles = num_cycles;
302 cmd->cmd.runtest->end_state = state;
303
304 return ERROR_OK;
305 }
306
307 int interface_jtag_add_clocks(int num_cycles)
308 {
309 /* allocate memory for a new list member */
310 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
311
312 jtag_queue_command(cmd);
313
314 cmd->type = JTAG_STABLECLOCKS;
315
316 cmd->cmd.stableclocks = cmd_queue_alloc(sizeof(struct stableclocks_command));
317 cmd->cmd.stableclocks->num_cycles = num_cycles;
318
319 return ERROR_OK;
320 }
321
322 int interface_jtag_add_reset(int req_trst, int req_srst)
323 {
324 /* allocate memory for a new list member */
325 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
326
327 jtag_queue_command(cmd);
328
329 cmd->type = JTAG_RESET;
330
331 cmd->cmd.reset = cmd_queue_alloc(sizeof(struct reset_command));
332 cmd->cmd.reset->trst = req_trst;
333 cmd->cmd.reset->srst = req_srst;
334
335 return ERROR_OK;
336 }
337
338 int interface_jtag_add_sleep(uint32_t us)
339 {
340 /* allocate memory for a new list member */
341 struct jtag_command *cmd = cmd_queue_alloc(sizeof(struct jtag_command));
342
343 jtag_queue_command(cmd);
344
345 cmd->type = JTAG_SLEEP;
346
347 cmd->cmd.sleep = cmd_queue_alloc(sizeof(struct sleep_command));
348 cmd->cmd.sleep->us = us;
349
350 return ERROR_OK;
351 }
352
353 /* add callback to end of queue */
354 void interface_jtag_add_callback4(jtag_callback_t callback,
355 jtag_callback_data_t data0, jtag_callback_data_t data1,
356 jtag_callback_data_t data2, jtag_callback_data_t data3)
357 {
358 struct jtag_callback_entry *entry = cmd_queue_alloc(sizeof(struct jtag_callback_entry));
359
360 entry->next = NULL;
361 entry->callback = callback;
362 entry->data0 = data0;
363 entry->data1 = data1;
364 entry->data2 = data2;
365 entry->data3 = data3;
366
367 if (jtag_callback_queue_head == NULL) {
368 jtag_callback_queue_head = entry;
369 jtag_callback_queue_tail = entry;
370 } else {
371 jtag_callback_queue_tail->next = entry;
372 jtag_callback_queue_tail = entry;
373 }
374 }
375
376 int interface_jtag_execute_queue(void)
377 {
378 static int reentry;
379
380 assert(reentry == 0);
381 reentry++;
382
383 int retval = default_interface_jtag_execute_queue();
384 if (retval == ERROR_OK) {
385 struct jtag_callback_entry *entry;
386 for (entry = jtag_callback_queue_head; entry != NULL; entry = entry->next) {
387 retval = entry->callback(entry->data0, entry->data1, entry->data2, entry->data3);
388 if (retval != ERROR_OK)
389 break;
390 }
391 }
392
393 jtag_command_queue_reset();
394 jtag_callback_queue_reset();
395
396 reentry--;
397
398 return retval;
399 }
400
401 static int jtag_convert_to_callback4(jtag_callback_data_t data0,
402 jtag_callback_data_t data1, jtag_callback_data_t data2, jtag_callback_data_t data3)
403 {
404 ((jtag_callback1_t)data1)(data0);
405 return ERROR_OK;
406 }
407
408 void interface_jtag_add_callback(jtag_callback1_t callback, jtag_callback_data_t data0)
409 {
410 jtag_add_callback4(jtag_convert_to_callback4, data0, (jtag_callback_data_t)callback, 0, 0);
411 }
412
413 void jtag_add_callback(jtag_callback1_t f, jtag_callback_data_t data0)
414 {
415 interface_jtag_add_callback(f, data0);
416 }
417
418 void jtag_add_callback4(jtag_callback_t f, jtag_callback_data_t data0,
419 jtag_callback_data_t data1, jtag_callback_data_t data2,
420 jtag_callback_data_t data3)
421 {
422 interface_jtag_add_callback4(f, data0, data1, data2, data3);
423 }

Linking to existing account procedure

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

SSH host keys fingerprints

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