jtag_vpi: use DIV_ROUND_UP
[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 = DIV_ROUND_UP(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 uint8_t trans[DIV_ROUND_UP(cmd->num_states, 8)];
127
128 memset(trans, 0, DIV_ROUND_UP(cmd->num_states, 8));
129
130 for (int i = 0; i < cmd->num_states; i++) {
131 if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
132 buf_set_u32(trans, i, 1, 1);
133 tap_set_state(cmd->path[i]);
134 }
135
136 return jtag_vpi_tms_seq(trans, cmd->num_states);
137 }
138
139 /**
140 * jtag_vpi_tms - ask a tms command
141 * @cmd: tms command
142 */
143 static int jtag_vpi_tms(struct tms_command *cmd)
144 {
145 return jtag_vpi_tms_seq(cmd->bits, cmd->num_bits);
146 }
147
148 static int jtag_vpi_state_move(tap_state_t state)
149 {
150 if (tap_get_state() == state)
151 return ERROR_OK;
152
153 uint8_t tms_scan = tap_get_tms_path(tap_get_state(), state);
154 int tms_len = tap_get_tms_path_len(tap_get_state(), state);
155
156 int retval = jtag_vpi_tms_seq(&tms_scan, tms_len);
157 if (retval != ERROR_OK)
158 return retval;
159
160 tap_set_state(state);
161
162 return ERROR_OK;
163 }
164
165 static int jtag_vpi_queue_tdi_xfer(uint8_t *bits, int nb_bits, int tap_shift)
166 {
167 struct vpi_cmd vpi;
168 int nb_bytes = DIV_ROUND_UP(nb_bits, 8);
169
170 vpi.cmd = tap_shift ? CMD_SCAN_CHAIN_FLIP_TMS : CMD_SCAN_CHAIN;
171
172 if (bits)
173 memcpy(vpi.buffer_out, bits, nb_bytes);
174 else
175 memset(vpi.buffer_out, 0xff, nb_bytes);
176
177 vpi.length = nb_bytes;
178 vpi.nb_bits = nb_bits;
179
180 int retval = jtag_vpi_send_cmd(&vpi);
181 if (retval != ERROR_OK)
182 return retval;
183
184 retval = jtag_vpi_receive_cmd(&vpi);
185 if (retval != ERROR_OK)
186 return retval;
187
188 if (bits)
189 memcpy(bits, vpi.buffer_in, nb_bytes);
190
191 return ERROR_OK;
192 }
193
194 /**
195 * jtag_vpi_queue_tdi - short description
196 * @bits: bits to be queued on TDI (or NULL if 0 are to be queued)
197 * @nb_bits: number of bits
198 */
199 static int jtag_vpi_queue_tdi(uint8_t *bits, int nb_bits, int tap_shift)
200 {
201 int nb_xfer = DIV_ROUND_UP(nb_bits, XFERT_MAX_SIZE * 8);
202 uint8_t *xmit_buffer = bits;
203 int xmit_nb_bits = nb_bits;
204 int i = 0;
205 int retval;
206
207 while (nb_xfer) {
208
209 if (nb_xfer == 1) {
210 retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], xmit_nb_bits, tap_shift);
211 if (retval != ERROR_OK)
212 return retval;
213 } else {
214 retval = jtag_vpi_queue_tdi_xfer(&xmit_buffer[i], XFERT_MAX_SIZE * 8, NO_TAP_SHIFT);
215 if (retval != ERROR_OK)
216 return retval;
217 xmit_nb_bits -= XFERT_MAX_SIZE * 8;
218 i += XFERT_MAX_SIZE;
219 }
220
221 nb_xfer--;
222 }
223
224 return ERROR_OK;
225 }
226
227 /**
228 * jtag_vpi_clock_tms - clock a TMS transition
229 * @tms: the TMS to be sent
230 *
231 * Triggers a TMS transition (ie. one JTAG TAP state move).
232 */
233 static int jtag_vpi_clock_tms(int tms)
234 {
235 const uint8_t tms_0 = 0;
236 const uint8_t tms_1 = 1;
237
238 return jtag_vpi_tms_seq(tms ? &tms_1 : &tms_0, 1);
239 }
240
241 /**
242 * jtag_vpi_scan - launches a DR-scan or IR-scan
243 * @cmd: the command to launch
244 *
245 * Launch a JTAG IR-scan or DR-scan
246 *
247 * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occured.
248 */
249 static int jtag_vpi_scan(struct scan_command *cmd)
250 {
251 int scan_bits;
252 uint8_t *buf = NULL;
253 int retval = ERROR_OK;
254
255 scan_bits = jtag_build_buffer(cmd, &buf);
256
257 if (cmd->ir_scan) {
258 retval = jtag_vpi_state_move(TAP_IRSHIFT);
259 if (retval != ERROR_OK)
260 return retval;
261 } else {
262 retval = jtag_vpi_state_move(TAP_DRSHIFT);
263 if (retval != ERROR_OK)
264 return retval;
265 }
266
267 if (cmd->end_state == TAP_DRSHIFT) {
268 retval = jtag_vpi_queue_tdi(buf, scan_bits, NO_TAP_SHIFT);
269 if (retval != ERROR_OK)
270 return retval;
271 } else {
272 retval = jtag_vpi_queue_tdi(buf, scan_bits, TAP_SHIFT);
273 if (retval != ERROR_OK)
274 return retval;
275 }
276
277 if (cmd->end_state != TAP_DRSHIFT) {
278 /*
279 * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it
280 * forward to a stable IRPAUSE or DRPAUSE.
281 */
282 retval = jtag_vpi_clock_tms(0);
283 if (retval != ERROR_OK)
284 return retval;
285
286 if (cmd->ir_scan)
287 tap_set_state(TAP_IRPAUSE);
288 else
289 tap_set_state(TAP_DRPAUSE);
290 }
291
292 retval = jtag_read_buffer(buf, cmd);
293 if (retval != ERROR_OK)
294 return retval;
295
296 if (buf)
297 free(buf);
298
299 if (cmd->end_state != TAP_DRSHIFT) {
300 retval = jtag_vpi_state_move(cmd->end_state);
301 if (retval != ERROR_OK)
302 return retval;
303 }
304
305 return ERROR_OK;
306 }
307
308 static int jtag_vpi_runtest(int cycles, tap_state_t state)
309 {
310 int retval;
311
312 retval = jtag_vpi_state_move(TAP_IDLE);
313 if (retval != ERROR_OK)
314 return retval;
315
316 retval = jtag_vpi_queue_tdi(NULL, cycles, TAP_SHIFT);
317 if (retval != ERROR_OK)
318 return retval;
319
320 return jtag_vpi_state_move(state);
321 }
322
323 static int jtag_vpi_stableclocks(int cycles)
324 {
325 return jtag_vpi_queue_tdi(NULL, cycles, TAP_SHIFT);
326 }
327
328 static int jtag_vpi_execute_queue(void)
329 {
330 struct jtag_command *cmd;
331 int retval = ERROR_OK;
332
333 for (cmd = jtag_command_queue; retval == ERROR_OK && cmd != NULL;
334 cmd = cmd->next) {
335 switch (cmd->type) {
336 case JTAG_RESET:
337 retval = jtag_vpi_reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
338 break;
339 case JTAG_RUNTEST:
340 retval = jtag_vpi_runtest(cmd->cmd.runtest->num_cycles,
341 cmd->cmd.runtest->end_state);
342 break;
343 case JTAG_STABLECLOCKS:
344 retval = jtag_vpi_stableclocks(cmd->cmd.stableclocks->num_cycles);
345 break;
346 case JTAG_TLR_RESET:
347 retval = jtag_vpi_state_move(cmd->cmd.statemove->end_state);
348 break;
349 case JTAG_PATHMOVE:
350 retval = jtag_vpi_path_move(cmd->cmd.pathmove);
351 break;
352 case JTAG_TMS:
353 retval = jtag_vpi_tms(cmd->cmd.tms);
354 break;
355 case JTAG_SLEEP:
356 jtag_sleep(cmd->cmd.sleep->us);
357 break;
358 case JTAG_SCAN:
359 retval = jtag_vpi_scan(cmd->cmd.scan);
360 break;
361 }
362 }
363
364 return retval;
365 }
366
367 static int jtag_vpi_init(void)
368 {
369 sockfd = socket(AF_INET, SOCK_STREAM, 0);
370 if (sockfd < 0) {
371 LOG_ERROR("Could not create socket");
372 return ERROR_FAIL;
373 }
374
375 memset(&serv_addr, 0, sizeof(serv_addr));
376
377 serv_addr.sin_family = AF_INET;
378 serv_addr.sin_port = htons(server_port);
379
380 if (inet_pton(AF_INET, SERVER_ADDRESS, &serv_addr.sin_addr) <= 0) {
381 LOG_ERROR("inet_pton error occured");
382 return ERROR_FAIL;
383 }
384
385 if (connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
386 close(sockfd);
387 LOG_ERROR("Can't connect to %s : %u", SERVER_ADDRESS, server_port);
388 return ERROR_COMMAND_CLOSE_CONNECTION;
389 }
390
391 LOG_INFO("Connection to %s : %u succeed", SERVER_ADDRESS, server_port);
392
393 return ERROR_OK;
394 }
395
396 static int jtag_vpi_quit(void)
397 {
398 return close(sockfd);
399 }
400
401 COMMAND_HANDLER(jtag_vpi_set_port)
402 {
403 if (CMD_ARGC == 0)
404 LOG_WARNING("You need to set a port number");
405 else
406 COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], server_port);
407
408 LOG_INFO("Set server port to %u", server_port);
409
410 return ERROR_OK;
411 }
412
413
414 static const struct command_registration jtag_vpi_command_handlers[] = {
415 {
416 .name = "jtag_vpi_set_port",
417 .handler = &jtag_vpi_set_port,
418 .mode = COMMAND_CONFIG,
419 .help = "set the port of the VPI server",
420 .usage = "description_string",
421 },
422 COMMAND_REGISTRATION_DONE
423 };
424
425 struct jtag_interface jtag_vpi_interface = {
426 .name = "jtag_vpi",
427 .supported = DEBUG_CAP_TMS_SEQ,
428 .commands = jtag_vpi_command_handlers,
429 .transports = jtag_only,
430
431 .init = jtag_vpi_init,
432 .quit = jtag_vpi_quit,
433 .execute_queue = jtag_vpi_execute_queue,
434 };

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)