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>
66 #include "mips32_pracc.h"
68 static int wait_for_pracc_rw(struct mips_ejtag
*ejtag_info
)
70 int64_t then
= timeval_ms();
72 /* wait for the PrAcc to become "1" */
73 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_CONTROL
);
76 ejtag_info
->pa_ctrl
= ejtag_info
->ejtag_ctrl
;
77 int retval
= mips_ejtag_drscan_32(ejtag_info
, &ejtag_info
->pa_ctrl
);
78 if (retval
!= ERROR_OK
)
81 if (ejtag_info
->pa_ctrl
& EJTAG_CTRL_PRACC
)
84 int64_t timeout
= timeval_ms() - then
;
86 LOG_DEBUG("DEBUGMODULE: No memory access in progress!");
87 return ERROR_JTAG_DEVICE_ERROR
;
94 /* Shift in control and address for a new processor access, save them in ejtag_info */
95 static int mips32_pracc_read_ctrl_addr(struct mips_ejtag
*ejtag_info
)
97 int retval
= wait_for_pracc_rw(ejtag_info
);
98 if (retval
!= ERROR_OK
)
101 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ADDRESS
);
103 ejtag_info
->pa_addr
= 0;
104 return mips_ejtag_drscan_32(ejtag_info
, &ejtag_info
->pa_addr
);
107 /* Finish processor access */
108 static void mips32_pracc_finish(struct mips_ejtag
*ejtag_info
)
110 uint32_t ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
111 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_CONTROL
);
112 mips_ejtag_drscan_32_out(ejtag_info
, ctrl
);
115 static int mips32_pracc_clean_text_jump(struct mips_ejtag
*ejtag_info
)
117 uint32_t jt_code
= MIPS32_J(ejtag_info
->isa
, MIPS32_PRACC_TEXT
);
118 pracc_swap16_array(ejtag_info
, &jt_code
, 1);
119 /* do 3 0/nops to clean pipeline before a jump to pracc text, NOP in delay slot */
120 for (int i
= 0; i
!= 5; i
++) {
122 int retval
= wait_for_pracc_rw(ejtag_info
);
123 if (retval
!= ERROR_OK
)
126 /* Data or instruction out */
127 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
128 uint32_t data
= (i
== 3) ? jt_code
: MIPS32_NOP
;
129 mips_ejtag_drscan_32_out(ejtag_info
, data
);
132 mips32_pracc_finish(ejtag_info
);
135 if (ejtag_info
->mode
!= 0) /* async mode support only for MIPS ... */
138 for (int i
= 0; i
!= 2; i
++) {
139 int retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
140 if (retval
!= ERROR_OK
)
143 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_TEXT
) { /* LEXRA/BMIPS ?, shift out another NOP, max 2 */
144 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
145 mips_ejtag_drscan_32_out(ejtag_info
, MIPS32_NOP
);
146 mips32_pracc_finish(ejtag_info
);
154 static int mips32_pracc_exec(struct mips_ejtag
*ejtag_info
, struct pracc_queue_info
*ctx
,
155 uint32_t *param_out
, bool check_last
)
158 int store_pending
= 0; /* increases with every store instr at dmseg, decreases with every store pa */
159 uint32_t max_store_addr
= 0; /* for store pa address testing */
160 bool restart
= 0; /* restarting control */
161 int restart_count
= 0;
163 bool final_check
= 0; /* set to 1 if in final checks after function code shifted out */
164 bool pass
= 0; /* to check the pass through pracc text after function code sent */
169 if (restart_count
< 3) { /* max 3 restarts allowed */
170 retval
= mips32_pracc_clean_text_jump(ejtag_info
);
171 if (retval
!= ERROR_OK
)
174 return ERROR_JTAG_DEVICE_ERROR
;
178 LOG_DEBUG("restarting code");
181 retval
= mips32_pracc_read_ctrl_addr(ejtag_info
); /* update current pa info: control and address */
182 if (retval
!= ERROR_OK
)
185 /* Check for read or write access */
186 if (ejtag_info
->pa_ctrl
& EJTAG_CTRL_PRNW
) { /* write/store access */
187 /* Check for pending store from a previous store instruction at dmseg */
188 if (store_pending
== 0) {
189 LOG_DEBUG("unexpected write at address %" PRIx32
, ejtag_info
->pa_addr
);
190 if (code_count
< 2) { /* allow for restart */
194 return ERROR_JTAG_DEVICE_ERROR
;
197 if (ejtag_info
->pa_addr
< MIPS32_PRACC_PARAM_OUT
||
198 ejtag_info
->pa_addr
> max_store_addr
) {
199 LOG_DEBUG("writing at unexpected address %" PRIx32
, ejtag_info
->pa_addr
);
200 return ERROR_JTAG_DEVICE_ERROR
;
205 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
206 retval
= mips_ejtag_drscan_32(ejtag_info
, &data
);
207 if (retval
!= ERROR_OK
)
210 /* store data at param out, address based offset */
211 param_out
[(ejtag_info
->pa_addr
- MIPS32_PRACC_PARAM_OUT
) / 4] = data
;
214 } else { /* read/fetch access */
215 if (!final_check
) { /* executing function code */
217 if (ejtag_info
->pa_addr
!= (MIPS32_PRACC_TEXT
+ code_count
* 4)) {
218 LOG_DEBUG("reading at unexpected address %" PRIx32
", expected %x",
219 ejtag_info
->pa_addr
, MIPS32_PRACC_TEXT
+ code_count
* 4);
221 /* restart code execution only in some cases */
222 if (code_count
== 1 && ejtag_info
->pa_addr
== MIPS32_PRACC_TEXT
&&
223 restart_count
== 0) {
224 LOG_DEBUG("restarting, without clean jump");
228 } else if (code_count
< 2) {
232 return ERROR_JTAG_DEVICE_ERROR
;
234 /* check for store instruction at dmseg */
235 uint32_t store_addr
= ctx
->pracc_list
[code_count
].addr
;
236 if (store_addr
!= 0) {
237 if (store_addr
> max_store_addr
)
238 max_store_addr
= store_addr
;
242 instr
= ctx
->pracc_list
[code_count
++].instr
;
243 if (code_count
== ctx
->code_count
) /* last instruction, start final check */
246 } else { /* final check after function code shifted out */
248 if (ejtag_info
->pa_addr
== MIPS32_PRACC_TEXT
) {
249 if (!pass
) { /* first pass through pracc text */
250 if (store_pending
== 0) /* done, normal exit */
252 pass
= 1; /* pracc text passed */
253 code_count
= 0; /* restart code count */
255 LOG_DEBUG("unexpected second pass through pracc text");
256 return ERROR_JTAG_DEVICE_ERROR
;
259 if (ejtag_info
->pa_addr
!= (MIPS32_PRACC_TEXT
+ code_count
* 4)) {
260 LOG_DEBUG("unexpected read address in final check: %"
261 PRIx32
", expected: %x", ejtag_info
->pa_addr
,
262 MIPS32_PRACC_TEXT
+ code_count
* 4);
263 return ERROR_JTAG_DEVICE_ERROR
;
267 if ((code_count
- ctx
->code_count
) > 1) { /* allow max 2 instr delay slot */
268 LOG_DEBUG("failed to jump back to pracc text");
269 return ERROR_JTAG_DEVICE_ERROR
;
272 if (code_count
> 10) { /* enough, abandon */
273 LOG_DEBUG("execution abandoned, store pending: %d", store_pending
);
274 return ERROR_JTAG_DEVICE_ERROR
;
276 instr
= MIPS32_NOP
; /* shift out NOPs instructions */
280 /* Send instruction out */
281 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
282 mips_ejtag_drscan_32_out(ejtag_info
, instr
);
284 /* finish processor access, let the processor eat! */
285 mips32_pracc_finish(ejtag_info
);
287 if (final_check
&& !check_last
) /* last instr, don't check, execute and exit */
288 return jtag_execute_queue();
290 if (store_pending
== 0 && pass
) { /* store access done, but after passing pracc text */
291 LOG_DEBUG("warning: store access pass pracc text");
297 inline void pracc_queue_init(struct pracc_queue_info
*ctx
)
299 ctx
->retval
= ERROR_OK
;
301 ctx
->store_count
= 0;
303 ctx
->pracc_list
= NULL
;
304 ctx
->isa
= ctx
->ejtag_info
->isa
? 1 : 0;
307 void pracc_add(struct pracc_queue_info
*ctx
, uint32_t addr
, uint32_t instr
)
309 if (ctx
->retval
!= ERROR_OK
) /* On previous out of memory, return */
311 if (ctx
->code_count
== ctx
->max_code
) {
312 void *p
= realloc(ctx
->pracc_list
, sizeof(struct pa_list
) * (ctx
->max_code
+ PRACC_BLOCK
));
314 ctx
->max_code
+= PRACC_BLOCK
;
317 ctx
->retval
= ERROR_FAIL
; /* Out of memory */
321 ctx
->pracc_list
[ctx
->code_count
].instr
= instr
;
322 ctx
->pracc_list
[ctx
->code_count
++].addr
= addr
;
327 static void pracc_add_li32(struct pracc_queue_info
*ctx
, uint32_t reg_num
, uint32_t data
, bool optimize
)
329 if (LOWER16(data
) == 0 && optimize
)
330 pracc_add(ctx
, 0, MIPS32_LUI(ctx
->isa
, reg_num
, UPPER16(data
))); /* load only upper value */
331 else if (UPPER16(data
) == 0 && optimize
)
332 pracc_add(ctx
, 0, MIPS32_ORI(ctx
->isa
, reg_num
, 0, LOWER16(data
))); /* load only lower */
334 pracc_add(ctx
, 0, MIPS32_LUI(ctx
->isa
, reg_num
, UPPER16(data
))); /* load upper and lower */
335 pracc_add(ctx
, 0, MIPS32_ORI(ctx
->isa
, reg_num
, reg_num
, LOWER16(data
)));
339 inline void pracc_queue_free(struct pracc_queue_info
*ctx
)
341 free(ctx
->pracc_list
);
344 int mips32_pracc_queue_exec(struct mips_ejtag
*ejtag_info
, struct pracc_queue_info
*ctx
,
345 uint32_t *buf
, bool check_last
)
347 if (ctx
->retval
!= ERROR_OK
) {
348 LOG_ERROR("Out of memory");
352 if (ejtag_info
->isa
&& ejtag_info
->endianness
)
353 for (int i
= 0; i
!= ctx
->code_count
; i
++)
354 ctx
->pracc_list
[i
].instr
= SWAP16(ctx
->pracc_list
[i
].instr
);
356 if (ejtag_info
->mode
== 0)
357 return mips32_pracc_exec(ejtag_info
, ctx
, buf
, check_last
);
367 } *scan_in
= malloc(sizeof(union scan_in
) * (ctx
->code_count
+ ctx
->store_count
));
369 LOG_ERROR("Out of memory");
373 unsigned num_clocks
=
374 ((uint64_t)(ejtag_info
->scan_delay
) * adapter_get_speed_khz() + 500000) / 1000000;
376 uint32_t ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
377 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ALL
);
380 for (int i
= 0; i
!= ctx
->code_count
; i
++) {
381 jtag_add_clocks(num_clocks
);
382 mips_ejtag_add_scan_96(ejtag_info
, ejtag_ctrl
, ctx
->pracc_list
[i
].instr
,
383 scan_in
[scan_count
++].scan_96
);
385 /* Check store address from previous instruction, if not the first */
386 if (i
> 0 && ctx
->pracc_list
[i
- 1].addr
) {
387 jtag_add_clocks(num_clocks
);
388 mips_ejtag_add_scan_96(ejtag_info
, ejtag_ctrl
, 0, scan_in
[scan_count
++].scan_96
);
392 int retval
= jtag_execute_queue(); /* execute queued scans */
393 if (retval
!= ERROR_OK
)
396 uint32_t fetch_addr
= MIPS32_PRACC_TEXT
; /* start address */
398 for (int i
= 0; i
!= ctx
->code_count
; i
++) { /* verify every pracc access */
399 /* check pracc bit */
400 ejtag_ctrl
= buf_get_u32(scan_in
[scan_count
].scan_32
.ctrl
, 0, 32);
401 uint32_t addr
= buf_get_u32(scan_in
[scan_count
].scan_32
.addr
, 0, 32);
402 if (!(ejtag_ctrl
& EJTAG_CTRL_PRACC
)) {
403 LOG_ERROR("Error: access not pending count: %d", scan_count
);
407 if (ejtag_ctrl
& EJTAG_CTRL_PRNW
) {
408 LOG_ERROR("Not a fetch/read access, count: %d", scan_count
);
412 if (addr
!= fetch_addr
) {
413 LOG_ERROR("Fetch addr mismatch, read: %" PRIx32
" expected: %" PRIx32
" count: %d",
414 addr
, fetch_addr
, scan_count
);
421 /* check if previous instruction is a store instruction at dmesg */
422 if (i
> 0 && ctx
->pracc_list
[i
- 1].addr
) {
423 uint32_t store_addr
= ctx
->pracc_list
[i
- 1].addr
;
424 ejtag_ctrl
= buf_get_u32(scan_in
[scan_count
].scan_32
.ctrl
, 0, 32);
425 addr
= buf_get_u32(scan_in
[scan_count
].scan_32
.addr
, 0, 32);
427 if (!(ejtag_ctrl
& EJTAG_CTRL_PRNW
)) {
428 LOG_ERROR("Not a store/write access, count: %d", scan_count
);
432 if (addr
!= store_addr
) {
433 LOG_ERROR("Store address mismatch, read: %" PRIx32
" expected: %" PRIx32
" count: %d",
434 addr
, store_addr
, scan_count
);
438 int buf_index
= (addr
- MIPS32_PRACC_PARAM_OUT
) / 4;
439 buf
[buf_index
] = buf_get_u32(scan_in
[scan_count
].scan_32
.data
, 0, 32);
448 static int mips32_pracc_read_u32(struct mips_ejtag
*ejtag_info
, uint32_t addr
, uint32_t *buf
)
450 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
451 pracc_queue_init(&ctx
);
453 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
454 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 8, UPPER16((addr
+ 0x8000)))); /* load $8 with modified upper addr */
455 pracc_add(&ctx
, 0, MIPS32_LW(ctx
.isa
, 8, LOWER16(addr
), 8)); /* lw $8, LOWER16(addr)($8) */
456 if (mips32_cpu_support_sync(ejtag_info
))
457 pracc_add(&ctx
, 0, MIPS32_SYNC(ctx
.isa
));
458 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
459 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */
460 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
461 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
462 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* move COP0 DeSave to $15 */
464 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, buf
, 1);
465 pracc_queue_free(&ctx
);
469 int mips32_pracc_read_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, void *buf
)
471 if (count
== 1 && size
== 4)
472 return mips32_pracc_read_u32(ejtag_info
, addr
, (uint32_t *)buf
);
474 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
475 pracc_queue_init(&ctx
);
477 uint32_t *data
= NULL
;
479 data
= malloc(256 * sizeof(uint32_t));
481 LOG_ERROR("Out of memory");
486 uint32_t *buf32
= buf
;
487 uint16_t *buf16
= buf
;
494 int this_round_count
= (count
> 256) ? 256 : count
;
495 uint32_t last_upper_base_addr
= UPPER16((addr
+ 0x8000));
497 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
498 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 9, last_upper_base_addr
)); /* upper memory addr to $9 */
500 for (int i
= 0; i
!= this_round_count
; i
++) { /* Main code loop */
501 uint32_t upper_base_addr
= UPPER16((addr
+ 0x8000));
502 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper addr in $9 */
503 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 9, upper_base_addr
));
504 last_upper_base_addr
= upper_base_addr
;
507 if (size
== 4) /* load from memory to $8 */
508 pracc_add(&ctx
, 0, MIPS32_LW(ctx
.isa
, 8, LOWER16(addr
), 9));
510 pracc_add(&ctx
, 0, MIPS32_LHU(ctx
.isa
, 8, LOWER16(addr
), 9));
512 pracc_add(&ctx
, 0, MIPS32_LBU(ctx
.isa
, 8, LOWER16(addr
), 9));
514 if (mips32_cpu_support_sync(ejtag_info
))
515 pracc_add(&ctx
, 0, MIPS32_SYNC(ctx
.isa
));
516 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ i
* 4, /* store $8 at param out */
517 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
+ i
* 4, 15));
520 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
521 pracc_add_li32(&ctx
, 9, ejtag_info
->reg9
, 0); /* restore $9 */
523 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
524 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
527 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, buf32
, 1);
528 if (ctx
.retval
!= ERROR_OK
)
530 buf32
+= this_round_count
;
532 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, data
, 1);
533 if (ctx
.retval
!= ERROR_OK
)
536 uint32_t *data_p
= data
;
537 for (int i
= 0; i
!= this_round_count
; i
++) {
539 *buf16
++ = *data_p
++;
544 count
-= this_round_count
;
547 pracc_queue_free(&ctx
);
552 int mips32_cp0_read(struct mips_ejtag
*ejtag_info
, uint32_t *val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
554 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
555 pracc_queue_init(&ctx
);
557 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
558 if (mips32_cpu_support_hazard_barrier(ejtag_info
))
559 pracc_add(&ctx
, 0, MIPS32_EHB(ctx
.isa
));
560 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 8, cp0_reg
, cp0_sel
)); /* move cp0 reg / sel to $8 */
561 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
562 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* store $8 to pracc_out */
563 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
564 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 8, UPPER16(ejtag_info
->reg8
))); /* restore upper 16 bits of $8 */
565 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
566 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 8, LOWER16(ejtag_info
->reg8
))); /* restore lower 16 bits of $8 */
568 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, val
, 1);
569 pracc_queue_free(&ctx
);
573 int mips32_cp0_write(struct mips_ejtag
*ejtag_info
, uint32_t val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
575 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
576 pracc_queue_init(&ctx
);
578 pracc_add_li32(&ctx
, 15, val
, 0); /* Load val to $15 */
580 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, cp0_reg
, cp0_sel
)); /* write $15 to cp0 reg / sel */
581 if (mips32_cpu_support_hazard_barrier(ejtag_info
))
582 pracc_add(&ctx
, 0, MIPS32_EHB(ctx
.isa
));
583 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
584 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
586 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
587 pracc_queue_free(&ctx
);
592 * \b mips32_pracc_sync_cache
594 * Synchronize Caches to Make Instruction Writes Effective
595 * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set,
596 * Document Number: MD00086, Revision 2.00, June 9, 2003)
598 * When the instruction stream is written, the SYNCI instruction should be used
599 * in conjunction with other instructions to make the newly-written instructions effective.
602 * A program that loads another program into memory is actually writing the D- side cache.
603 * The instructions it has loaded can't be executed until they reach the I-cache.
605 * After the instructions have been written, the loader should arrange
606 * to write back any containing D-cache line and invalidate any locations
607 * already in the I-cache.
609 * If the cache coherency attribute (CCA) is set to zero, it's a write through cache, there is no need
612 * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
613 * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
614 * That is, it arranges a D-cache write-back (if CCA = 3) and an I-cache invalidate.
616 * The line size is obtained with the rdhwr SYNCI_Step in release 2 or from cp0 config 1 register in release 1.
618 static int mips32_pracc_synchronize_cache(struct mips_ejtag
*ejtag_info
,
619 uint32_t start_addr
, uint32_t end_addr
, int cached
, int rel
)
621 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
622 pracc_queue_init(&ctx
);
624 /** Find cache line size in bytes */
626 if (rel
) { /* Release 2 (rel = 1) */
627 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
629 pracc_add(&ctx
, 0, MIPS32_RDHWR(ctx
.isa
, 8, MIPS32_SYNCI_STEP
)); /* load synci_step value to $8 */
631 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
632 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* store $8 to pracc_out */
634 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
636 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
637 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
639 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, &clsiz
, 1);
640 if (ctx
.retval
!= ERROR_OK
)
643 } else { /* Release 1 (rel = 0) */
645 ctx
.retval
= mips32_cp0_read(ejtag_info
, &conf
, 16, 1);
646 if (ctx
.retval
!= ERROR_OK
)
649 uint32_t dl
= (conf
& MIPS32_CONFIG1_DL_MASK
) >> MIPS32_CONFIG1_DL_SHIFT
;
651 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... max dl=6 => 128 bytes cache line size */
658 goto exit
; /* Nothing to do */
660 /* make sure clsiz is power of 2 */
661 if (!IS_PWR_OF_2(clsiz
)) {
662 LOG_DEBUG("clsiz must be power of 2");
663 ctx
.retval
= ERROR_FAIL
;
667 /* make sure start_addr and end_addr have the same offset inside de cache line */
668 start_addr
|= clsiz
- 1;
669 end_addr
|= clsiz
- 1;
675 uint32_t last_upper_base_addr
= UPPER16((start_addr
+ 0x8000));
677 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, last_upper_base_addr
)); /* load upper memory base addr to $15 */
679 while (start_addr
<= end_addr
) { /* main loop */
680 uint32_t upper_base_addr
= UPPER16((start_addr
+ 0x8000));
681 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper addr in $15 */
682 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, upper_base_addr
));
683 last_upper_base_addr
= upper_base_addr
;
685 if (rel
) /* synci instruction, offset($15) */
686 pracc_add(&ctx
, 0, MIPS32_SYNCI(ctx
.isa
, LOWER16(start_addr
), 15));
689 if (cached
== 3) /* cache Hit_Writeback_D, offset($15) */
690 pracc_add(&ctx
, 0, MIPS32_CACHE(ctx
.isa
, MIPS32_CACHE_D_HIT_WRITEBACK
,
691 LOWER16(start_addr
), 15));
692 /* cache Hit_Invalidate_I, offset($15) */
693 pracc_add(&ctx
, 0, MIPS32_CACHE(ctx
.isa
, MIPS32_CACHE_I_HIT_INVALIDATE
,
694 LOWER16(start_addr
), 15));
698 if (count
== 256 && start_addr
<= end_addr
) { /* more ?, then execute code list */
699 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* to start */
700 pracc_add(&ctx
, 0, MIPS32_NOP
); /* nop in delay slot */
702 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
703 if (ctx
.retval
!= ERROR_OK
)
706 ctx
.code_count
= 0; /* reset counters for another loop */
711 pracc_add(&ctx
, 0, MIPS32_SYNC(ctx
.isa
));
712 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
713 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave*/
715 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
717 pracc_queue_free(&ctx
);
721 static int mips32_pracc_write_mem_generic(struct mips_ejtag
*ejtag_info
,
722 uint32_t addr
, int size
, int count
, const void *buf
)
724 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
725 pracc_queue_init(&ctx
);
727 const uint32_t *buf32
= buf
;
728 const uint16_t *buf16
= buf
;
729 const uint8_t *buf8
= buf
;
735 int this_round_count
= (count
> 128) ? 128 : count
;
736 uint32_t last_upper_base_addr
= UPPER16((addr
+ 0x8000));
737 /* load $15 with memory base address */
738 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, last_upper_base_addr
));
740 for (int i
= 0; i
!= this_round_count
; i
++) {
741 uint32_t upper_base_addr
= UPPER16((addr
+ 0x8000));
742 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper address in $15*/
743 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, upper_base_addr
));
744 last_upper_base_addr
= upper_base_addr
;
748 pracc_add_li32(&ctx
, 8, *buf32
, 1); /* load with li32, optimize */
749 pracc_add(&ctx
, 0, MIPS32_SW(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store word to mem */
752 } else if (size
== 2) {
753 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 0, *buf16
)); /* load lower value */
754 pracc_add(&ctx
, 0, MIPS32_SH(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store half word */
758 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 0, *buf8
)); /* load lower value */
759 pracc_add(&ctx
, 0, MIPS32_SB(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store byte */
765 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
767 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
768 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
770 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
771 if (ctx
.retval
!= ERROR_OK
)
773 count
-= this_round_count
;
776 pracc_queue_free(&ctx
);
780 int mips32_pracc_write_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, const void *buf
)
782 int retval
= mips32_pracc_write_mem_generic(ejtag_info
, addr
, size
, count
, buf
);
783 if (retval
!= ERROR_OK
)
787 * If we are in the cacheable region and cache is activated,
788 * we must clean D$ (if Cache Coherency Attribute is set to 3) + invalidate I$ after we did the write,
789 * so that changes do not continue to live only in D$ (if CCA = 3), but to be
790 * replicated in I$ also (maybe we wrote the instructions)
795 if ((KSEGX(addr
) == KSEG1
) || ((addr
>= 0xff200000) && (addr
<= 0xff3fffff)))
796 return retval
; /*Nothing to do*/
799 mips32_cp0_read(ejtag_info
, &conf
, 16, 0);
801 switch (KSEGX(addr
)) {
803 cached
= (conf
& MIPS32_CONFIG0_KU_MASK
) >> MIPS32_CONFIG0_KU_SHIFT
;
806 cached
= (conf
& MIPS32_CONFIG0_K0_MASK
) >> MIPS32_CONFIG0_K0_SHIFT
;
810 cached
= (conf
& MIPS32_CONFIG0_K23_MASK
) >> MIPS32_CONFIG0_K23_SHIFT
;
818 * Check cacheability bits coherency algorithm
819 * is the region cacheable or uncached.
820 * If cacheable we have to synchronize the cache
822 if (cached
== 3 || cached
== 0) { /* Write back cache or write through cache */
823 uint32_t start_addr
= addr
;
824 uint32_t end_addr
= addr
+ count
* size
;
825 uint32_t rel
= (conf
& MIPS32_CONFIG0_AR_MASK
) >> MIPS32_CONFIG0_AR_SHIFT
;
826 /* FIXME: In MIPS Release 6, the encoding of CACHE instr has changed */
827 if (rel
> MIPS32_RELEASE_2
) {
828 LOG_DEBUG("Unsupported MIPS Release ( > 5)");
831 retval
= mips32_pracc_synchronize_cache(ejtag_info
, start_addr
, end_addr
, cached
, rel
);
833 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
835 pracc_queue_init(&ctx
);
836 if (mips32_cpu_support_sync(ejtag_info
))
837 pracc_add(&ctx
, 0, MIPS32_SYNC(ctx
.isa
));
838 if (mips32_cpu_support_hazard_barrier(ejtag_info
))
839 pracc_add(&ctx
, 0, MIPS32_EHB(ctx
.isa
));
840 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
841 pracc_add(&ctx
, 0, MIPS32_NOP
);
842 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
843 if (ctx
.retval
!= ERROR_OK
) {
844 LOG_ERROR("Unable to barrier");
847 pracc_queue_free(&ctx
);
853 int mips32_pracc_write_regs(struct mips32_common
*mips32
)
855 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
856 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
857 uint32_t *gprs
= mips32
->core_regs
.gpr
;
858 uint32_t *c0rs
= mips32
->core_regs
.cp0
;
860 pracc_queue_init(&ctx
);
862 uint32_t cp0_write_code
[] = {
863 MIPS32_MTC0(ctx
.isa
, 1, 12, 0), /* move $1 to status */
864 MIPS32_MTLO(ctx
.isa
, 1), /* move $1 to lo */
865 MIPS32_MTHI(ctx
.isa
, 1), /* move $1 to hi */
866 MIPS32_MTC0(ctx
.isa
, 1, 8, 0), /* move $1 to badvaddr */
867 MIPS32_MTC0(ctx
.isa
, 1, 13, 0), /* move $1 to cause*/
868 MIPS32_MTC0(ctx
.isa
, 1, 24, 0), /* move $1 to depc (pc) */
871 uint32_t cp0_write_data
[] = {
886 /* Write CP0 Status Register first, changes on EXL or ERL bits
887 * may lead to different behaviour on writing to other CP0 registers.
889 for (size_t i
= 0; i
< ARRAY_SIZE(cp0_write_code
); i
++) {
890 /* load CP0 value in $1 */
891 pracc_add_li32(&ctx
, 1, cp0_write_data
[i
], 0);
892 /* write value from $1 to CP0 register */
893 pracc_add(&ctx
, 0, cp0_write_code
[i
]);
896 if (mips32_cpu_support_hazard_barrier(ejtag_info
))
897 pracc_add(&ctx
, 0, MIPS32_EHB(ctx
.isa
));
898 /* load registers 2 to 31 with li32, optimize */
899 for (int i
= 2; i
< 32; i
++)
900 pracc_add_li32(&ctx
, i
, gprs
[i
], 1);
902 /* load $15 in DeSave */
903 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, 31, 0));
904 /* load upper half word in $1 */
905 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 1, UPPER16((gprs
[1]))));
907 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
)));
908 /* load lower half word in $1 */
909 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 1, 1, LOWER16((gprs
[1]))));
911 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
913 ejtag_info
->reg8
= gprs
[8];
914 ejtag_info
->reg9
= gprs
[9];
915 pracc_queue_free(&ctx
);
919 /* Saves content in `$1` to `DeSave(cp0.31.0)` and loads `MIPS32_PRACC_BASE_ADDR` into `$1` */
920 static void mips32_pracc_store_regs_set_base_addr(struct pracc_queue_info
*ctx
)
922 /* move $1 to COP0 DeSave */
923 pracc_add(ctx
, 0, MIPS32_MTC0(ctx
->isa
, 1, 31, 0));
924 /* $1 = MIP32_PRACC_BASE_ADDR */
925 pracc_add(ctx
, 0, MIPS32_LUI(ctx
->isa
, 1, PRACC_UPPER_BASE_ADDR
));
928 /* This function assumes the address for saving is stored in `$1`.
929 * And that action is performed in `mips32_pracc_set_save_base_addr`.
931 static void mips32_pracc_store_regs_gpr(struct pracc_queue_info
*ctx
, unsigned int offset_gpr
)
933 for (int i
= 2; i
!= 32; i
++)
934 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ offset_gpr
+ (i
* 4),
935 MIPS32_SW(ctx
->isa
, i
, PRACC_OUT_OFFSET
+ offset_gpr
+ (i
* 4), 1));
938 static void mips32_pracc_store_regs_lohi(struct pracc_queue_info
*ctx
)
940 uint32_t lohi_read_code
[] = {
941 MIPS32_MFLO(ctx
->isa
, 8), /* move lo to $8 */
942 MIPS32_MFHI(ctx
->isa
, 8), /* move hi to $8 */
946 for (int i
= 0; i
< 2; i
++) {
947 /* load COP0 needed registers to $8 */
948 pracc_add(ctx
, 0, lohi_read_code
[i
]);
949 /* store $8 at PARAM OUT */
950 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ (i
+ 32) * 4,
951 MIPS32_SW(ctx
->isa
, 8, PRACC_OUT_OFFSET
+ (i
+ 32) * 4, 1));
955 /* Saves CP0 registers [status, badvaddr, cause, depc] */
956 static void mips32_pracc_store_regs_cp0_context(struct pracc_queue_info
*ctx
, unsigned int offset_cp0
)
958 uint32_t cp0_read_code
[] = {
959 MIPS32_MFC0(ctx
->isa
, 8, 12, 0), /* move status to $8 */
960 MIPS32_MFC0(ctx
->isa
, 8, 8, 0), /* move badvaddr to $8 */
961 MIPS32_MFC0(ctx
->isa
, 8, 13, 0), /* move cause to $8 */
962 MIPS32_MFC0(ctx
->isa
, 8, 24, 0), /* move depc (pc) to $8 */
966 for (size_t i
= 0; i
< ARRAY_SIZE(cp0_read_code
); i
++) {
967 size_t offset
= offset_cp0
+ (i
* 4);
969 /* load COP0 needed registers to $8 */
970 pracc_add(ctx
, 0, cp0_read_code
[i
]);
971 /* store $8 at PARAM OUT */
972 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ offset
,
973 MIPS32_SW(ctx
->isa
, 8, PRACC_OUT_OFFSET
+ offset
, 1));
977 /* Loads original content of $1 into $8,
978 * then store it to the batch data access address.
979 * Finally it restores $1 from DeSave.
981 static void mips32_pracc_store_regs_restore(struct pracc_queue_info
*ctx
)
983 /* move DeSave to $8, reg1 value */
984 pracc_add(ctx
, 0, MIPS32_MFC0(ctx
->isa
, 8, 31, 0));
985 /* store reg1 value from $8 to param out */
986 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ 4,
987 MIPS32_SW(ctx
->isa
, 8, PRACC_OUT_OFFSET
+ 4, 1));
989 /* move COP0 DeSave to $1, restore reg1 */
990 pracc_add(ctx
, 0, MIPS32_MFC0(ctx
->isa
, 1, 31, 0));
993 /* This function performs following actions:
994 * Saves `$1` to `DeSave`,
995 * then load `PRACC_UPPER_BASE_ADDR` for saving the register data structure into `$1`,
996 * Saves `$2` ~ `$31` to `PRACC_UPPER_BASE_ADDR + offset_gpr`
998 * Saves necessary cp0 registers.
1000 static void mips32_pracc_store_regs(struct pracc_queue_info
*ctx
,
1001 unsigned int offset_gpr
, unsigned int offset_cp0
)
1003 mips32_pracc_store_regs_set_base_addr(ctx
);
1004 mips32_pracc_store_regs_gpr(ctx
, offset_gpr
);
1005 mips32_pracc_store_regs_lohi(ctx
);
1006 mips32_pracc_store_regs_cp0_context(ctx
, offset_cp0
);
1007 mips32_pracc_store_regs_restore(ctx
);
1010 int mips32_pracc_read_regs(struct mips32_common
*mips32
)
1012 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
1013 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
1014 struct mips32_core_regs
*core_regs
= &mips32
->core_regs
;
1015 unsigned int offset_gpr
= ((uint8_t *)&core_regs
->gpr
[0]) - (uint8_t *)core_regs
;
1016 unsigned int offset_cp0
= ((uint8_t *)&core_regs
->cp0
[0]) - (uint8_t *)core_regs
;
1019 * This procedure has to be in 2 distinctive steps, because we can
1020 * only know whether FP is enabled after reading CP0.
1022 * Step 1: Read everything except CP1 stuff
1023 * Step 2: Read CP1 stuff if FP is implemented
1026 pracc_queue_init(&ctx
);
1028 mips32_pracc_store_regs(&ctx
, offset_gpr
, offset_cp0
);
1031 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
)));
1032 /* load $15 in DeSave */
1033 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, 31, 0));
1035 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, (uint32_t *)&mips32
->core_regs
, 1);
1037 pracc_queue_free(&ctx
);
1039 /* reg8 is saved but not restored, next called function should restore it */
1040 ejtag_info
->reg8
= mips32
->core_regs
.gpr
[8];
1041 ejtag_info
->reg9
= mips32
->core_regs
.gpr
[9];
1043 /* we only care if FP is actually impl'd and if cp1 is enabled */
1044 /* since we already read cp0 in the prev step */
1045 /* now we know what's in cp0.status */
1046 /* TODO: Read FPRs */
1052 * mips32_pracc_fastdata_xfer_synchronize_cache - Synchronize cache for fast data transfer
1053 * @param[in] ejtag_info: EJTAG information structure
1054 * @param[in] addr: Starting address for cache synchronization
1055 * @param[in] size: Size of each data element
1056 * @param[in] count: Number of data elements
1058 * @brief Synchronizes the cache for fast data transfer based on
1059 * the specified address and cache configuration.
1060 * If the region is cacheable (write-back cache or write-through cache),
1061 * it synchronizes the cache for the specified range.
1062 * The synchronization is performed using the MIPS32 cache synchronization function.
1064 * @return ERROR_OK on success; error code on failure.
1066 static int mips32_pracc_fastdata_xfer_synchronize_cache(struct mips_ejtag
*ejtag_info
,
1067 uint32_t addr
, int size
, int count
)
1069 int retval
= ERROR_OK
;
1071 if ((KSEGX(addr
) == KSEG1
) || (addr
>= 0xff200000 && addr
<= 0xff3fffff)) // DESEG?
1072 return retval
; /*Nothing to do*/
1077 mips32_cp0_read(ejtag_info
, &conf
, 16, 0);
1079 switch (KSEGX(addr
)) {
1081 cached
= (conf
& MIPS32_CONFIG0_KU_MASK
) >> MIPS32_CONFIG0_KU_SHIFT
;
1084 cached
= (conf
& MIPS32_CONFIG0_K0_MASK
) >> MIPS32_CONFIG0_K0_SHIFT
;
1088 cached
= (conf
& MIPS32_CONFIG0_K23_MASK
) >> MIPS32_CONFIG0_K23_SHIFT
;
1096 * Check cacheability bits coherency algorithm
1097 * is the region cacheable or uncached.
1098 * If cacheable we have to synchronize the cache
1100 if (cached
== 3 || cached
== 0) { /* Write back cache or write through cache */
1101 uint32_t start_addr
= addr
;
1102 uint32_t end_addr
= addr
+ count
* size
;
1103 uint32_t rel
= (conf
& MIPS32_CONFIG0_AR_MASK
) >> MIPS32_CONFIG0_AR_SHIFT
;
1104 /* FIXME: In MIPS Release 6, the encoding of CACHE instr has changed */
1105 if (rel
> MIPS32_RELEASE_2
) {
1106 LOG_DEBUG("Unsupported MIPS Release ( > 5)");
1109 retval
= mips32_pracc_synchronize_cache(ejtag_info
, start_addr
, end_addr
, cached
, rel
);
1115 /* fastdata upload/download requires an initialized working area
1116 * to load the download code; it should not be called otherwise
1117 * fetch order from the fastdata area
1122 int mips32_pracc_fastdata_xfer(struct mips_ejtag
*ejtag_info
, struct working_area
*source
,
1123 int write_t
, uint32_t addr
, int count
, uint32_t *buf
)
1125 uint32_t isa
= ejtag_info
->isa
? 1 : 0;
1126 uint32_t handler_code
[] = {
1127 /* r15 points to the start of this code */
1128 MIPS32_SW(isa
, 8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
1129 MIPS32_SW(isa
, 9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
1130 MIPS32_SW(isa
, 10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
1131 MIPS32_SW(isa
, 11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
1132 /* start of fastdata area in t0 */
1133 MIPS32_LUI(isa
, 8, UPPER16(MIPS32_PRACC_FASTDATA_AREA
)),
1134 MIPS32_ORI(isa
, 8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA
)),
1135 MIPS32_LW(isa
, 9, 0, 8), /* start addr in t1 */
1136 mips32_cpu_support_sync(ejtag_info
) ? MIPS32_SYNC(isa
) : MIPS32_NOP
, /* barrier for ordering */
1137 MIPS32_LW(isa
, 10, 0, 8), /* end addr to t2 */
1138 mips32_cpu_support_sync(ejtag_info
) ? MIPS32_SYNC(isa
) : MIPS32_NOP
, /* barrier for ordering */
1140 write_t
? MIPS32_LW(isa
, 11, 0, 8) : MIPS32_LW(isa
, 11, 0, 9), /* from xfer area : from memory */
1141 write_t
? MIPS32_SW(isa
, 11, 0, 9) : MIPS32_SW(isa
, 11, 0, 8), /* to memory : to xfer area */
1143 mips32_cpu_support_sync(ejtag_info
) ? MIPS32_SYNC(isa
) : MIPS32_NOP
, /* barrier for ordering */
1145 MIPS32_BNE(isa
, 10, 9, NEG16(4 << isa
)), /* bne $t2,t1,loop */
1146 MIPS32_ADDI(isa
, 9, 9, 4), /* addi t1,t1,4 */
1148 MIPS32_LW(isa
, 8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
1149 MIPS32_LW(isa
, 9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
1150 MIPS32_LW(isa
, 10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
1151 MIPS32_LW(isa
, 11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
1153 MIPS32_LUI(isa
, 15, UPPER16(MIPS32_PRACC_TEXT
)),
1154 MIPS32_ORI(isa
, 15, 15, LOWER16(MIPS32_PRACC_TEXT
) | isa
), /* isa bit for JR instr */
1155 mips32_cpu_support_hazard_barrier(ejtag_info
)
1156 ? MIPS32_JRHB(isa
, 15)
1157 : MIPS32_JR(isa
, 15), /* jr start */
1158 MIPS32_MFC0(isa
, 15, 31, 0), /* move COP0 DeSave to $15 */
1161 if (source
->size
< MIPS32_FASTDATA_HANDLER_SIZE
)
1162 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1164 pracc_swap16_array(ejtag_info
, handler_code
, ARRAY_SIZE(handler_code
));
1165 /* write program into RAM */
1166 if (write_t
!= ejtag_info
->fast_access_save
) {
1167 mips32_pracc_write_mem(ejtag_info
, source
->address
, 4, ARRAY_SIZE(handler_code
), handler_code
);
1168 /* save previous operation to speed to any consecutive read/writes */
1169 ejtag_info
->fast_access_save
= write_t
;
1172 LOG_DEBUG("%s using 0x%.8" TARGET_PRIxADDR
" for write handler", __func__
, source
->address
);
1174 uint32_t jmp_code
[] = {
1175 MIPS32_LUI(isa
, 15, UPPER16(source
->address
)), /* load addr of jump in $15 */
1176 MIPS32_ORI(isa
, 15, 15, LOWER16(source
->address
) | isa
), /* isa bit for JR instr */
1177 mips32_cpu_support_hazard_barrier(ejtag_info
)
1178 ? MIPS32_JRHB(isa
, 15)
1179 : MIPS32_JR(isa
, 15), /* jump to ram program */
1180 isa
? MIPS32_XORI(isa
, 15, 15, 1) : MIPS32_NOP
, /* drop isa bit, needed for LW/SW instructions */
1183 pracc_swap16_array(ejtag_info
, jmp_code
, ARRAY_SIZE(jmp_code
));
1185 /* execute jump code, with no address check */
1186 for (unsigned i
= 0; i
< ARRAY_SIZE(jmp_code
); i
++) {
1187 int retval
= wait_for_pracc_rw(ejtag_info
);
1188 if (retval
!= ERROR_OK
)
1191 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
1192 mips_ejtag_drscan_32_out(ejtag_info
, jmp_code
[i
]);
1194 /* Clear the access pending bit (let the processor eat!) */
1195 mips32_pracc_finish(ejtag_info
);
1198 /* wait PrAcc pending bit for FASTDATA write, read address */
1199 int retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
1200 if (retval
!= ERROR_OK
)
1203 /* next fetch to dmseg should be in FASTDATA_AREA, check */
1204 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_FASTDATA_AREA
)
1207 /* Send the load start address */
1208 uint32_t val
= addr
;
1209 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1210 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1212 retval
= wait_for_pracc_rw(ejtag_info
);
1213 if (retval
!= ERROR_OK
)
1216 /* Send the load end address */
1217 val
= addr
+ (count
- 1) * 4;
1218 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1219 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1221 unsigned num_clocks
= 0; /* like in legacy code */
1222 if (ejtag_info
->mode
!= 0)
1223 num_clocks
= ((uint64_t)(ejtag_info
->scan_delay
) * adapter_get_speed_khz() + 500000) / 1000000;
1225 for (int i
= 0; i
< count
; i
++) {
1226 jtag_add_clocks(num_clocks
);
1227 mips_ejtag_fastdata_scan(ejtag_info
, write_t
, buf
++);
1230 retval
= jtag_execute_queue();
1231 if (retval
!= ERROR_OK
) {
1232 LOG_ERROR("fastdata load failed");
1236 retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
1237 if (retval
!= ERROR_OK
)
1240 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_TEXT
)
1241 LOG_ERROR("mini program did not return to start");
1243 return mips32_pracc_fastdata_xfer_synchronize_cache(ejtag_info
, addr
, 4, count
);
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)