1 /***************************************************************************
2 * Copyright (C) 2008 by Spencer Oliver *
3 * spen@spen-soft.co.uk *
5 * Copyright (C) 2008 by David T.L. Wong *
7 * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> *
9 * Copyright (C) 2011 by Drasko DRASKOVIC *
10 * drasko.draskovic@gmail.com *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
17 * This program is distributed in the hope that it will be useful, *
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
20 * GNU General Public License for more details. *
22 * You should have received a copy of the GNU General Public License *
23 * along with this program; if not, write to the *
24 * Free Software Foundation, Inc., *
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
26 ***************************************************************************/
29 * This version has optimized assembly routines for 32 bit operations:
32 * - write array of words
34 * One thing to be aware of is that the MIPS32 cpu will execute the
35 * instruction after a branch instruction (one delay slot).
42 * The LW $1, ($2 +100) instruction is also executed. If this is
43 * not wanted a NOP can be inserted:
50 * or the code can be changed to:
56 * The original code contained NOPs. I have removed these and moved
59 * I also moved the PRACC_STACK to 0xFF204000. This allows
60 * the use of 16 bits offsets to get pointers to the input
61 * and output area relative to the stack. Note that the stack
62 * isn't really a stack (the stack pointer is not 'moving')
63 * but a FIFO simulated in software.
65 * These changes result in a 35% speed increase when programming an
68 * More improvement could be gained if the registers do no need
69 * to be preserved but in that case the routines should be aware
70 * OpenOCD is used as a flash programmer or as a debug tool.
79 #include <helper/time_support.h>
82 #include "mips32_pracc.h"
84 struct mips32_pracc_context
{
85 uint32_t *local_iparam
;
87 uint32_t *local_oparam
;
93 struct mips_ejtag
*ejtag_info
;
96 static int mips32_pracc_sync_cache(struct mips_ejtag
*ejtag_info
,
97 uint32_t start_addr
, uint32_t end_addr
);
98 static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag
*ejtag_info
,
99 uint32_t start_addr
, uint32_t end_addr
);
101 static int wait_for_pracc_rw(struct mips_ejtag
*ejtag_info
, uint32_t *ctrl
)
104 long long then
= timeval_ms();
108 /* wait for the PrAcc to become "1" */
109 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_CONTROL
);
112 ejtag_ctrl
= ejtag_info
->ejtag_ctrl
;
113 retval
= mips_ejtag_drscan_32(ejtag_info
, &ejtag_ctrl
);
114 if (retval
!= ERROR_OK
)
117 if (ejtag_ctrl
& EJTAG_CTRL_PRACC
)
120 timeout
= timeval_ms() - then
;
121 if (timeout
> 1000) {
122 LOG_DEBUG("DEBUGMODULE: No memory access in progress!");
123 return ERROR_JTAG_DEVICE_ERROR
;
131 static int mips32_pracc_exec_read(struct mips32_pracc_context
*ctx
, uint32_t address
)
133 struct mips_ejtag
*ejtag_info
= ctx
->ejtag_info
;
135 uint32_t ejtag_ctrl
, data
;
137 if ((address
>= MIPS32_PRACC_PARAM_IN
)
138 && (address
< MIPS32_PRACC_PARAM_IN
+ ctx
->num_iparam
* 4)) {
139 offset
= (address
- MIPS32_PRACC_PARAM_IN
) / 4;
140 data
= ctx
->local_iparam
[offset
];
141 } else if ((address
>= MIPS32_PRACC_PARAM_OUT
)
142 && (address
< MIPS32_PRACC_PARAM_OUT
+ ctx
->num_oparam
* 4)) {
143 offset
= (address
- MIPS32_PRACC_PARAM_OUT
) / 4;
144 data
= ctx
->local_oparam
[offset
];
145 } else if ((address
>= MIPS32_PRACC_TEXT
)
146 && (address
< MIPS32_PRACC_TEXT
+ ctx
->code_len
* 4)) {
147 offset
= (address
- MIPS32_PRACC_TEXT
) / 4;
148 data
= ctx
->code
[offset
];
149 } else if (address
== MIPS32_PRACC_STACK
) {
150 if (ctx
->stack_offset
<= 0) {
151 LOG_ERROR("Error: Pracc stack out of bounds");
152 return ERROR_JTAG_DEVICE_ERROR
;
154 /* save to our debug stack */
155 data
= ctx
->stack
[--ctx
->stack_offset
];
157 /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back
158 * to start of debug vector */
160 LOG_ERROR("Error reading unexpected address 0x%8.8" PRIx32
"", address
);
161 return ERROR_JTAG_DEVICE_ERROR
;
164 /* Send the data out */
165 mips_ejtag_set_instr(ctx
->ejtag_info
, EJTAG_INST_DATA
);
166 mips_ejtag_drscan_32_out(ctx
->ejtag_info
, data
);
168 /* Clear the access pending bit (let the processor eat!) */
169 ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
170 mips_ejtag_set_instr(ctx
->ejtag_info
, EJTAG_INST_CONTROL
);
171 mips_ejtag_drscan_32_out(ctx
->ejtag_info
, ejtag_ctrl
);
173 return jtag_execute_queue();
176 static int mips32_pracc_exec_write(struct mips32_pracc_context
*ctx
, uint32_t address
)
178 uint32_t ejtag_ctrl
, data
;
180 struct mips_ejtag
*ejtag_info
= ctx
->ejtag_info
;
183 mips_ejtag_set_instr(ctx
->ejtag_info
, EJTAG_INST_DATA
);
184 retval
= mips_ejtag_drscan_32(ctx
->ejtag_info
, &data
);
185 if (retval
!= ERROR_OK
)
188 /* Clear access pending bit */
189 ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
190 mips_ejtag_set_instr(ctx
->ejtag_info
, EJTAG_INST_CONTROL
);
191 mips_ejtag_drscan_32_out(ctx
->ejtag_info
, ejtag_ctrl
);
193 retval
= jtag_execute_queue();
194 if (retval
!= ERROR_OK
)
197 if ((address
>= MIPS32_PRACC_PARAM_IN
)
198 && (address
< MIPS32_PRACC_PARAM_IN
+ ctx
->num_iparam
* 4)) {
199 offset
= (address
- MIPS32_PRACC_PARAM_IN
) / 4;
200 ctx
->local_iparam
[offset
] = data
;
201 } else if ((address
>= MIPS32_PRACC_PARAM_OUT
)
202 && (address
< MIPS32_PRACC_PARAM_OUT
+ ctx
->num_oparam
* 4)) {
203 offset
= (address
- MIPS32_PRACC_PARAM_OUT
) / 4;
204 ctx
->local_oparam
[offset
] = data
;
205 } else if (address
== MIPS32_PRACC_STACK
) {
206 if (ctx
->stack_offset
>= 32) {
207 LOG_ERROR("Error: Pracc stack out of bounds");
208 return ERROR_JTAG_DEVICE_ERROR
;
210 /* save data onto our stack */
211 ctx
->stack
[ctx
->stack_offset
++] = data
;
213 LOG_ERROR("Error writing unexpected address 0x%8.8" PRIx32
"", address
);
214 return ERROR_JTAG_DEVICE_ERROR
;
220 int mips32_pracc_exec(struct mips_ejtag
*ejtag_info
, int code_len
, const uint32_t *code
,
221 int num_param_in
, uint32_t *param_in
, int num_param_out
, uint32_t *param_out
, int cycle
)
225 struct mips32_pracc_context ctx
;
229 ctx
.local_iparam
= param_in
;
230 ctx
.local_oparam
= param_out
;
231 ctx
.num_iparam
= num_param_in
;
232 ctx
.num_oparam
= num_param_out
;
234 ctx
.code_len
= code_len
;
235 ctx
.ejtag_info
= ejtag_info
;
236 ctx
.stack_offset
= 0;
239 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
240 if (retval
!= ERROR_OK
)
244 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ADDRESS
);
245 retval
= mips_ejtag_drscan_32(ejtag_info
, &address
);
246 if (retval
!= ERROR_OK
)
249 /* Check for read or write */
250 if (ejtag_ctrl
& EJTAG_CTRL_PRNW
) {
251 retval
= mips32_pracc_exec_write(&ctx
, address
);
252 if (retval
!= ERROR_OK
)
255 /* Check to see if its reading at the debug vector. The first pass through
256 * the module is always read at the vector, so the first one we allow. When
257 * the second read from the vector occurs we are done and just exit. */
258 if ((address
== MIPS32_PRACC_TEXT
) && (pass
++))
261 retval
= mips32_pracc_exec_read(&ctx
, address
);
262 if (retval
!= ERROR_OK
)
270 /* stack sanity check */
271 if (ctx
.stack_offset
!= 0)
272 LOG_DEBUG("Pracc Stack not zero");
277 static int mips32_pracc_read_u32(struct mips_ejtag
*ejtag_info
, uint32_t addr
, uint32_t *buf
)
281 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
282 MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR
), /* $15 = MIPS32_PRACC_BASE_ADDR */
283 MIPS32_SW(8, PRACC_STACK_OFFSET
, 15), /* sw $8,PRACC_STACK_OFFSET($15) */
285 MIPS32_LUI(8, UPPER16((addr
+ 0x8000))), /* load $8 with modified upper address */
286 MIPS32_LW(8, LOWER16(addr
), 8), /* lw $8, LOWER16(addr)($8) */
287 MIPS32_SW(8, PRACC_OUT_OFFSET
, 15), /* sw $8,PRACC_OUT_OFFSET($15) */
289 MIPS32_LW(8, PRACC_STACK_OFFSET
, 15), /* lw $8,PRACC_STACK_OFFSET($15) */
290 MIPS32_B(NEG16(8)), /* b start */
291 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
294 return mips32_pracc_exec(ejtag_info
, ARRAY_SIZE(code
), code
, 0, NULL
, 1, buf
, 1);
297 int mips32_pracc_read_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, void *buf
)
299 if (count
== 1 && size
== 4)
300 return mips32_pracc_read_u32(ejtag_info
, addr
, (uint32_t *)buf
);
302 int retval
= ERROR_FAIL
;
304 uint32_t *code
= NULL
;
305 uint32_t *data
= NULL
;
307 code
= malloc((256 * 2 + 10) * sizeof(uint32_t));
309 LOG_ERROR("Out of memory");
314 data
= malloc(256 * sizeof(uint32_t));
316 LOG_ERROR("Out of memory");
321 uint32_t *buf32
= buf
;
322 uint16_t *buf16
= buf
;
326 uint32_t upper_base_addr
, last_upper_base_addr
;
327 int this_round_count
;
331 this_round_count
= (count
> 256) ? 256 : count
;
332 last_upper_base_addr
= UPPER16((addr
+ 0x8000));
333 uint32_t *code_p
= code
;
335 *code_p
++ = MIPS32_MTC0(15, 31, 0); /* save $15 in DeSave */
336 *code_p
++ = MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR
); /* $15 = MIPS32_PRACC_BASE_ADDR */
337 *code_p
++ = MIPS32_SW(8, PRACC_STACK_OFFSET
, 15); /* save $8 and $9 to pracc stack */
338 *code_p
++ = MIPS32_SW(9, PRACC_STACK_OFFSET
, 15);
339 *code_p
++ = MIPS32_LUI(9, last_upper_base_addr
); /* load the upper memory address in $9*/
342 for (i
= 0; i
!= this_round_count
; i
++) { /* Main code loop */
343 upper_base_addr
= UPPER16((addr
+ 0x8000));
344 if (last_upper_base_addr
!= upper_base_addr
) {
345 *code_p
++ = MIPS32_LUI(9, upper_base_addr
); /* if needed, change upper address in $9*/
347 last_upper_base_addr
= upper_base_addr
;
351 *code_p
++ = MIPS32_LW(8, LOWER16(addr
), 9); /* load from memory to $8 */
353 *code_p
++ = MIPS32_LHU(8, LOWER16(addr
), 9);
355 *code_p
++ = MIPS32_LBU(8, LOWER16(addr
), 9);
357 *code_p
++ = MIPS32_SW(8, PRACC_OUT_OFFSET
+ i
* 4, 15); /* store $8 at param out */
363 *code_p
++ = MIPS32_LW(9, PRACC_STACK_OFFSET
, 15); /* restore $8 and $9 from pracc stack */
364 *code_p
++ = MIPS32_LW(8, PRACC_STACK_OFFSET
, 15);
367 *code_p
++ = MIPS32_B(NEG16(code_len
- 1)); /* jump to start */
368 *code_p
= MIPS32_MFC0(15, 31, 0); /* restore $15 from DeSave */
371 retval
= mips32_pracc_exec(ejtag_info
, code_len
, code
, 0, NULL
, this_round_count
, buf32
, 1);
372 if (retval
!= ERROR_OK
)
374 buf32
+= this_round_count
;
376 retval
= mips32_pracc_exec(ejtag_info
, code_len
, code
, 0, NULL
, this_round_count
, data
, 1);
377 if (retval
!= ERROR_OK
)
379 uint32_t *data_p
= data
;
380 for (i
= 0; i
!= this_round_count
; i
++) {
382 *buf16
++ = *data_p
++;
387 count
-= this_round_count
;
398 int mips32_cp0_read(struct mips_ejtag
*ejtag_info
, uint32_t *val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
401 * Do not make this code static, but regenerate it every time,
402 * as 3th element has to be changed to add parameters
406 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
407 MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR
), /* $15 = MIPS32_PRACC_BASE_ADDR */
408 MIPS32_SW(8, PRACC_STACK_OFFSET
, 15), /* sw $8,PRACC_STACK_OFFSET($15) */
410 /* 3 */ MIPS32_MFC0(8, 0, 0), /* move COP0 [cp0_reg select] to $8 */
411 MIPS32_SW(8, PRACC_OUT_OFFSET
, 15), /* sw $8,PRACC_OUT_OFFSET($15) */
413 MIPS32_LW(8, PRACC_STACK_OFFSET
, 15), /* lw $8,PRACC_STACK_OFFSET($15) */
414 MIPS32_B(NEG16(7)), /* b start */
415 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
419 * Note that our input parametes cp0_reg and cp0_sel
420 * are numbers (not gprs) which make part of mfc0 instruction opcode.
422 * These are not fix, but can be different for each mips32_cp0_read() function call,
423 * and that is why we must insert them directly into opcode,
424 * i.e. we can not pass it on EJTAG microprogram stack (via param_in),
425 * and put them into the gprs later from MIPS32_PRACC_STACK
426 * because mfc0 do not use gpr as a parameter for the cp0_reg and select part,
427 * but plain (immediate) number.
429 * MIPS32_MTC0 is implemented via MIPS32_R_INST macro.
430 * In order to insert our parameters, we must change rd and funct fields.
432 code
[3] |= (cp0_reg
<< 11) | cp0_sel
; /* change rd and funct of MIPS32_R_INST macro */
434 return mips32_pracc_exec(ejtag_info
, ARRAY_SIZE(code
), code
, 0, NULL
, 1, val
, 1);
437 int mips32_cp0_write(struct mips_ejtag
*ejtag_info
, uint32_t val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
441 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
442 MIPS32_LUI(15, UPPER16(val
)), /* Load val to $15 */
443 MIPS32_ORI(15, 15, LOWER16(val
)),
445 /* 3 */ MIPS32_MTC0(15, 0, 0), /* move $15 to COP0 [cp0_reg select] */
447 MIPS32_B(NEG16(5)), /* b start */
448 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
452 * Note that MIPS32_MTC0 macro is implemented via MIPS32_R_INST macro.
453 * In order to insert our parameters, we must change rd and funct fields.
455 code
[3] |= (cp0_reg
<< 11) | cp0_sel
; /* change rd and funct fields of MIPS32_R_INST macro */
457 return mips32_pracc_exec(ejtag_info
, ARRAY_SIZE(code
), code
, 0, NULL
, 0, NULL
, 1);
461 * \b mips32_pracc_sync_cache
463 * Synchronize Caches to Make Instruction Writes Effective
464 * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set,
465 * Document Number: MD00086, Revision 2.00, June 9, 2003)
467 * When the instruction stream is written, the SYNCI instruction should be used
468 * in conjunction with other instructions to make the newly-written instructions effective.
471 * A program that loads another program into memory is actually writing the D- side cache.
472 * The instructions it has loaded can't be executed until they reach the I-cache.
474 * After the instructions have been written, the loader should arrange
475 * to write back any containing D-cache line and invalidate any locations
476 * already in the I-cache.
478 * You can do that with cache instructions, but those instructions are only available in kernel mode,
479 * and a loader writing instructions for the use of its own process need not be privileged software.
481 * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
482 * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
483 * That is, it arranges a D-cache write-back and an I-cache invalidate.
485 * To employ synci at user level, you need to know the size of a cache line,
486 * and that can be obtained with a rdhwr SYNCI_Step
487 * from one of the standard “hardware registers”.
489 static int mips32_pracc_sync_cache(struct mips_ejtag
*ejtag_info
,
490 uint32_t start_addr
, uint32_t end_addr
)
492 static const uint32_t code
[] = {
494 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
495 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK
)), /* $15 = MIPS32_PRACC_STACK */
496 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK
)),
497 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
498 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
499 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
500 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
502 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN
)), /* $8 = MIPS32_PRACC_PARAM_IN */
503 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN
)),
504 MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */
505 MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */
507 MIPS32_RDHWR(11, MIPS32_SYNCI_STEP
), /* $11 = MIPS32_SYNCI_STEP */
508 MIPS32_BEQ(11, 0, 6), /* beq $11, $0, end */
511 MIPS32_SYNCI(0, 9), /* synci 0($9) */
512 MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 # $8 = $10 < $9 ? 1 : 0 */
513 MIPS32_BNE(8, 0, NEG16(3)), /* bne $8, $0, synci_loop */
514 MIPS32_ADDU(9, 9, 11), /* $9 += MIPS32_SYNCI_STEP */
517 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
518 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
519 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
520 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
521 MIPS32_B(NEG16(24)), /* b start */
522 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
525 /* TODO remove array */
526 uint32_t *param_in
= malloc(2 * sizeof(uint32_t));
528 param_in
[0] = start_addr
;
529 param_in
[1] = end_addr
;
531 retval
= mips32_pracc_exec(ejtag_info
, ARRAY_SIZE(code
), code
, 2, param_in
, 0, NULL
, 1);
539 * \b mips32_pracc_clean_invalidate_cache
541 * Writeback D$ and Invalidate I$
542 * so that the instructions written can be visible to CPU
544 static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag
*ejtag_info
,
545 uint32_t start_addr
, uint32_t end_addr
)
547 static const uint32_t code
[] = {
549 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
550 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK
)), /* $15 = MIPS32_PRACC_STACK */
551 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK
)),
552 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
553 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
554 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
555 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
557 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN
)), /* $8 = MIPS32_PRACC_PARAM_IN */
558 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN
)),
559 MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */
560 MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */
561 MIPS32_LW(11, 8, 8), /* Load write clsiz to $11 */
564 MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 : $8 <- $10 < $9 ? */
565 MIPS32_BGTZ(8, 6), /* bgtz $8, end */
568 MIPS32_CACHE(MIPS32_CACHE_D_HIT_WRITEBACK
, 0, 9), /* cache Hit_Writeback_D, 0($9) */
569 MIPS32_CACHE(MIPS32_CACHE_I_HIT_INVALIDATE
, 0, 9), /* cache Hit_Invalidate_I, 0($9) */
571 MIPS32_ADDU(9, 9, 11), /* $9 += $11 */
573 MIPS32_B(NEG16(7)), /* b cache_loop */
576 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
577 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
578 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
579 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
580 MIPS32_B(NEG16(25)), /* b start */
581 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
585 * Find cache line size in bytes
590 mips32_cp0_read(ejtag_info
, &conf
, 16, 1);
591 dl
= (conf
& MIPS32_CONFIG1_DL_MASK
) >> MIPS32_CONFIG1_DL_SHIFT
;
593 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... */
596 /* TODO remove array */
597 uint32_t *param_in
= malloc(3 * sizeof(uint32_t));
599 param_in
[0] = start_addr
;
600 param_in
[1] = end_addr
;
603 retval
= mips32_pracc_exec(ejtag_info
, ARRAY_SIZE(code
), code
, 3, param_in
, 0, NULL
, 1);
610 static int mips32_pracc_write_mem_generic(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, void *buf
)
613 code
= malloc((128 * 3 + 9) * sizeof(uint32_t)); /* alloc memory for the worst case */
615 LOG_ERROR("Out of memory");
619 uint32_t *buf32
= buf
;
620 uint16_t *buf16
= buf
;
624 int retval
= ERROR_FAIL
;
626 uint32_t upper_base_addr
, last_upper_base_addr
;
627 int this_round_count
;
631 this_round_count
= (count
> 128) ? 128 : count
;
632 last_upper_base_addr
= UPPER16((addr
+ 0x8000));
635 *code_p
++ = MIPS32_MTC0(15, 31, 0); /* save $15 in DeSave */
636 *code_p
++ = MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR
); /* $15 = MIPS32_PRACC_BASE_ADDR */
637 *code_p
++ = MIPS32_SW(8, PRACC_STACK_OFFSET
, 15); /* save $8 to pracc stack */
638 *code_p
++ = MIPS32_LUI(15, last_upper_base_addr
); /* reuse $15 as memory base address */
641 for (i
= 0; i
!= this_round_count
; i
++) {
642 upper_base_addr
= UPPER16((addr
+ 0x8000));
643 if (last_upper_base_addr
!= upper_base_addr
) {
644 *code_p
++ = MIPS32_LUI(15, upper_base_addr
); /* if needed, change upper address in $15*/
646 last_upper_base_addr
= upper_base_addr
;
649 if (size
== 4) { /* for word write check if one half word is 0 and load it accordingly */
650 if (LOWER16(*buf32
) == 0) {
651 *code_p
++ = MIPS32_LUI(8, UPPER16(*buf32
)); /* load only upper value */
653 } else if (UPPER16(*buf32
) == 0) {
654 *code_p
++ = MIPS32_ORI(8, 0, LOWER16(*buf32
)); /* load only lower value */
657 *code_p
++ = MIPS32_LUI(8, UPPER16(*buf32
)); /* load upper and lower */
658 *code_p
++ = MIPS32_ORI(8, 8, LOWER16(*buf32
));
661 *code_p
++ = MIPS32_SW(8, LOWER16(addr
), 15); /* store word to memory */
665 } else if (size
== 2) {
666 *code_p
++ = MIPS32_ORI(8, 0, *buf16
); /* load lower value */
667 *code_p
++ = MIPS32_SH(8, LOWER16(addr
), 15); /* store half word to memory */
672 *code_p
++ = MIPS32_ORI(8, 0, *buf8
); /* load lower value */
673 *code_p
++ = MIPS32_SB(8, LOWER16(addr
), 15); /* store byte to memory */
681 *code_p
++ = MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR
); /* $15 = MIPS32_PRACC_BASE_ADDR */
682 *code_p
++ = MIPS32_LW(8, PRACC_STACK_OFFSET
, 15); /* restore $8 from pracc stack */
685 *code_p
++ = MIPS32_B(NEG16(code_len
- 1)); /* jump to start */
686 *code_p
= MIPS32_MFC0(15, 31, 0); /* restore $15 from DeSave */
688 retval
= mips32_pracc_exec(ejtag_info
, code_len
, code
, 0, NULL
, 0, NULL
, 1);
689 if (retval
!= ERROR_OK
)
692 count
-= this_round_count
;
700 int mips32_pracc_write_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, void *buf
)
702 int retval
= mips32_pracc_write_mem_generic(ejtag_info
, addr
, size
, count
, buf
);
703 if (retval
!= ERROR_OK
)
707 * If we are in the cachable regoion and cache is activated,
708 * we must clean D$ + invalidate I$ after we did the write,
709 * so that changes do not continue to live only in D$, but to be
710 * replicated in I$ also (maybe we wrote the istructions)
715 if ((KSEGX(addr
) == KSEG1
) || ((addr
>= 0xff200000) && (addr
<= 0xff3fffff)))
716 return retval
; /*Nothing to do*/
718 mips32_cp0_read(ejtag_info
, &conf
, 16, 0);
720 switch (KSEGX(addr
)) {
722 cached
= (conf
& MIPS32_CONFIG0_KU_MASK
) >> MIPS32_CONFIG0_KU_SHIFT
;
725 cached
= (conf
& MIPS32_CONFIG0_K0_MASK
) >> MIPS32_CONFIG0_K0_SHIFT
;
729 cached
= (conf
& MIPS32_CONFIG0_K23_MASK
) >> MIPS32_CONFIG0_K23_SHIFT
;
737 * Check cachablitiy bits coherency algorithm -
738 * is the region cacheable or uncached.
739 * If cacheable we have to synchronize the cache
742 uint32_t start_addr
, end_addr
;
746 end_addr
= addr
+ count
* size
;
748 /** select cache synchronisation mechanism based on Architecture Release */
749 rel
= (conf
& MIPS32_CONFIG0_AR_MASK
) >> MIPS32_CONFIG0_AR_SHIFT
;
751 case MIPS32_ARCH_REL1
:
752 /* MIPS32/64 Release 1 - we must use cache instruction */
753 mips32_pracc_clean_invalidate_cache(ejtag_info
, start_addr
, end_addr
);
755 case MIPS32_ARCH_REL2
:
756 /* MIPS32/64 Release 2 - we can use synci instruction */
757 mips32_pracc_sync_cache(ejtag_info
, start_addr
, end_addr
);
768 int mips32_pracc_write_regs(struct mips_ejtag
*ejtag_info
, uint32_t *regs
)
770 static const uint32_t code
[] = {
772 MIPS32_LUI(2, UPPER16(MIPS32_PRACC_PARAM_IN
)), /* $2 = MIPS32_PRACC_PARAM_IN */
773 MIPS32_ORI(2, 2, LOWER16(MIPS32_PRACC_PARAM_IN
)),
774 MIPS32_LW(1, 1*4, 2), /* lw $1,1*4($2) */
775 MIPS32_LW(15, 15*4, 2), /* lw $15,15*4($2) */
776 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
777 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK
)), /* $15 = MIPS32_PRACC_STACK */
778 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK
)),
779 MIPS32_SW(1, 0, 15), /* sw $1,($15) */
780 MIPS32_LUI(1, UPPER16(MIPS32_PRACC_PARAM_IN
)), /* $1 = MIPS32_PRACC_PARAM_IN */
781 MIPS32_ORI(1, 1, LOWER16(MIPS32_PRACC_PARAM_IN
)),
782 MIPS32_LW(3, 3*4, 1), /* lw $3,3*4($1) */
783 MIPS32_LW(4, 4*4, 1), /* lw $4,4*4($1) */
784 MIPS32_LW(5, 5*4, 1), /* lw $5,5*4($1) */
785 MIPS32_LW(6, 6*4, 1), /* lw $6,6*4($1) */
786 MIPS32_LW(7, 7*4, 1), /* lw $7,7*4($1) */
787 MIPS32_LW(8, 8*4, 1), /* lw $8,8*4($1) */
788 MIPS32_LW(9, 9*4, 1), /* lw $9,9*4($1) */
789 MIPS32_LW(10, 10*4, 1), /* lw $10,10*4($1) */
790 MIPS32_LW(11, 11*4, 1), /* lw $11,11*4($1) */
791 MIPS32_LW(12, 12*4, 1), /* lw $12,12*4($1) */
792 MIPS32_LW(13, 13*4, 1), /* lw $13,13*4($1) */
793 MIPS32_LW(14, 14*4, 1), /* lw $14,14*4($1) */
794 MIPS32_LW(16, 16*4, 1), /* lw $16,16*4($1) */
795 MIPS32_LW(17, 17*4, 1), /* lw $17,17*4($1) */
796 MIPS32_LW(18, 18*4, 1), /* lw $18,18*4($1) */
797 MIPS32_LW(19, 19*4, 1), /* lw $19,19*4($1) */
798 MIPS32_LW(20, 20*4, 1), /* lw $20,20*4($1) */
799 MIPS32_LW(21, 21*4, 1), /* lw $21,21*4($1) */
800 MIPS32_LW(22, 22*4, 1), /* lw $22,22*4($1) */
801 MIPS32_LW(23, 23*4, 1), /* lw $23,23*4($1) */
802 MIPS32_LW(24, 24*4, 1), /* lw $24,24*4($1) */
803 MIPS32_LW(25, 25*4, 1), /* lw $25,25*4($1) */
804 MIPS32_LW(26, 26*4, 1), /* lw $26,26*4($1) */
805 MIPS32_LW(27, 27*4, 1), /* lw $27,27*4($1) */
806 MIPS32_LW(28, 28*4, 1), /* lw $28,28*4($1) */
807 MIPS32_LW(29, 29*4, 1), /* lw $29,29*4($1) */
808 MIPS32_LW(30, 30*4, 1), /* lw $30,30*4($1) */
809 MIPS32_LW(31, 31*4, 1), /* lw $31,31*4($1) */
811 MIPS32_LW(2, 32*4, 1), /* lw $2,32*4($1) */
812 MIPS32_MTC0(2, 12, 0), /* move $2 to status */
813 MIPS32_LW(2, 33*4, 1), /* lw $2,33*4($1) */
814 MIPS32_MTLO(2), /* move $2 to lo */
815 MIPS32_LW(2, 34*4, 1), /* lw $2,34*4($1) */
816 MIPS32_MTHI(2), /* move $2 to hi */
817 MIPS32_LW(2, 35*4, 1), /* lw $2,35*4($1) */
818 MIPS32_MTC0(2, 8, 0), /* move $2 to badvaddr */
819 MIPS32_LW(2, 36*4, 1), /* lw $2,36*4($1) */
820 MIPS32_MTC0(2, 13, 0), /* move $2 to cause*/
821 MIPS32_LW(2, 37*4, 1), /* lw $2,37*4($1) */
822 MIPS32_MTC0(2, 24, 0), /* move $2 to depc (pc) */
824 MIPS32_LW(2, 2*4, 1), /* lw $2,2*4($1) */
825 MIPS32_LW(1, 0, 15), /* lw $1,($15) */
826 MIPS32_B(NEG16(53)), /* b start */
827 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
832 retval
= mips32_pracc_exec(ejtag_info
, ARRAY_SIZE(code
), code
,
833 MIPS32NUMCOREREGS
, regs
, 0, NULL
, 1);
838 int mips32_pracc_read_regs(struct mips_ejtag
*ejtag_info
, uint32_t *regs
)
840 static const uint32_t code
[] = {
842 MIPS32_MTC0(2, 31, 0), /* move $2 to COP0 DeSave */
843 MIPS32_LUI(2, UPPER16(MIPS32_PRACC_PARAM_OUT
)), /* $2 = MIPS32_PRACC_PARAM_OUT */
844 MIPS32_ORI(2, 2, LOWER16(MIPS32_PRACC_PARAM_OUT
)),
845 MIPS32_SW(0, 0*4, 2), /* sw $0,0*4($2) */
846 MIPS32_SW(1, 1*4, 2), /* sw $1,1*4($2) */
847 MIPS32_SW(15, 15*4, 2), /* sw $15,15*4($2) */
848 MIPS32_MFC0(2, 31, 0), /* move COP0 DeSave to $2 */
849 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
850 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK
)), /* $15 = MIPS32_PRACC_STACK */
851 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK
)),
852 MIPS32_SW(1, 0, 15), /* sw $1,($15) */
853 MIPS32_SW(2, 0, 15), /* sw $2,($15) */
854 MIPS32_LUI(1, UPPER16(MIPS32_PRACC_PARAM_OUT
)), /* $1 = MIPS32_PRACC_PARAM_OUT */
855 MIPS32_ORI(1, 1, LOWER16(MIPS32_PRACC_PARAM_OUT
)),
856 MIPS32_SW(2, 2*4, 1), /* sw $2,2*4($1) */
857 MIPS32_SW(3, 3*4, 1), /* sw $3,3*4($1) */
858 MIPS32_SW(4, 4*4, 1), /* sw $4,4*4($1) */
859 MIPS32_SW(5, 5*4, 1), /* sw $5,5*4($1) */
860 MIPS32_SW(6, 6*4, 1), /* sw $6,6*4($1) */
861 MIPS32_SW(7, 7*4, 1), /* sw $7,7*4($1) */
862 MIPS32_SW(8, 8*4, 1), /* sw $8,8*4($1) */
863 MIPS32_SW(9, 9*4, 1), /* sw $9,9*4($1) */
864 MIPS32_SW(10, 10*4, 1), /* sw $10,10*4($1) */
865 MIPS32_SW(11, 11*4, 1), /* sw $11,11*4($1) */
866 MIPS32_SW(12, 12*4, 1), /* sw $12,12*4($1) */
867 MIPS32_SW(13, 13*4, 1), /* sw $13,13*4($1) */
868 MIPS32_SW(14, 14*4, 1), /* sw $14,14*4($1) */
869 MIPS32_SW(16, 16*4, 1), /* sw $16,16*4($1) */
870 MIPS32_SW(17, 17*4, 1), /* sw $17,17*4($1) */
871 MIPS32_SW(18, 18*4, 1), /* sw $18,18*4($1) */
872 MIPS32_SW(19, 19*4, 1), /* sw $19,19*4($1) */
873 MIPS32_SW(20, 20*4, 1), /* sw $20,20*4($1) */
874 MIPS32_SW(21, 21*4, 1), /* sw $21,21*4($1) */
875 MIPS32_SW(22, 22*4, 1), /* sw $22,22*4($1) */
876 MIPS32_SW(23, 23*4, 1), /* sw $23,23*4($1) */
877 MIPS32_SW(24, 24*4, 1), /* sw $24,24*4($1) */
878 MIPS32_SW(25, 25*4, 1), /* sw $25,25*4($1) */
879 MIPS32_SW(26, 26*4, 1), /* sw $26,26*4($1) */
880 MIPS32_SW(27, 27*4, 1), /* sw $27,27*4($1) */
881 MIPS32_SW(28, 28*4, 1), /* sw $28,28*4($1) */
882 MIPS32_SW(29, 29*4, 1), /* sw $29,29*4($1) */
883 MIPS32_SW(30, 30*4, 1), /* sw $30,30*4($1) */
884 MIPS32_SW(31, 31*4, 1), /* sw $31,31*4($1) */
886 MIPS32_MFC0(2, 12, 0), /* move status to $2 */
887 MIPS32_SW(2, 32*4, 1), /* sw $2,32*4($1) */
888 MIPS32_MFLO(2), /* move lo to $2 */
889 MIPS32_SW(2, 33*4, 1), /* sw $2,33*4($1) */
890 MIPS32_MFHI(2), /* move hi to $2 */
891 MIPS32_SW(2, 34*4, 1), /* sw $2,34*4($1) */
892 MIPS32_MFC0(2, 8, 0), /* move badvaddr to $2 */
893 MIPS32_SW(2, 35*4, 1), /* sw $2,35*4($1) */
894 MIPS32_MFC0(2, 13, 0), /* move cause to $2 */
895 MIPS32_SW(2, 36*4, 1), /* sw $2,36*4($1) */
896 MIPS32_MFC0(2, 24, 0), /* move depc (pc) to $2 */
897 MIPS32_SW(2, 37*4, 1), /* sw $2,37*4($1) */
899 MIPS32_LW(2, 0, 15), /* lw $2,($15) */
900 MIPS32_LW(1, 0, 15), /* lw $1,($15) */
901 MIPS32_B(NEG16(58)), /* b start */
902 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
907 retval
= mips32_pracc_exec(ejtag_info
, ARRAY_SIZE(code
), code
,
908 0, NULL
, MIPS32NUMCOREREGS
, regs
, 1);
913 /* fastdata upload/download requires an initialized working area
914 * to load the download code; it should not be called otherwise
915 * fetch order from the fastdata area
920 int mips32_pracc_fastdata_xfer(struct mips_ejtag
*ejtag_info
, struct working_area
*source
,
921 int write_t
, uint32_t addr
, int count
, uint32_t *buf
)
923 uint32_t handler_code
[] = {
924 /* caution when editing, table is modified below */
925 /* r15 points to the start of this code */
926 MIPS32_SW(8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
927 MIPS32_SW(9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
928 MIPS32_SW(10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
929 MIPS32_SW(11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
930 /* start of fastdata area in t0 */
931 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_FASTDATA_AREA
)),
932 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA
)),
933 MIPS32_LW(9, 0, 8), /* start addr in t1 */
934 MIPS32_LW(10, 0, 8), /* end addr to t2 */
936 /* 8 */ MIPS32_LW(11, 0, 0), /* lw t3,[t8 | r9] */
937 /* 9 */ MIPS32_SW(11, 0, 0), /* sw t3,[r9 | r8] */
938 MIPS32_BNE(10, 9, NEG16(3)), /* bne $t2,t1,loop */
939 MIPS32_ADDI(9, 9, 4), /* addi t1,t1,4 */
941 MIPS32_LW(8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
942 MIPS32_LW(9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
943 MIPS32_LW(10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
944 MIPS32_LW(11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
946 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_TEXT
)),
947 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_TEXT
)),
948 MIPS32_JR(15), /* jr start */
949 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
952 uint32_t jmp_code
[] = {
953 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
954 /* 1 */ MIPS32_LUI(15, 0), /* addr of working area added below */
955 /* 2 */ MIPS32_ORI(15, 15, 0), /* addr of working area added below */
956 MIPS32_JR(15), /* jump to ram program */
961 uint32_t val
, ejtag_ctrl
, address
;
963 if (source
->size
< MIPS32_FASTDATA_HANDLER_SIZE
)
964 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
967 handler_code
[8] = MIPS32_LW(11, 0, 8); /* load data from probe at fastdata area */
968 handler_code
[9] = MIPS32_SW(11, 0, 9); /* store data to RAM @ r9 */
970 handler_code
[8] = MIPS32_LW(11, 0, 9); /* load data from RAM @ r9 */
971 handler_code
[9] = MIPS32_SW(11, 0, 8); /* store data to probe at fastdata area */
974 /* write program into RAM */
975 if (write_t
!= ejtag_info
->fast_access_save
) {
976 mips32_pracc_write_mem_generic(ejtag_info
, source
->address
, 4, ARRAY_SIZE(handler_code
), handler_code
);
977 /* save previous operation to speed to any consecutive read/writes */
978 ejtag_info
->fast_access_save
= write_t
;
981 LOG_DEBUG("%s using 0x%.8" PRIx32
" for write handler", __func__
, source
->address
);
983 jmp_code
[1] |= UPPER16(source
->address
);
984 jmp_code
[2] |= LOWER16(source
->address
);
986 for (i
= 0; i
< (int) ARRAY_SIZE(jmp_code
); i
++) {
987 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
988 if (retval
!= ERROR_OK
)
991 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
992 mips_ejtag_drscan_32_out(ejtag_info
, jmp_code
[i
]);
994 /* Clear the access pending bit (let the processor eat!) */
995 ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
996 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_CONTROL
);
997 mips_ejtag_drscan_32_out(ejtag_info
, ejtag_ctrl
);
1000 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
1001 if (retval
!= ERROR_OK
)
1004 /* next fetch to dmseg should be in FASTDATA_AREA, check */
1006 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ADDRESS
);
1007 retval
= mips_ejtag_drscan_32(ejtag_info
, &address
);
1008 if (retval
!= ERROR_OK
)
1011 if (address
!= MIPS32_PRACC_FASTDATA_AREA
)
1014 /* wait PrAcc pending bit for FASTDATA write */
1015 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
1016 if (retval
!= ERROR_OK
)
1019 /* Send the load start address */
1021 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1022 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1024 /* Send the load end address */
1025 val
= addr
+ (count
- 1) * 4;
1026 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1028 for (i
= 0; i
< count
; i
++) {
1029 retval
= mips_ejtag_fastdata_scan(ejtag_info
, write_t
, buf
++);
1030 if (retval
!= ERROR_OK
)
1034 retval
= jtag_execute_queue();
1035 if (retval
!= ERROR_OK
) {
1036 LOG_ERROR("fastdata load failed");
1040 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
1041 if (retval
!= ERROR_OK
)
1045 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ADDRESS
);
1046 retval
= mips_ejtag_drscan_32(ejtag_info
, &address
);
1047 if (retval
!= ERROR_OK
)
1050 if (address
!= MIPS32_PRACC_TEXT
)
1051 LOG_ERROR("mini program did not return to start");
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)