jtag: drivers: Add JTAP VPI client driver
[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 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <jtag/interface.h>
26 #include <arpa/inet.h>
27
28 #define NO_TAP_SHIFT 0
29 #define TAP_SHIFT 1
30
31 #define SERVER_ADDRESS "127.0.0.1"
32 #define SERVER_PORT 5555
33
34 #define XFERT_MAX_SIZE 512
35
36 #define CMD_RESET 0
37 #define CMD_TMS_SEQ 1
38 #define CMD_SCAN_CHAIN 2
39 #define CMD_SCAN_CHAIN_FLIP_TMS 3
40 #define CMD_STOP_SIMU 4
41
42 int server_port = SERVER_PORT;
43
44 int sockfd;
45 struct sockaddr_in serv_addr;
46
47 struct vpi_cmd {
48 int cmd;
49 unsigned char buffer_out[XFERT_MAX_SIZE];
50 unsigned char buffer_in[XFERT_MAX_SIZE];
51 int length;
52 int nb_bits;
53 };
54
55 static int jtag_vpi_send_cmd(struct vpi_cmd *vpi)
56 {
57 int retval = write(sockfd, vpi, sizeof(struct vpi_cmd));
58 if (retval <= 0)
59 return ERROR_FAIL;
60
61 return ERROR_OK;
62 }
63
64 static int jtag_vpi_receive_cmd(struct vpi_cmd *vpi)
65 {
66 int retval = read(sockfd, vpi, sizeof(struct vpi_cmd));
67 if (retval < (int)sizeof(struct vpi_cmd))
68 return ERROR_FAIL;
69
70 return ERROR_OK;
71 }
72
73 /**
74 * jtag_vpi_reset - ask to reset the JTAG device
75 * @trst: 1 if TRST is to be asserted
76 * @srst: 1 if SRST is to be asserted
77 */
78 static int jtag_vpi_reset(int trst, int srst)
79 {
80 struct vpi_cmd vpi;
81
82 vpi.cmd = CMD_RESET;
83 vpi.length = 0;
84 return jtag_vpi_send_cmd(&vpi);
85 }
86
87 /**
88 * jtag_vpi_tms_seq - ask a TMS sequence transition to JTAG
89 * @bits: TMS bits to be written (bit0, bit1 .. bitN)
90 * @nb_bits: number of TMS bits (between 1 and 8)
91 *
92 * Write a serie of TMS transitions, where each transition consists in :
93 * - writing out TCK=0, TMS=<new_state>, TDI=<???>
94 * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition
95 * The function ensures that at the end of the sequence, the clock (TCK) is put
96 * low.
97 */
98 static int jtag_vpi_tms_seq(const uint8_t *bits, int nb_bits)
99 {
100 struct vpi_cmd vpi;
101 int nb_bytes;
102
103 nb_bytes = (nb_bits / 8) + !!(nb_bits % 8);
104
105 vpi.cmd = CMD_TMS_SEQ;
106 memcpy(vpi.buffer_out, bits, nb_bytes);
107 vpi.length = nb_bytes;
108 vpi.nb_bits = nb_bits;
109
110 return jtag_vpi_send_cmd(&vpi);
111 }
112
113 /**
114 * jtag_vpi_path_move - ask a TMS sequence transition to JTAG
115 * @cmd: path transition
116 *
117 * Write a serie of TMS transitions, where each transition consists in :
118 * - writing out TCK=0, TMS=<new_state>, TDI=<???>
119 * - writing out TCK=1, TMS=<new_state>, TDI=<???> which triggers the transition
120 * The function ensures that at the end of the sequence, the clock (TCK) is put
121 * low.
122 */
123
124 static int jtag_vpi_path_move(struct pathmove_command *cmd)
125 {
126 uint16_t trans = 0;
127 int retval;
128 int i;
129
130 for (i = 0; i < cmd->num_states; i++) {
131 if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
132 trans = trans | 1;
133 trans = trans << 1;
134 }
135
136 retval = jtag_vpi_tms_seq((uint8_t *)&trans, 1);
137 if (retval != ERROR_OK)
138 return retval;
139
140 tap_set_state(cmd->path[i]);
141
142 return ERROR_OK;
143 }
144
145 /**
146 * jtag_vpi_tms - ask a tms command
147 * @cmd: tms command
148 */
149 static int jtag_vpi_tms(struct tms_command *cmd)
150 {
151 return jtag_vpi_tms_seq(cmd->bits, cmd->num_bits);
152 }
153
154 static int jtag_vpi_state_move(tap_state_t state)
155 {
156 if (tap_get_state() == state)
157 return ERROR_OK;
158
159 uint8_t tms_scan = tap_get_tms_path(tap_get_state(), state);
160 int tms_len = tap_get_tms_path_len(tap_get_state(), state);
161
162 int retval = jtag_vpi_tms_seq(&tms_scan, tms_len);
163 if (retval != ERROR_OK)
164 return retval;
165
166 tap_set_state(state);
167
168 return ERROR_OK;
169 }
170
171 static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
172 {
173 struct vpi_cmd vpi;
174 int nb_bytes = (nb_bits / 8) + !!(nb_bits % 8);
175
176 vpi.cmd = tap_shift ? CMD_SCAN_CHAIN_FLIP_TMS : CMD_SCAN_CHAIN;
177
178 if (bits)
179 memcpy(vpi.buffer_out, bits, nb_bytes);
180 else
181 memset(vpi.buffer_out, 0xff, nb_bytes);
182
183 vpi.length = nb_bytes;
184 vpi.nb_bits = nb_bits;
185
186 int retval = jtag_vpi_send_cmd(&vpi);
187 if (retval != ERROR_OK)
188 return retval;
189
190 retval = jtag_vpi_receive_cmd(&vpi);
191 if (retval != ERROR_OK)
192 return retval;
193
194 if (bits)
195 memcpy(bits, vpi.buffer_in, nb_bytes);
196
197 return ERROR_OK;
198 }
199
200 /**
201 * jtag_vpi_queue_tdi - short description
202 * @bits: bits to be queued on TDI (or NULL if 0 are to be queued)
203 * @nb_bits: number of bits
204 */
205 static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift)
206 {
207 int nb_xfer = (nb_bits / (XFERT_MAX_SIZE * 8)) + !!(nb_bits % (XFERT_MAX_SIZE * 8));
208 uint8_t *xmit_buffer = bits;
209 int xmit_nb_bits = nb_bits;
210 int i = 0;
211 int retval;
212
213 while (nb_xfer) {
214
215 if (nb_xfer == 1) {
216 retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], xmit_nb_bits, tap_shift);
217 if (retval != ERROR_OK)
218 return retval;
219 } else {
220 retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
221 if (retval != ERROR_OK)
222 return retval;
223 xmit_nb_bits -= XFERT_MAX_SIZE * 8;
224 i += 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, 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 return jtag_vpi_queue_tdi(NULL, cycles, TAP_SHIFT);
332 }
333
334 static int jtag_vpi_execute_queue(void)
335 {
336 struct jtag_command *cmd;
337 int retval = ERROR_OK;
338
339 for (cmd = jtag_command_queue; retval == ERROR_OK && cmd != NULL;
340 cmd = cmd->next) {
341 switch (cmd->type) {
342 case JTAG_RESET:
343 retval = jtag_vpi_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
344 break;
345 case JTAG_RUNTEST:
346 retval = jtag_vpi_runtest(cmd->cmd.runtest->num_cycles,
347 cmd->cmd.runtest->end_state);
348 break;
349 case JTAG_STABLECLOCKS:
350 retval = jtag_vpi_stableclocks(cmd->cmd.stableclocks->num_cycles);
351 break;
352 case JTAG_TLR_RESET:
353 retval = jtag_vpi_state_move(cmd->cmd.statemove->end_state);
354 break;
355 case JTAG_PATHMOVE:
356 retval = jtag_vpi_path_move(cmd->cmd.pathmove);
357 break;
358 case JTAG_TMS:
359 retval = jtag_vpi_tms(cmd->cmd.tms);
360 break;
361 case JTAG_SLEEP:
362 jtag_sleep(cmd->cmd.sleep->us);
363 break;
364 case JTAG_SCAN:
365 retval = jtag_vpi_scan(cmd->cmd.scan);
366 break;
367 }
368 }
369
370 return retval;
371 }
372
373 static int jtag_vpi_init(void)
374 {
375 sockfd = socket(AF_INET, SOCK_STREAM, 0);
376 if (sockfd < 0) {
377 LOG_ERROR("Could not create socket");
378 return ERROR_FAIL;
379 }
380
381 memset(&serv_addr, 0, sizeof(serv_addr));
382
383 serv_addr.sin_family = AF_INET;
384 serv_addr.sin_port = htons(server_port);
385
386 if (inet_pton(AF_INET, SERVER_ADDRESS, &serv_addr.sin_addr) <= 0) {
387 LOG_ERROR("inet_pton error occured");
388 return ERROR_FAIL;
389 }
390
391 if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
392 close(sockfd);
393 LOG_ERROR("Can't connect to %s : %u", SERVER_ADDRESS, server_port);
394 return ERROR_COMMAND_CLOSE_CONNECTION;
395 }
396
397 LOG_INFO("Connection to %s : %u succeed", SERVER_ADDRESS, server_port);
398
399 return ERROR_OK;
400 }
401
402 static int jtag_vpi_quit(void)
403 {
404 return close(sockfd);
405 }
406
407 COMMAND_HANDLER(jtag_vpi_set_port)
408 {
409 if (CMD_ARGC == 0)
410 LOG_WARNING("You need to set a port number");
411 else
412 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port);
413
414 LOG_INFO("Set server port to %u", server_port);
415
416 return ERROR_OK;
417 }
418
419
420 static const struct command_registration jtag_vpi_command_handlers[] = {
421 {
422 .name = "jtag_vpi_set_port",
423 .handler = &jtag_vpi_set_port,
424 .mode = COMMAND_CONFIG,
425 .help = "set the port of the VPI server",
426 .usage = "description_string",
427 },
428 COMMAND_REGISTRATION_DONE
429 };
430
431 struct jtag_interface jtag_vpi_interface = {
432 .name = "jtag_vpi",
433 .supported = DEBUG_CAP_TMS_SEQ,
434 .commands = jtag_vpi_command_handlers,
435 .transports = jtag_only,
436
437 .init = jtag_vpi_init,
438 .quit = jtag_vpi_quit,
439 .execute_queue = jtag_vpi_execute_queue,
440 };

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)