1 /***************************************************************************
2 * Copyright (C) 2005 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2007,2008 Øyvind Harboe *
6 * oyvind.harboe@zylin.com *
8 * Copyright (C) 2008 Peter Hettkamp *
9 * peter.hettkamp@htp-tel.de *
11 * Copyright (C) 2009 SoftPLC Corporation. http://softplc.com *
12 * Dick Hollenbeck <dick@softplc.com> *
14 * This program is free software; you can redistribute it and/or modify *
15 * it under the terms of the GNU General Public License as published by *
16 * the Free Software Foundation; either version 2 of the License, or *
17 * (at your option) any later version. *
19 * This program is distributed in the hope that it will be useful, *
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
22 * GNU General Public License for more details. *
24 * You should have received a copy of the GNU General Public License *
25 * along with this program; if not, write to the *
26 * Free Software Foundation, Inc., *
27 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
28 ***************************************************************************/
30 /* The specification for SVF is available here:
31 * http://www.asset-intertech.com/support/svf.pdf
32 * Below, this document is refered to as the "SVF spec".
34 * The specification for XSVF is available here:
35 * http://www.xilinx.com/support/documentation/application_notes/xapp503.pdf
36 * Below, this document is refered to as the "XSVF spec".
44 #include <jtag/jtag.h>
47 /* XSVF commands, from appendix B of xapp503.pdf */
48 #define XCOMPLETE 0x00
56 #define XSETSDRMASKS 0x0A
71 /* XWAITSTATE is not in the xilinx XSVF spec, but the svf2xsvf.py translator
72 * generates this. Arguably it is needed because the XSVF XRUNTEST command
73 * was ill conceived and does not directly flow out of the SVF RUNTEST command.
74 * This XWAITSTATE does map directly from the SVF RUNTEST command.
76 #define XWAITSTATE 0x18
78 /* Lattice has extended the SVF file format, and Dick Hollenbeck's python based
79 * SVF2XSVF converter supports these 3 additional XSVF opcodes, LCOUNT, LDELAY, LSDR.
80 * Here is an example of usage of the 3 lattice opcode extensions:
82 ! Set the maximum loop count to 25.
84 ! Step to DRPAUSE give 5 clocks and wait for 1.00e + 000 SEC.
85 LDELAY DRPAUSE 5 TCK 1.00E-003 SEC;
86 ! Test for the completed status. Match means pass.
87 ! Loop back to LDELAY line if not match and loop count less than 25.
98 /* XSVF valid state values for the XSTATE command, from appendix B of xapp503.pdf */
99 #define XSV_RESET 0x00
100 #define XSV_IDLE 0x01
101 #define XSV_DRSELECT 0x02
102 #define XSV_DRCAPTURE 0x03
103 #define XSV_DRSHIFT 0x04
104 #define XSV_DREXIT1 0x05
105 #define XSV_DRPAUSE 0x06
106 #define XSV_DREXIT2 0x07
107 #define XSV_DRUPDATE 0x08
108 #define XSV_IRSELECT 0x09
109 #define XSV_IRCAPTURE 0x0A
110 #define XSV_IRSHIFT 0x0B
111 #define XSV_IREXIT1 0x0C
112 #define XSV_IRPAUSE 0x0D
113 #define XSV_IREXIT2 0x0E
114 #define XSV_IRUPDATE 0x0F
116 /* arguments to XTRST */
120 #define XTRST_ABSENT 3
122 #define XSTATE_MAX_PATH 12
126 /* map xsvf tap state to an openocd "tap_state_t" */
127 static tap_state_t
xsvf_to_tap(int xsvf_state
)
131 switch (xsvf_state
) {
181 LOG_ERROR("UNKNOWN XSVF STATE 0x%02X", xsvf_state
);
188 static int xsvf_read_buffer(int num_bits
, int fd
, uint8_t *buf
)
192 for (num_bytes
= (num_bits
+ 7) / 8; num_bytes
> 0; num_bytes
--) {
193 /* reverse the order of bytes as they are read sequentially from file */
194 if (read(fd
, buf
+ num_bytes
- 1, 1) < 0)
195 return ERROR_XSVF_EOF
;
201 COMMAND_HANDLER(handle_xsvf_command
)
203 uint8_t *dr_out_buf
= NULL
; /* from host to device (TDI) */
204 uint8_t *dr_in_buf
= NULL
; /* from device to host (TDO) */
205 uint8_t *dr_in_mask
= NULL
;
208 int xruntest
= 0; /* number of TCK cycles OR *microseconds */
209 int xrepeat
= 0; /* number of retries */
211 tap_state_t xendir
= TAP_IDLE
; /* see page 8 of the SVF spec, initial
212 *xendir to be TAP_IDLE */
213 tap_state_t xenddr
= TAP_IDLE
;
217 long file_offset
= 0;
220 tap_state_t loop_state
= TAP_IDLE
;
226 int tdo_mismatch
= 0;
230 bool collecting_path
= false;
231 tap_state_t path
[XSTATE_MAX_PATH
];
232 unsigned pathlen
= 0;
234 /* a flag telling whether to clock TCK during waits,
235 * or simply sleep, controled by virt2
237 int runtest_requires_tck
= 0;
239 /* use NULL to indicate a "plain" xsvf file which accounts for
240 * additional devices in the scan chain, otherwise the device
241 * that should be affected
243 struct jtag_tap
*tap
= NULL
;
246 return ERROR_COMMAND_SYNTAX_ERROR
;
248 /* we mess with CMD_ARGV starting point below, snapshot filename here */
249 const char *filename
= CMD_ARGV
[1];
251 if (strcmp(CMD_ARGV
[0], "plain") != 0) {
252 tap
= jtag_tap_by_string(CMD_ARGV
[0]);
254 command_print(CMD_CTX
, "Tap: %s unknown", CMD_ARGV
[0]);
259 xsvf_fd
= open(filename
, O_RDONLY
);
261 command_print(CMD_CTX
, "file \"%s\" not found", filename
);
265 /* if this argument is present, then interpret xruntest counts as TCK cycles rather than as
267 if ((CMD_ARGC
> 2) && (strcmp(CMD_ARGV
[2], "virt2") == 0)) {
268 runtest_requires_tck
= 1;
273 if ((CMD_ARGC
> 2) && (strcmp(CMD_ARGV
[2], "quiet") == 0))
276 LOG_WARNING("XSVF support in OpenOCD is limited. Consider using SVF instead");
277 LOG_USER("xsvf processing file: \"%s\"", filename
);
279 while (read(xsvf_fd
, &opcode
, 1) > 0) {
280 /* record the position of this opcode within the file */
281 file_offset
= lseek(xsvf_fd
, 0, SEEK_CUR
) - 1;
283 /* maybe collect another state for a pathmove();
284 * or terminate a path.
286 if (collecting_path
) {
291 /* ignore/show comments between XSTATE ops */
294 /* try to collect another transition */
295 if (pathlen
== XSTATE_MAX_PATH
) {
296 LOG_ERROR("XSVF: path too long");
301 if (read(xsvf_fd
, &uc
, 1) < 0) {
306 mystate
= xsvf_to_tap(uc
);
307 path
[pathlen
++] = mystate
;
309 LOG_DEBUG("XSTATE 0x%02X %s", uc
,
310 tap_state_name(mystate
));
312 /* If path is incomplete, collect more */
313 if (!svf_tap_state_is_stable(mystate
))
316 /* Else execute the path transitions we've
319 * NOTE: Punting on the saved path is not
320 * strictly correct, but we must to do this
321 * unless jtag_add_pathmove() stops rejecting
322 * paths containing RESET. This is probably
323 * harmless, since there aren't many options
324 * for going from a stable state to reset;
325 * at the worst, we may issue extra clocks
326 * once we get to RESET.
328 if (mystate
== TAP_RESET
) {
329 LOG_WARNING("XSVF: dodgey RESET");
335 /* Execute the path we collected
337 * NOTE: OpenOCD requires something that XSVF
338 * doesn't: the last TAP state in the path
339 * must be stable. In practice, tools that
340 * create XSVF seem to follow that rule too.
342 collecting_path
= false;
344 if (path
[0] == TAP_RESET
)
347 jtag_add_pathmove(pathlen
, path
);
349 result
= jtag_execute_queue();
350 if (result
!= ERROR_OK
) {
351 LOG_ERROR("XSVF: pathmove error %d", result
);
361 LOG_DEBUG("XCOMPLETE");
363 result
= jtag_execute_queue();
364 if (result
!= ERROR_OK
) {
371 LOG_DEBUG("XTDOMASK");
373 (xsvf_read_buffer(xsdrsize
, xsvf_fd
, dr_in_mask
) != ERROR_OK
))
379 uint8_t xruntest_buf
[4];
381 if (read(xsvf_fd
, xruntest_buf
, 4) < 0) {
386 xruntest
= be_to_h_u32(xruntest_buf
);
387 LOG_DEBUG("XRUNTEST %d 0x%08X", xruntest
, xruntest
);
395 if (read(xsvf_fd
, &myrepeat
, 1) < 0)
399 LOG_DEBUG("XREPEAT %d", xrepeat
);
406 uint8_t xsdrsize_buf
[4];
408 if (read(xsvf_fd
, xsdrsize_buf
, 4) < 0) {
413 xsdrsize
= be_to_h_u32(xsdrsize_buf
);
414 LOG_DEBUG("XSDRSIZE %d", xsdrsize
);
423 dr_out_buf
= malloc((xsdrsize
+ 7) / 8);
424 dr_in_buf
= malloc((xsdrsize
+ 7) / 8);
425 dr_in_mask
= malloc((xsdrsize
+ 7) / 8);
429 case XSDR
: /* these two are identical except for the dr_in_buf */
436 const char *op_name
= (opcode
== XSDR
? "XSDR" : "XSDRTDO");
438 if (xsvf_read_buffer(xsdrsize
, xsvf_fd
, dr_out_buf
) != ERROR_OK
) {
443 if (opcode
== XSDRTDO
) {
444 if (xsvf_read_buffer(xsdrsize
, xsvf_fd
,
445 dr_in_buf
) != ERROR_OK
) {
454 LOG_DEBUG("%s %d", op_name
, xsdrsize
);
456 for (attempt
= 0; attempt
< limit
; ++attempt
) {
457 struct scan_field field
;
460 /* perform the XC9500 exception handling sequence shown in xapp067.pdf and
461 * illustrated in psuedo code at end of this file. We start from state
467 * go to Run-Test/Idle
469 * This sequence should be harmless for other devices, and it
470 * will be skipped entirely if xrepeat is set to zero.
473 static tap_state_t exception_path
[] = {
481 jtag_add_pathmove(ARRAY_SIZE(exception_path
), exception_path
);
484 LOG_USER("%s mismatch, xsdrsize=%d retry=%d",
490 field
.num_bits
= xsdrsize
;
491 field
.out_value
= dr_out_buf
;
492 field
.in_value
= calloc(DIV_ROUND_UP(field
.num_bits
, 8), 1);
495 jtag_add_plain_dr_scan(field
.num_bits
,
500 jtag_add_dr_scan(tap
, 1, &field
, TAP_DRPAUSE
);
502 jtag_check_value_mask(&field
, dr_in_buf
, dr_in_mask
);
504 free(field
.in_value
);
506 /* LOG_DEBUG("FLUSHING QUEUE"); */
507 result
= jtag_execute_queue();
508 if (result
== ERROR_OK
) {
515 LOG_USER("%s mismatch", op_name
);
520 /* See page 19 of XSVF spec regarding opcode "XSDR" */
522 result
= svf_add_statemove(TAP_IDLE
);
523 if (result
!= ERROR_OK
)
526 if (runtest_requires_tck
)
527 jtag_add_clocks(xruntest
);
529 jtag_add_sleep(xruntest
);
530 } else if (xendir
!= TAP_DRPAUSE
) {
531 /* we are already in TAP_DRPAUSE */
532 result
= svf_add_statemove(xenddr
);
533 if (result
!= ERROR_OK
)
540 LOG_ERROR("unsupported XSETSDRMASKS");
545 LOG_ERROR("unsupported XSDRINC");
550 LOG_ERROR("unsupported XSDRB");
555 LOG_ERROR("unsupported XSDRC");
560 LOG_ERROR("unsupported XSDRE");
565 LOG_ERROR("unsupported XSDRTDOB");
570 LOG_ERROR("unsupported XSDRTDOC");
575 LOG_ERROR("unsupported XSDRTDOE");
583 if (read(xsvf_fd
, &uc
, 1) < 0) {
588 mystate
= xsvf_to_tap(uc
);
590 LOG_DEBUG("XSTATE 0x%02X %s", uc
, tap_state_name(mystate
));
592 if (mystate
== TAP_INVALID
) {
593 LOG_ERROR("XSVF: bad XSTATE %02x", uc
);
598 /* NOTE: the current state is SVF-stable! */
600 /* no change == NOP */
601 if (mystate
== cmd_queue_cur_state
602 && mystate
!= TAP_RESET
)
605 /* Hand off to SVF? */
606 if (svf_tap_state_is_stable(mystate
)) {
607 result
= svf_add_statemove(mystate
);
608 if (result
!= ERROR_OK
)
614 * A sequence of XSTATE transitions, each TAP
615 * state adjacent to the previous one. Start
618 collecting_path
= true;
626 if (read(xsvf_fd
, &uc
, 1) < 0) {
631 /* see page 22 of XSVF spec */
635 xendir
= TAP_IRPAUSE
;
637 LOG_ERROR("illegial XENDIR argument: 0x%02X", uc
);
642 LOG_DEBUG("XENDIR 0x%02X %s", uc
, tap_state_name(xendir
));
647 if (read(xsvf_fd
, &uc
, 1) < 0) {
652 /* see page 22 of XSVF spec */
656 xenddr
= TAP_DRPAUSE
;
658 LOG_ERROR("illegial XENDDR argument: 0x%02X", uc
);
663 LOG_DEBUG("XENDDR %02X %s", uc
, tap_state_name(xenddr
));
669 uint8_t short_buf
[2];
672 tap_state_t my_end_state
= xruntest
? TAP_IDLE
: xendir
;
674 if (opcode
== XSIR
) {
675 /* one byte bitcount */
676 if (read(xsvf_fd
, short_buf
, 1) < 0) {
680 bitcount
= short_buf
[0];
681 LOG_DEBUG("XSIR %d", bitcount
);
683 if (read(xsvf_fd
, short_buf
, 2) < 0) {
687 bitcount
= be_to_h_u16(short_buf
);
688 LOG_DEBUG("XSIR2 %d", bitcount
);
691 ir_buf
= malloc((bitcount
+ 7) / 8);
693 if (xsvf_read_buffer(bitcount
, xsvf_fd
, ir_buf
) != ERROR_OK
)
696 struct scan_field field
;
698 field
.num_bits
= bitcount
;
699 field
.out_value
= ir_buf
;
701 field
.in_value
= NULL
;
704 jtag_add_plain_ir_scan(field
.num_bits
,
705 field
.out_value
, field
.in_value
, my_end_state
);
707 jtag_add_ir_scan(tap
, &field
, my_end_state
);
710 if (runtest_requires_tck
)
711 jtag_add_clocks(xruntest
);
713 jtag_add_sleep(xruntest
);
716 /* Note that an -irmask of non-zero in your config file
717 * can cause this to fail. Setting -irmask to zero cand work
718 * around the problem.
721 /* LOG_DEBUG("FLUSHING QUEUE"); */
722 result
= jtag_execute_queue();
723 if (result
!= ERROR_OK
)
732 unsigned int ndx
= 0;
736 if (read(xsvf_fd
, &uc
, 1) < 0) {
741 if (ndx
< sizeof(comment
)-1)
746 comment
[sizeof(comment
)-1] = 0; /* regardless, terminate */
748 LOG_USER("# %s", comment
);
754 /* expected in stream:
755 XWAIT <uint8_t wait_state> <uint8_t end_state> <uint32_t usecs>
760 uint8_t delay_buf
[4];
762 tap_state_t wait_state
;
763 tap_state_t end_state
;
766 if (read(xsvf_fd
, &wait_local
, 1) < 0
767 || read(xsvf_fd
, &end
, 1) < 0
768 || read(xsvf_fd
, delay_buf
, 4) < 0) {
773 wait_state
= xsvf_to_tap(wait_local
);
774 end_state
= xsvf_to_tap(end
);
775 delay
= be_to_h_u32(delay_buf
);
777 LOG_DEBUG("XWAIT %s %s usecs:%d", tap_state_name(
778 wait_state
), tap_state_name(end_state
), delay
);
780 if (runtest_requires_tck
&& wait_state
== TAP_IDLE
)
781 jtag_add_runtest(delay
, end_state
);
783 /* FIXME handle statemove errors ... */
784 result
= svf_add_statemove(wait_state
);
785 if (result
!= ERROR_OK
)
787 jtag_add_sleep(delay
);
788 result
= svf_add_statemove(end_state
);
789 if (result
!= ERROR_OK
)
797 /* expected in stream:
798 * XWAITSTATE <uint8_t wait_state> <uint8_t end_state> <uint32_t clock_count>
802 uint8_t clock_buf
[4];
803 uint8_t usecs_buf
[4];
806 tap_state_t wait_state
;
807 tap_state_t end_state
;
811 if (read(xsvf_fd
, &wait_local
, 1) < 0
812 || read(xsvf_fd
, &end
, 1) < 0
813 || read(xsvf_fd
, clock_buf
, 4) < 0
814 || read(xsvf_fd
, usecs_buf
, 4) < 0) {
819 wait_state
= xsvf_to_tap(wait_local
);
820 end_state
= xsvf_to_tap(end
);
822 clock_count
= be_to_h_u32(clock_buf
);
823 usecs
= be_to_h_u32(usecs_buf
);
825 LOG_DEBUG("XWAITSTATE %s %s clocks:%i usecs:%i",
826 tap_state_name(wait_state
),
827 tap_state_name(end_state
),
830 /* the following states are 'stable', meaning that they have a transition
831 * in the state diagram back to themselves. This is necessary because we will
832 * be issuing a number of clocks in this state. This set of allowed states is also
833 * determined by the SVF RUNTEST command's allowed states.
835 if (!svf_tap_state_is_stable(wait_state
)) {
836 LOG_ERROR("illegal XWAITSTATE wait_state: \"%s\"",
837 tap_state_name(wait_state
));
839 /* REVISIT "break" so we won't run? */
842 /* FIXME handle statemove errors ... */
843 result
= svf_add_statemove(wait_state
);
844 if (result
!= ERROR_OK
)
847 jtag_add_clocks(clock_count
);
848 jtag_add_sleep(usecs
);
850 result
= svf_add_statemove(end_state
);
851 if (result
!= ERROR_OK
)
858 /* expected in stream:
859 * LCOUNT <uint32_t loop_count>
861 uint8_t count_buf
[4];
863 if (read(xsvf_fd
, count_buf
, 4) < 0) {
868 loop_count
= be_to_h_u32(count_buf
);
869 LOG_DEBUG("LCOUNT %d", loop_count
);
875 /* expected in stream:
876 * LDELAY <uint8_t wait_state> <uint32_t clock_count> <uint32_t usecs_to_sleep>
879 uint8_t clock_buf
[4];
880 uint8_t usecs_buf
[4];
882 if (read(xsvf_fd
, &state
, 1) < 0
883 || read(xsvf_fd
, clock_buf
, 4) < 0
884 || read(xsvf_fd
, usecs_buf
, 4) < 0) {
889 /* NOTE: loop_state must be stable! */
890 loop_state
= xsvf_to_tap(state
);
891 loop_clocks
= be_to_h_u32(clock_buf
);
892 loop_usecs
= be_to_h_u32(usecs_buf
);
894 LOG_DEBUG("LDELAY %s clocks:%d usecs:%d", tap_state_name(
895 loop_state
), loop_clocks
, loop_usecs
);
899 /* LSDR is more like XSDRTDO than it is like XSDR. It uses LDELAY which
900 * comes with clocks !AND! sleep requirements.
904 int limit
= loop_count
;
910 if (xsvf_read_buffer(xsdrsize
, xsvf_fd
, dr_out_buf
) != ERROR_OK
911 || xsvf_read_buffer(xsdrsize
, xsvf_fd
, dr_in_buf
) != ERROR_OK
) {
919 for (attempt
= 0; attempt
< limit
; ++attempt
) {
920 struct scan_field field
;
922 result
= svf_add_statemove(loop_state
);
923 if (result
!= ERROR_OK
)
925 jtag_add_clocks(loop_clocks
);
926 jtag_add_sleep(loop_usecs
);
928 field
.num_bits
= xsdrsize
;
929 field
.out_value
= dr_out_buf
;
930 field
.in_value
= calloc(DIV_ROUND_UP(field
.num_bits
, 8), 1);
932 if (attempt
> 0 && verbose
)
933 LOG_USER("LSDR retry %d", attempt
);
936 jtag_add_plain_dr_scan(field
.num_bits
,
941 jtag_add_dr_scan(tap
, 1, &field
, TAP_DRPAUSE
);
943 jtag_check_value_mask(&field
, dr_in_buf
, dr_in_mask
);
945 free(field
.in_value
);
948 /* LOG_DEBUG("FLUSHING QUEUE"); */
949 result
= jtag_execute_queue();
950 if (result
== ERROR_OK
) {
957 LOG_USER("LSDR mismatch");
968 if (read(xsvf_fd
, &trst_mode
, 1) < 0) {
975 jtag_add_reset(1, 0);
979 jtag_add_reset(0, 0);
984 LOG_ERROR("XTRST mode argument (0x%02X) out of range", trst_mode
);
991 LOG_ERROR("unknown xsvf command (0x%02X)", uc
);
995 if (do_abort
|| unsupported
|| tdo_mismatch
) {
996 LOG_DEBUG("xsvf failed, setting taps to reasonable state");
998 /* upon error, return the TAPs to a reasonable state */
999 result
= svf_add_statemove(TAP_IDLE
);
1000 if (result
!= ERROR_OK
)
1002 result
= jtag_execute_queue();
1003 if (result
!= ERROR_OK
)
1010 command_print(CMD_CTX
,
1011 "TDO mismatch, somewhere near offset %lu in xsvf file, aborting",
1018 off_t offset
= lseek(xsvf_fd
, 0, SEEK_CUR
) - 1;
1019 command_print(CMD_CTX
,
1020 "unsupported xsvf command (0x%02X) at offset %jd, aborting",
1021 uc
, (intmax_t)offset
);
1026 command_print(CMD_CTX
, "premature end of xsvf file detected, aborting");
1041 command_print(CMD_CTX
, "XSVF file programmed successfully");
1046 static const struct command_registration xsvf_command_handlers
[] = {
1049 .handler
= handle_xsvf_command
,
1050 .mode
= COMMAND_EXEC
,
1051 .help
= "Runs a XSVF file. If 'virt2' is given, xruntest "
1052 "counts are interpreted as TCK cycles rather than "
1053 "as microseconds. Without the 'quiet' option, all "
1054 "comments, retries, and mismatches will be reported.",
1055 .usage
= "(tapname|'plain') filename ['virt2'] ['quiet']",
1057 COMMAND_REGISTRATION_DONE
1060 int xsvf_register_commands(struct command_context
*cmd_ctx
)
1062 return register_commands(cmd_ctx
, NULL
, xsvf_command_handlers
);
1067 PSUEDO-Code from Xilinx Appnote XAPP067.pdf :
1069 the following pseudo code clarifies the intent of the xrepeat support.The
1070 flow given is for the entire processing of an SVF file, not an XSVF file.
1071 No idea if this is just for the XC9500/XL/XV devices or all Xilinx parts.
1073 "Pseudo-Code Algorithm for SVF-Based ISP"
1075 1. Go to Test-Logic-Reset state
1076 2. Go to Run-Test Idle state
1079 4. if SIR record then
1080 go to Shift-IR state
1083 5. else if SDR record then
1084 set <repeat count> to 0
1085 store <TDI value> as <current TDI value>
1086 store <TDO value> as <current TDO value>
1087 6. go to Shift-DR state
1088 scan in <current TDI value>
1089 if < current TDO value > is specified then
1090 if < current TDO value > does not equal <actual TDO value> then
1091 if < repeat count > > 32 then
1093 go to Run-Test Idle state
1102 increment <repeat count> by 1
1103 pause <current pause time> microseconds
1107 go to Run-Test Idle state
1110 else if RUNTEST record then
1111 pause tester for < TCK value > microseconds
1112 store <TCK value> as <current pause time>
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)