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 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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
];
156 } else if (address
>= 0xFF200000) {
157 /* CPU keeps reading at the end of execution.
158 * If we after 0xF0000000 address range, we can use
159 * one shot jump instruction.
160 * Since this instruction is limited to
161 * 26bit, we need to do some magic to fit it to our needs. */
162 LOG_DEBUG("Reading unexpected address. Jump to 0xFF200200\n");
163 data
= MIPS32_J((0x0FFFFFFF & 0xFF200200) >> 2);
165 LOG_ERROR("Error reading unexpected address 0x%8.8" PRIx32
"", address
);
166 return ERROR_JTAG_DEVICE_ERROR
;
169 /* Send the data out */
170 mips_ejtag_set_instr(ctx
->ejtag_info
, EJTAG_INST_DATA
);
171 mips_ejtag_drscan_32_out(ctx
->ejtag_info
, data
);
173 /* Clear the access pending bit (let the processor eat!) */
174 ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
175 mips_ejtag_set_instr(ctx
->ejtag_info
, EJTAG_INST_CONTROL
);
176 mips_ejtag_drscan_32_out(ctx
->ejtag_info
, ejtag_ctrl
);
178 return jtag_execute_queue();
181 static int mips32_pracc_exec_write(struct mips32_pracc_context
*ctx
, uint32_t address
)
183 uint32_t ejtag_ctrl
, data
;
185 struct mips_ejtag
*ejtag_info
= ctx
->ejtag_info
;
188 mips_ejtag_set_instr(ctx
->ejtag_info
, EJTAG_INST_DATA
);
189 retval
= mips_ejtag_drscan_32(ctx
->ejtag_info
, &data
);
190 if (retval
!= ERROR_OK
)
193 /* Clear access pending bit */
194 ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
195 mips_ejtag_set_instr(ctx
->ejtag_info
, EJTAG_INST_CONTROL
);
196 mips_ejtag_drscan_32_out(ctx
->ejtag_info
, ejtag_ctrl
);
198 retval
= jtag_execute_queue();
199 if (retval
!= ERROR_OK
)
202 if ((address
>= MIPS32_PRACC_PARAM_OUT
)
203 && (address
< MIPS32_PRACC_PARAM_OUT
+ ctx
->num_oparam
* 4)) {
204 offset
= (address
- MIPS32_PRACC_PARAM_OUT
) / 4;
205 ctx
->local_oparam
[offset
] = data
;
206 } else if (address
== MIPS32_PRACC_STACK
) {
207 if (ctx
->stack_offset
>= 32) {
208 LOG_ERROR("Error: Pracc stack out of bounds");
209 return ERROR_JTAG_DEVICE_ERROR
;
211 /* save data onto our stack */
212 ctx
->stack
[ctx
->stack_offset
++] = data
;
214 LOG_ERROR("Error writing unexpected address 0x%8.8" PRIx32
"", address
);
215 return ERROR_JTAG_DEVICE_ERROR
;
221 int mips32_pracc_exec(struct mips_ejtag
*ejtag_info
, int code_len
, const uint32_t *code
,
222 int num_param_in
, uint32_t *param_in
, int num_param_out
, uint32_t *param_out
, int cycle
)
226 struct mips32_pracc_context ctx
;
230 ctx
.local_iparam
= param_in
;
231 ctx
.local_oparam
= param_out
;
232 ctx
.num_iparam
= num_param_in
;
233 ctx
.num_oparam
= num_param_out
;
235 ctx
.code_len
= code_len
;
236 ctx
.ejtag_info
= ejtag_info
;
237 ctx
.stack_offset
= 0;
240 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
241 if (retval
!= ERROR_OK
)
245 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ADDRESS
);
246 retval
= mips_ejtag_drscan_32(ejtag_info
, &address
);
247 if (retval
!= ERROR_OK
)
250 /* Check for read or write */
251 if (ejtag_ctrl
& EJTAG_CTRL_PRNW
) {
252 retval
= mips32_pracc_exec_write(&ctx
, address
);
253 if (retval
!= ERROR_OK
)
256 /* Check to see if its reading at the debug vector. The first pass through
257 * the module is always read at the vector, so the first one we allow. When
258 * the second read from the vector occurs we are done and just exit. */
259 if ((address
== MIPS32_PRACC_TEXT
) && (pass
++))
262 retval
= mips32_pracc_exec_read(&ctx
, address
);
263 if (retval
!= ERROR_OK
)
271 /* stack sanity check */
272 if (ctx
.stack_offset
!= 0)
273 LOG_DEBUG("Pracc Stack not zero");
278 inline void pracc_queue_init(struct pracc_queue_info
*ctx
)
280 ctx
->retval
= ERROR_OK
;
282 ctx
->store_count
= 0;
284 ctx
->pracc_list
= malloc(2 * ctx
->max_code
* sizeof(uint32_t));
285 if (ctx
->pracc_list
== NULL
) {
286 LOG_ERROR("Out of memory");
287 ctx
->retval
= ERROR_FAIL
;
291 inline void pracc_add(struct pracc_queue_info
*ctx
, uint32_t addr
, uint32_t instr
)
293 ctx
->pracc_list
[ctx
->max_code
+ ctx
->code_count
] = addr
;
294 ctx
->pracc_list
[ctx
->code_count
++] = instr
;
299 inline void pracc_queue_free(struct pracc_queue_info
*ctx
)
301 if (ctx
->code_count
> ctx
->max_code
) /* Only for internal check, will be erased */
302 LOG_ERROR("Internal error, code count: %d > max code: %d", ctx
->code_count
, ctx
->max_code
);
303 if (ctx
->pracc_list
!= NULL
)
304 free(ctx
->pracc_list
);
307 int mips32_pracc_queue_exec(struct mips_ejtag
*ejtag_info
, struct pracc_queue_info
*ctx
, uint32_t *buf
)
309 if (ejtag_info
->mode
== 0)
310 return mips32_pracc_exec(ejtag_info
, ctx
->code_count
, ctx
->pracc_list
, 0, NULL
,
311 ctx
->store_count
, buf
, ctx
->code_count
- 1);
321 } *scan_in
= malloc(sizeof(union scan_in
) * (ctx
->code_count
+ ctx
->store_count
));
322 if (scan_in
== NULL
) {
323 LOG_ERROR("Out of memory");
327 unsigned num_clocks
=
328 ((uint64_t)(ejtag_info
->scan_delay
) * jtag_get_speed_khz() + 500000) / 1000000;
330 uint32_t ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
331 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ALL
);
334 for (int i
= 0; i
!= 2 * ctx
->code_count
; i
++) {
336 if (i
& 1u) { /* Check store address from previous instruction, if not the first */
337 if (i
< 2 || 0 == ctx
->pracc_list
[ctx
->max_code
+ (i
/ 2) - 1])
340 data
= ctx
->pracc_list
[i
/ 2];
342 jtag_add_clocks(num_clocks
);
343 mips_ejtag_add_scan_96(ejtag_info
, ejtag_ctrl
, data
, scan_in
[scan_count
++].scan_96
);
346 int retval
= jtag_execute_queue(); /* execute queued scans */
347 if (retval
!= ERROR_OK
)
350 uint32_t fetch_addr
= MIPS32_PRACC_TEXT
; /* start address */
352 for (int i
= 0; i
!= 2 * ctx
->code_count
; i
++) { /* verify every pracc access */
353 uint32_t store_addr
= 0;
354 if (i
& 1u) { /* Read store addres from previous instruction, if not the first */
355 store_addr
= ctx
->pracc_list
[ctx
->max_code
+ (i
/ 2) - 1];
356 if (i
< 2 || 0 == store_addr
)
360 ejtag_ctrl
= buf_get_u32(scan_in
[scan_count
].scan_32
.ctrl
, 0, 32);
361 if (!(ejtag_ctrl
& EJTAG_CTRL_PRACC
)) {
362 LOG_ERROR("Error: access not pending count: %d", scan_count
);
367 uint32_t addr
= buf_get_u32(scan_in
[scan_count
].scan_32
.addr
, 0, 32);
369 if (store_addr
!= 0) {
370 if (!(ejtag_ctrl
& EJTAG_CTRL_PRNW
)) {
371 LOG_ERROR("Not a store/write access, count: %d", scan_count
);
375 if (addr
!= store_addr
) {
376 LOG_ERROR("Store address mismatch, read: %x expected: %x count: %d",
377 addr
, store_addr
, scan_count
);
381 int buf_index
= (addr
- MIPS32_PRACC_PARAM_OUT
) / 4;
382 buf
[buf_index
] = buf_get_u32(scan_in
[scan_count
].scan_32
.data
, 0, 32);
385 if (ejtag_ctrl
& EJTAG_CTRL_PRNW
) {
386 LOG_ERROR("Not a fetch/read access, count: %d", scan_count
);
390 if (addr
!= fetch_addr
) {
391 LOG_ERROR("Fetch addr mismatch, read: %x expected: %x count: %d", addr
, fetch_addr
, scan_count
);
404 int mips32_pracc_read_u32(struct mips_ejtag
*ejtag_info
, uint32_t addr
, uint32_t *buf
)
406 struct pracc_queue_info ctx
= {.max_code
= 9};
407 pracc_queue_init(&ctx
);
408 if (ctx
.retval
!= ERROR_OK
)
411 pracc_add(&ctx
, 0, MIPS32_MTC0(15, 31, 0)); /* move $15 to COP0 DeSave */
412 pracc_add(&ctx
, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
413 pracc_add(&ctx
, 0, MIPS32_LUI(8, UPPER16((addr
+ 0x8000)))); /* load $8 with modified upper address */
414 pracc_add(&ctx
, 0, MIPS32_LW(8, LOWER16(addr
), 8)); /* lw $8, LOWER16(addr)($8) */
415 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
416 MIPS32_SW(8, PRACC_OUT_OFFSET
, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */
417 pracc_add(&ctx
, 0, MIPS32_LUI(8, UPPER16(ejtag_info
->reg8
))); /* restore upper 16 of $8 */
418 pracc_add(&ctx
, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info
->reg8
))); /* restore lower 16 of $8 */
419 pracc_add(&ctx
, 0, MIPS32_B(NEG16(ctx
.code_count
+ 1))); /* jump to start */
420 pracc_add(&ctx
, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */
422 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, buf
);
424 pracc_queue_free(&ctx
);
428 int mips32_pracc_read_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, void *buf
)
430 if (count
== 1 && size
== 4)
431 return mips32_pracc_read_u32(ejtag_info
, addr
, (uint32_t *)buf
);
433 uint32_t *data
= NULL
;
434 struct pracc_queue_info ctx
= {.max_code
= 256 * 3 + 9 + 1}; /* alloc memory for the worst case */
435 pracc_queue_init(&ctx
);
436 if (ctx
.retval
!= ERROR_OK
)
440 data
= malloc(256 * sizeof(uint32_t));
442 LOG_ERROR("Out of memory");
447 uint32_t *buf32
= buf
;
448 uint16_t *buf16
= buf
;
454 int this_round_count
= (count
> 256) ? 256 : count
;
455 uint32_t last_upper_base_addr
= UPPER16((addr
+ 0x8000));
457 pracc_add(&ctx
, 0, MIPS32_MTC0(15, 31, 0)); /* save $15 in DeSave */
458 pracc_add(&ctx
, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
459 pracc_add(&ctx
, 0, MIPS32_LUI(9, last_upper_base_addr
)); /* load the upper memory address in $9 */
461 for (int i
= 0; i
!= this_round_count
; i
++) { /* Main code loop */
462 uint32_t upper_base_addr
= UPPER16((addr
+ 0x8000));
463 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper address in $9 */
464 pracc_add(&ctx
, 0, MIPS32_LUI(9, upper_base_addr
));
465 last_upper_base_addr
= upper_base_addr
;
469 pracc_add(&ctx
, 0, MIPS32_LW(8, LOWER16(addr
), 9)); /* load from memory to $8 */
471 pracc_add(&ctx
, 0, MIPS32_LHU(8, LOWER16(addr
), 9));
473 pracc_add(&ctx
, 0, MIPS32_LBU(8, LOWER16(addr
), 9));
475 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ i
* 4,
476 MIPS32_SW(8, PRACC_OUT_OFFSET
+ i
* 4, 15)); /* store $8 at param out */
479 pracc_add(&ctx
, 0, MIPS32_LUI(8, UPPER16(ejtag_info
->reg8
))); /* restore upper 16 bits of reg 8 */
480 pracc_add(&ctx
, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info
->reg8
))); /* restore lower 16 bits of reg 8 */
481 pracc_add(&ctx
, 0, MIPS32_LUI(9, UPPER16(ejtag_info
->reg9
))); /* restore upper 16 bits of reg 9 */
482 pracc_add(&ctx
, 0, MIPS32_ORI(9, 9, LOWER16(ejtag_info
->reg9
))); /* restore lower 16 bits of reg 9 */
484 pracc_add(&ctx
, 0, MIPS32_B(NEG16(ctx
.code_count
+ 1))); /* jump to start */
485 pracc_add(&ctx
, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */
488 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, buf32
);
489 if (ctx
.retval
!= ERROR_OK
)
491 buf32
+= this_round_count
;
493 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, data
);
494 if (ctx
.retval
!= ERROR_OK
)
497 uint32_t *data_p
= data
;
498 for (int i
= 0; i
!= this_round_count
; i
++) {
500 *buf16
++ = *data_p
++;
505 count
-= this_round_count
;
508 pracc_queue_free(&ctx
);
514 int mips32_cp0_read(struct mips_ejtag
*ejtag_info
, uint32_t *val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
516 struct pracc_queue_info ctx
= {.max_code
= 8};
517 pracc_queue_init(&ctx
);
518 if (ctx
.retval
!= ERROR_OK
)
521 pracc_add(&ctx
, 0, MIPS32_MTC0(15, 31, 0)); /* move $15 to COP0 DeSave */
522 pracc_add(&ctx
, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
523 pracc_add(&ctx
, 0, MIPS32_MFC0(8, 0, 0) | (cp0_reg
<< 11) | cp0_sel
); /* move COP0 [cp0_reg select] to $8 */
524 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
525 MIPS32_SW(8, PRACC_OUT_OFFSET
, 15)); /* store $8 to pracc_out */
526 pracc_add(&ctx
, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */
527 pracc_add(&ctx
, 0, MIPS32_LUI(8, UPPER16(ejtag_info
->reg8
))); /* restore upper 16 bits of $8 */
528 pracc_add(&ctx
, 0, MIPS32_B(NEG16(ctx
.code_count
+ 1))); /* jump to start */
529 pracc_add(&ctx
, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info
->reg8
))); /* restore lower 16 bits of $8 */
531 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, val
);
533 pracc_queue_free(&ctx
);
537 * Note that our input parametes cp0_reg and cp0_sel
538 * are numbers (not gprs) which make part of mfc0 instruction opcode.
540 * These are not fix, but can be different for each mips32_cp0_read() function call,
541 * and that is why we must insert them directly into opcode,
542 * i.e. we can not pass it on EJTAG microprogram stack (via param_in),
543 * and put them into the gprs later from MIPS32_PRACC_STACK
544 * because mfc0 do not use gpr as a parameter for the cp0_reg and select part,
545 * but plain (immediate) number.
547 * MIPS32_MTC0 is implemented via MIPS32_R_INST macro.
548 * In order to insert our parameters, we must change rd and funct fields.
550 * code[2] |= (cp0_reg << 11) | cp0_sel; change rd and funct of MIPS32_R_INST macro
554 int mips32_cp0_write(struct mips_ejtag
*ejtag_info
, uint32_t val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
556 struct pracc_queue_info ctx
= {.max_code
= 6};
557 pracc_queue_init(&ctx
);
558 if (ctx
.retval
!= ERROR_OK
)
561 pracc_add(&ctx
, 0, MIPS32_MTC0(15, 31, 0)); /* move $15 to COP0 DeSave */
562 pracc_add(&ctx
, 0, MIPS32_LUI(15, UPPER16(val
))); /* Load val to $15 */
563 pracc_add(&ctx
, 0, MIPS32_ORI(15, 15, LOWER16(val
)));
565 pracc_add(&ctx
, 0, MIPS32_MTC0(15, 0, 0) | (cp0_reg
<< 11) | cp0_sel
); /* write cp0 reg / sel */
567 pracc_add(&ctx
, 0, MIPS32_B(NEG16(ctx
.code_count
+ 1))); /* jump to start */
568 pracc_add(&ctx
, 0, MIPS32_MFC0(15, 31, 0)); /* move COP0 DeSave to $15 */
570 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
);
572 pracc_queue_free(&ctx
);
576 * Note that MIPS32_MTC0 macro is implemented via MIPS32_R_INST macro.
577 * In order to insert our parameters, we must change rd and funct fields.
578 * code[3] |= (cp0_reg << 11) | cp0_sel; change rd and funct fields of MIPS32_R_INST macro
583 * \b mips32_pracc_sync_cache
585 * Synchronize Caches to Make Instruction Writes Effective
586 * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set,
587 * Document Number: MD00086, Revision 2.00, June 9, 2003)
589 * When the instruction stream is written, the SYNCI instruction should be used
590 * in conjunction with other instructions to make the newly-written instructions effective.
593 * A program that loads another program into memory is actually writing the D- side cache.
594 * The instructions it has loaded can't be executed until they reach the I-cache.
596 * After the instructions have been written, the loader should arrange
597 * to write back any containing D-cache line and invalidate any locations
598 * already in the I-cache.
600 * You can do that with cache instructions, but those instructions are only available in kernel mode,
601 * and a loader writing instructions for the use of its own process need not be privileged software.
603 * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
604 * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
605 * That is, it arranges a D-cache write-back and an I-cache invalidate.
607 * To employ synci at user level, you need to know the size of a cache line,
608 * and that can be obtained with a rdhwr SYNCI_Step
609 * from one of the standard “hardware registers”.
611 static int mips32_pracc_sync_cache(struct mips_ejtag
*ejtag_info
,
612 uint32_t start_addr
, uint32_t end_addr
)
614 static const uint32_t code
[] = {
616 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
617 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK
)), /* $15 = MIPS32_PRACC_STACK */
618 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK
)),
619 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
620 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
621 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
622 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
624 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN
)), /* $8 = MIPS32_PRACC_PARAM_IN */
625 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN
)),
626 MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */
627 MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */
629 MIPS32_RDHWR(11, MIPS32_SYNCI_STEP
), /* $11 = MIPS32_SYNCI_STEP */
630 MIPS32_BEQ(11, 0, 6), /* beq $11, $0, end */
633 MIPS32_SYNCI(0, 9), /* synci 0($9) */
634 MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 # $8 = $10 < $9 ? 1 : 0 */
635 MIPS32_BNE(8, 0, NEG16(3)), /* bne $8, $0, synci_loop */
636 MIPS32_ADDU(9, 9, 11), /* $9 += MIPS32_SYNCI_STEP */
639 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
640 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
641 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
642 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
643 MIPS32_B(NEG16(24)), /* b start */
644 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
647 /* TODO remove array */
648 uint32_t *param_in
= malloc(2 * sizeof(uint32_t));
650 param_in
[0] = start_addr
;
651 param_in
[1] = end_addr
;
653 retval
= mips32_pracc_exec(ejtag_info
, ARRAY_SIZE(code
), code
, 2, param_in
, 0, NULL
, 1);
661 * \b mips32_pracc_clean_invalidate_cache
663 * Writeback D$ and Invalidate I$
664 * so that the instructions written can be visible to CPU
666 static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag
*ejtag_info
,
667 uint32_t start_addr
, uint32_t end_addr
)
669 static const uint32_t code
[] = {
671 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
672 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK
)), /* $15 = MIPS32_PRACC_STACK */
673 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK
)),
674 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
675 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
676 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
677 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
679 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN
)), /* $8 = MIPS32_PRACC_PARAM_IN */
680 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN
)),
681 MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */
682 MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */
683 MIPS32_LW(11, 8, 8), /* Load write clsiz to $11 */
686 MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 : $8 <- $10 < $9 ? */
687 MIPS32_BGTZ(8, 6), /* bgtz $8, end */
690 MIPS32_CACHE(MIPS32_CACHE_D_HIT_WRITEBACK
, 0, 9), /* cache Hit_Writeback_D, 0($9) */
691 MIPS32_CACHE(MIPS32_CACHE_I_HIT_INVALIDATE
, 0, 9), /* cache Hit_Invalidate_I, 0($9) */
693 MIPS32_ADDU(9, 9, 11), /* $9 += $11 */
695 MIPS32_B(NEG16(7)), /* b cache_loop */
698 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
699 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
700 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
701 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
702 MIPS32_B(NEG16(25)), /* b start */
703 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
707 * Find cache line size in bytes
712 mips32_cp0_read(ejtag_info
, &conf
, 16, 1);
713 dl
= (conf
& MIPS32_CONFIG1_DL_MASK
) >> MIPS32_CONFIG1_DL_SHIFT
;
715 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... */
718 /* TODO remove array */
719 uint32_t *param_in
= malloc(3 * sizeof(uint32_t));
721 param_in
[0] = start_addr
;
722 param_in
[1] = end_addr
;
725 retval
= mips32_pracc_exec(ejtag_info
, ARRAY_SIZE(code
), code
, 3, param_in
, 0, NULL
, 1);
732 static int mips32_pracc_write_mem_generic(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, void *buf
)
734 struct pracc_queue_info ctx
= {.max_code
= 128 * 3 + 6 + 1}; /* alloc memory for the worst case */
735 pracc_queue_init(&ctx
);
736 if (ctx
.retval
!= ERROR_OK
)
739 uint32_t *buf32
= buf
;
740 uint16_t *buf16
= buf
;
746 int this_round_count
= (count
> 128) ? 128 : count
;
747 uint32_t last_upper_base_addr
= UPPER16((addr
+ 0x8000));
749 pracc_add(&ctx
, 0, MIPS32_MTC0(15, 31, 0)); /* save $15 in DeSave */
750 pracc_add(&ctx
, 0, MIPS32_LUI(15, last_upper_base_addr
)); /* load $15 with memory base address */
752 for (int i
= 0; i
!= this_round_count
; i
++) {
753 uint32_t upper_base_addr
= UPPER16((addr
+ 0x8000));
754 if (last_upper_base_addr
!= upper_base_addr
) {
755 pracc_add(&ctx
, 0, MIPS32_LUI(15, upper_base_addr
)); /* if needed, change upper address in $15*/
756 last_upper_base_addr
= upper_base_addr
;
759 if (size
== 4) { /* for word writes check if one half word is 0 and load it accordingly */
760 if (LOWER16(*buf32
) == 0)
761 pracc_add(&ctx
, 0, MIPS32_LUI(8, UPPER16(*buf32
))); /* load only upper value */
762 else if (UPPER16(*buf32
) == 0)
763 pracc_add(&ctx
, 0, MIPS32_ORI(8, 0, LOWER16(*buf32
))); /* load only lower */
765 pracc_add(&ctx
, 0, MIPS32_LUI(8, UPPER16(*buf32
))); /* load upper and lower */
766 pracc_add(&ctx
, 0, MIPS32_ORI(8, 8, LOWER16(*buf32
)));
768 pracc_add(&ctx
, 0, MIPS32_SW(8, LOWER16(addr
), 15)); /* store word to memory */
771 } else if (size
== 2) {
772 pracc_add(&ctx
, 0, MIPS32_ORI(8, 0, *buf16
)); /* load lower value */
773 pracc_add(&ctx
, 0, MIPS32_SH(8, LOWER16(addr
), 15)); /* store half word to memory */
777 pracc_add(&ctx
, 0, MIPS32_ORI(8, 0, *buf8
)); /* load lower value */
778 pracc_add(&ctx
, 0, MIPS32_SB(8, LOWER16(addr
), 15)); /* store byte to memory */
784 pracc_add(&ctx
, 0, MIPS32_LUI(8, UPPER16(ejtag_info
->reg8
))); /* restore upper 16 bits of reg 8 */
785 pracc_add(&ctx
, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info
->reg8
))); /* restore lower 16 bits of reg 8 */
787 pracc_add(&ctx
, 0, MIPS32_B(NEG16(ctx
.code_count
+ 1))); /* jump to start */
788 pracc_add(&ctx
, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */
790 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
);
791 if (ctx
.retval
!= ERROR_OK
)
793 count
-= this_round_count
;
796 pracc_queue_free(&ctx
);
800 int mips32_pracc_write_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, void *buf
)
802 int retval
= mips32_pracc_write_mem_generic(ejtag_info
, addr
, size
, count
, buf
);
803 if (retval
!= ERROR_OK
)
807 * If we are in the cachable regoion and cache is activated,
808 * we must clean D$ + invalidate I$ after we did the write,
809 * so that changes do not continue to live only in D$, but to be
810 * replicated in I$ also (maybe we wrote the istructions)
815 if ((KSEGX(addr
) == KSEG1
) || ((addr
>= 0xff200000) && (addr
<= 0xff3fffff)))
816 return retval
; /*Nothing to do*/
818 mips32_cp0_read(ejtag_info
, &conf
, 16, 0);
820 switch (KSEGX(addr
)) {
822 cached
= (conf
& MIPS32_CONFIG0_KU_MASK
) >> MIPS32_CONFIG0_KU_SHIFT
;
825 cached
= (conf
& MIPS32_CONFIG0_K0_MASK
) >> MIPS32_CONFIG0_K0_SHIFT
;
829 cached
= (conf
& MIPS32_CONFIG0_K23_MASK
) >> MIPS32_CONFIG0_K23_SHIFT
;
837 * Check cachablitiy bits coherency algorithm -
838 * is the region cacheable or uncached.
839 * If cacheable we have to synchronize the cache
842 uint32_t start_addr
, end_addr
;
846 end_addr
= addr
+ count
* size
;
848 /** select cache synchronisation mechanism based on Architecture Release */
849 rel
= (conf
& MIPS32_CONFIG0_AR_MASK
) >> MIPS32_CONFIG0_AR_SHIFT
;
851 case MIPS32_ARCH_REL1
:
852 /* MIPS32/64 Release 1 - we must use cache instruction */
853 mips32_pracc_clean_invalidate_cache(ejtag_info
, start_addr
, end_addr
);
855 case MIPS32_ARCH_REL2
:
856 /* MIPS32/64 Release 2 - we can use synci instruction */
857 mips32_pracc_sync_cache(ejtag_info
, start_addr
, end_addr
);
868 int mips32_pracc_write_regs(struct mips_ejtag
*ejtag_info
, uint32_t *regs
)
870 static const uint32_t cp0_write_code
[] = {
871 MIPS32_MTC0(1, 12, 0), /* move $1 to status */
872 MIPS32_MTLO(1), /* move $1 to lo */
873 MIPS32_MTHI(1), /* move $1 to hi */
874 MIPS32_MTC0(1, 8, 0), /* move $1 to badvaddr */
875 MIPS32_MTC0(1, 13, 0), /* move $1 to cause*/
876 MIPS32_MTC0(1, 24, 0), /* move $1 to depc (pc) */
879 struct pracc_queue_info ctx
= {.max_code
= 37 * 2 + 6 + 1};
880 pracc_queue_init(&ctx
);
881 if (ctx
.retval
!= ERROR_OK
)
884 /* load registers 2 to 31 with lui and ori instructions, check if some instructions can be saved */
885 for (int i
= 2; i
< 32; i
++) {
886 if (LOWER16((regs
[i
])) == 0) /* if lower half word is 0, lui instruction only */
887 pracc_add(&ctx
, 0, MIPS32_LUI(i
, UPPER16((regs
[i
]))));
888 else if (UPPER16((regs
[i
])) == 0) /* if upper half word is 0, ori with $0 only*/
889 pracc_add(&ctx
, 0, MIPS32_ORI(i
, 0, LOWER16((regs
[i
]))));
890 else { /* default, load with lui and ori instructions */
891 pracc_add(&ctx
, 0, MIPS32_LUI(i
, UPPER16((regs
[i
]))));
892 pracc_add(&ctx
, 0, MIPS32_ORI(i
, i
, LOWER16((regs
[i
]))));
896 for (int i
= 0; i
!= 6; i
++) {
897 pracc_add(&ctx
, 0, MIPS32_LUI(1, UPPER16((regs
[i
+ 32])))); /* load CPO value in $1, with lui and ori */
898 pracc_add(&ctx
, 0, MIPS32_ORI(1, 1, LOWER16((regs
[i
+ 32]))));
899 pracc_add(&ctx
, 0, cp0_write_code
[i
]); /* write value from $1 to CPO register */
902 pracc_add(&ctx
, 0, MIPS32_LUI(1, UPPER16((regs
[1])))); /* load upper half word in $1 */
903 pracc_add(&ctx
, 0, MIPS32_B(NEG16(ctx
.code_count
+ 1))); /* jump to start */
904 pracc_add(&ctx
, 0, MIPS32_ORI(1, 1, LOWER16((regs
[1])))); /* load lower half word in $1 */
906 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
);
908 ejtag_info
->reg8
= regs
[8];
909 ejtag_info
->reg9
= regs
[9];
911 pracc_queue_free(&ctx
);
915 int mips32_pracc_read_regs(struct mips_ejtag
*ejtag_info
, uint32_t *regs
)
917 static int cp0_read_code
[] = {
918 MIPS32_MFC0(8, 12, 0), /* move status to $8 */
919 MIPS32_MFLO(8), /* move lo to $8 */
920 MIPS32_MFHI(8), /* move hi to $8 */
921 MIPS32_MFC0(8, 8, 0), /* move badvaddr to $8 */
922 MIPS32_MFC0(8, 13, 0), /* move cause to $8 */
923 MIPS32_MFC0(8, 24, 0), /* move depc (pc) to $8 */
926 struct pracc_queue_info ctx
= {.max_code
= 48};
927 pracc_queue_init(&ctx
);
928 if (ctx
.retval
!= ERROR_OK
)
931 pracc_add(&ctx
, 0, MIPS32_MTC0(1, 31, 0)); /* move $1 to COP0 DeSave */
932 pracc_add(&ctx
, 0, MIPS32_LUI(1, PRACC_UPPER_BASE_ADDR
)); /* $1 = MIP32_PRACC_BASE_ADDR */
934 for (int i
= 2; i
!= 32; i
++) /* store GPR's 2 to 31 */
935 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ (i
* 4),
936 MIPS32_SW(i
, PRACC_OUT_OFFSET
+ (i
* 4), 1));
938 for (int i
= 0; i
!= 6; i
++) {
939 pracc_add(&ctx
, 0, cp0_read_code
[i
]); /* load COP0 needed registers to $8 */
940 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ (i
+ 32) * 4, /* store $8 at PARAM OUT */
941 MIPS32_SW(8, PRACC_OUT_OFFSET
+ (i
+ 32) * 4, 1));
943 pracc_add(&ctx
, 0, MIPS32_MFC0(8, 31, 0)); /* move DeSave to $8, reg1 value */
944 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ 4, /* store reg1 value from $8 to param out */
945 MIPS32_SW(8, PRACC_OUT_OFFSET
+ 4, 1));
947 pracc_add(&ctx
, 0, MIPS32_B(NEG16(ctx
.code_count
+ 1))); /* jump to start */
948 pracc_add(&ctx
, 0, MIPS32_MFC0(1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */
950 if (ejtag_info
->mode
== 0)
951 ctx
.store_count
++; /* Needed by legacy code, due to offset from reg0 */
953 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, regs
);
955 ejtag_info
->reg8
= regs
[8]; /* reg8 is saved but not restored, next called function should restore it */
956 ejtag_info
->reg9
= regs
[9];
958 pracc_queue_free(&ctx
);
962 /* fastdata upload/download requires an initialized working area
963 * to load the download code; it should not be called otherwise
964 * fetch order from the fastdata area
969 int mips32_pracc_fastdata_xfer(struct mips_ejtag
*ejtag_info
, struct working_area
*source
,
970 int write_t
, uint32_t addr
, int count
, uint32_t *buf
)
972 uint32_t handler_code
[] = {
973 /* caution when editing, table is modified below */
974 /* r15 points to the start of this code */
975 MIPS32_SW(8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
976 MIPS32_SW(9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
977 MIPS32_SW(10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
978 MIPS32_SW(11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
979 /* start of fastdata area in t0 */
980 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_FASTDATA_AREA
)),
981 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA
)),
982 MIPS32_LW(9, 0, 8), /* start addr in t1 */
983 MIPS32_LW(10, 0, 8), /* end addr to t2 */
985 /* 8 */ MIPS32_LW(11, 0, 0), /* lw t3,[t8 | r9] */
986 /* 9 */ MIPS32_SW(11, 0, 0), /* sw t3,[r9 | r8] */
987 MIPS32_BNE(10, 9, NEG16(3)), /* bne $t2,t1,loop */
988 MIPS32_ADDI(9, 9, 4), /* addi t1,t1,4 */
990 MIPS32_LW(8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
991 MIPS32_LW(9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
992 MIPS32_LW(10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
993 MIPS32_LW(11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
995 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_TEXT
)),
996 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_TEXT
)),
997 MIPS32_JR(15), /* jr start */
998 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
1001 uint32_t jmp_code
[] = {
1002 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
1003 /* 1 */ MIPS32_LUI(15, 0), /* addr of working area added below */
1004 /* 2 */ MIPS32_ORI(15, 15, 0), /* addr of working area added below */
1005 MIPS32_JR(15), /* jump to ram program */
1010 uint32_t val
, ejtag_ctrl
, address
;
1012 if (source
->size
< MIPS32_FASTDATA_HANDLER_SIZE
)
1013 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1016 handler_code
[8] = MIPS32_LW(11, 0, 8); /* load data from probe at fastdata area */
1017 handler_code
[9] = MIPS32_SW(11, 0, 9); /* store data to RAM @ r9 */
1019 handler_code
[8] = MIPS32_LW(11, 0, 9); /* load data from RAM @ r9 */
1020 handler_code
[9] = MIPS32_SW(11, 0, 8); /* store data to probe at fastdata area */
1023 /* write program into RAM */
1024 if (write_t
!= ejtag_info
->fast_access_save
) {
1025 mips32_pracc_write_mem_generic(ejtag_info
, source
->address
, 4, ARRAY_SIZE(handler_code
), handler_code
);
1026 /* save previous operation to speed to any consecutive read/writes */
1027 ejtag_info
->fast_access_save
= write_t
;
1030 LOG_DEBUG("%s using 0x%.8" PRIx32
" for write handler", __func__
, source
->address
);
1032 jmp_code
[1] |= UPPER16(source
->address
);
1033 jmp_code
[2] |= LOWER16(source
->address
);
1035 for (i
= 0; i
< (int) ARRAY_SIZE(jmp_code
); i
++) {
1036 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
1037 if (retval
!= ERROR_OK
)
1040 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
1041 mips_ejtag_drscan_32_out(ejtag_info
, jmp_code
[i
]);
1043 /* Clear the access pending bit (let the processor eat!) */
1044 ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
1045 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_CONTROL
);
1046 mips_ejtag_drscan_32_out(ejtag_info
, ejtag_ctrl
);
1049 /* wait PrAcc pending bit for FASTDATA write */
1050 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
1051 if (retval
!= ERROR_OK
)
1054 /* next fetch to dmseg should be in FASTDATA_AREA, check */
1056 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ADDRESS
);
1057 retval
= mips_ejtag_drscan_32(ejtag_info
, &address
);
1058 if (retval
!= ERROR_OK
)
1061 if (address
!= MIPS32_PRACC_FASTDATA_AREA
)
1064 /* Send the load start address */
1066 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1067 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1069 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
1070 if (retval
!= ERROR_OK
)
1073 /* Send the load end address */
1074 val
= addr
+ (count
- 1) * 4;
1075 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1076 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1078 unsigned num_clocks
= 0; /* like in legacy code */
1079 if (ejtag_info
->mode
!= 0)
1080 num_clocks
= ((uint64_t)(ejtag_info
->scan_delay
) * jtag_get_speed_khz() + 500000) / 1000000;
1082 for (i
= 0; i
< count
; i
++) {
1083 jtag_add_clocks(num_clocks
);
1084 retval
= mips_ejtag_fastdata_scan(ejtag_info
, write_t
, buf
++);
1085 if (retval
!= ERROR_OK
)
1089 retval
= jtag_execute_queue();
1090 if (retval
!= ERROR_OK
) {
1091 LOG_ERROR("fastdata load failed");
1095 retval
= wait_for_pracc_rw(ejtag_info
, &ejtag_ctrl
);
1096 if (retval
!= ERROR_OK
)
1100 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ADDRESS
);
1101 retval
= mips_ejtag_drscan_32(ejtag_info
, &address
);
1102 if (retval
!= ERROR_OK
)
1105 if (address
!= MIPS32_PRACC_TEXT
)
1106 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)