27b9da116187adaf0de4bea6415e119975826414
[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 /* One jtag_vpi "packet" as sent over a TCP channel. */
57 struct vpi_cmd {
58 union {
59 uint32_t cmd;
60 unsigned char cmd_buf[4];
61 };
62 unsigned char buffer_out[XFERT_MAX_SIZE];
63 unsigned char buffer_in[XFERT_MAX_SIZE];
64 union {
65 uint32_t length;
66 unsigned char length_buf[4];
67 };
68 union {
69 uint32_t nb_bits;
70 unsigned char nb_bits_buf[4];
71 };
72 };
73
74 static int jtag_vpi_send_cmd(struct vpi_cmd *vpi)
75 {
76 /* Use little endian when transmitting/receiving jtag_vpi cmds.
77 The choice of little endian goes against usual networking conventions
78 but is intentional to remain compatible with most older OpenOCD builds
79 (i.e. builds on little-endian platforms). */
80 h_u32_to_le(vpi->cmd_buf, vpi->cmd);
81 h_u32_to_le(vpi->length_buf, vpi->length);
82 h_u32_to_le(vpi->nb_bits_buf, vpi->nb_bits);
83
84 int retval = write_socket(sockfd, vpi, sizeof(struct vpi_cmd));
85 if (retval <= 0)
86 return ERROR_FAIL;
87
88 return ERROR_OK;
89 }
90
91 static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi)
92 {
93 int retval = read_socket(sockfd, vpi, sizeof(struct vpi_cmd));
94 if (retval < (int)sizeof(struct vpi_cmd))
95 return ERROR_FAIL;
96
97 /* Use little endian when transmitting/receiving jtag_vpi cmds. */
98 vpi->cmd = le_to_h_u32(vpi->cmd_buf);
99 vpi->length = le_to_h_u32(vpi->length_buf);
100 vpi->nb_bits = le_to_h_u32(vpi->nb_bits_buf);
101
102 return ERROR_OK;
103 }
104
105 /**
106 * jtag_vpi_reset - ask to reset the JTAG device
107 * @trst: 1 if TRST is to be asserted
108 * @srst: 1 if SRST is to be asserted
109 */
110 static int jtag_vpi_reset(int trst, int srst)
111 {
112 struct vpi_cmd vpi;
113
114 vpi.cmd = CMD_RESET;
115 vpi.length = 0;
116 return jtag_vpi_send_cmd(&vpi);
117 }
118
119 /**
120 * jtag_vpi_tms_seq - ask a TMS sequence transition to JTAG
121 * @bits: TMS bits to be written (bit0, bit1 .. bitN)
122 * @nb_bits: number of TMS bits (between 1 and 8)
123 *
124 * Write a serie of TMS transitions, where each transition consists in :
125 * - writing out TCK=0, TMS=<new_state>, TDI=<???>
126 * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition
127 * The function ensures that at the end of the sequence, the clock (TCK) is put
128 * low.
129 */
130 static int jtag_vpi_tms_seq(const uint8_t *bits, int nb_bits)
131 {
132 struct vpi_cmd vpi;
133 int nb_bytes;
134
135 nb_bytes = DIV_ROUND_UP(nb_bits, 8);
136
137 vpi.cmd = CMD_TMS_SEQ;
138 memcpy(vpi.buffer_out, bits, nb_bytes);
139 vpi.length = nb_bytes;
140 vpi.nb_bits = nb_bits;
141
142 return jtag_vpi_send_cmd(&vpi);
143 }
144
145 /**
146 * jtag_vpi_path_move - ask a TMS sequence transition to JTAG
147 * @cmd: path transition
148 *
149 * Write a serie of TMS transitions, where each transition consists in :
150 * - writing out TCK=0, TMS=<new_state>, TDI=<???>
151 * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition
152 * The function ensures that at the end of the sequence, the clock (TCK) is put
153 * low.
154 */
155
156 static int jtag_vpi_path_move(struct pathmove_command *cmd)
157 {
158 uint8_t trans[DIV_ROUND_UP(cmd->num_states, 8)];
159
160 memset(trans, 0, DIV_ROUND_UP(cmd->num_states, 8));
161
162 for (int i = 0; i < cmd->num_states; i++) {
163 if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
164 buf_set_u32(trans, i, 1, 1);
165 tap_set_state(cmd->path[i]);
166 }
167
168 return jtag_vpi_tms_seq(trans, cmd->num_states);
169 }
170
171 /**
172 * jtag_vpi_tms - ask a tms command
173 * @cmd: tms command
174 */
175 static int jtag_vpi_tms(struct tms_command *cmd)
176 {
177 return jtag_vpi_tms_seq(cmd->bits, cmd->num_bits);
178 }
179
180 static int jtag_vpi_state_move(tap_state_t state)
181 {
182 if (tap_get_state() == state)
183 return ERROR_OK;
184
185 uint8_t tms_scan = tap_get_tms_path(tap_get_state(), state);
186 int tms_len = tap_get_tms_path_len(tap_get_state(), state);
187
188 int retval = jtag_vpi_tms_seq(&tms_scan, tms_len);
189 if (retval != ERROR_OK)
190 return retval;
191
192 tap_set_state(state);
193
194 return ERROR_OK;
195 }
196
197 static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
198 {
199 struct vpi_cmd vpi;
200 int nb_bytes = DIV_ROUND_UP(nb_bits, 8);
201
202 vpi.cmd = tap_shift ? CMD_SCAN_CHAIN_FLIP_TMS : CMD_SCAN_CHAIN;
203
204 if (bits)
205 memcpy(vpi.buffer_out, bits, nb_bytes);
206 else
207 memset(vpi.buffer_out, 0xff, nb_bytes);
208
209 vpi.length = nb_bytes;
210 vpi.nb_bits = nb_bits;
211
212 int retval = jtag_vpi_send_cmd(&vpi);
213 if (retval != ERROR_OK)
214 return retval;
215
216 retval = jtag_vpi_receive_cmd(&vpi);
217 if (retval != ERROR_OK)
218 return retval;
219
220 if (bits)
221 memcpy(bits, vpi.buffer_in, nb_bytes);
222
223 return ERROR_OK;
224 }
225
226 /**
227 * jtag_vpi_queue_tdi - short description
228 * @bits: bits to be queued on TDI (or NULL if 0 are to be queued)
229 * @nb_bits: number of bits
230 */
231 static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift)
232 {
233 int nb_xfer = DIV_ROUND_UP(nb_bits, XFERT_MAX_SIZE * 8);
234 int retval;
235
236 while (nb_xfer) {
237 if (nb_xfer == 1) {
238 retval = jtag_vpi_queue_tdi_xfer(bits, nb_bits, tap_shift);
239 if (retval != ERROR_OK)
240 return retval;
241 } else {
242 retval = jtag_vpi_queue_tdi_xfer(bits, XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
243 if (retval != ERROR_OK)
244 return retval;
245 nb_bits -= XFERT_MAX_SIZE * 8;
246 if (bits)
247 bits += XFERT_MAX_SIZE;
248 }
249
250 nb_xfer--;
251 }
252
253 return ERROR_OK;
254 }
255
256 /**
257 * jtag_vpi_clock_tms - clock a TMS transition
258 * @tms: the TMS to be sent
259 *
260 * Triggers a TMS transition (ie. one JTAG TAP state move).
261 */
262 static int jtag_vpi_clock_tms(int tms)
263 {
264 const uint8_t tms_0 = 0;
265 const uint8_t tms_1 = 1;
266
267 return jtag_vpi_tms_seq(tms ? &tms_1 : &tms_0, 1);
268 }
269
270 /**
271 * jtag_vpi_scan - launches a DR-scan or IR-scan
272 * @cmd: the command to launch
273 *
274 * Launch a JTAG IR-scan or DR-scan
275 *
276 * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occured.
277 */
278 static int jtag_vpi_scan(struct scan_command *cmd)
279 {
280 int scan_bits;
281 uint8_t *buf = NULL;
282 int retval = ERROR_OK;
283
284 scan_bits = jtag_build_buffer(cmd, &buf);
285
286 if (cmd->ir_scan) {
287 retval = jtag_vpi_state_move(TAP_IRSHIFT);
288 if (retval != ERROR_OK)
289 return retval;
290 } else {
291 retval = jtag_vpi_state_move(TAP_DRSHIFT);
292 if (retval != ERROR_OK)
293 return retval;
294 }
295
296 if (cmd->end_state == TAP_DRSHIFT) {
297 retval = jtag_vpi_queue_tdi(buf, scan_bits, NO_TAP_SHIFT);
298 if (retval != ERROR_OK)
299 return retval;
300 } else {
301 retval = jtag_vpi_queue_tdi(buf, scan_bits, TAP_SHIFT);
302 if (retval != ERROR_OK)
303 return retval;
304 }
305
306 if (cmd->end_state != TAP_DRSHIFT) {
307 /*
308 * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it
309 * forward to a stable IRPAUSE or DRPAUSE.
310 */
311 retval = jtag_vpi_clock_tms(0);
312 if (retval != ERROR_OK)
313 return retval;
314
315 if (cmd->ir_scan)
316 tap_set_state(TAP_IRPAUSE);
317 else
318 tap_set_state(TAP_DRPAUSE);
319 }
320
321 retval = jtag_read_buffer(buf, cmd);
322 if (retval != ERROR_OK)
323 return retval;
324
325 if (buf)
326 free(buf);
327
328 if (cmd->end_state != TAP_DRSHIFT) {
329 retval = jtag_vpi_state_move(cmd->end_state);
330 if (retval != ERROR_OK)
331 return retval;
332 }
333
334 return ERROR_OK;
335 }
336
337 static int jtag_vpi_runtest(int cycles, tap_state_t state)
338 {
339 int retval;
340
341 retval = jtag_vpi_state_move(TAP_IDLE);
342 if (retval != ERROR_OK)
343 return retval;
344
345 retval = jtag_vpi_queue_tdi(NULL, cycles, NO_TAP_SHIFT);
346 if (retval != ERROR_OK)
347 return retval;
348
349 return jtag_vpi_state_move(state);
350 }
351
352 static int jtag_vpi_stableclocks(int cycles)
353 {
354 uint8_t tms_bits[4];
355 int cycles_remain = cycles;
356 int nb_bits;
357 int retval;
358 const int CYCLES_ONE_BATCH = sizeof(tms_bits) * 8;
359
360 assert(cycles >= 0);
361
362 /* use TMS=1 in TAP RESET state, TMS=0 in all other stable states */
363 memset(&tms_bits, (tap_get_state() == TAP_RESET) ? 0xff : 0x00, sizeof(tms_bits));
364
365 /* send the TMS bits */
366 while (cycles_remain > 0) {
367 nb_bits = (cycles_remain < CYCLES_ONE_BATCH) ? cycles_remain : CYCLES_ONE_BATCH;
368 retval = jtag_vpi_tms_seq(tms_bits, nb_bits);
369 if (retval != ERROR_OK)
370 return retval;
371 cycles_remain -= nb_bits;
372 }
373
374 return ERROR_OK;
375 }
376
377 static int jtag_vpi_execute_queue(void)
378 {
379 struct jtag_command *cmd;
380 int retval = ERROR_OK;
381
382 for (cmd = jtag_command_queue; retval == ERROR_OK && cmd != NULL;
383 cmd = cmd->next) {
384 switch (cmd->type) {
385 case JTAG_RESET:
386 retval = jtag_vpi_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
387 break;
388 case JTAG_RUNTEST:
389 retval = jtag_vpi_runtest(cmd->cmd.runtest->num_cycles,
390 cmd->cmd.runtest->end_state);
391 break;
392 case JTAG_STABLECLOCKS:
393 retval = jtag_vpi_stableclocks(cmd->cmd.stableclocks->num_cycles);
394 break;
395 case JTAG_TLR_RESET:
396 retval = jtag_vpi_state_move(cmd->cmd.statemove->end_state);
397 break;
398 case JTAG_PATHMOVE:
399 retval = jtag_vpi_path_move(cmd->cmd.pathmove);
400 break;
401 case JTAG_TMS:
402 retval = jtag_vpi_tms(cmd->cmd.tms);
403 break;
404 case JTAG_SLEEP:
405 jtag_sleep(cmd->cmd.sleep->us);
406 break;
407 case JTAG_SCAN:
408 retval = jtag_vpi_scan(cmd->cmd.scan);
409 break;
410 default:
411 LOG_ERROR("BUG: unknown JTAG command type 0x%X",
412 cmd->type);
413 retval = ERROR_FAIL;
414 break;
415 }
416 }
417
418 return retval;
419 }
420
421 static int jtag_vpi_init(void)
422 {
423 int flag = 1;
424
425 sockfd = socket(AF_INET, SOCK_STREAM, 0);
426 if (sockfd < 0) {
427 LOG_ERROR("Could not create socket");
428 return ERROR_FAIL;
429 }
430
431 memset(&serv_addr, 0, sizeof(serv_addr));
432
433 serv_addr.sin_family = AF_INET;
434 serv_addr.sin_port = htons(server_port);
435
436 if (!server_address)
437 server_address = strdup(SERVER_ADDRESS);
438
439 serv_addr.sin_addr.s_addr = inet_addr(server_address);
440
441 if (serv_addr.sin_addr.s_addr == INADDR_NONE) {
442 LOG_ERROR("inet_addr error occured");
443 return ERROR_FAIL;
444 }
445
446 if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
447 close(sockfd);
448 LOG_ERROR("Can't connect to %s : %u", server_address, server_port);
449 return ERROR_COMMAND_CLOSE_CONNECTION;
450 }
451
452 if (serv_addr.sin_addr.s_addr == htonl(INADDR_LOOPBACK)) {
453 /* This increases performance drematically for local
454 * connections, which is the most likely arrangement
455 * for a VPI connection. */
456 setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
457 }
458
459 LOG_INFO("Connection to %s : %u succeed", server_address, server_port);
460
461 return ERROR_OK;
462 }
463
464 static int jtag_vpi_quit(void)
465 {
466 free(server_address);
467 return close(sockfd);
468 }
469
470 COMMAND_HANDLER(jtag_vpi_set_port)
471 {
472 if (CMD_ARGC == 0)
473 LOG_WARNING("You need to set a port number");
474 else
475 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port);
476
477 LOG_INFO("Set server port to %u", server_port);
478
479 return ERROR_OK;
480 }
481
482 COMMAND_HANDLER(jtag_vpi_set_address)
483 {
484 free(server_address);
485
486 if (CMD_ARGC == 0) {
487 LOG_WARNING("You need to set an address");
488 server_address = strdup(SERVER_ADDRESS);
489 } else
490 server_address = strdup(CMD_ARGV[0]);
491
492 LOG_INFO("Set server address to %s", server_address);
493
494 return ERROR_OK;
495 }
496
497 static const struct command_registration jtag_vpi_command_handlers[] = {
498 {
499 .name = "jtag_vpi_set_port",
500 .handler = &jtag_vpi_set_port,
501 .mode = COMMAND_CONFIG,
502 .help = "set the port of the VPI server",
503 .usage = "description_string",
504 },
505 {
506 .name = "jtag_vpi_set_address",
507 .handler = &jtag_vpi_set_address,
508 .mode = COMMAND_CONFIG,
509 .help = "set the address of the VPI server",
510 .usage = "description_string",
511 },
512 COMMAND_REGISTRATION_DONE
513 };
514
515 struct jtag_interface jtag_vpi_interface = {
516 .name = "jtag_vpi",
517 .supported = DEBUG_CAP_TMS_SEQ,
518 .commands = jtag_vpi_command_handlers,
519 .transports = jtag_only,
520
521 .init = jtag_vpi_init,
522 .quit = jtag_vpi_quit,
523 .execute_queue = jtag_vpi_execute_queue,
524 };

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)