1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2008 by Spencer Oliver *
5 * spen@spen-soft.co.uk *
7 * Copyright (C) 2008 by David T.L. Wong *
9 * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> *
11 * Copyright (C) 2011 by Drasko DRASKOVIC *
12 * drasko.draskovic@gmail.com *
13 ***************************************************************************/
16 * This version has optimized assembly routines for 32 bit operations:
19 * - write array of words
21 * One thing to be aware of is that the MIPS32 cpu will execute the
22 * instruction after a branch instruction (one delay slot).
29 * The LW $1, ($2 +100) instruction is also executed. If this is
30 * not wanted a NOP can be inserted:
37 * or the code can be changed to:
43 * The original code contained NOPs. I have removed these and moved
46 * These changes result in a 35% speed increase when programming an
49 * More improvement could be gained if the registers do no need
50 * to be preserved but in that case the routines should be aware
51 * OpenOCD is used as a flash programmer or as a debug tool.
60 #include <helper/align.h>
61 #include <helper/time_support.h>
62 #include <jtag/adapter.h>
65 #include "mips32_pracc.h"
67 static int wait_for_pracc_rw(struct mips_ejtag
*ejtag_info
)
69 int64_t then
= timeval_ms();
71 /* wait for the PrAcc to become "1" */
72 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_CONTROL
);
75 ejtag_info
->pa_ctrl
= ejtag_info
->ejtag_ctrl
;
76 int retval
= mips_ejtag_drscan_32(ejtag_info
, &ejtag_info
->pa_ctrl
);
77 if (retval
!= ERROR_OK
)
80 if (ejtag_info
->pa_ctrl
& EJTAG_CTRL_PRACC
)
83 int64_t timeout
= timeval_ms() - then
;
85 LOG_DEBUG("DEBUGMODULE: No memory access in progress!");
86 return ERROR_JTAG_DEVICE_ERROR
;
93 /* Shift in control and address for a new processor access, save them in ejtag_info */
94 static int mips32_pracc_read_ctrl_addr(struct mips_ejtag
*ejtag_info
)
96 int retval
= wait_for_pracc_rw(ejtag_info
);
97 if (retval
!= ERROR_OK
)
100 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ADDRESS
);
102 ejtag_info
->pa_addr
= 0;
103 return mips_ejtag_drscan_32(ejtag_info
, &ejtag_info
->pa_addr
);
106 /* Finish processor access */
107 static void mips32_pracc_finish(struct mips_ejtag
*ejtag_info
)
109 uint32_t ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
110 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_CONTROL
);
111 mips_ejtag_drscan_32_out(ejtag_info
, ctrl
);
114 static int mips32_pracc_clean_text_jump(struct mips_ejtag
*ejtag_info
)
116 uint32_t jt_code
= MIPS32_J(ejtag_info
->isa
, MIPS32_PRACC_TEXT
);
117 pracc_swap16_array(ejtag_info
, &jt_code
, 1);
118 /* do 3 0/nops to clean pipeline before a jump to pracc text, NOP in delay slot */
119 for (int i
= 0; i
!= 5; i
++) {
121 int retval
= wait_for_pracc_rw(ejtag_info
);
122 if (retval
!= ERROR_OK
)
125 /* Data or instruction out */
126 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
127 uint32_t data
= (i
== 3) ? jt_code
: MIPS32_NOP
;
128 mips_ejtag_drscan_32_out(ejtag_info
, data
);
131 mips32_pracc_finish(ejtag_info
);
134 if (ejtag_info
->mode
!= 0) /* async mode support only for MIPS ... */
137 for (int i
= 0; i
!= 2; i
++) {
138 int retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
139 if (retval
!= ERROR_OK
)
142 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_TEXT
) { /* LEXRA/BMIPS ?, shift out another NOP, max 2 */
143 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
144 mips_ejtag_drscan_32_out(ejtag_info
, MIPS32_NOP
);
145 mips32_pracc_finish(ejtag_info
);
153 static int mips32_pracc_exec(struct mips_ejtag
*ejtag_info
, struct pracc_queue_info
*ctx
,
154 uint32_t *param_out
, bool check_last
)
157 int store_pending
= 0; /* increases with every store instr at dmseg, decreases with every store pa */
158 uint32_t max_store_addr
= 0; /* for store pa address testing */
159 bool restart
= 0; /* restarting control */
160 int restart_count
= 0;
162 bool final_check
= 0; /* set to 1 if in final checks after function code shifted out */
163 bool pass
= 0; /* to check the pass through pracc text after function code sent */
168 if (restart_count
< 3) { /* max 3 restarts allowed */
169 retval
= mips32_pracc_clean_text_jump(ejtag_info
);
170 if (retval
!= ERROR_OK
)
173 return ERROR_JTAG_DEVICE_ERROR
;
177 LOG_DEBUG("restarting code");
180 retval
= mips32_pracc_read_ctrl_addr(ejtag_info
); /* update current pa info: control and address */
181 if (retval
!= ERROR_OK
)
184 /* Check for read or write access */
185 if (ejtag_info
->pa_ctrl
& EJTAG_CTRL_PRNW
) { /* write/store access */
186 /* Check for pending store from a previous store instruction at dmseg */
187 if (store_pending
== 0) {
188 LOG_DEBUG("unexpected write at address %" PRIx32
, ejtag_info
->pa_addr
);
189 if (code_count
< 2) { /* allow for restart */
193 return ERROR_JTAG_DEVICE_ERROR
;
196 if (ejtag_info
->pa_addr
< MIPS32_PRACC_PARAM_OUT
||
197 ejtag_info
->pa_addr
> max_store_addr
) {
198 LOG_DEBUG("writing at unexpected address %" PRIx32
, ejtag_info
->pa_addr
);
199 return ERROR_JTAG_DEVICE_ERROR
;
204 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
205 retval
= mips_ejtag_drscan_32(ejtag_info
, &data
);
206 if (retval
!= ERROR_OK
)
209 /* store data at param out, address based offset */
210 param_out
[(ejtag_info
->pa_addr
- MIPS32_PRACC_PARAM_OUT
) / 4] = data
;
213 } else { /* read/fetch access */
214 if (!final_check
) { /* executing function code */
216 if (ejtag_info
->pa_addr
!= (MIPS32_PRACC_TEXT
+ code_count
* 4)) {
217 LOG_DEBUG("reading at unexpected address %" PRIx32
", expected %x",
218 ejtag_info
->pa_addr
, MIPS32_PRACC_TEXT
+ code_count
* 4);
220 /* restart code execution only in some cases */
221 if (code_count
== 1 && ejtag_info
->pa_addr
== MIPS32_PRACC_TEXT
&&
222 restart_count
== 0) {
223 LOG_DEBUG("restarting, without clean jump");
227 } else if (code_count
< 2) {
231 return ERROR_JTAG_DEVICE_ERROR
;
233 /* check for store instruction at dmseg */
234 uint32_t store_addr
= ctx
->pracc_list
[code_count
].addr
;
235 if (store_addr
!= 0) {
236 if (store_addr
> max_store_addr
)
237 max_store_addr
= store_addr
;
241 instr
= ctx
->pracc_list
[code_count
++].instr
;
242 if (code_count
== ctx
->code_count
) /* last instruction, start final check */
245 } else { /* final check after function code shifted out */
247 if (ejtag_info
->pa_addr
== MIPS32_PRACC_TEXT
) {
248 if (!pass
) { /* first pass through pracc text */
249 if (store_pending
== 0) /* done, normal exit */
251 pass
= 1; /* pracc text passed */
252 code_count
= 0; /* restart code count */
254 LOG_DEBUG("unexpected second pass through pracc text");
255 return ERROR_JTAG_DEVICE_ERROR
;
258 if (ejtag_info
->pa_addr
!= (MIPS32_PRACC_TEXT
+ code_count
* 4)) {
259 LOG_DEBUG("unexpected read address in final check: %"
260 PRIx32
", expected: %x", ejtag_info
->pa_addr
,
261 MIPS32_PRACC_TEXT
+ code_count
* 4);
262 return ERROR_JTAG_DEVICE_ERROR
;
266 if ((code_count
- ctx
->code_count
) > 1) { /* allow max 2 instr delay slot */
267 LOG_DEBUG("failed to jump back to pracc text");
268 return ERROR_JTAG_DEVICE_ERROR
;
271 if (code_count
> 10) { /* enough, abandon */
272 LOG_DEBUG("execution abandoned, store pending: %d", store_pending
);
273 return ERROR_JTAG_DEVICE_ERROR
;
275 instr
= MIPS32_NOP
; /* shift out NOPs instructions */
279 /* Send instruction out */
280 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
281 mips_ejtag_drscan_32_out(ejtag_info
, instr
);
283 /* finish processor access, let the processor eat! */
284 mips32_pracc_finish(ejtag_info
);
286 if (final_check
&& !check_last
) /* last instr, don't check, execute and exit */
287 return jtag_execute_queue();
289 if (store_pending
== 0 && pass
) { /* store access done, but after passing pracc text */
290 LOG_DEBUG("warning: store access pass pracc text");
296 inline void pracc_queue_init(struct pracc_queue_info
*ctx
)
298 ctx
->retval
= ERROR_OK
;
300 ctx
->store_count
= 0;
302 ctx
->pracc_list
= NULL
;
303 ctx
->isa
= ctx
->ejtag_info
->isa
? 1 : 0;
306 void pracc_add(struct pracc_queue_info
*ctx
, uint32_t addr
, uint32_t instr
)
308 if (ctx
->retval
!= ERROR_OK
) /* On previous out of memory, return */
310 if (ctx
->code_count
== ctx
->max_code
) {
311 void *p
= realloc(ctx
->pracc_list
, sizeof(struct pa_list
) * (ctx
->max_code
+ PRACC_BLOCK
));
313 ctx
->max_code
+= PRACC_BLOCK
;
316 ctx
->retval
= ERROR_FAIL
; /* Out of memory */
320 ctx
->pracc_list
[ctx
->code_count
].instr
= instr
;
321 ctx
->pracc_list
[ctx
->code_count
++].addr
= addr
;
326 static void pracc_add_li32(struct pracc_queue_info
*ctx
, uint32_t reg_num
, uint32_t data
, bool optimize
)
328 if (LOWER16(data
) == 0 && optimize
)
329 pracc_add(ctx
, 0, MIPS32_LUI(ctx
->isa
, reg_num
, UPPER16(data
))); /* load only upper value */
330 else if (UPPER16(data
) == 0 && optimize
)
331 pracc_add(ctx
, 0, MIPS32_ORI(ctx
->isa
, reg_num
, 0, LOWER16(data
))); /* load only lower */
333 pracc_add(ctx
, 0, MIPS32_LUI(ctx
->isa
, reg_num
, UPPER16(data
))); /* load upper and lower */
334 pracc_add(ctx
, 0, MIPS32_ORI(ctx
->isa
, reg_num
, reg_num
, LOWER16(data
)));
338 inline void pracc_queue_free(struct pracc_queue_info
*ctx
)
340 free(ctx
->pracc_list
);
343 int mips32_pracc_queue_exec(struct mips_ejtag
*ejtag_info
, struct pracc_queue_info
*ctx
,
344 uint32_t *buf
, bool check_last
)
346 if (ctx
->retval
!= ERROR_OK
) {
347 LOG_ERROR("Out of memory");
351 if (ejtag_info
->isa
&& ejtag_info
->endianness
)
352 for (int i
= 0; i
!= ctx
->code_count
; i
++)
353 ctx
->pracc_list
[i
].instr
= SWAP16(ctx
->pracc_list
[i
].instr
);
355 if (ejtag_info
->mode
== 0)
356 return mips32_pracc_exec(ejtag_info
, ctx
, buf
, check_last
);
366 } *scan_in
= malloc(sizeof(union scan_in
) * (ctx
->code_count
+ ctx
->store_count
));
368 LOG_ERROR("Out of memory");
372 unsigned num_clocks
=
373 ((uint64_t)(ejtag_info
->scan_delay
) * adapter_get_speed_khz() + 500000) / 1000000;
375 uint32_t ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
376 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ALL
);
379 for (int i
= 0; i
!= ctx
->code_count
; i
++) {
380 jtag_add_clocks(num_clocks
);
381 mips_ejtag_add_scan_96(ejtag_info
, ejtag_ctrl
, ctx
->pracc_list
[i
].instr
,
382 scan_in
[scan_count
++].scan_96
);
384 /* Check store address from previous instruction, if not the first */
385 if (i
> 0 && ctx
->pracc_list
[i
- 1].addr
) {
386 jtag_add_clocks(num_clocks
);
387 mips_ejtag_add_scan_96(ejtag_info
, ejtag_ctrl
, 0, scan_in
[scan_count
++].scan_96
);
391 int retval
= jtag_execute_queue(); /* execute queued scans */
392 if (retval
!= ERROR_OK
)
395 uint32_t fetch_addr
= MIPS32_PRACC_TEXT
; /* start address */
397 for (int i
= 0; i
!= ctx
->code_count
; i
++) { /* verify every pracc access */
398 /* check pracc bit */
399 ejtag_ctrl
= buf_get_u32(scan_in
[scan_count
].scan_32
.ctrl
, 0, 32);
400 uint32_t addr
= buf_get_u32(scan_in
[scan_count
].scan_32
.addr
, 0, 32);
401 if (!(ejtag_ctrl
& EJTAG_CTRL_PRACC
)) {
402 LOG_ERROR("Error: access not pending count: %d", scan_count
);
406 if (ejtag_ctrl
& EJTAG_CTRL_PRNW
) {
407 LOG_ERROR("Not a fetch/read access, count: %d", scan_count
);
411 if (addr
!= fetch_addr
) {
412 LOG_ERROR("Fetch addr mismatch, read: %" PRIx32
" expected: %" PRIx32
" count: %d",
413 addr
, fetch_addr
, scan_count
);
420 /* check if previous instruction is a store instruction at dmesg */
421 if (i
> 0 && ctx
->pracc_list
[i
- 1].addr
) {
422 uint32_t store_addr
= ctx
->pracc_list
[i
- 1].addr
;
423 ejtag_ctrl
= buf_get_u32(scan_in
[scan_count
].scan_32
.ctrl
, 0, 32);
424 addr
= buf_get_u32(scan_in
[scan_count
].scan_32
.addr
, 0, 32);
426 if (!(ejtag_ctrl
& EJTAG_CTRL_PRNW
)) {
427 LOG_ERROR("Not a store/write access, count: %d", scan_count
);
431 if (addr
!= store_addr
) {
432 LOG_ERROR("Store address mismatch, read: %" PRIx32
" expected: %" PRIx32
" count: %d",
433 addr
, store_addr
, scan_count
);
437 int buf_index
= (addr
- MIPS32_PRACC_PARAM_OUT
) / 4;
438 buf
[buf_index
] = buf_get_u32(scan_in
[scan_count
].scan_32
.data
, 0, 32);
447 static int mips32_pracc_read_u32(struct mips_ejtag
*ejtag_info
, uint32_t addr
, uint32_t *buf
)
449 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
450 pracc_queue_init(&ctx
);
452 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
453 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 8, UPPER16((addr
+ 0x8000)))); /* load $8 with modified upper addr */
454 pracc_add(&ctx
, 0, MIPS32_LW(ctx
.isa
, 8, LOWER16(addr
), 8)); /* lw $8, LOWER16(addr)($8) */
455 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
456 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */
457 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
458 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
459 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* move COP0 DeSave to $15 */
461 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, buf
, 1);
462 pracc_queue_free(&ctx
);
466 int mips32_pracc_read_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, void *buf
)
468 if (count
== 1 && size
== 4)
469 return mips32_pracc_read_u32(ejtag_info
, addr
, (uint32_t *)buf
);
471 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
472 pracc_queue_init(&ctx
);
474 uint32_t *data
= NULL
;
476 data
= malloc(256 * sizeof(uint32_t));
478 LOG_ERROR("Out of memory");
483 uint32_t *buf32
= buf
;
484 uint16_t *buf16
= buf
;
491 int this_round_count
= (count
> 256) ? 256 : count
;
492 uint32_t last_upper_base_addr
= UPPER16((addr
+ 0x8000));
494 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
495 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 9, last_upper_base_addr
)); /* upper memory addr to $9 */
497 for (int i
= 0; i
!= this_round_count
; i
++) { /* Main code loop */
498 uint32_t upper_base_addr
= UPPER16((addr
+ 0x8000));
499 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper addr in $9 */
500 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 9, upper_base_addr
));
501 last_upper_base_addr
= upper_base_addr
;
504 if (size
== 4) /* load from memory to $8 */
505 pracc_add(&ctx
, 0, MIPS32_LW(ctx
.isa
, 8, LOWER16(addr
), 9));
507 pracc_add(&ctx
, 0, MIPS32_LHU(ctx
.isa
, 8, LOWER16(addr
), 9));
509 pracc_add(&ctx
, 0, MIPS32_LBU(ctx
.isa
, 8, LOWER16(addr
), 9));
511 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ i
* 4, /* store $8 at param out */
512 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
+ i
* 4, 15));
515 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
516 pracc_add_li32(&ctx
, 9, ejtag_info
->reg9
, 0); /* restore $9 */
518 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
519 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
522 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, buf32
, 1);
523 if (ctx
.retval
!= ERROR_OK
)
525 buf32
+= this_round_count
;
527 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, data
, 1);
528 if (ctx
.retval
!= ERROR_OK
)
531 uint32_t *data_p
= data
;
532 for (int i
= 0; i
!= this_round_count
; i
++) {
534 *buf16
++ = *data_p
++;
539 count
-= this_round_count
;
542 pracc_queue_free(&ctx
);
547 int mips32_cp0_read(struct mips_ejtag
*ejtag_info
, uint32_t *val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
549 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
550 pracc_queue_init(&ctx
);
552 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
553 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 8, cp0_reg
, cp0_sel
)); /* move cp0 reg / sel to $8 */
554 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
555 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* store $8 to pracc_out */
556 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
557 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 8, UPPER16(ejtag_info
->reg8
))); /* restore upper 16 bits of $8 */
558 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
559 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 8, LOWER16(ejtag_info
->reg8
))); /* restore lower 16 bits of $8 */
561 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, val
, 1);
562 pracc_queue_free(&ctx
);
566 int mips32_cp0_write(struct mips_ejtag
*ejtag_info
, uint32_t val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
568 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
569 pracc_queue_init(&ctx
);
571 pracc_add_li32(&ctx
, 15, val
, 0); /* Load val to $15 */
573 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, cp0_reg
, cp0_sel
)); /* write $15 to cp0 reg / sel */
574 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
575 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
577 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
578 pracc_queue_free(&ctx
);
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 * If the cache coherency attribute (CCA) is set to zero, it's a write through cache, there is no need
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 (if CCA = 3) and an I-cache invalidate.
607 * The line size is obtained with the rdhwr SYNCI_Step in release 2 or from cp0 config 1 register in release 1.
609 static int mips32_pracc_synchronize_cache(struct mips_ejtag
*ejtag_info
,
610 uint32_t start_addr
, uint32_t end_addr
, int cached
, int rel
)
612 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
613 pracc_queue_init(&ctx
);
615 /** Find cache line size in bytes */
617 if (rel
) { /* Release 2 (rel = 1) */
618 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
620 pracc_add(&ctx
, 0, MIPS32_RDHWR(ctx
.isa
, 8, MIPS32_SYNCI_STEP
)); /* load synci_step value to $8 */
622 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
623 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* store $8 to pracc_out */
625 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
627 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
628 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
630 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, &clsiz
, 1);
631 if (ctx
.retval
!= ERROR_OK
)
634 } else { /* Release 1 (rel = 0) */
636 ctx
.retval
= mips32_cp0_read(ejtag_info
, &conf
, 16, 1);
637 if (ctx
.retval
!= ERROR_OK
)
640 uint32_t dl
= (conf
& MIPS32_CONFIG1_DL_MASK
) >> MIPS32_CONFIG1_DL_SHIFT
;
642 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... max dl=6 => 128 bytes cache line size */
649 goto exit
; /* Nothing to do */
651 /* make sure clsiz is power of 2 */
652 if (!IS_PWR_OF_2(clsiz
)) {
653 LOG_DEBUG("clsiz must be power of 2");
654 ctx
.retval
= ERROR_FAIL
;
658 /* make sure start_addr and end_addr have the same offset inside de cache line */
659 start_addr
|= clsiz
- 1;
660 end_addr
|= clsiz
- 1;
666 uint32_t last_upper_base_addr
= UPPER16((start_addr
+ 0x8000));
668 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, last_upper_base_addr
)); /* load upper memory base addr to $15 */
670 while (start_addr
<= end_addr
) { /* main loop */
671 uint32_t upper_base_addr
= UPPER16((start_addr
+ 0x8000));
672 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper addr in $15 */
673 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, upper_base_addr
));
674 last_upper_base_addr
= upper_base_addr
;
676 if (rel
) /* synci instruction, offset($15) */
677 pracc_add(&ctx
, 0, MIPS32_SYNCI(ctx
.isa
, LOWER16(start_addr
), 15));
680 if (cached
== 3) /* cache Hit_Writeback_D, offset($15) */
681 pracc_add(&ctx
, 0, MIPS32_CACHE(ctx
.isa
, MIPS32_CACHE_D_HIT_WRITEBACK
,
682 LOWER16(start_addr
), 15));
683 /* cache Hit_Invalidate_I, offset($15) */
684 pracc_add(&ctx
, 0, MIPS32_CACHE(ctx
.isa
, MIPS32_CACHE_I_HIT_INVALIDATE
,
685 LOWER16(start_addr
), 15));
689 if (count
== 256 && start_addr
<= end_addr
) { /* more ?, then execute code list */
690 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* to start */
691 pracc_add(&ctx
, 0, MIPS32_NOP
); /* nop in delay slot */
693 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
694 if (ctx
.retval
!= ERROR_OK
)
697 ctx
.code_count
= 0; /* reset counters for another loop */
702 pracc_add(&ctx
, 0, MIPS32_SYNC(ctx
.isa
));
703 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
704 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave*/
706 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
708 pracc_queue_free(&ctx
);
712 static int mips32_pracc_write_mem_generic(struct mips_ejtag
*ejtag_info
,
713 uint32_t addr
, int size
, int count
, const void *buf
)
715 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
716 pracc_queue_init(&ctx
);
718 const uint32_t *buf32
= buf
;
719 const uint16_t *buf16
= buf
;
720 const uint8_t *buf8
= buf
;
726 int this_round_count
= (count
> 128) ? 128 : count
;
727 uint32_t last_upper_base_addr
= UPPER16((addr
+ 0x8000));
728 /* load $15 with memory base address */
729 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, last_upper_base_addr
));
731 for (int i
= 0; i
!= this_round_count
; i
++) {
732 uint32_t upper_base_addr
= UPPER16((addr
+ 0x8000));
733 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper address in $15*/
734 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, upper_base_addr
));
735 last_upper_base_addr
= upper_base_addr
;
739 pracc_add_li32(&ctx
, 8, *buf32
, 1); /* load with li32, optimize */
740 pracc_add(&ctx
, 0, MIPS32_SW(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store word to mem */
743 } else if (size
== 2) {
744 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 0, *buf16
)); /* load lower value */
745 pracc_add(&ctx
, 0, MIPS32_SH(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store half word */
749 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 0, *buf8
)); /* load lower value */
750 pracc_add(&ctx
, 0, MIPS32_SB(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store byte */
756 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
758 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
759 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
761 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
762 if (ctx
.retval
!= ERROR_OK
)
764 count
-= this_round_count
;
767 pracc_queue_free(&ctx
);
771 int mips32_pracc_write_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, const void *buf
)
773 int retval
= mips32_pracc_write_mem_generic(ejtag_info
, addr
, size
, count
, buf
);
774 if (retval
!= ERROR_OK
)
778 * If we are in the cacheable region and cache is activated,
779 * we must clean D$ (if Cache Coherency Attribute is set to 3) + invalidate I$ after we did the write,
780 * so that changes do not continue to live only in D$ (if CCA = 3), but to be
781 * replicated in I$ also (maybe we wrote the instructions)
786 if ((KSEGX(addr
) == KSEG1
) || ((addr
>= 0xff200000) && (addr
<= 0xff3fffff)))
787 return retval
; /*Nothing to do*/
789 mips32_cp0_read(ejtag_info
, &conf
, 16, 0);
791 switch (KSEGX(addr
)) {
793 cached
= (conf
& MIPS32_CONFIG0_KU_MASK
) >> MIPS32_CONFIG0_KU_SHIFT
;
796 cached
= (conf
& MIPS32_CONFIG0_K0_MASK
) >> MIPS32_CONFIG0_K0_SHIFT
;
800 cached
= (conf
& MIPS32_CONFIG0_K23_MASK
) >> MIPS32_CONFIG0_K23_SHIFT
;
808 * Check cacheability bits coherency algorithm
809 * is the region cacheable or uncached.
810 * If cacheable we have to synchronize the cache
812 if (cached
== 3 || cached
== 0) { /* Write back cache or write through cache */
813 uint32_t start_addr
= addr
;
814 uint32_t end_addr
= addr
+ count
* size
;
815 uint32_t rel
= (conf
& MIPS32_CONFIG0_AR_MASK
) >> MIPS32_CONFIG0_AR_SHIFT
;
817 LOG_DEBUG("Unknown release in cache code");
820 retval
= mips32_pracc_synchronize_cache(ejtag_info
, start_addr
, end_addr
, cached
, rel
);
826 int mips32_pracc_write_regs(struct mips32_common
*mips32
)
828 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
829 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
830 uint32_t *gprs
= mips32
->core_regs
.gpr
;
831 uint32_t *c0rs
= mips32
->core_regs
.cp0
;
833 pracc_queue_init(&ctx
);
835 uint32_t cp0_write_code
[] = {
836 MIPS32_MTC0(ctx
.isa
, 1, 12, 0), /* move $1 to status */
837 MIPS32_MTLO(ctx
.isa
, 1), /* move $1 to lo */
838 MIPS32_MTHI(ctx
.isa
, 1), /* move $1 to hi */
839 MIPS32_MTC0(ctx
.isa
, 1, 8, 0), /* move $1 to badvaddr */
840 MIPS32_MTC0(ctx
.isa
, 1, 13, 0), /* move $1 to cause*/
841 MIPS32_MTC0(ctx
.isa
, 1, 24, 0), /* move $1 to depc (pc) */
844 uint32_t cp0_write_data
[] = {
859 for (size_t i
= 0; i
< ARRAY_SIZE(cp0_write_code
); i
++) {
860 /* load CP0 value in $1 */
861 pracc_add_li32(&ctx
, 1, cp0_write_data
[i
], 0);
862 /* write value from $1 to CP0 register */
863 pracc_add(&ctx
, 0, cp0_write_code
[i
]);
866 /* load registers 2 to 31 with li32, optimize */
867 for (int i
= 2; i
< 32; i
++)
868 pracc_add_li32(&ctx
, i
, gprs
[i
], 1);
870 /* load $15 in DeSave */
871 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, 31, 0));
872 /* load upper half word in $1 */
873 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 1, UPPER16((gprs
[1]))));
875 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
)));
876 /* load lower half word in $1 */
877 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 1, 1, LOWER16((gprs
[1]))));
879 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
881 ejtag_info
->reg8
= gprs
[8];
882 ejtag_info
->reg9
= gprs
[9];
883 pracc_queue_free(&ctx
);
887 /* Saves content in `$1` to `DeSave(cp0.31.0)` and loads `MIPS32_PRACC_BASE_ADDR` into `$1` */
888 static void mips32_pracc_store_regs_set_base_addr(struct pracc_queue_info
*ctx
)
890 /* move $1 to COP0 DeSave */
891 pracc_add(ctx
, 0, MIPS32_MTC0(ctx
->isa
, 1, 31, 0));
892 /* $1 = MIP32_PRACC_BASE_ADDR */
893 pracc_add(ctx
, 0, MIPS32_LUI(ctx
->isa
, 1, PRACC_UPPER_BASE_ADDR
));
896 /* This function assumes the address for saving is stored in `$1`.
897 * And that action is performed in `mips32_pracc_set_save_base_addr`.
899 static void mips32_pracc_store_regs_gpr(struct pracc_queue_info
*ctx
, unsigned int offset_gpr
)
901 for (int i
= 2; i
!= 32; i
++)
902 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ offset_gpr
+ (i
* 4),
903 MIPS32_SW(ctx
->isa
, i
, PRACC_OUT_OFFSET
+ offset_gpr
+ (i
* 4), 1));
906 static void mips32_pracc_store_regs_lohi(struct pracc_queue_info
*ctx
)
908 uint32_t lohi_read_code
[] = {
909 MIPS32_MFLO(ctx
->isa
, 8), /* move lo to $8 */
910 MIPS32_MFHI(ctx
->isa
, 8), /* move hi to $8 */
914 for (int i
= 0; i
< 2; i
++) {
915 /* load COP0 needed registers to $8 */
916 pracc_add(ctx
, 0, lohi_read_code
[i
]);
917 /* store $8 at PARAM OUT */
918 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ (i
+ 32) * 4,
919 MIPS32_SW(ctx
->isa
, 8, PRACC_OUT_OFFSET
+ (i
+ 32) * 4, 1));
923 /* Saves CP0 registers [status, badvaddr, cause, depc] */
924 static void mips32_pracc_store_regs_cp0_context(struct pracc_queue_info
*ctx
, unsigned int offset_cp0
)
926 uint32_t cp0_read_code
[] = {
927 MIPS32_MFC0(ctx
->isa
, 8, 12, 0), /* move status to $8 */
928 MIPS32_MFC0(ctx
->isa
, 8, 8, 0), /* move badvaddr to $8 */
929 MIPS32_MFC0(ctx
->isa
, 8, 13, 0), /* move cause to $8 */
930 MIPS32_MFC0(ctx
->isa
, 8, 24, 0), /* move depc (pc) to $8 */
934 for (size_t i
= 0; i
< ARRAY_SIZE(cp0_read_code
); i
++) {
935 size_t offset
= offset_cp0
+ (i
* 4);
937 /* load COP0 needed registers to $8 */
938 pracc_add(ctx
, 0, cp0_read_code
[i
]);
939 /* store $8 at PARAM OUT */
940 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ offset
,
941 MIPS32_SW(ctx
->isa
, 8, PRACC_OUT_OFFSET
+ offset
, 1));
945 /* Loads original content of $1 into $8,
946 * then store it to the batch data access address.
947 * Finally it restores $1 from DeSave.
949 static void mips32_pracc_store_regs_restore(struct pracc_queue_info
*ctx
)
951 /* move DeSave to $8, reg1 value */
952 pracc_add(ctx
, 0, MIPS32_MFC0(ctx
->isa
, 8, 31, 0));
953 /* store reg1 value from $8 to param out */
954 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ 4,
955 MIPS32_SW(ctx
->isa
, 8, PRACC_OUT_OFFSET
+ 4, 1));
957 /* move COP0 DeSave to $1, restore reg1 */
958 pracc_add(ctx
, 0, MIPS32_MFC0(ctx
->isa
, 1, 31, 0));
961 /* This function performs following actions:
962 * Saves `$1` to `DeSave`,
963 * then load `PRACC_UPPER_BASE_ADDR` for saving the register data structure into `$1`,
964 * Saves `$2` ~ `$31` to `PRACC_UPPER_BASE_ADDR + offset_gpr`
966 * Saves necessary cp0 registers.
968 static void mips32_pracc_store_regs(struct pracc_queue_info
*ctx
,
969 unsigned int offset_gpr
, unsigned int offset_cp0
)
971 mips32_pracc_store_regs_set_base_addr(ctx
);
972 mips32_pracc_store_regs_gpr(ctx
, offset_gpr
);
973 mips32_pracc_store_regs_lohi(ctx
);
974 mips32_pracc_store_regs_cp0_context(ctx
, offset_cp0
);
975 mips32_pracc_store_regs_restore(ctx
);
978 int mips32_pracc_read_regs(struct mips32_common
*mips32
)
980 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
981 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
982 struct mips32_core_regs
*core_regs
= &mips32
->core_regs
;
983 unsigned int offset_gpr
= ((uint8_t *)&core_regs
->gpr
[0]) - (uint8_t *)core_regs
;
984 unsigned int offset_cp0
= ((uint8_t *)&core_regs
->cp0
[0]) - (uint8_t *)core_regs
;
987 * This procedure has to be in 2 distinctive steps, because we can
988 * only know whether FP is enabled after reading CP0.
990 * Step 1: Read everything except CP1 stuff
991 * Step 2: Read CP1 stuff if FP is implemented
994 pracc_queue_init(&ctx
);
996 mips32_pracc_store_regs(&ctx
, offset_gpr
, offset_cp0
);
999 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
)));
1000 /* load $15 in DeSave */
1001 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, 31, 0));
1003 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, (uint32_t *)&mips32
->core_regs
, 1);
1005 pracc_queue_free(&ctx
);
1007 /* reg8 is saved but not restored, next called function should restore it */
1008 ejtag_info
->reg8
= mips32
->core_regs
.gpr
[8];
1009 ejtag_info
->reg9
= mips32
->core_regs
.gpr
[9];
1011 /* we only care if FP is actually impl'd and if cp1 is enabled */
1012 /* since we already read cp0 in the prev step */
1013 /* now we know what's in cp0.status */
1014 /* TODO: Read FPRs */
1019 /* fastdata upload/download requires an initialized working area
1020 * to load the download code; it should not be called otherwise
1021 * fetch order from the fastdata area
1026 int mips32_pracc_fastdata_xfer(struct mips_ejtag
*ejtag_info
, struct working_area
*source
,
1027 int write_t
, uint32_t addr
, int count
, uint32_t *buf
)
1029 uint32_t isa
= ejtag_info
->isa
? 1 : 0;
1030 uint32_t handler_code
[] = {
1031 /* r15 points to the start of this code */
1032 MIPS32_SW(isa
, 8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
1033 MIPS32_SW(isa
, 9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
1034 MIPS32_SW(isa
, 10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
1035 MIPS32_SW(isa
, 11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
1036 /* start of fastdata area in t0 */
1037 MIPS32_LUI(isa
, 8, UPPER16(MIPS32_PRACC_FASTDATA_AREA
)),
1038 MIPS32_ORI(isa
, 8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA
)),
1039 MIPS32_LW(isa
, 9, 0, 8), /* start addr in t1 */
1040 MIPS32_LW(isa
, 10, 0, 8), /* end addr to t2 */
1042 write_t
? MIPS32_LW(isa
, 11, 0, 8) : MIPS32_LW(isa
, 11, 0, 9), /* from xfer area : from memory */
1043 write_t
? MIPS32_SW(isa
, 11, 0, 9) : MIPS32_SW(isa
, 11, 0, 8), /* to memory : to xfer area */
1045 MIPS32_BNE(isa
, 10, 9, NEG16(3 << isa
)), /* bne $t2,t1,loop */
1046 MIPS32_ADDI(isa
, 9, 9, 4), /* addi t1,t1,4 */
1048 MIPS32_LW(isa
, 8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
1049 MIPS32_LW(isa
, 9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
1050 MIPS32_LW(isa
, 10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
1051 MIPS32_LW(isa
, 11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
1053 MIPS32_LUI(isa
, 15, UPPER16(MIPS32_PRACC_TEXT
)),
1054 MIPS32_ORI(isa
, 15, 15, LOWER16(MIPS32_PRACC_TEXT
) | isa
), /* isa bit for JR instr */
1055 MIPS32_JR(isa
, 15), /* jr start */
1056 MIPS32_MFC0(isa
, 15, 31, 0), /* move COP0 DeSave to $15 */
1059 if (source
->size
< MIPS32_FASTDATA_HANDLER_SIZE
)
1060 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1062 pracc_swap16_array(ejtag_info
, handler_code
, ARRAY_SIZE(handler_code
));
1063 /* write program into RAM */
1064 if (write_t
!= ejtag_info
->fast_access_save
) {
1065 mips32_pracc_write_mem(ejtag_info
, source
->address
, 4, ARRAY_SIZE(handler_code
), handler_code
);
1066 /* save previous operation to speed to any consecutive read/writes */
1067 ejtag_info
->fast_access_save
= write_t
;
1070 LOG_DEBUG("%s using 0x%.8" TARGET_PRIxADDR
" for write handler", __func__
, source
->address
);
1072 uint32_t jmp_code
[] = {
1073 MIPS32_LUI(isa
, 15, UPPER16(source
->address
)), /* load addr of jump in $15 */
1074 MIPS32_ORI(isa
, 15, 15, LOWER16(source
->address
) | isa
), /* isa bit for JR instr */
1075 MIPS32_JR(isa
, 15), /* jump to ram program */
1076 isa
? MIPS32_XORI(isa
, 15, 15, 1) : MIPS32_NOP
, /* drop isa bit, needed for LW/SW instructions */
1079 pracc_swap16_array(ejtag_info
, jmp_code
, ARRAY_SIZE(jmp_code
));
1081 /* execute jump code, with no address check */
1082 for (unsigned i
= 0; i
< ARRAY_SIZE(jmp_code
); i
++) {
1083 int retval
= wait_for_pracc_rw(ejtag_info
);
1084 if (retval
!= ERROR_OK
)
1087 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
1088 mips_ejtag_drscan_32_out(ejtag_info
, jmp_code
[i
]);
1090 /* Clear the access pending bit (let the processor eat!) */
1091 mips32_pracc_finish(ejtag_info
);
1094 /* wait PrAcc pending bit for FASTDATA write, read address */
1095 int retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
1096 if (retval
!= ERROR_OK
)
1099 /* next fetch to dmseg should be in FASTDATA_AREA, check */
1100 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_FASTDATA_AREA
)
1103 /* Send the load start address */
1104 uint32_t val
= addr
;
1105 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1106 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1108 retval
= wait_for_pracc_rw(ejtag_info
);
1109 if (retval
!= ERROR_OK
)
1112 /* Send the load end address */
1113 val
= addr
+ (count
- 1) * 4;
1114 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1115 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1117 unsigned num_clocks
= 0; /* like in legacy code */
1118 if (ejtag_info
->mode
!= 0)
1119 num_clocks
= ((uint64_t)(ejtag_info
->scan_delay
) * adapter_get_speed_khz() + 500000) / 1000000;
1121 for (int i
= 0; i
< count
; i
++) {
1122 jtag_add_clocks(num_clocks
);
1123 mips_ejtag_fastdata_scan(ejtag_info
, write_t
, buf
++);
1126 retval
= jtag_execute_queue();
1127 if (retval
!= ERROR_OK
) {
1128 LOG_ERROR("fastdata load failed");
1132 retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
1133 if (retval
!= ERROR_OK
)
1136 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_TEXT
)
1137 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)