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

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)