adiv6: use struct adiv5_ap->ap_num to contain the AP base address
[openocd.git] / src / jtag / drivers / vdebug.c
1 /* SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause) */
2 /*----------------------------------------------------------------------------
3 * Copyright 2020-2021 Cadence Design Systems, Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without modification,
6 * are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright notice,
10 * this list of conditions and the following disclaimer in the documentation
11 * and/or other materials provided with the distribution.
12 *----------------------------------------------------------------------------
13 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
20 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
21 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 *----------------------------------------------------------------------------
24 */
25
26 /*!
27 * @file
28 *
29 * @brief the virtual debug interface provides a connection between a sw debugger
30 * and the simulated, emulated core over a soft connection, implemented by DPI
31 * The vdebug debug driver currently supports JTAG transport
32 * TODO: implement support and test big endian platforms
33 *
34 */
35
36 #ifdef HAVE_CONFIG_H
37 #include "config.h"
38 #endif
39
40 #ifdef _WIN32
41 #define WIN32_LEAN_AND_MEAN
42 #include <windows.h>
43 #else
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h> /* close */
46 #endif
47 #ifdef HAVE_SYS_SOCKET_H
48 #include <sys/socket.h>
49 #endif
50 #ifdef HAVE_ARPA_INET_H
51 #include <arpa/inet.h>
52 #endif
53 #ifdef HAVE_NETDB_H
54 #include <netdb.h>
55 #endif
56 #endif
57 #include <stdio.h>
58 #ifdef HAVE_STDINT_H
59 #include <stdint.h>
60 #endif
61 #ifdef HAVE_STDLIB_H
62 #include <stdlib.h>
63 #endif
64 #include <stdarg.h>
65 #include <string.h>
66 #include <errno.h>
67
68 #include "jtag/interface.h"
69 #include "jtag/commands.h"
70 #include "transport/transport.h"
71 #include "helper/time_support.h"
72 #include "helper/replacements.h"
73 #include "helper/log.h"
74
75 #define VD_VERSION 43
76 #define VD_BUFFER_LEN 4024
77 #define VD_CHEADER_LEN 24
78 #define VD_SHEADER_LEN 16
79
80 #define VD_MAX_MEMORIES 4
81 #define VD_POLL_INTERVAL 500
82 #define VD_SCALE_PSTOMS 1000000000
83
84 /**
85 * @brief List of transactor types
86 */
87 enum {
88 VD_BFM_JTDP = 0x0001, /* transactor DAP JTAG DP */
89 VD_BFM_SWDP = 0x0002, /* transactor DAP SWD DP */
90 VD_BFM_AHB = 0x0003, /* transactor AMBA AHB */
91 VD_BFM_APB = 0x0004, /* transactor AMBA APB */
92 VD_BFM_AXI = 0x0005, /* transactor AMBA AXI */
93 VD_BFM_JTAG = 0x0006, /* transactor serial JTAG */
94 VD_BFM_SWD = 0x0007, /* transactor serial SWD */
95 };
96
97 /**
98 * @brief List of signals that can be read or written by the debugger
99 */
100 enum {
101 VD_SIG_TCK = 0x0001, /* JTAG clock; tclk */
102 VD_SIG_TDI = 0x0002, /* JTAG TDI; tdi */
103 VD_SIG_TMS = 0x0004, /* JTAG TMS; tms */
104 VD_SIG_RESET = 0x0008, /* DUT reset; rst */
105 VD_SIG_TRST = 0x0010, /* JTAG Reset; trstn */
106 VD_SIG_TDO = 0x0020, /* JTAG TDO; tdo */
107 VD_SIG_POWER = 0x0100, /* BFM power; bfm_up */
108 VD_SIG_TCKDIV = 0x0200, /* JTAG clock divider; tclkdiv */
109 VD_SIG_BUF = 0x1000, /* memory buffer; mem */
110 };
111
112 /**
113 * @brief List of errors
114 */
115 enum {
116 VD_ERR_NONE = 0x0000, /* no error */
117 VD_ERR_NOT_IMPL = 0x0100, /* feature not implemented */
118 VD_ERR_USAGE = 0x0101, /* incorrect usage */
119 VD_ERR_PARAM = 0x0102, /* incorrect parameter */
120 VD_ERR_CONFIG = 0x0107, /* incorrect configuration */
121 VD_ERR_NO_MEMORY = 0x0104, /* out of memory */
122 VD_ERR_SHM_OPEN = 0x010a, /* cannot open shared memory */
123 VD_ERR_SHM_MAP = 0x010b, /* cannot map shared memory */
124 VD_ERR_SOC_OPEN = 0x011a, /* cannot open socket */
125 VD_ERR_SOC_OPT = 0x011b, /* cannot set socket option */
126 VD_ERR_SOC_ADDR = 0x011c, /* cannot resolve host address */
127 VD_ERR_SOC_CONN = 0x011d, /* cannot connect to host */
128 VD_ERR_SOC_SEND = 0x011e, /* error sending data on socket */
129 VD_ERR_SOC_RECV = 0x011f, /* error receiving data from socket */
130 VD_ERR_LOCKED = 0x0202, /* device locked */
131 VD_ERR_NOT_RUN = 0x0204, /* transactor not running */
132 VD_ERR_NOT_OPEN = 0x0205, /* transactor not open/connected */
133 VD_ERR_LICENSE = 0x0206, /* cannot check out the license */
134 VD_ERR_VERSION = 0x0207, /* transactor version mismatch */
135 VD_ERR_TIME_OUT = 0x0301, /* time out, waiting */
136 VD_ERR_NO_POWER = 0x0302, /* power out error */
137 VD_ERR_BUS_ERROR = 0x0304, /* bus protocol error, like pslverr */
138 VD_ERR_NO_ACCESS = 0x0306, /* no access to an object */
139 VD_ERR_INV_HANDLE = 0x0307, /* invalid object handle */
140 VD_ERR_INV_SCOPE = 0x0308, /* invalid scope */
141 };
142
143 enum {
144 VD_CMD_OPEN = 0x01,
145 VD_CMD_CLOSE = 0x02,
146 VD_CMD_CONNECT = 0x04,
147 VD_CMD_DISCONNECT = 0x05,
148 VD_CMD_WAIT = 0x09,
149 VD_CMD_SIGSET = 0x0a,
150 VD_CMD_SIGGET = 0x0b,
151 VD_CMD_JTAGCLOCK = 0x0f,
152 VD_CMD_JTAGSHTAP = 0x1a,
153 VD_CMD_MEMOPEN = 0x21,
154 VD_CMD_MEMCLOSE = 0x22,
155 VD_CMD_MEMWRITE = 0x23,
156 };
157
158 enum {
159 VD_BATCH_NO = 0,
160 VD_BATCH_WO = 1,
161 VD_BATCH_WR = 2,
162 };
163
164 struct vd_shm {
165 struct { /* VD_CHEADER_LEN written by client */
166 uint8_t cmd; /* 000; command */
167 uint8_t type; /* 001; interface type */
168 uint16_t waddr; /* 002; write pointer */
169 uint16_t wbytes; /* 004; data bytes */
170 uint16_t rbytes; /* 006; data bytes to read */
171 uint16_t wwords; /* 008; data words */
172 uint16_t rwords; /* 00a; data words to read */
173 uint32_t rwdata; /* 00c; read/write data */
174 uint32_t offset; /* 010; address offset */
175 uint16_t offseth; /* 014; address offset 47:32 */
176 uint16_t wid; /* 016; request id*/
177 };
178 union { /* 018; */
179 uint8_t wd8[VD_BUFFER_LEN];
180 uint16_t wd16[VD_BUFFER_LEN / 2];
181 uint32_t wd32[VD_BUFFER_LEN / 4];
182 uint64_t wd64[VD_BUFFER_LEN / 8];
183 };
184 struct { /* VD_SHEADER_LEN written by server */
185 uint16_t rid; /* fd0: request id read */
186 uint16_t awords; /* fd2: actual data words read back */
187 int32_t status; /* fd4; */
188 uint64_t duttime; /* fd8; */
189 };
190 union { /* fe0: */
191 uint8_t rd8[VD_BUFFER_LEN];
192 uint16_t rd16[VD_BUFFER_LEN / 2];
193 uint32_t rd32[VD_BUFFER_LEN / 4];
194 uint64_t rd64[VD_BUFFER_LEN / 8];
195 };
196 uint32_t state; /* 1f98; connection state */
197 uint32_t count; /* 1f9c; */
198 uint8_t dummy[96]; /* 1fa0; 48+40B+8B; */
199 };
200
201 struct vd_client {
202 uint8_t trans_batch;
203 bool trans_first;
204 bool trans_last;
205 uint8_t mem_ndx;
206 uint8_t buf_width;
207 uint8_t addr_bits;
208 uint8_t bfm_type;
209 uint16_t sig_read;
210 uint16_t sig_write;
211 uint32_t bfm_period;
212 uint32_t mem_base[VD_MAX_MEMORIES];
213 uint32_t mem_size[VD_MAX_MEMORIES];
214 uint32_t mem_width[VD_MAX_MEMORIES];
215 uint32_t mem_depth[VD_MAX_MEMORIES];
216 uint16_t server_port;
217 uint32_t poll_cycles;
218 uint32_t poll_min;
219 uint32_t poll_max;
220 uint32_t targ_time;
221 int hsocket;
222 char server_name[32];
223 char bfm_path[128];
224 char mem_path[VD_MAX_MEMORIES][128];
225 uint8_t *tdo;
226 };
227
228 struct vd_jtag_hdr {
229 uint64_t tlen:24;
230 uint64_t post:3;
231 uint64_t pre:3;
232 uint64_t cmd:2;
233 uint64_t wlen:16;
234 uint64_t rlen:16;
235 };
236
237 static struct vd_shm *pbuf;
238 static struct vd_client vdc;
239
240 static int vdebug_socket_error(void)
241 {
242 #ifdef _WIN32
243 return WSAGetLastError();
244 #else
245 return errno;
246 #endif
247 }
248
249 static int vdebug_socket_open(char *server_addr, uint32_t port)
250 {
251 int hsock;
252 int rc = 0;
253 uint32_t buflen = sizeof(struct vd_shm); /* size of the send and rcv buffer */
254 struct addrinfo *ainfo = NULL;
255 struct addrinfo ahint = { 0, AF_INET, SOCK_STREAM, 0, 0, NULL, NULL, NULL };
256
257 #ifdef _WIN32
258 hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
259 if (hsock == INVALID_SOCKET)
260 rc = vdebug_socket_error();
261 #else
262 uint32_t rcvwat = VD_SHEADER_LEN; /* size of the rcv header, as rcv min watermark */
263 hsock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
264 if (hsock < 0)
265 rc = errno;
266 else if (setsockopt(hsock, SOL_SOCKET, SO_RCVLOWAT, &rcvwat, sizeof(rcvwat)) < 0)
267 rc = errno;
268 #endif
269 else if (setsockopt(hsock, SOL_SOCKET, SO_SNDBUF, (const char *)&buflen, sizeof(buflen)) < 0)
270 rc = vdebug_socket_error();
271 else if (setsockopt(hsock, SOL_SOCKET, SO_RCVBUF, (const char *)&buflen, sizeof(buflen)) < 0)
272 rc = vdebug_socket_error();
273
274 if (rc) {
275 LOG_ERROR("socket_open: cannot set socket option, error %d", rc);
276 } else if (getaddrinfo(server_addr, NULL, &ahint, &ainfo) != 0) {
277 LOG_ERROR("socket_open: cannot resolve address %s, error %d", server_addr, vdebug_socket_error());
278 rc = VD_ERR_SOC_ADDR;
279 } else {
280 ((struct sockaddr_in *)(ainfo->ai_addr))->sin_port = htons(port);
281 if (connect(hsock, ainfo->ai_addr, sizeof(struct sockaddr)) < 0) {
282 LOG_ERROR("socket_open: cannot connect to %s:%d, error %d", server_addr, port, vdebug_socket_error());
283 rc = VD_ERR_SOC_CONN;
284 }
285 }
286
287 if (rc) {
288 close_socket(hsock);
289 hsock = 0;
290 }
291
292 if (ainfo)
293 freeaddrinfo(ainfo);
294
295 return hsock;
296 }
297
298 static int vdebug_socket_receive(int hsock, struct vd_shm *pmem)
299 {
300 int rc;
301 int dreceived = 0;
302 int offset = (uint8_t *)&pmem->rid - &pmem->cmd;
303 int to_receive = VD_SHEADER_LEN + pmem->rbytes;
304 char *pb = (char *)pmem;
305
306 do {
307 rc = recv(hsock, pb + offset, to_receive, 0);
308 if (rc <= 0) {
309 LOG_WARNING("socket_receive: recv failed, error %d", rc < 0 ? vdebug_socket_error() : 0);
310 return rc;
311 }
312 to_receive -= rc;
313 offset += rc;
314 LOG_DEBUG_IO("socket_receive: received %d, to receive %d", rc, to_receive);
315 dreceived += rc;
316 } while (to_receive);
317
318 return dreceived;
319 }
320
321 static int vdebug_socket_send(int hsock, struct vd_shm *pmem)
322 {
323 int rc = send(hsock, (const char *)&pmem->cmd, VD_CHEADER_LEN + pmem->wbytes, 0);
324 if (rc <= 0)
325 LOG_WARNING("socket_send: send failed, error %d", vdebug_socket_error());
326 else
327 LOG_DEBUG_IO("socket_send: sent %d, to send 0", rc);
328
329 return rc;
330 }
331
332 static uint32_t vdebug_wait_server(int hsock, struct vd_shm *pmem)
333 {
334 if (!hsock)
335 return VD_ERR_SOC_OPEN;
336 int st = vdebug_socket_send(hsock, pmem);
337 if (st <= 0)
338 return VD_ERR_SOC_SEND;
339
340 int rd = vdebug_socket_receive(hsock, pmem);
341 if (rd <= 0)
342 return VD_ERR_SOC_RECV;
343
344 int rc = pmem->status;
345 LOG_DEBUG_IO("wait_server: cmd %02" PRIx8 " done, sent %d, rcvd %d, status %d",
346 pmem->cmd, st, rd, rc);
347
348 return rc;
349 }
350
351 int vdebug_run_jtag_queue(int hsock, struct vd_shm *pm, unsigned int count)
352 {
353 uint8_t num_pre, num_post, tdi, tms;
354 unsigned int num, anum, bytes, hwords, words;
355 unsigned int req, waddr, rwords;
356 int64_t ts, te;
357 uint8_t *tdo;
358 int rc;
359 struct vd_jtag_hdr *hdr;
360
361 req = 0; /* beginning of request */
362 waddr = 0;
363 rwords = 0;
364 pm->wbytes = pm->wwords * vdc.buf_width;
365 pm->rbytes = pm->rwords * vdc.buf_width;
366 ts = timeval_ms();
367 rc = vdebug_wait_server(hsock, pm);
368 while (!rc && (req < count)) { /* loop over requests to read data and print out */
369 hdr = (struct vd_jtag_hdr *)&pm->wd8[waddr * 4];
370 hwords = hdr->wlen;
371 words = hdr->rlen;
372 anum = hdr->tlen;
373 num_pre = hdr->pre;
374 num_post = hdr->post;
375 if (num_post)
376 num = anum - num_pre - num_post + 1;
377 else
378 num = anum - num_pre;
379 bytes = (num + 7) / 8;
380 vdc.trans_last = (req + 1) < count ? 0 : 1;
381 vdc.trans_first = waddr ? 0 : 1;
382 if (hdr->cmd == 3) { /* read */
383 tdo = vdc.tdo;
384 for (unsigned int j = 0; j < bytes; j++) {
385 tdo[j] = (pm->rd8[rwords * 8 + j] >> num_pre) | (pm->rd8[rwords * 8 + j + 1] << (8 - num_pre));
386 LOG_DEBUG_IO("%04x D0[%02x]:%02x", pm->wid - count + req, j, tdo[j]);
387 }
388 rwords += words; /* read data offset */
389 } else {
390 tdo = NULL;
391 }
392 waddr += sizeof(struct vd_jtag_hdr) / 4; /* waddr past header */
393 tdi = (pm->wd8[waddr * 4] >> num_pre) | (pm->wd8[waddr * 4 + 1] << (8 - num_pre));
394 tms = (pm->wd8[waddr * 4 + 4] >> num_pre) | (pm->wd8[waddr * 4 + 4 + 1] << (8 - num_pre));
395 LOG_DEBUG("%04x L:%02d O:%05x @%03x DI:%02x MS:%02x DO:%02x",
396 pm->wid - count + req, num, (vdc.trans_first << 14) | (vdc.trans_last << 15),
397 waddr - 2, tdi, tms, (tdo ? tdo[0] : 0xdd));
398 waddr += hwords * 2; /* start of next request */
399 req += 1;
400 }
401
402 if (rc) {
403 LOG_ERROR("0x%x executing transaction", rc);
404 rc = ERROR_FAIL;
405 }
406
407 te = timeval_ms();
408 vdc.targ_time += (uint32_t)(te - ts);
409 pm->offseth = 0; /* reset buffer write address */
410 pm->offset = 0;
411 pm->rwords = 0;
412 pm->waddr = 0;
413
414 return rc;
415 }
416
417 static int vdebug_open(int hsock, struct vd_shm *pm, const char *path,
418 uint8_t type, uint32_t period_ps, uint32_t sig_mask)
419 {
420 int rc = VD_ERR_NOT_OPEN;
421
422 pm->cmd = VD_CMD_OPEN;
423 pm->wid = VD_VERSION; /* client version */
424 pm->wbytes = 0;
425 pm->rbytes = 0;
426 pm->wwords = 0;
427 pm->rwords = 0;
428 rc = vdebug_wait_server(hsock, pm);
429 if (rc != 0) { /* communication problem */
430 LOG_ERROR("0x%x connecting to server", rc);
431 } else if (pm->rid < pm->wid) {
432 LOG_ERROR("server version %d too old for the client %d", pm->rid, pm->wid);
433 pm->cmd = VD_CMD_CLOSE; /* let server close the connection */
434 vdebug_wait_server(hsock, pm);
435 rc = VD_ERR_VERSION;
436 } else {
437 pm->cmd = VD_CMD_CONNECT;
438 pm->type = type; /* BFM type to connect to, here JTAG */
439 pm->rwdata = sig_mask | VD_SIG_BUF | (VD_SIG_BUF << 16);
440 pm->wbytes = strlen(path) + 1;
441 pm->rbytes = 12;
442 pm->wid = 0; /* reset wid for transaction ID */
443 pm->wwords = 0;
444 pm->rwords = 0;
445 memcpy(pm->wd8, path, pm->wbytes + 1);
446 rc = vdebug_wait_server(hsock, pm);
447 vdc.sig_read = pm->rwdata >> 16; /* signal read mask */
448 vdc.sig_write = pm->rwdata; /* signal write mask */
449 vdc.bfm_period = period_ps;
450 vdc.buf_width = pm->rd32[0] / 8;/* access width in bytes */
451 vdc.addr_bits = pm->rd32[2]; /* supported address bits */
452 }
453
454 if (rc) {
455 LOG_ERROR("0x%x connecting to BFM %s", rc, path);
456 return ERROR_FAIL;
457 }
458
459 LOG_DEBUG("%s type %0x, period %dps, buffer %dx%dB signals r%04xw%04x",
460 path, type, vdc.bfm_period, VD_BUFFER_LEN / vdc.buf_width,
461 vdc.buf_width, vdc.sig_read, vdc.sig_write);
462
463 return ERROR_OK;
464 }
465
466 static int vdebug_close(int hsock, struct vd_shm *pm, uint8_t type)
467 {
468 pm->cmd = VD_CMD_DISCONNECT;
469 pm->type = type; /* BFM type, here JTAG */
470 pm->wbytes = 0;
471 pm->rbytes = 0;
472 pm->wwords = 0;
473 pm->rwords = 0;
474 vdebug_wait_server(hsock, pm);
475 pm->cmd = VD_CMD_CLOSE;
476 pm->wid = VD_VERSION; /* client version */
477 pm->wbytes = 0;
478 pm->rbytes = 0;
479 pm->wwords = 0;
480 pm->rwords = 0;
481 vdebug_wait_server(hsock, pm);
482 LOG_DEBUG("type %0x", type);
483
484 return ERROR_OK;
485 }
486
487 static int vdebug_wait(int hsock, struct vd_shm *pm, uint32_t cycles)
488 {
489 if (cycles) {
490 pm->cmd = VD_CMD_WAIT;
491 pm->wbytes = 0;
492 pm->rbytes = 0;
493 pm->rwdata = cycles; /* clock sycles to wait */
494 int rc = vdebug_wait_server(hsock, pm);
495 if (rc) {
496 LOG_ERROR("0x%x waiting %" PRIx32 " cycles", rc, cycles);
497 return ERROR_FAIL;
498 }
499 LOG_DEBUG("%d cycles", cycles);
500 }
501
502 return ERROR_OK;
503 }
504
505 static int vdebug_sig_set(int hsock, struct vd_shm *pm, uint32_t write_mask, uint32_t value)
506 {
507 pm->cmd = VD_CMD_SIGSET;
508 pm->wbytes = 0;
509 pm->rbytes = 0;
510 pm->rwdata = (write_mask << 16) | (value & 0xffff); /* mask and value of signals to set */
511 int rc = vdebug_wait_server(hsock, pm);
512 if (rc) {
513 LOG_ERROR("0x%x setting signals %04" PRIx32, rc, write_mask);
514 return ERROR_FAIL;
515 }
516
517 LOG_DEBUG("setting signals %04" PRIx32 " to %04" PRIx32, write_mask, value);
518
519 return ERROR_OK;
520 }
521
522 static int vdebug_jtag_clock(int hsock, struct vd_shm *pm, uint32_t value)
523 {
524 pm->cmd = VD_CMD_JTAGCLOCK;
525 pm->wbytes = 0;
526 pm->rbytes = 0;
527 pm->rwdata = value; /* divider value */
528 int rc = vdebug_wait_server(hsock, pm);
529 if (rc) {
530 LOG_ERROR("0x%x setting jtag_clock", rc);
531 return ERROR_FAIL;
532 }
533
534 LOG_DEBUG("setting jtag clock divider to %" PRIx32, value);
535
536 return ERROR_OK;
537 }
538
539 static int vdebug_jtag_shift_tap(int hsock, struct vd_shm *pm, uint8_t num_pre,
540 const uint8_t tms_pre, uint32_t num, const uint8_t *tdi,
541 uint8_t num_post, const uint8_t tms_post, uint8_t *tdo,
542 uint8_t f_last)
543 {
544 const uint32_t tobits = 8;
545 uint16_t bytes, hwords, anum, words, waddr;
546 int rc = 0;
547
548 pm->cmd = VD_CMD_JTAGSHTAP;
549 vdc.trans_last = f_last || (vdc.trans_batch == VD_BATCH_NO) || tdo;
550 if (vdc.trans_first)
551 waddr = 0; /* reset buffer offset */
552 else
553 waddr = pm->offseth; /* continue from the previous transaction */
554 if (num_post) /* actual number of bits to shift */
555 anum = num + num_pre + num_post - 1;
556 else
557 anum = num + num_pre;
558 hwords = (anum + 4 * vdc.buf_width - 1) / (4 * vdc.buf_width); /* in 4B TDI/TMS words */
559 words = (hwords + 1) / 2; /* in 8B TDO words to read */
560 bytes = (num + 7) / 8; /* data only portion in bytes */
561 /* buffer overflow check and flush */
562 if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords + 64 > VD_BUFFER_LEN) {
563 vdc.trans_last = 1; /* force flush within 64B of buffer end */
564 } else if (4 * waddr + sizeof(struct vd_jtag_hdr) + 8 * hwords > VD_BUFFER_LEN) {
565 /* this req does not fit, discard it */
566 LOG_ERROR("%04x L:%02d O:%05x @%04x too many bits to shift",
567 pm->wid, anum, (vdc.trans_first << 14) | (vdc.trans_last << 15), waddr);
568 rc = ERROR_FAIL;
569 }
570
571 if (!rc && anum) {
572 uint16_t i, j;
573 struct vd_jtag_hdr *hdr = (struct vd_jtag_hdr *)&pm->wd8[4 * waddr]; /* 8 bytes header */
574 hdr->cmd = (tdo ? 3 : 1); /* R and W bits */
575 hdr->pre = num_pre;
576 hdr->post = num_post;
577 hdr->tlen = anum;
578 hdr->wlen = hwords;
579 hdr->rlen = words;
580 pm->wid++; /* transaction ID */
581 waddr += 2; /* waddr past header */
582 /* TDI/TMS data follows as 32 bit word pairs {TMS,TDI} */
583 pm->wd8[4 * waddr] = (tdi ? (tdi[0] << num_pre) : 0);
584 pm->wd8[4 * waddr + 4] = tms_pre; /* init with tms_pre */
585 if (num + num_pre <= 8) /* and tms_post for num <=4 */
586 pm->wd8[4 * waddr + 4] |= (tms_post << (num + num_pre - 1));
587 for (i = 1, j = 4 * waddr; i < bytes; i++) {
588 if (i == bytes - 1 && num + num_pre <= bytes * tobits)
589 pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8);
590 else
591 pm->wd8[j + i + 4] = 0x0;/* placing 4 bytes of TMS bits into high word */
592 if (!tdi) /* placing 4 bytes of TDI bits into low word */
593 pm->wd8[j + i] = 0x0;
594 else
595 pm->wd8[j + i] = (tdi[i] << num_pre) | (tdi[i - 1] >> (8 - num_pre));
596 if (i % 4 == 3)
597 j += 4;
598 }
599
600 if (tdi)
601 if (num + num_pre > bytes * tobits) /* in case 1 additional byte needed for TDI */
602 pm->wd8[j + i] = (tdi[i - 1] >> (8 - num_pre)); /* put last TDI bits there */
603
604 if (num + num_pre <= bytes * tobits) { /* in case no or 1 additional byte needed */
605 pm->wd8[j + i + 4] = tms_post >> (8 - (num + num_pre - 1) % 8); /* may need to add higher part */
606 /* in case exactly 1 additional byte needed */
607 } else if (num + num_pre > bytes * tobits && anum <= (bytes + 1) * tobits) {
608 pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8); /* add whole tms_post */
609 } else { /* in case 2 additional bytes, tms_post split */
610 pm->wd8[j + i + 4] = tms_post << ((num + num_pre - 1) % 8);/* add lower part of tms_post */
611 if (i % 4 == 3) /* next byte is in the next 32b word */
612 pm->wd8[j + i + 4 + 5] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */
613 else /* next byte is in the same 32b word */
614 pm->wd8[j + i + 4 + 1] = tms_post >> (8 - (num + num_pre - 1) % 8); /* and higher part */
615 }
616
617 if (tdo) {
618 pm->rwords += words; /* keep track of the words to read */
619 vdc.tdo = tdo;
620 }
621 pm->wwords = waddr / 2 + hwords; /* payload size *2 to include both TDI and TMS data */
622 pm->waddr++;
623 }
624
625 if (!waddr) /* flush issued, but buffer empty */
626 ;
627 else if (!vdc.trans_last) /* buffered request */
628 pm->offseth = waddr + hwords * 2; /* offset for next transaction, must be even */
629 else /* execute batch of requests */
630 rc = vdebug_run_jtag_queue(hsock, pm, pm->waddr);
631 vdc.trans_first = vdc.trans_last; /* flush forces trans_first flag */
632
633 return rc;
634 }
635
636 static int vdebug_mem_open(int hsock, struct vd_shm *pm, const char *path, uint8_t ndx)
637 {
638 int rc;
639
640 if (!path)
641 return ERROR_OK;
642
643 pm->cmd = VD_CMD_MEMOPEN;
644 pm->wbytes = strlen(path) + 1; /* includes terminating 0 */
645 pm->rbytes = 8;
646 pm->wwords = 0;
647 pm->rwords = 0;
648 memcpy(pm->wd8, path, pm->wbytes);
649 rc = vdebug_wait_server(hsock, pm);
650 if (rc) {
651 LOG_ERROR("0x%x opening memory %s", rc, path);
652 } else if (ndx != pm->rd16[1]) {
653 LOG_WARNING("Invalid memory index %" PRIu16 " returned. Direct memory access disabled", pm->rd16[1]);
654 } else {
655 vdc.mem_width[ndx] = pm->rd16[0] / 8; /* memory width in bytes */
656 vdc.mem_depth[ndx] = pm->rd32[1]; /* memory depth in words */
657 LOG_DEBUG("%" PRIx8 ": %s memory %" PRIu32 "x%" PRIu32 "B, buffer %" PRIu32 "x%" PRIu32 "B", ndx, path,
658 vdc.mem_depth[ndx], vdc.mem_width[ndx], VD_BUFFER_LEN / vdc.mem_width[ndx], vdc.mem_width[ndx]);
659 }
660
661 return ERROR_OK;
662 }
663
664 static void vdebug_mem_close(int hsock, struct vd_shm *pm, uint8_t ndx)
665 {
666 pm->cmd = VD_CMD_MEMCLOSE;
667 pm->rwdata = ndx; /* which memory */
668 pm->wbytes = 0;
669 pm->rbytes = 0;
670 pm->wwords = 0;
671 pm->rwords = 0;
672 vdebug_wait_server(hsock, pm);
673 LOG_DEBUG("%" PRIx8 ": %s", ndx, vdc.mem_path[ndx]);
674 }
675
676 static int vdebug_init(void)
677 {
678 vdc.hsocket = vdebug_socket_open(vdc.server_name, vdc.server_port);
679 pbuf = calloc(1, sizeof(struct vd_shm));
680 if (!pbuf) {
681 close_socket(vdc.hsocket);
682 vdc.hsocket = 0;
683 LOG_ERROR("cannot allocate %lu bytes", sizeof(struct vd_shm));
684 return ERROR_FAIL;
685 }
686 if (vdc.hsocket <= 0) {
687 free(pbuf);
688 pbuf = NULL;
689 LOG_ERROR("cannot connect to vdebug server %s:%" PRIu16,
690 vdc.server_name, vdc.server_port);
691 return ERROR_FAIL;
692 }
693 vdc.trans_first = 1;
694 vdc.poll_cycles = vdc.poll_max;
695 uint32_t sig_mask = VD_SIG_RESET | VD_SIG_TRST | VD_SIG_TCKDIV;
696 int rc = vdebug_open(vdc.hsocket, pbuf, vdc.bfm_path, vdc.bfm_type, vdc.bfm_period, sig_mask);
697 if (rc != 0) {
698 LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.bfm_path, rc);
699 close_socket(vdc.hsocket);
700 vdc.hsocket = 0;
701 free(pbuf);
702 pbuf = NULL;
703 } else {
704 for (uint8_t i = 0; i < vdc.mem_ndx; i++) {
705 rc = vdebug_mem_open(vdc.hsocket, pbuf, vdc.mem_path[i], i);
706 if (rc != 0)
707 LOG_ERROR("cannot connect to %s, rc 0x%x", vdc.mem_path[i], rc);
708 }
709
710 LOG_INFO("vdebug %d connected to %s through %s:%" PRIu16,
711 VD_VERSION, vdc.bfm_path, vdc.server_name, vdc.server_port);
712 }
713
714 return rc;
715 }
716
717 static int vdebug_quit(void)
718 {
719 for (uint8_t i = 0; i < vdc.mem_ndx; i++)
720 if (vdc.mem_width[i])
721 vdebug_mem_close(vdc.hsocket, pbuf, i);
722 int rc = vdebug_close(vdc.hsocket, pbuf, vdc.bfm_type);
723 LOG_INFO("vdebug %d disconnected from %s through %s:%" PRIu16 " rc:%d", VD_VERSION,
724 vdc.bfm_path, vdc.server_name, vdc.server_port, rc);
725 if (vdc.hsocket)
726 close_socket(vdc.hsocket);
727 free(pbuf);
728 pbuf = NULL;
729
730 return ERROR_OK;
731 }
732
733 static int vdebug_reset(int trst, int srst)
734 {
735 uint16_t sig_val = 0xffff;
736 uint16_t sig_mask = 0;
737
738 sig_mask |= VD_SIG_RESET;
739 if (srst)
740 sig_val &= ~VD_SIG_RESET;/* active low */
741 if (transport_is_jtag()) {
742 sig_mask |= VD_SIG_TRST;
743 if (trst)
744 sig_val &= ~VD_SIG_TRST; /* active low */
745 }
746
747 LOG_INFO("rst trst:%d srst:%d mask:%" PRIx16 " val:%" PRIx16, trst, srst, sig_mask, sig_val);
748 int rc = vdebug_sig_set(vdc.hsocket, pbuf, sig_mask, sig_val);
749 if (rc == 0)
750 rc = vdebug_wait(vdc.hsocket, pbuf, 20); /* 20 clock cycles pulse */
751
752 return rc;
753 }
754
755 static int vdebug_jtag_tms_seq(const uint8_t *tms, int num, uint8_t f_flush)
756 {
757 LOG_INFO("tms len:%d tms:%x", num, *(const uint32_t *)tms);
758
759 return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num, *tms, 0, NULL, 0, 0, NULL, f_flush);
760 }
761
762 static int vdebug_jtag_path_move(struct pathmove_command *cmd, uint8_t f_flush)
763 {
764 uint8_t tms[DIV_ROUND_UP(cmd->num_states, 8)];
765 LOG_INFO("path num states %d", cmd->num_states);
766
767 memset(tms, 0, DIV_ROUND_UP(cmd->num_states, 8));
768
769 for (uint8_t i = 0; i < cmd->num_states; i++) {
770 if (tap_state_transition(tap_get_state(), true) == cmd->path[i])
771 buf_set_u32(tms, i, 1, 1);
772 tap_set_state(cmd->path[i]);
773 }
774
775 return vdebug_jtag_tms_seq(tms, cmd->num_states, f_flush);
776 }
777
778 static int vdebug_jtag_tlr(tap_state_t state, uint8_t f_flush)
779 {
780 int rc = ERROR_OK;
781
782 uint8_t cur = tap_get_state();
783 uint8_t tms_pre = tap_get_tms_path(cur, state);
784 uint8_t num_pre = tap_get_tms_path_len(cur, state);
785 LOG_INFO("tlr from %" PRIx8 " to %" PRIx8, cur, state);
786 if (cur != state) {
787 rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, 0, NULL, 0, 0, NULL, f_flush);
788 tap_set_state(state);
789 }
790
791 return rc;
792 }
793
794 static int vdebug_jtag_scan(struct scan_command *cmd, uint8_t f_flush)
795 {
796 int rc = ERROR_OK;
797
798 uint8_t cur = tap_get_state();
799 uint8_t state = cmd->ir_scan ? TAP_IRSHIFT : TAP_DRSHIFT;
800 uint8_t tms_pre = tap_get_tms_path(cur, state);
801 uint8_t num_pre = tap_get_tms_path_len(cur, state);
802 uint8_t tms_post = tap_get_tms_path(state, cmd->end_state);
803 uint8_t num_post = tap_get_tms_path_len(state, cmd->end_state);
804 int num_bits = jtag_scan_size(cmd);
805 LOG_DEBUG("scan len:%d fields:%d ir/!dr:%d state cur:%x end:%x",
806 num_bits, cmd->num_fields, cmd->ir_scan, cur, cmd->end_state);
807 for (int i = 0; i < cmd->num_fields; i++) {
808 uint8_t cur_num_pre = i == 0 ? num_pre : 0;
809 uint8_t cur_tms_pre = i == 0 ? tms_pre : 0;
810 uint8_t cur_num_post = i == cmd->num_fields - 1 ? num_post : 0;
811 uint8_t cur_tms_post = i == cmd->num_fields - 1 ? tms_post : 0;
812 uint8_t cur_flush = i == cmd->num_fields - 1 ? f_flush : 0;
813 rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, cur_num_pre, cur_tms_pre,
814 cmd->fields[i].num_bits, cmd->fields[i].out_value, cur_num_post, cur_tms_post,
815 cmd->fields[i].in_value, cur_flush);
816 if (rc)
817 break;
818 }
819
820 if (cur != cmd->end_state)
821 tap_set_state(cmd->end_state);
822
823 return rc;
824 }
825
826 static int vdebug_jtag_runtest(int cycles, tap_state_t state, uint8_t f_flush)
827 {
828 uint8_t cur = tap_get_state();
829 uint8_t tms_pre = tap_get_tms_path(cur, state);
830 uint8_t num_pre = tap_get_tms_path_len(cur, state);
831 LOG_DEBUG("idle len:%d state cur:%x end:%x", cycles, cur, state);
832 int rc = vdebug_jtag_shift_tap(vdc.hsocket, pbuf, num_pre, tms_pre, cycles, NULL, 0, 0, NULL, f_flush);
833 if (cur != state)
834 tap_set_state(state);
835
836 return rc;
837 }
838
839 static int vdebug_jtag_stableclocks(int num, uint8_t f_flush)
840 {
841 LOG_INFO("stab len:%d state cur:%x", num, tap_get_state());
842
843 return vdebug_jtag_shift_tap(vdc.hsocket, pbuf, 0, 0, num, NULL, 0, 0, NULL, f_flush);
844 }
845
846 static int vdebug_sleep(int us)
847 {
848 LOG_INFO("sleep %d us", us);
849
850 return vdebug_wait(vdc.hsocket, pbuf, us / 1000);
851 }
852
853 static int vdebug_jtag_speed(int speed)
854 {
855 unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */
856 unsigned int divval = clkmax / speed;
857 LOG_INFO("jclk speed:%d kHz set, BFM divider %u", speed, divval);
858
859 return vdebug_jtag_clock(vdc.hsocket, pbuf, divval);
860 }
861
862 static int vdebug_jtag_khz(int khz, int *jtag_speed)
863 {
864 unsigned int clkmax = VD_SCALE_PSTOMS / (vdc.bfm_period * 2); /* kHz */
865 unsigned int divval = khz ? clkmax / khz : 1;
866 *jtag_speed = clkmax / divval;
867 LOG_DEBUG("khz speed:%d from khz:%d", *jtag_speed, khz);
868
869 return ERROR_OK;
870 }
871
872 static int vdebug_jtag_div(int speed, int *khz)
873 {
874 *khz = speed;
875 LOG_DEBUG("div khz:%d from speed:%d", *khz, speed);
876
877 return ERROR_OK;
878 }
879
880 static int vdebug_jtag_execute_queue(void)
881 {
882 int rc = ERROR_OK;
883
884 for (struct jtag_command *cmd = jtag_command_queue; rc == ERROR_OK && cmd; cmd = cmd->next) {
885 switch (cmd->type) {
886 case JTAG_RUNTEST:
887 rc = vdebug_jtag_runtest(cmd->cmd.runtest->num_cycles, cmd->cmd.runtest->end_state, !cmd->next);
888 break;
889 case JTAG_STABLECLOCKS:
890 rc = vdebug_jtag_stableclocks(cmd->cmd.stableclocks->num_cycles, !cmd->next);
891 break;
892 case JTAG_TLR_RESET:
893 rc = vdebug_jtag_tlr(cmd->cmd.statemove->end_state, !cmd->next);
894 break;
895 case JTAG_PATHMOVE:
896 rc = vdebug_jtag_path_move(cmd->cmd.pathmove, !cmd->next);
897 break;
898 case JTAG_TMS:
899 rc = vdebug_jtag_tms_seq(cmd->cmd.tms->bits, cmd->cmd.tms->num_bits, !cmd->next);
900 break;
901 case JTAG_SLEEP:
902 rc = vdebug_sleep(cmd->cmd.sleep->us);
903 break;
904 case JTAG_SCAN:
905 rc = vdebug_jtag_scan(cmd->cmd.scan, !cmd->next);
906 break;
907 default:
908 LOG_ERROR("Unknown JTAG command type 0x%x encountered", cmd->type);
909 rc = ERROR_FAIL;
910 }
911 }
912
913 return rc;
914 }
915
916 COMMAND_HANDLER(vdebug_set_server)
917 {
918 if ((CMD_ARGC != 1) || !strchr(CMD_ARGV[0], ':'))
919 return ERROR_COMMAND_SYNTAX_ERROR;
920
921 char *pchar = strchr(CMD_ARGV[0], ':');
922 *pchar = '\0';
923 strncpy(vdc.server_name, CMD_ARGV[0], sizeof(vdc.server_name) - 1);
924 int port = atoi(++pchar);
925 if (port < 0 || port > UINT16_MAX) {
926 LOG_ERROR("invalid port number %d specified", port);
927 return ERROR_COMMAND_SYNTAX_ERROR;
928 }
929 vdc.server_port = port;
930 LOG_DEBUG("server: %s port %u", vdc.server_name, vdc.server_port);
931
932 return ERROR_OK;
933 }
934
935 COMMAND_HANDLER(vdebug_set_bfm)
936 {
937 char prefix;
938
939 if ((CMD_ARGC != 2) || (sscanf(CMD_ARGV[1], "%u%c", &vdc.bfm_period, &prefix) != 2))
940 return ERROR_COMMAND_SYNTAX_ERROR;
941
942 strncpy(vdc.bfm_path, CMD_ARGV[0], sizeof(vdc.bfm_path) - 1);
943 switch (prefix) {
944 case 'u':
945 vdc.bfm_period *= 1000000;
946 break;
947 case 'n':
948 vdc.bfm_period *= 1000;
949 break;
950 case 'p':
951 default:
952 break;
953 }
954 vdc.bfm_type = VD_BFM_JTAG;
955 LOG_DEBUG("bfm_path: %s clk_period %ups", vdc.bfm_path, vdc.bfm_period);
956
957 return ERROR_OK;
958 }
959
960 COMMAND_HANDLER(vdebug_set_mem)
961 {
962 if (CMD_ARGC != 3)
963 return ERROR_COMMAND_SYNTAX_ERROR;
964
965 if (vdc.mem_ndx >= VD_MAX_MEMORIES) {
966 LOG_ERROR("mem_path declared more than %d allowed times", VD_MAX_MEMORIES);
967 return ERROR_FAIL;
968 }
969
970 strncpy(vdc.mem_path[vdc.mem_ndx], CMD_ARGV[0], sizeof(vdc.mem_path[vdc.mem_ndx]) - 1);
971 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], vdc.mem_base[vdc.mem_ndx]);
972 COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], vdc.mem_size[vdc.mem_ndx]);
973 LOG_DEBUG("mem_path: set %s @ 0x%08x+0x%08x", vdc.mem_path[vdc.mem_ndx],
974 vdc.mem_base[vdc.mem_ndx], vdc.mem_size[vdc.mem_ndx]);
975 vdc.mem_ndx++;
976
977 return ERROR_OK;
978 }
979
980 COMMAND_HANDLER(vdebug_set_batching)
981 {
982 if (CMD_ARGC != 1)
983 return ERROR_COMMAND_SYNTAX_ERROR;
984
985 if (isdigit((unsigned char)CMD_ARGV[0][0]))
986 vdc.trans_batch = (CMD_ARGV[0][0] == '0' ? 0 : (CMD_ARGV[0][0] == '1' ? 1 : 2));
987 else if (CMD_ARGV[0][0] == 'r')
988 vdc.trans_batch = VD_BATCH_WR;
989 else if (CMD_ARGV[0][0] == 'w')
990 vdc.trans_batch = VD_BATCH_WO;
991 else
992 vdc.trans_batch = VD_BATCH_NO;
993 LOG_DEBUG("batching: set to %u", vdc.trans_batch);
994
995 return ERROR_OK;
996 }
997
998 COMMAND_HANDLER(vdebug_set_polling)
999 {
1000 if (CMD_ARGC != 2)
1001 return ERROR_COMMAND_SYNTAX_ERROR;
1002
1003 vdc.poll_min = atoi(CMD_ARGV[0]);
1004 vdc.poll_max = atoi(CMD_ARGV[1]);
1005 LOG_DEBUG("polling: set min %u max %u", vdc.poll_min, vdc.poll_max);
1006
1007 return ERROR_OK;
1008 }
1009
1010 static const struct command_registration vdebug_command_handlers[] = {
1011 {
1012 .name = "server",
1013 .handler = &vdebug_set_server,
1014 .mode = COMMAND_CONFIG,
1015 .help = "set the vdebug server name or address",
1016 .usage = "<host:port>",
1017 },
1018 {
1019 .name = "bfm_path",
1020 .handler = &vdebug_set_bfm,
1021 .mode = COMMAND_CONFIG,
1022 .help = "set the vdebug BFM hierarchical path",
1023 .usage = "<path> <clk_period[p|n|u]s>",
1024 },
1025 {
1026 .name = "mem_path",
1027 .handler = &vdebug_set_mem,
1028 .mode = COMMAND_ANY,
1029 .help = "set the design memory for the code load",
1030 .usage = "<path> <base_address> <size>",
1031 },
1032 {
1033 .name = "batching",
1034 .handler = &vdebug_set_batching,
1035 .mode = COMMAND_CONFIG,
1036 .help = "set the transaction batching no|wr|rd [0|1|2]",
1037 .usage = "<level>",
1038 },
1039 {
1040 .name = "polling",
1041 .handler = &vdebug_set_polling,
1042 .mode = COMMAND_CONFIG,
1043 .help = "set the polling pause, executing hardware cycles between min and max",
1044 .usage = "<min cycles> <max cycles>",
1045 },
1046 COMMAND_REGISTRATION_DONE
1047 };
1048
1049 static const struct command_registration vdebug_command[] = {
1050 {
1051 .name = "vdebug",
1052 .chain = vdebug_command_handlers,
1053 .mode = COMMAND_ANY,
1054 .help = "vdebug command group",
1055 .usage = "",
1056 },
1057 COMMAND_REGISTRATION_DONE
1058 };
1059
1060 static struct jtag_interface vdebug_jtag_ops = {
1061 .supported = DEBUG_CAP_TMS_SEQ,
1062 .execute_queue = vdebug_jtag_execute_queue,
1063 };
1064
1065 struct adapter_driver vdebug_adapter_driver = {
1066 .name = "vdebug",
1067 .transports = jtag_only,
1068 .speed = vdebug_jtag_speed,
1069 .khz = vdebug_jtag_khz,
1070 .speed_div = vdebug_jtag_div,
1071 .commands = vdebug_command,
1072 .init = vdebug_init,
1073 .quit = vdebug_quit,
1074 .reset = vdebug_reset,
1075 .jtag_ops = &vdebug_jtag_ops,
1076 };

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)