jtag: jtag_vpi: Add missing 'default' to switch statement
[openocd.git] / src / jtag / drivers / jtag_vpi.c
1 /*
2 * JTAG to VPI driver
3 *
4 * Copyright (C) 2013 Franck Jullien, <elec4fun@gmail.com>
5 *
6 * See file CREDITS for list of people who contributed to this
7 * project.
8 *
9 * This program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <jtag/interface.h>
28 #ifdef HAVE_ARPA_INET_H
29 #include <arpa/inet.h>
30 #endif
31
32 #ifndef _WIN32
33 #include <netinet/tcp.h>
34 #endif
35
36 #define NO_TAP_SHIFT 0
37 #define TAP_SHIFT 1
38
39 #define SERVER_ADDRESS "127.0.0.1"
40 #define SERVER_PORT 5555
41
42 #define XFERT_MAX_SIZE 512
43
44 #define CMD_RESET 0
45 #define CMD_TMS_SEQ 1
46 #define CMD_SCAN_CHAIN 2
47 #define CMD_SCAN_CHAIN_FLIP_TMS 3
48 #define CMD_STOP_SIMU 4
49
50 int server_port = SERVER_PORT;
51 char *server_address;
52
53 int sockfd;
54 struct sockaddr_in serv_addr;
55
56 struct vpi_cmd {
57 int cmd;
58 unsigned char buffer_out[XFERT_MAX_SIZE];
59 unsigned char buffer_in[XFERT_MAX_SIZE];
60 int length;
61 int nb_bits;
62 };
63
64 static int jtag_vpi_send_cmd(struct vpi_cmd *vpi)
65 {
66 int retval = write_socket(sockfd, vpi, sizeof(struct vpi_cmd));
67 if (retval <= 0)
68 return ERROR_FAIL;
69
70 return ERROR_OK;
71 }
72
73 static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi)
74 {
75 int retval = read_socket(sockfd, vpi, sizeof(struct vpi_cmd));
76 if (retval < (int)sizeof(struct vpi_cmd))
77 return ERROR_FAIL;
78
79 return ERROR_OK;
80 }
81
82 /**
83 * jtag_vpi_reset - ask to reset the JTAG device
84 * @trst: 1 if TRST is to be asserted
85 * @srst: 1 if SRST is to be asserted
86 */
87 static int jtag_vpi_reset(int trst, int srst)
88 {
89 struct vpi_cmd vpi;
90
91 vpi.cmd = CMD_RESET;
92 vpi.length = 0;
93 return jtag_vpi_send_cmd(&vpi);
94 }
95
96 /**
97 * jtag_vpi_tms_seq - ask a TMS sequence transition to JTAG
98 * @bits: TMS bits to be written (bit0, bit1 .. bitN)
99 * @nb_bits: number of TMS bits (between 1 and 8)
100 *
101 * Write a serie of TMS transitions, where each transition consists in :
102 * - writing out TCK=0, TMS=<new_state>, TDI=<???>
103 * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition
104 * The function ensures that at the end of the sequence, the clock (TCK) is put
105 * low.
106 */
107 static int jtag_vpi_tms_seq(const uint8_t *bits, int nb_bits)
108 {
109 struct vpi_cmd vpi;
110 int nb_bytes;
111
112 nb_bytes = DIV_ROUND_UP(nb_bits, 8);
113
114 vpi.cmd = CMD_TMS_SEQ;
115 memcpy(vpi.buffer_out, bits, nb_bytes);
116 vpi.length = nb_bytes;
117 vpi.nb_bits = nb_bits;
118
119 return jtag_vpi_send_cmd(&vpi);
120 }
121
122 /**
123 * jtag_vpi_path_move - ask a TMS sequence transition to JTAG
124 * @cmd: path transition
125 *
126 * Write a serie of TMS transitions, where each transition consists in :
127 * - writing out TCK=0, TMS=<new_state>, TDI=<???>
128 * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition
129 * The function ensures that at the end of the sequence, the clock (TCK) is put
130 * low.
131 */
132
133 static int jtag_vpi_path_move(struct pathmove_command *cmd)
134 {
135 uint8_t trans[DIV_ROUND_UP(cmd->num_states, 8)];
136
137 memset(trans, 0, DIV_ROUND_UP(cmd->num_states, 8));
138
139 for (int i = 0; i < cmd->num_states; i++) {
140 if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
141 buf_set_u32(trans, i, 1, 1);
142 tap_set_state(cmd->path[i]);
143 }
144
145 return jtag_vpi_tms_seq(trans, cmd->num_states);
146 }
147
148 /**
149 * jtag_vpi_tms - ask a tms command
150 * @cmd: tms command
151 */
152 static int jtag_vpi_tms(struct tms_command *cmd)
153 {
154 return jtag_vpi_tms_seq(cmd->bits, cmd->num_bits);
155 }
156
157 static int jtag_vpi_state_move(tap_state_t state)
158 {
159 if (tap_get_state() == state)
160 return ERROR_OK;
161
162 uint8_t tms_scan = tap_get_tms_path(tap_get_state(), state);
163 int tms_len = tap_get_tms_path_len(tap_get_state(), state);
164
165 int retval = jtag_vpi_tms_seq(&tms_scan, tms_len);
166 if (retval != ERROR_OK)
167 return retval;
168
169 tap_set_state(state);
170
171 return ERROR_OK;
172 }
173
174 static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
175 {
176 struct vpi_cmd vpi;
177 int nb_bytes = DIV_ROUND_UP(nb_bits, 8);
178
179 vpi.cmd = tap_shift ? CMD_SCAN_CHAIN_FLIP_TMS : CMD_SCAN_CHAIN;
180
181 if (bits)
182 memcpy(vpi.buffer_out, bits, nb_bytes);
183 else
184 memset(vpi.buffer_out, 0xff, nb_bytes);
185
186 vpi.length = nb_bytes;
187 vpi.nb_bits = nb_bits;
188
189 int retval = jtag_vpi_send_cmd(&vpi);
190 if (retval != ERROR_OK)
191 return retval;
192
193 retval = jtag_vpi_receive_cmd(&vpi);
194 if (retval != ERROR_OK)
195 return retval;
196
197 if (bits)
198 memcpy(bits, vpi.buffer_in, nb_bytes);
199
200 return ERROR_OK;
201 }
202
203 /**
204 * jtag_vpi_queue_tdi - short description
205 * @bits: bits to be queued on TDI (or NULL if 0 are to be queued)
206 * @nb_bits: number of bits
207 */
208 static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift)
209 {
210 int nb_xfer = DIV_ROUND_UP(nb_bits, XFERT_MAX_SIZE * 8);
211 int retval;
212
213 while (nb_xfer) {
214 if (nb_xfer == 1) {
215 retval = jtag_vpi_queue_tdi_xfer(bits, nb_bits, tap_shift);
216 if (retval != ERROR_OK)
217 return retval;
218 } else {
219 retval = jtag_vpi_queue_tdi_xfer(bits, XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
220 if (retval != ERROR_OK)
221 return retval;
222 nb_bits -= XFERT_MAX_SIZE * 8;
223 if (bits)
224 bits += XFERT_MAX_SIZE;
225 }
226
227 nb_xfer--;
228 }
229
230 return ERROR_OK;
231 }
232
233 /**
234 * jtag_vpi_clock_tms - clock a TMS transition
235 * @tms: the TMS to be sent
236 *
237 * Triggers a TMS transition (ie. one JTAG TAP state move).
238 */
239 static int jtag_vpi_clock_tms(int tms)
240 {
241 const uint8_t tms_0 = 0;
242 const uint8_t tms_1 = 1;
243
244 return jtag_vpi_tms_seq(tms ? &tms_1 : &tms_0, 1);
245 }
246
247 /**
248 * jtag_vpi_scan - launches a DR-scan or IR-scan
249 * @cmd: the command to launch
250 *
251 * Launch a JTAG IR-scan or DR-scan
252 *
253 * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occured.
254 */
255 static int jtag_vpi_scan(struct scan_command *cmd)
256 {
257 int scan_bits;
258 uint8_t *buf = NULL;
259 int retval = ERROR_OK;
260
261 scan_bits = jtag_build_buffer(cmd, &buf);
262
263 if (cmd->ir_scan) {
264 retval = jtag_vpi_state_move(TAP_IRSHIFT);
265 if (retval != ERROR_OK)
266 return retval;
267 } else {
268 retval = jtag_vpi_state_move(TAP_DRSHIFT);
269 if (retval != ERROR_OK)
270 return retval;
271 }
272
273 if (cmd->end_state == TAP_DRSHIFT) {
274 retval = jtag_vpi_queue_tdi(buf, scan_bits, NO_TAP_SHIFT);
275 if (retval != ERROR_OK)
276 return retval;
277 } else {
278 retval = jtag_vpi_queue_tdi(buf, scan_bits, TAP_SHIFT);
279 if (retval != ERROR_OK)
280 return retval;
281 }
282
283 if (cmd->end_state != TAP_DRSHIFT) {
284 /*
285 * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it
286 * forward to a stable IRPAUSE or DRPAUSE.
287 */
288 retval = jtag_vpi_clock_tms(0);
289 if (retval != ERROR_OK)
290 return retval;
291
292 if (cmd->ir_scan)
293 tap_set_state(TAP_IRPAUSE);
294 else
295 tap_set_state(TAP_DRPAUSE);
296 }
297
298 retval = jtag_read_buffer(buf, cmd);
299 if (retval != ERROR_OK)
300 return retval;
301
302 if (buf)
303 free(buf);
304
305 if (cmd->end_state != TAP_DRSHIFT) {
306 retval = jtag_vpi_state_move(cmd->end_state);
307 if (retval != ERROR_OK)
308 return retval;
309 }
310
311 return ERROR_OK;
312 }
313
314 static int jtag_vpi_runtest(int cycles, tap_state_t state)
315 {
316 int retval;
317
318 retval = jtag_vpi_state_move(TAP_IDLE);
319 if (retval != ERROR_OK)
320 return retval;
321
322 retval = jtag_vpi_queue_tdi(NULL, cycles, NO_TAP_SHIFT);
323 if (retval != ERROR_OK)
324 return retval;
325
326 return jtag_vpi_state_move(state);
327 }
328
329 static int jtag_vpi_stableclocks(int cycles)
330 {
331 uint8_t tms_bits[4];
332 int cycles_remain = cycles;
333 int nb_bits;
334 int retval;
335 const int CYCLES_ONE_BATCH = sizeof(tms_bits) * 8;
336
337 assert(cycles >= 0);
338
339 /* use TMS=1 in TAP RESET state, TMS=0 in all other stable states */
340 memset(&tms_bits, (tap_get_state() == TAP_RESET) ? 0xff : 0x00, sizeof(tms_bits));
341
342 /* send the TMS bits */
343 while (cycles_remain > 0) {
344 nb_bits = (cycles_remain < CYCLES_ONE_BATCH) ? cycles_remain : CYCLES_ONE_BATCH;
345 retval = jtag_vpi_tms_seq(tms_bits, nb_bits);
346 if (retval != ERROR_OK)
347 return retval;
348 cycles_remain -= nb_bits;
349 }
350
351 return ERROR_OK;
352 }
353
354 static int jtag_vpi_execute_queue(void)
355 {
356 struct jtag_command *cmd;
357 int retval = ERROR_OK;
358
359 for (cmd = jtag_command_queue; retval == ERROR_OK && cmd != NULL;
360 cmd = cmd->next) {
361 switch (cmd->type) {
362 case JTAG_RESET:
363 retval = jtag_vpi_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
364 break;
365 case JTAG_RUNTEST:
366 retval = jtag_vpi_runtest(cmd->cmd.runtest->num_cycles,
367 cmd->cmd.runtest->end_state);
368 break;
369 case JTAG_STABLECLOCKS:
370 retval = jtag_vpi_stableclocks(cmd->cmd.stableclocks->num_cycles);
371 break;
372 case JTAG_TLR_RESET:
373 retval = jtag_vpi_state_move(cmd->cmd.statemove->end_state);
374 break;
375 case JTAG_PATHMOVE:
376 retval = jtag_vpi_path_move(cmd->cmd.pathmove);
377 break;
378 case JTAG_TMS:
379 retval = jtag_vpi_tms(cmd->cmd.tms);
380 break;
381 case JTAG_SLEEP:
382 jtag_sleep(cmd->cmd.sleep->us);
383 break;
384 case JTAG_SCAN:
385 retval = jtag_vpi_scan(cmd->cmd.scan);
386 break;
387 default:
388 LOG_ERROR("BUG: unknown JTAG command type 0x%X",
389 cmd->type);
390 retval = ERROR_FAIL;
391 break;
392 }
393 }
394
395 return retval;
396 }
397
398 static int jtag_vpi_init(void)
399 {
400 int flag = 1;
401
402 sockfd = socket(AF_INET, SOCK_STREAM, 0);
403 if (sockfd < 0) {
404 LOG_ERROR("Could not create socket");
405 return ERROR_FAIL;
406 }
407
408 memset(&serv_addr, 0, sizeof(serv_addr));
409
410 serv_addr.sin_family = AF_INET;
411 serv_addr.sin_port = htons(server_port);
412
413 if (!server_address)
414 server_address = strdup(SERVER_ADDRESS);
415
416 serv_addr.sin_addr.s_addr = inet_addr(server_address);
417
418 if (serv_addr.sin_addr.s_addr == INADDR_NONE) {
419 LOG_ERROR("inet_addr error occured");
420 return ERROR_FAIL;
421 }
422
423 if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
424 close(sockfd);
425 LOG_ERROR("Can't connect to %s : %u", server_address, server_port);
426 return ERROR_COMMAND_CLOSE_CONNECTION;
427 }
428
429 if (serv_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
430 /* This increases performance drematically for local
431 * connections, which is the most likely arrangement
432 * for a VPI connection. */
433 setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
434 }
435
436 LOG_INFO("Connection to %s : %u succeed", server_address, server_port);
437
438 return ERROR_OK;
439 }
440
441 static int jtag_vpi_quit(void)
442 {
443 free(server_address);
444 return close(sockfd);
445 }
446
447 COMMAND_HANDLER(jtag_vpi_set_port)
448 {
449 if (CMD_ARGC == 0)
450 LOG_WARNING("You need to set a port number");
451 else
452 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port);
453
454 LOG_INFO("Set server port to %u", server_port);
455
456 return ERROR_OK;
457 }
458
459 COMMAND_HANDLER(jtag_vpi_set_address)
460 {
461 free(server_address);
462
463 if (CMD_ARGC == 0) {
464 LOG_WARNING("You need to set an address");
465 server_address = strdup(SERVER_ADDRESS);
466 } else
467 server_address = strdup(CMD_ARGV[0]);
468
469 LOG_INFO("Set server address to %s", server_address);
470
471 return ERROR_OK;
472 }
473
474 static const struct command_registration jtag_vpi_command_handlers[] = {
475 {
476 .name = "jtag_vpi_set_port",
477 .handler = &jtag_vpi_set_port,
478 .mode = COMMAND_CONFIG,
479 .help = "set the port of the VPI server",
480 .usage = "description_string",
481 },
482 {
483 .name = "jtag_vpi_set_address",
484 .handler = &jtag_vpi_set_address,
485 .mode = COMMAND_CONFIG,
486 .help = "set the address of the VPI server",
487 .usage = "description_string",
488 },
489 COMMAND_REGISTRATION_DONE
490 };
491
492 struct jtag_interface jtag_vpi_interface = {
493 .name = "jtag_vpi",
494 .supported = DEBUG_CAP_TMS_SEQ,
495 .commands = jtag_vpi_command_handlers,
496 .transports = jtag_only,
497
498 .init = jtag_vpi_init,
499 .quit = jtag_vpi_quit,
500 .execute_queue = jtag_vpi_execute_queue,
501 };

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)