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
);
591 int mips32_cp1_control_read(struct mips_ejtag
*ejtag_info
, uint32_t *val
, uint32_t cp1_c_reg
)
593 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
594 pracc_queue_init(&ctx
);
596 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
597 pracc_add(&ctx
, 0, MIPS32_EHB(ctx
.isa
));
598 pracc_add(&ctx
, 0, MIPS32_CFC1(ctx
.isa
, 8, cp1_c_reg
)); /* move cp1c reg to $8 */
599 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
600 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* store $8 to pracc_out */
601 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
602 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 8, UPPER16(ejtag_info
->reg8
))); /* restore upper 16 bits of $8 */
603 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
604 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 8, LOWER16(ejtag_info
->reg8
))); /* restore lower 16 bits of $8 */
606 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, val
, 1);
607 pracc_queue_free(&ctx
);
612 * \b mips32_pracc_sync_cache
614 * Synchronize Caches to Make Instruction Writes Effective
615 * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set,
616 * Document Number: MD00086, Revision 2.00, June 9, 2003)
618 * When the instruction stream is written, the SYNCI instruction should be used
619 * in conjunction with other instructions to make the newly-written instructions effective.
622 * A program that loads another program into memory is actually writing the D- side cache.
623 * The instructions it has loaded can't be executed until they reach the I-cache.
625 * After the instructions have been written, the loader should arrange
626 * to write back any containing D-cache line and invalidate any locations
627 * already in the I-cache.
629 * If the cache coherency attribute (CCA) is set to zero, it's a write through cache, there is no need
632 * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
633 * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
634 * That is, it arranges a D-cache write-back (if CCA = 3) and an I-cache invalidate.
636 * The line size is obtained with the rdhwr SYNCI_Step in release 2 or from cp0 config 1 register in release 1.
638 static int mips32_pracc_synchronize_cache(struct mips_ejtag
*ejtag_info
,
639 uint32_t start_addr
, uint32_t end_addr
, int cached
, int rel
)
641 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
642 pracc_queue_init(&ctx
);
644 /** Find cache line size in bytes */
646 if (rel
) { /* Release 2 (rel = 1) */
647 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
649 pracc_add(&ctx
, 0, MIPS32_RDHWR(ctx
.isa
, 8, MIPS32_SYNCI_STEP
)); /* load synci_step value to $8 */
651 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
652 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* store $8 to pracc_out */
654 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
656 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
657 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
659 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, &clsiz
, 1);
660 if (ctx
.retval
!= ERROR_OK
)
663 } else { /* Release 1 (rel = 0) */
665 ctx
.retval
= mips32_cp0_read(ejtag_info
, &conf
, 16, 1);
666 if (ctx
.retval
!= ERROR_OK
)
669 uint32_t dl
= (conf
& MIPS32_CONFIG1_DL_MASK
) >> MIPS32_CONFIG1_DL_SHIFT
;
671 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... max dl=6 => 128 bytes cache line size */
678 goto exit
; /* Nothing to do */
680 /* make sure clsiz is power of 2 */
681 if (!IS_PWR_OF_2(clsiz
)) {
682 LOG_DEBUG("clsiz must be power of 2");
683 ctx
.retval
= ERROR_FAIL
;
687 /* make sure start_addr and end_addr have the same offset inside de cache line */
688 start_addr
|= clsiz
- 1;
689 end_addr
|= clsiz
- 1;
695 uint32_t last_upper_base_addr
= UPPER16((start_addr
+ 0x8000));
697 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, last_upper_base_addr
)); /* load upper memory base addr to $15 */
699 while (start_addr
<= end_addr
) { /* main loop */
700 uint32_t upper_base_addr
= UPPER16((start_addr
+ 0x8000));
701 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper addr in $15 */
702 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, upper_base_addr
));
703 last_upper_base_addr
= upper_base_addr
;
705 if (rel
) /* synci instruction, offset($15) */
706 pracc_add(&ctx
, 0, MIPS32_SYNCI(ctx
.isa
, LOWER16(start_addr
), 15));
709 if (cached
== 3) /* cache Hit_Writeback_D, offset($15) */
710 pracc_add(&ctx
, 0, MIPS32_CACHE(ctx
.isa
, MIPS32_CACHE_D_HIT_WRITEBACK
,
711 LOWER16(start_addr
), 15));
712 /* cache Hit_Invalidate_I, offset($15) */
713 pracc_add(&ctx
, 0, MIPS32_CACHE(ctx
.isa
, MIPS32_CACHE_I_HIT_INVALIDATE
,
714 LOWER16(start_addr
), 15));
718 if (count
== 256 && start_addr
<= end_addr
) { /* more ?, then execute code list */
719 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* to start */
720 pracc_add(&ctx
, 0, MIPS32_NOP
); /* nop in delay slot */
722 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
723 if (ctx
.retval
!= ERROR_OK
)
726 ctx
.code_count
= 0; /* reset counters for another loop */
731 pracc_add(&ctx
, 0, MIPS32_SYNC(ctx
.isa
));
732 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
733 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave*/
735 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
737 pracc_queue_free(&ctx
);
741 static int mips32_pracc_write_mem_generic(struct mips_ejtag
*ejtag_info
,
742 uint32_t addr
, int size
, int count
, const void *buf
)
744 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
745 pracc_queue_init(&ctx
);
747 const uint32_t *buf32
= buf
;
748 const uint16_t *buf16
= buf
;
749 const uint8_t *buf8
= buf
;
755 int this_round_count
= (count
> 128) ? 128 : count
;
756 uint32_t last_upper_base_addr
= UPPER16((addr
+ 0x8000));
757 /* load $15 with memory base address */
758 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, last_upper_base_addr
));
760 for (int i
= 0; i
!= this_round_count
; i
++) {
761 uint32_t upper_base_addr
= UPPER16((addr
+ 0x8000));
762 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper address in $15*/
763 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, upper_base_addr
));
764 last_upper_base_addr
= upper_base_addr
;
768 pracc_add_li32(&ctx
, 8, *buf32
, 1); /* load with li32, optimize */
769 pracc_add(&ctx
, 0, MIPS32_SW(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store word to mem */
772 } else if (size
== 2) {
773 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 0, *buf16
)); /* load lower value */
774 pracc_add(&ctx
, 0, MIPS32_SH(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store half word */
778 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 0, *buf8
)); /* load lower value */
779 pracc_add(&ctx
, 0, MIPS32_SB(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store byte */
785 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
787 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
788 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
790 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
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
, const 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 cacheable region and cache is activated,
808 * we must clean D$ (if Cache Coherency Attribute is set to 3) + invalidate I$ after we did the write,
809 * so that changes do not continue to live only in D$ (if CCA = 3), but to be
810 * replicated in I$ also (maybe we wrote the instructions)
815 if ((KSEGX(addr
) == KSEG1
) || ((addr
>= 0xff200000) && (addr
<= 0xff3fffff)))
816 return retval
; /*Nothing to do*/
819 mips32_cp0_read(ejtag_info
, &conf
, 16, 0);
821 switch (KSEGX(addr
)) {
823 cached
= (conf
& MIPS32_CONFIG0_KU_MASK
) >> MIPS32_CONFIG0_KU_SHIFT
;
826 cached
= (conf
& MIPS32_CONFIG0_K0_MASK
) >> MIPS32_CONFIG0_K0_SHIFT
;
830 cached
= (conf
& MIPS32_CONFIG0_K23_MASK
) >> MIPS32_CONFIG0_K23_SHIFT
;
838 * Check cacheability bits coherency algorithm
839 * is the region cacheable or uncached.
840 * If cacheable we have to synchronize the cache
842 if (cached
== 3 || cached
== 0) { /* Write back cache or write through cache */
843 uint32_t start_addr
= addr
;
844 uint32_t end_addr
= addr
+ count
* size
;
845 uint32_t rel
= (conf
& MIPS32_CONFIG0_AR_MASK
) >> MIPS32_CONFIG0_AR_SHIFT
;
846 /* FIXME: In MIPS Release 6, the encoding of CACHE instr has changed */
847 if (rel
> MIPS32_RELEASE_2
) {
848 LOG_DEBUG("Unsupported MIPS Release ( > 5)");
851 retval
= mips32_pracc_synchronize_cache(ejtag_info
, start_addr
, end_addr
, cached
, rel
);
853 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
855 pracc_queue_init(&ctx
);
856 if (mips32_cpu_support_sync(ejtag_info
))
857 pracc_add(&ctx
, 0, MIPS32_SYNC(ctx
.isa
));
858 if (mips32_cpu_support_hazard_barrier(ejtag_info
))
859 pracc_add(&ctx
, 0, MIPS32_EHB(ctx
.isa
));
860 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
861 pracc_add(&ctx
, 0, MIPS32_NOP
);
862 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
863 if (ctx
.retval
!= ERROR_OK
) {
864 LOG_ERROR("Unable to barrier");
867 pracc_queue_free(&ctx
);
873 int mips32_pracc_write_regs(struct mips32_common
*mips32
)
875 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
876 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
877 uint32_t *gprs
= mips32
->core_regs
.gpr
;
878 uint32_t *c0rs
= mips32
->core_regs
.cp0
;
879 bool fpu_in_64bit
= ((c0rs
[0] & BIT(MIPS32_CP0_STATUS_FR_SHIFT
)) != 0);
880 bool fp_enabled
= ((c0rs
[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT
)) != 0);
881 uint32_t rel
= (ejtag_info
->config
[0] & MIPS32_CONFIG0_AR_MASK
) >> MIPS32_CONFIG0_AR_SHIFT
;
883 pracc_queue_init(&ctx
);
885 uint32_t cp0_write_code
[] = {
886 MIPS32_MTC0(ctx
.isa
, 1, 12, 0), /* move $1 to status */
887 MIPS32_MTLO(ctx
.isa
, 1), /* move $1 to lo */
888 MIPS32_MTHI(ctx
.isa
, 1), /* move $1 to hi */
889 MIPS32_MTC0(ctx
.isa
, 1, 8, 0), /* move $1 to badvaddr */
890 MIPS32_MTC0(ctx
.isa
, 1, 13, 0), /* move $1 to cause*/
891 MIPS32_MTC0(ctx
.isa
, 1, 24, 0), /* move $1 to depc (pc) */
894 uint32_t cp0_write_data
[] = {
909 /* Write CP0 Status Register first, changes on EXL or ERL bits
910 * may lead to different behaviour on writing to other CP0 registers.
912 for (size_t i
= 0; i
< ARRAY_SIZE(cp0_write_code
); i
++) {
913 /* load CP0 value in $1 */
914 pracc_add_li32(&ctx
, 1, cp0_write_data
[i
], 0);
915 /* write value from $1 to CP0 register */
916 pracc_add(&ctx
, 0, cp0_write_code
[i
]);
919 if (mips32_cpu_support_hazard_barrier(ejtag_info
))
920 pracc_add(&ctx
, 0, MIPS32_EHB(ctx
.isa
));
923 if (mips32
->fp_imp
&& fp_enabled
) {
924 uint64_t *fprs
= mips32
->core_regs
.fpr
;
926 for (int i
= 0; i
!= MIPS32_REG_FP_COUNT
; i
++) {
927 uint32_t fp_lo
= fprs
[i
] & 0xffffffff;
928 uint32_t fp_hi
= (fprs
[i
] >> 32) & 0xffffffff;
929 pracc_add_li32(&ctx
, 2, fp_lo
, 0);
930 pracc_add_li32(&ctx
, 3, fp_hi
, 0);
931 pracc_add(&ctx
, 0, MIPS32_MTC1(ctx
.isa
, 2, i
));
932 pracc_add(&ctx
, 0, MIPS32_MTHC1(ctx
.isa
, 3, i
));
935 for (int i
= 0; i
!= MIPS32_REG_FP_COUNT
; i
++) {
936 uint32_t fp_lo
= fprs
[i
] & 0xffffffff;
937 pracc_add_li32(&ctx
, 2, fp_lo
, 0);
938 pracc_add(&ctx
, 0, MIPS32_MTC1(ctx
.isa
, 2, i
));
942 if (rel
> MIPS32_RELEASE_1
)
943 pracc_add(&ctx
, 0, MIPS32_EHB(ctx
.isa
));
946 /* load registers 2 to 31 with li32, optimize */
947 for (int i
= 2; i
< 32; i
++)
948 pracc_add_li32(&ctx
, i
, gprs
[i
], 1);
950 /* load $15 in DeSave */
951 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, 31, 0));
952 /* load upper half word in $1 */
953 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 1, UPPER16((gprs
[1]))));
955 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
)));
956 /* load lower half word in $1 */
957 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 1, 1, LOWER16((gprs
[1]))));
959 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
961 ejtag_info
->reg8
= gprs
[8];
962 ejtag_info
->reg9
= gprs
[9];
963 pracc_queue_free(&ctx
);
967 /* Saves content in `$1` to `DeSave(cp0.31.0)` and loads `MIPS32_PRACC_BASE_ADDR` into `$1` */
968 static void mips32_pracc_store_regs_set_base_addr(struct pracc_queue_info
*ctx
)
970 /* move $1 to COP0 DeSave */
971 pracc_add(ctx
, 0, MIPS32_MTC0(ctx
->isa
, 1, 31, 0));
972 /* $1 = MIP32_PRACC_BASE_ADDR */
973 pracc_add(ctx
, 0, MIPS32_LUI(ctx
->isa
, 1, PRACC_UPPER_BASE_ADDR
));
976 /* This function assumes the address for saving is stored in `$1`.
977 * And that action is performed in `mips32_pracc_set_save_base_addr`.
979 static void mips32_pracc_store_regs_gpr(struct pracc_queue_info
*ctx
, unsigned int offset_gpr
)
981 for (int i
= 2; i
!= 32; i
++)
982 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ offset_gpr
+ (i
* 4),
983 MIPS32_SW(ctx
->isa
, i
, PRACC_OUT_OFFSET
+ offset_gpr
+ (i
* 4), 1));
986 static void mips32_pracc_store_regs_lohi(struct pracc_queue_info
*ctx
)
988 uint32_t lohi_read_code
[] = {
989 MIPS32_MFLO(ctx
->isa
, 8), /* move lo to $8 */
990 MIPS32_MFHI(ctx
->isa
, 8), /* move hi to $8 */
994 for (int i
= 0; i
< 2; i
++) {
995 /* load COP0 needed registers to $8 */
996 pracc_add(ctx
, 0, lohi_read_code
[i
]);
997 /* store $8 at PARAM OUT */
998 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ (i
+ 32) * 4,
999 MIPS32_SW(ctx
->isa
, 8, PRACC_OUT_OFFSET
+ (i
+ 32) * 4, 1));
1003 /* Saves CP0 registers [status, badvaddr, cause, depc] */
1004 static void mips32_pracc_store_regs_cp0_context(struct pracc_queue_info
*ctx
, unsigned int offset_cp0
)
1006 uint32_t cp0_read_code
[] = {
1007 MIPS32_MFC0(ctx
->isa
, 8, 12, 0), /* move status to $8 */
1008 MIPS32_MFC0(ctx
->isa
, 8, 8, 0), /* move badvaddr to $8 */
1009 MIPS32_MFC0(ctx
->isa
, 8, 13, 0), /* move cause to $8 */
1010 MIPS32_MFC0(ctx
->isa
, 8, 24, 0), /* move depc (pc) to $8 */
1014 for (size_t i
= 0; i
< ARRAY_SIZE(cp0_read_code
); i
++) {
1015 size_t offset
= offset_cp0
+ (i
* 4);
1017 /* load COP0 needed registers to $8 */
1018 pracc_add(ctx
, 0, cp0_read_code
[i
]);
1019 /* store $8 at PARAM OUT */
1020 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ offset
,
1021 MIPS32_SW(ctx
->isa
, 8, PRACC_OUT_OFFSET
+ offset
, 1));
1025 /* Loads original content of $1 into $8,
1026 * then store it to the batch data access address.
1027 * Finally it restores $1 from DeSave.
1029 static void mips32_pracc_store_regs_restore(struct pracc_queue_info
*ctx
)
1031 /* move DeSave to $8, reg1 value */
1032 pracc_add(ctx
, 0, MIPS32_MFC0(ctx
->isa
, 8, 31, 0));
1033 /* store reg1 value from $8 to param out */
1034 pracc_add(ctx
, MIPS32_PRACC_PARAM_OUT
+ 4,
1035 MIPS32_SW(ctx
->isa
, 8, PRACC_OUT_OFFSET
+ 4, 1));
1037 /* move COP0 DeSave to $1, restore reg1 */
1038 pracc_add(ctx
, 0, MIPS32_MFC0(ctx
->isa
, 1, 31, 0));
1041 /* This function performs following actions:
1042 * Saves `$1` to `DeSave`,
1043 * then load `PRACC_UPPER_BASE_ADDR` for saving the register data structure into `$1`,
1044 * Saves `$2` ~ `$31` to `PRACC_UPPER_BASE_ADDR + offset_gpr`
1046 * Saves necessary cp0 registers.
1048 static void mips32_pracc_store_regs(struct pracc_queue_info
*ctx
,
1049 unsigned int offset_gpr
, unsigned int offset_cp0
)
1051 mips32_pracc_store_regs_set_base_addr(ctx
);
1052 mips32_pracc_store_regs_gpr(ctx
, offset_gpr
);
1053 mips32_pracc_store_regs_lohi(ctx
);
1054 mips32_pracc_store_regs_cp0_context(ctx
, offset_cp0
);
1055 mips32_pracc_store_regs_restore(ctx
);
1058 int mips32_pracc_read_regs(struct mips32_common
*mips32
)
1060 struct mips_ejtag
*ejtag_info
= &mips32
->ejtag_info
;
1061 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
1062 struct mips32_core_regs
*core_regs
= &mips32
->core_regs
;
1063 unsigned int offset_gpr
= ((uint8_t *)&core_regs
->gpr
[0]) - (uint8_t *)core_regs
;
1064 unsigned int offset_cp0
= ((uint8_t *)&core_regs
->cp0
[0]) - (uint8_t *)core_regs
;
1065 unsigned int offset_fpr
= ((uint8_t *)&core_regs
->fpr
[0]) - (uint8_t *)core_regs
;
1066 unsigned int offset_fpcr
= ((uint8_t *)&core_regs
->fpcr
[0]) - (uint8_t *)core_regs
;
1070 * This procedure has to be in 2 distinctive steps, because we can
1071 * only know whether FP is enabled after reading CP0.
1073 * Step 1: Read everything except CP1 stuff
1074 * Step 2: Read CP1 stuff if FP is implemented
1077 pracc_queue_init(&ctx
);
1079 mips32_pracc_store_regs(&ctx
, offset_gpr
, offset_cp0
);
1082 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
)));
1083 /* load $15 in DeSave */
1084 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, 31, 0));
1086 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, (uint32_t *)&mips32
->core_regs
, 1);
1088 pracc_queue_free(&ctx
);
1090 /* reg8 is saved but not restored, next called function should restore it */
1091 ejtag_info
->reg8
= mips32
->core_regs
.gpr
[8];
1092 ejtag_info
->reg9
= mips32
->core_regs
.gpr
[9];
1094 if (ctx
.retval
!= ERROR_OK
)
1097 /* we only care if FP is actually impl'd and if cp1 is enabled */
1098 /* since we already read cp0 in the prev step */
1099 /* now we know what's in cp0.status */
1100 fp_enabled
= (mips32
->core_regs
.cp0
[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT
)) != 0;
1101 if (mips32
->fp_imp
&& fp_enabled
) {
1102 pracc_queue_init(&ctx
);
1104 mips32_pracc_store_regs_set_base_addr(&ctx
);
1107 pracc_add(&ctx
, 0, MIPS32_CFC1(ctx
.isa
, 8, 31));
1108 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ offset_fpcr
,
1109 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
+ offset_fpcr
, 1));
1112 pracc_add(&ctx
, 0, MIPS32_CFC1(ctx
.isa
, 8, 0));
1113 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ offset_fpcr
+ 4,
1114 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
+ offset_fpcr
+ 4, 1));
1117 if (mips32
->fpu_in_64bit
) {
1118 for (int i
= 0; i
!= 32; i
++) {
1119 size_t offset
= offset_fpr
+ (i
* 8);
1120 /* current pracc implementation (or EJTAG itself) only supports 32b access */
1121 /* so there is no way to use SDC1 */
1124 pracc_add(&ctx
, 0, MIPS32_MFC1(ctx
.isa
, 8, i
));
1125 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ offset
,
1126 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
+ offset
, 1));
1129 pracc_add(&ctx
, 0, MIPS32_MFHC1(ctx
.isa
, 8, i
));
1130 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ offset
+ 4,
1131 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
+ offset
+ 4, 1));
1134 for (int i
= 0; i
!= 32; i
++) {
1135 size_t offset
= offset_fpr
+ (i
* 8);
1136 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ offset
,
1137 MIPS32_SWC1(ctx
.isa
, i
, PRACC_OUT_OFFSET
+ offset
, 1));
1141 mips32_pracc_store_regs_restore(&ctx
);
1144 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
)));
1145 /* load $15 in DeSave */
1146 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, 31, 0));
1148 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, (uint32_t *)&mips32
->core_regs
, 1);
1150 pracc_queue_free(&ctx
);
1156 * mips32_pracc_fastdata_xfer_synchronize_cache - Synchronize cache for fast data transfer
1157 * @param[in] ejtag_info: EJTAG information structure
1158 * @param[in] addr: Starting address for cache synchronization
1159 * @param[in] size: Size of each data element
1160 * @param[in] count: Number of data elements
1162 * @brief Synchronizes the cache for fast data transfer based on
1163 * the specified address and cache configuration.
1164 * If the region is cacheable (write-back cache or write-through cache),
1165 * it synchronizes the cache for the specified range.
1166 * The synchronization is performed using the MIPS32 cache synchronization function.
1168 * @return ERROR_OK on success; error code on failure.
1170 static int mips32_pracc_fastdata_xfer_synchronize_cache(struct mips_ejtag
*ejtag_info
,
1171 uint32_t addr
, int size
, int count
)
1173 int retval
= ERROR_OK
;
1175 if ((KSEGX(addr
) == KSEG1
) || (addr
>= 0xff200000 && addr
<= 0xff3fffff)) // DESEG?
1176 return retval
; /*Nothing to do*/
1181 mips32_cp0_read(ejtag_info
, &conf
, 16, 0);
1183 switch (KSEGX(addr
)) {
1185 cached
= (conf
& MIPS32_CONFIG0_KU_MASK
) >> MIPS32_CONFIG0_KU_SHIFT
;
1188 cached
= (conf
& MIPS32_CONFIG0_K0_MASK
) >> MIPS32_CONFIG0_K0_SHIFT
;
1192 cached
= (conf
& MIPS32_CONFIG0_K23_MASK
) >> MIPS32_CONFIG0_K23_SHIFT
;
1200 * Check cacheability bits coherency algorithm
1201 * is the region cacheable or uncached.
1202 * If cacheable we have to synchronize the cache
1204 if (cached
== 3 || cached
== 0) { /* Write back cache or write through cache */
1205 uint32_t start_addr
= addr
;
1206 uint32_t end_addr
= addr
+ count
* size
;
1207 uint32_t rel
= (conf
& MIPS32_CONFIG0_AR_MASK
) >> MIPS32_CONFIG0_AR_SHIFT
;
1208 /* FIXME: In MIPS Release 6, the encoding of CACHE instr has changed */
1209 if (rel
> MIPS32_RELEASE_2
) {
1210 LOG_DEBUG("Unsupported MIPS Release ( > 5)");
1213 retval
= mips32_pracc_synchronize_cache(ejtag_info
, start_addr
, end_addr
, cached
, rel
);
1219 /* fastdata upload/download requires an initialized working area
1220 * to load the download code; it should not be called otherwise
1221 * fetch order from the fastdata area
1226 int mips32_pracc_fastdata_xfer(struct mips_ejtag
*ejtag_info
, struct working_area
*source
,
1227 int write_t
, uint32_t addr
, int count
, uint32_t *buf
)
1229 uint32_t isa
= ejtag_info
->isa
? 1 : 0;
1230 uint32_t handler_code
[] = {
1231 /* r15 points to the start of this code */
1232 MIPS32_SW(isa
, 8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
1233 MIPS32_SW(isa
, 9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
1234 MIPS32_SW(isa
, 10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
1235 MIPS32_SW(isa
, 11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
1236 /* start of fastdata area in t0 */
1237 MIPS32_LUI(isa
, 8, UPPER16(MIPS32_PRACC_FASTDATA_AREA
)),
1238 MIPS32_ORI(isa
, 8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA
)),
1239 MIPS32_LW(isa
, 9, 0, 8), /* start addr in t1 */
1240 mips32_cpu_support_sync(ejtag_info
) ? MIPS32_SYNC(isa
) : MIPS32_NOP
, /* barrier for ordering */
1241 MIPS32_LW(isa
, 10, 0, 8), /* end addr to t2 */
1242 mips32_cpu_support_sync(ejtag_info
) ? MIPS32_SYNC(isa
) : MIPS32_NOP
, /* barrier for ordering */
1244 write_t
? MIPS32_LW(isa
, 11, 0, 8) : MIPS32_LW(isa
, 11, 0, 9), /* from xfer area : from memory */
1245 write_t
? MIPS32_SW(isa
, 11, 0, 9) : MIPS32_SW(isa
, 11, 0, 8), /* to memory : to xfer area */
1247 mips32_cpu_support_sync(ejtag_info
) ? MIPS32_SYNC(isa
) : MIPS32_NOP
, /* barrier for ordering */
1249 MIPS32_BNE(isa
, 10, 9, NEG16(4 << isa
)), /* bne $t2,t1,loop */
1250 MIPS32_ADDI(isa
, 9, 9, 4), /* addi t1,t1,4 */
1252 MIPS32_LW(isa
, 8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
1253 MIPS32_LW(isa
, 9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
1254 MIPS32_LW(isa
, 10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
1255 MIPS32_LW(isa
, 11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
1257 MIPS32_LUI(isa
, 15, UPPER16(MIPS32_PRACC_TEXT
)),
1258 MIPS32_ORI(isa
, 15, 15, LOWER16(MIPS32_PRACC_TEXT
) | isa
), /* isa bit for JR instr */
1259 mips32_cpu_support_hazard_barrier(ejtag_info
)
1260 ? MIPS32_JRHB(isa
, 15)
1261 : MIPS32_JR(isa
, 15), /* jr start */
1262 MIPS32_MFC0(isa
, 15, 31, 0), /* move COP0 DeSave to $15 */
1265 if (source
->size
< MIPS32_FASTDATA_HANDLER_SIZE
)
1266 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
1268 pracc_swap16_array(ejtag_info
, handler_code
, ARRAY_SIZE(handler_code
));
1269 /* write program into RAM */
1270 if (write_t
!= ejtag_info
->fast_access_save
) {
1271 mips32_pracc_write_mem(ejtag_info
, source
->address
, 4, ARRAY_SIZE(handler_code
), handler_code
);
1272 /* save previous operation to speed to any consecutive read/writes */
1273 ejtag_info
->fast_access_save
= write_t
;
1276 LOG_DEBUG("%s using 0x%.8" TARGET_PRIxADDR
" for write handler", __func__
, source
->address
);
1278 uint32_t jmp_code
[] = {
1279 MIPS32_LUI(isa
, 15, UPPER16(source
->address
)), /* load addr of jump in $15 */
1280 MIPS32_ORI(isa
, 15, 15, LOWER16(source
->address
) | isa
), /* isa bit for JR instr */
1281 mips32_cpu_support_hazard_barrier(ejtag_info
)
1282 ? MIPS32_JRHB(isa
, 15)
1283 : MIPS32_JR(isa
, 15), /* jump to ram program */
1284 isa
? MIPS32_XORI(isa
, 15, 15, 1) : MIPS32_NOP
, /* drop isa bit, needed for LW/SW instructions */
1287 pracc_swap16_array(ejtag_info
, jmp_code
, ARRAY_SIZE(jmp_code
));
1289 /* execute jump code, with no address check */
1290 for (unsigned i
= 0; i
< ARRAY_SIZE(jmp_code
); i
++) {
1291 int retval
= wait_for_pracc_rw(ejtag_info
);
1292 if (retval
!= ERROR_OK
)
1295 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
1296 mips_ejtag_drscan_32_out(ejtag_info
, jmp_code
[i
]);
1298 /* Clear the access pending bit (let the processor eat!) */
1299 mips32_pracc_finish(ejtag_info
);
1302 /* wait PrAcc pending bit for FASTDATA write, read address */
1303 int retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
1304 if (retval
!= ERROR_OK
)
1307 /* next fetch to dmseg should be in FASTDATA_AREA, check */
1308 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_FASTDATA_AREA
)
1311 /* Send the load start address */
1312 uint32_t val
= addr
;
1313 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1314 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1316 retval
= wait_for_pracc_rw(ejtag_info
);
1317 if (retval
!= ERROR_OK
)
1320 /* Send the load end address */
1321 val
= addr
+ (count
- 1) * 4;
1322 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1323 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1325 unsigned num_clocks
= 0; /* like in legacy code */
1326 if (ejtag_info
->mode
!= 0)
1327 num_clocks
= ((uint64_t)(ejtag_info
->scan_delay
) * adapter_get_speed_khz() + 500000) / 1000000;
1329 for (int i
= 0; i
< count
; i
++) {
1330 jtag_add_clocks(num_clocks
);
1331 mips_ejtag_fastdata_scan(ejtag_info
, write_t
, buf
++);
1334 retval
= jtag_execute_queue();
1335 if (retval
!= ERROR_OK
) {
1336 LOG_ERROR("fastdata load failed");
1340 retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
1341 if (retval
!= ERROR_OK
)
1344 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_TEXT
)
1345 LOG_ERROR("mini program did not return to start");
1347 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)