4 * Copyright (C) 2013 Franck Jullien, <elec4fun@gmail.com>
6 * See file CREDITS for list of people who contributed to this
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.
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.
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/>.
27 #include <jtag/interface.h>
28 #ifdef HAVE_ARPA_INET_H
29 #include <arpa/inet.h>
33 #include <netinet/tcp.h>
36 #define NO_TAP_SHIFT 0
39 #define SERVER_ADDRESS "127.0.0.1"
40 #define SERVER_PORT 5555
42 #define XFERT_MAX_SIZE 512
46 #define CMD_SCAN_CHAIN 2
47 #define CMD_SCAN_CHAIN_FLIP_TMS 3
48 #define CMD_STOP_SIMU 4
50 int server_port
= SERVER_PORT
;
54 struct sockaddr_in serv_addr
;
58 unsigned char buffer_out
[XFERT_MAX_SIZE
];
59 unsigned char buffer_in
[XFERT_MAX_SIZE
];
64 static int jtag_vpi_send_cmd(struct vpi_cmd
*vpi
)
66 int retval
= write_socket(sockfd
, vpi
, sizeof(struct vpi_cmd
));
73 static int jtag_vpi_receive_cmd(struct vpi_cmd
*vpi
)
75 int retval
= read_socket(sockfd
, vpi
, sizeof(struct vpi_cmd
));
76 if (retval
< (int)sizeof(struct vpi_cmd
))
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
87 static int jtag_vpi_reset(int trst
, int srst
)
93 return jtag_vpi_send_cmd(&vpi
);
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)
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
107 static int jtag_vpi_tms_seq(const uint8_t *bits
, int nb_bits
)
112 nb_bytes
= DIV_ROUND_UP(nb_bits
, 8);
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
;
119 return jtag_vpi_send_cmd(&vpi
);
123 * jtag_vpi_path_move - ask a TMS sequence transition to JTAG
124 * @cmd: path transition
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
133 static int jtag_vpi_path_move(struct pathmove_command
*cmd
)
135 uint8_t trans
[DIV_ROUND_UP(cmd
->num_states
, 8)];
137 memset(trans
, 0, DIV_ROUND_UP(cmd
->num_states
, 8));
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
]);
145 return jtag_vpi_tms_seq(trans
, cmd
->num_states
);
149 * jtag_vpi_tms - ask a tms command
152 static int jtag_vpi_tms(struct tms_command
*cmd
)
154 return jtag_vpi_tms_seq(cmd
->bits
, cmd
->num_bits
);
157 static int jtag_vpi_state_move(tap_state_t state
)
159 if (tap_get_state() == state
)
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
);
165 int retval
= jtag_vpi_tms_seq(&tms_scan
, tms_len
);
166 if (retval
!= ERROR_OK
)
169 tap_set_state(state
);
174 static int jtag_vpi_queue_tdi_xfer(uint8_t *bits
, int nb_bits
, int tap_shift
)
177 int nb_bytes
= DIV_ROUND_UP(nb_bits
, 8);
179 vpi
.cmd
= tap_shift
? CMD_SCAN_CHAIN_FLIP_TMS
: CMD_SCAN_CHAIN
;
182 memcpy(vpi
.buffer_out
, bits
, nb_bytes
);
184 memset(vpi
.buffer_out
, 0xff, nb_bytes
);
186 vpi
.length
= nb_bytes
;
187 vpi
.nb_bits
= nb_bits
;
189 int retval
= jtag_vpi_send_cmd(&vpi
);
190 if (retval
!= ERROR_OK
)
193 retval
= jtag_vpi_receive_cmd(&vpi
);
194 if (retval
!= ERROR_OK
)
198 memcpy(bits
, vpi
.buffer_in
, nb_bytes
);
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
208 static int jtag_vpi_queue_tdi(uint8_t *bits
, int nb_bits
, int tap_shift
)
210 int nb_xfer
= DIV_ROUND_UP(nb_bits
, XFERT_MAX_SIZE
* 8);
215 retval
= jtag_vpi_queue_tdi_xfer(bits
, nb_bits
, tap_shift
);
216 if (retval
!= ERROR_OK
)
219 retval
= jtag_vpi_queue_tdi_xfer(bits
, XFERT_MAX_SIZE
* 8, NO_TAP_SHIFT
);
220 if (retval
!= ERROR_OK
)
222 nb_bits
-= XFERT_MAX_SIZE
* 8;
224 bits
+= XFERT_MAX_SIZE
;
234 * jtag_vpi_clock_tms - clock a TMS transition
235 * @tms: the TMS to be sent
237 * Triggers a TMS transition (ie. one JTAG TAP state move).
239 static int jtag_vpi_clock_tms(int tms
)
241 const uint8_t tms_0
= 0;
242 const uint8_t tms_1
= 1;
244 return jtag_vpi_tms_seq(tms
? &tms_1
: &tms_0
, 1);
248 * jtag_vpi_scan - launches a DR-scan or IR-scan
249 * @cmd: the command to launch
251 * Launch a JTAG IR-scan or DR-scan
253 * Returns ERROR_OK if OK, ERROR_xxx if a read/write error occured.
255 static int jtag_vpi_scan(struct scan_command
*cmd
)
259 int retval
= ERROR_OK
;
261 scan_bits
= jtag_build_buffer(cmd
, &buf
);
264 retval
= jtag_vpi_state_move(TAP_IRSHIFT
);
265 if (retval
!= ERROR_OK
)
268 retval
= jtag_vpi_state_move(TAP_DRSHIFT
);
269 if (retval
!= ERROR_OK
)
273 if (cmd
->end_state
== TAP_DRSHIFT
) {
274 retval
= jtag_vpi_queue_tdi(buf
, scan_bits
, NO_TAP_SHIFT
);
275 if (retval
!= ERROR_OK
)
278 retval
= jtag_vpi_queue_tdi(buf
, scan_bits
, TAP_SHIFT
);
279 if (retval
!= ERROR_OK
)
283 if (cmd
->end_state
!= TAP_DRSHIFT
) {
285 * As our JTAG is in an unstable state (IREXIT1 or DREXIT1), move it
286 * forward to a stable IRPAUSE or DRPAUSE.
288 retval
= jtag_vpi_clock_tms(0);
289 if (retval
!= ERROR_OK
)
293 tap_set_state(TAP_IRPAUSE
);
295 tap_set_state(TAP_DRPAUSE
);
298 retval
= jtag_read_buffer(buf
, cmd
);
299 if (retval
!= ERROR_OK
)
305 if (cmd
->end_state
!= TAP_DRSHIFT
) {
306 retval
= jtag_vpi_state_move(cmd
->end_state
);
307 if (retval
!= ERROR_OK
)
314 static int jtag_vpi_runtest(int cycles
, tap_state_t state
)
318 retval
= jtag_vpi_state_move(TAP_IDLE
);
319 if (retval
!= ERROR_OK
)
322 retval
= jtag_vpi_queue_tdi(NULL
, cycles
, NO_TAP_SHIFT
);
323 if (retval
!= ERROR_OK
)
326 return jtag_vpi_state_move(state
);
329 static int jtag_vpi_stableclocks(int cycles
)
332 int cycles_remain
= cycles
;
335 const int CYCLES_ONE_BATCH
= sizeof(tms_bits
) * 8;
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
));
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
)
348 cycles_remain
-= nb_bits
;
354 static int jtag_vpi_execute_queue(void)
356 struct jtag_command
*cmd
;
357 int retval
= ERROR_OK
;
359 for (cmd
= jtag_command_queue
; retval
== ERROR_OK
&& cmd
!= NULL
;
363 retval
= jtag_vpi_reset(cmd
->cmd
.reset
->trst
, cmd
->cmd
.reset
->srst
);
366 retval
= jtag_vpi_runtest(cmd
->cmd
.runtest
->num_cycles
,
367 cmd
->cmd
.runtest
->end_state
);
369 case JTAG_STABLECLOCKS
:
370 retval
= jtag_vpi_stableclocks(cmd
->cmd
.stableclocks
->num_cycles
);
373 retval
= jtag_vpi_state_move(cmd
->cmd
.statemove
->end_state
);
376 retval
= jtag_vpi_path_move(cmd
->cmd
.pathmove
);
379 retval
= jtag_vpi_tms(cmd
->cmd
.tms
);
382 jtag_sleep(cmd
->cmd
.sleep
->us
);
385 retval
= jtag_vpi_scan(cmd
->cmd
.scan
);
393 static int jtag_vpi_init(void)
397 sockfd
= socket(AF_INET
, SOCK_STREAM
, 0);
399 LOG_ERROR("Could not create socket");
403 memset(&serv_addr
, 0, sizeof(serv_addr
));
405 serv_addr
.sin_family
= AF_INET
;
406 serv_addr
.sin_port
= htons(server_port
);
409 server_address
= strdup(SERVER_ADDRESS
);
411 serv_addr
.sin_addr
.s_addr
= inet_addr(server_address
);
413 if (serv_addr
.sin_addr
.s_addr
== INADDR_NONE
) {
414 LOG_ERROR("inet_addr error occured");
418 if (connect(sockfd
, (struct sockaddr
*)&serv_addr
, sizeof(serv_addr
)) < 0) {
420 LOG_ERROR("Can't connect to %s : %u", server_address
, server_port
);
421 return ERROR_COMMAND_CLOSE_CONNECTION
;
424 if (serv_addr
.sin_addr
.s_addr
== htonl(INADDR_LOOPBACK
)) {
425 /* This increases performance drematically for local
426 * connections, which is the most likely arrangement
427 * for a VPI connection. */
428 setsockopt(sockfd
, IPPROTO_TCP
, TCP_NODELAY
, (char *)&flag
, sizeof(int));
431 LOG_INFO("Connection to %s : %u succeed", server_address
, server_port
);
436 static int jtag_vpi_quit(void)
438 free(server_address
);
439 return close(sockfd
);
442 COMMAND_HANDLER(jtag_vpi_set_port
)
445 LOG_WARNING("You need to set a port number");
447 COMMAND_PARSE_NUMBER(int, CMD_ARGV
[0], server_port
);
449 LOG_INFO("Set server port to %u", server_port
);
454 COMMAND_HANDLER(jtag_vpi_set_address
)
456 free(server_address
);
459 LOG_WARNING("You need to set an address");
460 server_address
= strdup(SERVER_ADDRESS
);
462 server_address
= strdup(CMD_ARGV
[0]);
464 LOG_INFO("Set server address to %s", server_address
);
469 static const struct command_registration jtag_vpi_command_handlers
[] = {
471 .name
= "jtag_vpi_set_port",
472 .handler
= &jtag_vpi_set_port
,
473 .mode
= COMMAND_CONFIG
,
474 .help
= "set the port of the VPI server",
475 .usage
= "description_string",
478 .name
= "jtag_vpi_set_address",
479 .handler
= &jtag_vpi_set_address
,
480 .mode
= COMMAND_CONFIG
,
481 .help
= "set the address of the VPI server",
482 .usage
= "description_string",
484 COMMAND_REGISTRATION_DONE
487 struct jtag_interface jtag_vpi_interface
= {
489 .supported
= DEBUG_CAP_TMS_SEQ
,
490 .commands
= jtag_vpi_command_handlers
,
491 .transports
= jtag_only
,
493 .init
= jtag_vpi_init
,
494 .quit
= jtag_vpi_quit
,
495 .execute_queue
= jtag_vpi_execute_queue
,
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)