1 /***************************************************************************
2 * Copyright (C) 2008 by Spencer Oliver *
3 * spen@spen-soft.co.uk *
5 * Copyright (C) 2008 by David T.L. Wong *
7 * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> *
9 * Copyright (C) 2011 by Drasko DRASKOVIC *
10 * drasko.draskovic@gmail.com *
12 * This program is free software; you can redistribute it and/or modify *
13 * it under the terms of the GNU General Public License as published by *
14 * the Free Software Foundation; either version 2 of the License, or *
15 * (at your option) any later version. *
17 * This program is distributed in the hope that it will be useful, *
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
20 * GNU General Public License for more details. *
22 * You should have received a copy of the GNU General Public License *
23 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
24 ***************************************************************************/
27 * This version has optimized assembly routines for 32 bit operations:
30 * - write array of words
32 * One thing to be aware of is that the MIPS32 cpu will execute the
33 * instruction after a branch instruction (one delay slot).
40 * The LW $1, ($2 +100) instruction is also executed. If this is
41 * not wanted a NOP can be inserted:
48 * or the code can be changed to:
54 * The original code contained NOPs. I have removed these and moved
57 * These changes result in a 35% speed increase when programming an
60 * More improvement could be gained if the registers do no need
61 * to be preserved but in that case the routines should be aware
62 * OpenOCD is used as a flash programmer or as a debug tool.
71 #include <helper/time_support.h>
74 #include "mips32_pracc.h"
76 static int wait_for_pracc_rw(struct mips_ejtag
*ejtag_info
)
78 int64_t then
= timeval_ms();
80 /* wait for the PrAcc to become "1" */
81 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_CONTROL
);
84 ejtag_info
->pa_ctrl
= ejtag_info
->ejtag_ctrl
;
85 int retval
= mips_ejtag_drscan_32(ejtag_info
, &ejtag_info
->pa_ctrl
);
86 if (retval
!= ERROR_OK
)
89 if (ejtag_info
->pa_ctrl
& EJTAG_CTRL_PRACC
)
92 int64_t timeout
= timeval_ms() - then
;
94 LOG_DEBUG("DEBUGMODULE: No memory access in progress!");
95 return ERROR_JTAG_DEVICE_ERROR
;
102 /* Shift in control and address for a new processor access, save them in ejtag_info */
103 static int mips32_pracc_read_ctrl_addr(struct mips_ejtag
*ejtag_info
)
105 int retval
= wait_for_pracc_rw(ejtag_info
);
106 if (retval
!= ERROR_OK
)
109 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ADDRESS
);
111 ejtag_info
->pa_addr
= 0;
112 return mips_ejtag_drscan_32(ejtag_info
, &ejtag_info
->pa_addr
);
115 /* Finish processor access */
116 static void mips32_pracc_finish(struct mips_ejtag
*ejtag_info
)
118 uint32_t ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
119 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_CONTROL
);
120 mips_ejtag_drscan_32_out(ejtag_info
, ctrl
);
123 int mips32_pracc_clean_text_jump(struct mips_ejtag
*ejtag_info
)
125 uint32_t jt_code
= MIPS32_J(ejtag_info
->isa
, MIPS32_PRACC_TEXT
);
126 pracc_swap16_array(ejtag_info
, &jt_code
, 1);
127 /* do 3 0/nops to clean pipeline before a jump to pracc text, NOP in delay slot */
128 for (int i
= 0; i
!= 5; i
++) {
130 int retval
= wait_for_pracc_rw(ejtag_info
);
131 if (retval
!= ERROR_OK
)
134 /* Data or instruction out */
135 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
136 uint32_t data
= (i
== 3) ? jt_code
: MIPS32_NOP
;
137 mips_ejtag_drscan_32_out(ejtag_info
, data
);
140 mips32_pracc_finish(ejtag_info
);
143 if (ejtag_info
->mode
!= 0) /* async mode support only for MIPS ... */
146 for (int i
= 0; i
!= 2; i
++) {
147 int retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
148 if (retval
!= ERROR_OK
)
151 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_TEXT
) { /* LEXRA/BMIPS ?, shift out another NOP, max 2 */
152 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
153 mips_ejtag_drscan_32_out(ejtag_info
, MIPS32_NOP
);
154 mips32_pracc_finish(ejtag_info
);
162 int mips32_pracc_exec(struct mips_ejtag
*ejtag_info
, struct pracc_queue_info
*ctx
,
163 uint32_t *param_out
, bool check_last
)
166 int store_pending
= 0; /* increases with every store instr at dmseg, decreases with every store pa */
167 uint32_t max_store_addr
= 0; /* for store pa address testing */
168 bool restart
= 0; /* restarting control */
169 int restart_count
= 0;
171 bool final_check
= 0; /* set to 1 if in final checks after function code shifted out */
172 bool pass
= 0; /* to check the pass through pracc text after function code sent */
177 if (restart_count
< 3) { /* max 3 restarts allowed */
178 retval
= mips32_pracc_clean_text_jump(ejtag_info
);
179 if (retval
!= ERROR_OK
)
182 return ERROR_JTAG_DEVICE_ERROR
;
186 LOG_DEBUG("restarting code");
189 retval
= mips32_pracc_read_ctrl_addr(ejtag_info
); /* update current pa info: control and address */
190 if (retval
!= ERROR_OK
)
193 /* Check for read or write access */
194 if (ejtag_info
->pa_ctrl
& EJTAG_CTRL_PRNW
) { /* write/store access */
195 /* Check for pending store from a previous store instruction at dmseg */
196 if (store_pending
== 0) {
197 LOG_DEBUG("unexpected write at address %" PRIx32
, ejtag_info
->pa_addr
);
198 if (code_count
< 2) { /* allow for restart */
202 return ERROR_JTAG_DEVICE_ERROR
;
205 if (ejtag_info
->pa_addr
< MIPS32_PRACC_PARAM_OUT
||
206 ejtag_info
->pa_addr
> max_store_addr
) {
207 LOG_DEBUG("writing at unexpected address %" PRIx32
, ejtag_info
->pa_addr
);
208 return ERROR_JTAG_DEVICE_ERROR
;
213 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
214 retval
= mips_ejtag_drscan_32(ejtag_info
, &data
);
215 if (retval
!= ERROR_OK
)
218 /* store data at param out, address based offset */
219 param_out
[(ejtag_info
->pa_addr
- MIPS32_PRACC_PARAM_OUT
) / 4] = data
;
222 } else { /* read/fetch access */
223 if (!final_check
) { /* executing function code */
225 if (ejtag_info
->pa_addr
!= (MIPS32_PRACC_TEXT
+ code_count
* 4)) {
226 LOG_DEBUG("reading at unexpected address %" PRIx32
", expected %x",
227 ejtag_info
->pa_addr
, MIPS32_PRACC_TEXT
+ code_count
* 4);
229 /* restart code execution only in some cases */
230 if (code_count
== 1 && ejtag_info
->pa_addr
== MIPS32_PRACC_TEXT
&&
231 restart_count
== 0) {
232 LOG_DEBUG("restarting, without clean jump");
236 } else if (code_count
< 2) {
240 return ERROR_JTAG_DEVICE_ERROR
;
242 /* check for store instruction at dmseg */
243 uint32_t store_addr
= ctx
->pracc_list
[code_count
].addr
;
244 if (store_addr
!= 0) {
245 if (store_addr
> max_store_addr
)
246 max_store_addr
= store_addr
;
250 instr
= ctx
->pracc_list
[code_count
++].instr
;
251 if (code_count
== ctx
->code_count
) /* last instruction, start final check */
254 } else { /* final check after function code shifted out */
256 if (ejtag_info
->pa_addr
== MIPS32_PRACC_TEXT
) {
257 if (!pass
) { /* first pass through pracc text */
258 if (store_pending
== 0) /* done, normal exit */
260 pass
= 1; /* pracc text passed */
261 code_count
= 0; /* restart code count */
263 LOG_DEBUG("unexpected second pass through pracc text");
264 return ERROR_JTAG_DEVICE_ERROR
;
267 if (ejtag_info
->pa_addr
!= (MIPS32_PRACC_TEXT
+ code_count
* 4)) {
268 LOG_DEBUG("unexpected read address in final check: %"
269 PRIx32
", expected: %x", ejtag_info
->pa_addr
,
270 MIPS32_PRACC_TEXT
+ code_count
* 4);
271 return ERROR_JTAG_DEVICE_ERROR
;
275 if ((code_count
- ctx
->code_count
) > 1) { /* allow max 2 instr delay slot */
276 LOG_DEBUG("failed to jump back to pracc text");
277 return ERROR_JTAG_DEVICE_ERROR
;
280 if (code_count
> 10) { /* enough, abandone */
281 LOG_DEBUG("execution abandoned, store pending: %d", store_pending
);
282 return ERROR_JTAG_DEVICE_ERROR
;
284 instr
= MIPS32_NOP
; /* shift out NOPs instructions */
288 /* Send instruction out */
289 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
290 mips_ejtag_drscan_32_out(ejtag_info
, instr
);
292 /* finish processor access, let the processor eat! */
293 mips32_pracc_finish(ejtag_info
);
295 if (final_check
&& !check_last
) /* last instr, don't check, execute and exit */
296 return jtag_execute_queue();
298 if (store_pending
== 0 && pass
) { /* store access done, but after passing pracc text */
299 LOG_DEBUG("warning: store access pass pracc text");
305 inline void pracc_queue_init(struct pracc_queue_info
*ctx
)
307 ctx
->retval
= ERROR_OK
;
309 ctx
->store_count
= 0;
311 ctx
->pracc_list
= NULL
;
312 ctx
->isa
= ctx
->ejtag_info
->isa
? 1 : 0;
315 void pracc_add(struct pracc_queue_info
*ctx
, uint32_t addr
, uint32_t instr
)
317 if (ctx
->retval
!= ERROR_OK
) /* On previous out of memory, return */
319 if (ctx
->code_count
== ctx
->max_code
) {
320 void *p
= realloc(ctx
->pracc_list
, sizeof(pa_list
) * (ctx
->max_code
+ PRACC_BLOCK
));
322 ctx
->max_code
+= PRACC_BLOCK
;
325 ctx
->retval
= ERROR_FAIL
; /* Out of memory */
329 ctx
->pracc_list
[ctx
->code_count
].instr
= instr
;
330 ctx
->pracc_list
[ctx
->code_count
++].addr
= addr
;
335 void pracc_add_li32(struct pracc_queue_info
*ctx
, uint32_t reg_num
, uint32_t data
, bool optimize
)
337 if (LOWER16(data
) == 0 && optimize
)
338 pracc_add(ctx
, 0, MIPS32_LUI(ctx
->isa
, reg_num
, UPPER16(data
))); /* load only upper value */
339 else if (UPPER16(data
) == 0 && optimize
)
340 pracc_add(ctx
, 0, MIPS32_ORI(ctx
->isa
, reg_num
, 0, LOWER16(data
))); /* load only lower */
342 pracc_add(ctx
, 0, MIPS32_LUI(ctx
->isa
, reg_num
, UPPER16(data
))); /* load upper and lower */
343 pracc_add(ctx
, 0, MIPS32_ORI(ctx
->isa
, reg_num
, reg_num
, LOWER16(data
)));
347 inline void pracc_queue_free(struct pracc_queue_info
*ctx
)
349 if (ctx
->pracc_list
!= NULL
)
350 free(ctx
->pracc_list
);
353 int mips32_pracc_queue_exec(struct mips_ejtag
*ejtag_info
, struct pracc_queue_info
*ctx
,
354 uint32_t *buf
, bool check_last
)
356 if (ctx
->retval
!= ERROR_OK
) {
357 LOG_ERROR("Out of memory");
361 if (ejtag_info
->isa
&& ejtag_info
->endianness
)
362 for (int i
= 0; i
!= ctx
->code_count
; i
++)
363 ctx
->pracc_list
[i
].instr
= SWAP16(ctx
->pracc_list
[i
].instr
);
365 if (ejtag_info
->mode
== 0)
366 return mips32_pracc_exec(ejtag_info
, ctx
, buf
, check_last
);
376 } *scan_in
= malloc(sizeof(union scan_in
) * (ctx
->code_count
+ ctx
->store_count
));
377 if (scan_in
== NULL
) {
378 LOG_ERROR("Out of memory");
382 unsigned num_clocks
=
383 ((uint64_t)(ejtag_info
->scan_delay
) * jtag_get_speed_khz() + 500000) / 1000000;
385 uint32_t ejtag_ctrl
= ejtag_info
->ejtag_ctrl
& ~EJTAG_CTRL_PRACC
;
386 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_ALL
);
389 for (int i
= 0; i
!= ctx
->code_count
; i
++) {
390 jtag_add_clocks(num_clocks
);
391 mips_ejtag_add_scan_96(ejtag_info
, ejtag_ctrl
, ctx
->pracc_list
[i
].instr
,
392 scan_in
[scan_count
++].scan_96
);
394 /* Check store address from previous instruction, if not the first */
395 if (i
> 0 && ctx
->pracc_list
[i
- 1].addr
) {
396 jtag_add_clocks(num_clocks
);
397 mips_ejtag_add_scan_96(ejtag_info
, ejtag_ctrl
, 0, scan_in
[scan_count
++].scan_96
);
401 int retval
= jtag_execute_queue(); /* execute queued scans */
402 if (retval
!= ERROR_OK
)
405 uint32_t fetch_addr
= MIPS32_PRACC_TEXT
; /* start address */
407 for (int i
= 0; i
!= ctx
->code_count
; i
++) { /* verify every pracc access */
408 /* check pracc bit */
409 ejtag_ctrl
= buf_get_u32(scan_in
[scan_count
].scan_32
.ctrl
, 0, 32);
410 uint32_t addr
= buf_get_u32(scan_in
[scan_count
].scan_32
.addr
, 0, 32);
411 if (!(ejtag_ctrl
& EJTAG_CTRL_PRACC
)) {
412 LOG_ERROR("Error: access not pending count: %d", scan_count
);
416 if (ejtag_ctrl
& EJTAG_CTRL_PRNW
) {
417 LOG_ERROR("Not a fetch/read access, count: %d", scan_count
);
421 if (addr
!= fetch_addr
) {
422 LOG_ERROR("Fetch addr mismatch, read: %" PRIx32
" expected: %" PRIx32
" count: %d",
423 addr
, fetch_addr
, scan_count
);
430 /* check if previous intrucction is a store instruction at dmesg */
431 if (i
> 0 && ctx
->pracc_list
[i
- 1].addr
) {
432 uint32_t store_addr
= ctx
->pracc_list
[i
- 1].addr
;
433 ejtag_ctrl
= buf_get_u32(scan_in
[scan_count
].scan_32
.ctrl
, 0, 32);
434 addr
= buf_get_u32(scan_in
[scan_count
].scan_32
.addr
, 0, 32);
436 if (!(ejtag_ctrl
& EJTAG_CTRL_PRNW
)) {
437 LOG_ERROR("Not a store/write access, count: %d", scan_count
);
441 if (addr
!= store_addr
) {
442 LOG_ERROR("Store address mismatch, read: %" PRIx32
" expected: %" PRIx32
" count: %d",
443 addr
, store_addr
, scan_count
);
447 int buf_index
= (addr
- MIPS32_PRACC_PARAM_OUT
) / 4;
448 buf
[buf_index
] = buf_get_u32(scan_in
[scan_count
].scan_32
.data
, 0, 32);
457 int mips32_pracc_read_u32(struct mips_ejtag
*ejtag_info
, uint32_t addr
, uint32_t *buf
)
459 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
460 pracc_queue_init(&ctx
);
462 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
463 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 8, UPPER16((addr
+ 0x8000)))); /* load $8 with modified upper addr */
464 pracc_add(&ctx
, 0, MIPS32_LW(ctx
.isa
, 8, LOWER16(addr
), 8)); /* lw $8, LOWER16(addr)($8) */
465 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
466 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* sw $8,PRACC_OUT_OFFSET($15) */
467 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
468 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
469 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* move COP0 DeSave to $15 */
471 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, buf
, 1);
472 pracc_queue_free(&ctx
);
476 int mips32_pracc_read_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, void *buf
)
478 if (count
== 1 && size
== 4)
479 return mips32_pracc_read_u32(ejtag_info
, addr
, (uint32_t *)buf
);
481 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
482 pracc_queue_init(&ctx
);
484 uint32_t *data
= NULL
;
486 data
= malloc(256 * sizeof(uint32_t));
488 LOG_ERROR("Out of memory");
493 uint32_t *buf32
= buf
;
494 uint16_t *buf16
= buf
;
501 int this_round_count
= (count
> 256) ? 256 : count
;
502 uint32_t last_upper_base_addr
= UPPER16((addr
+ 0x8000));
504 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
505 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 9, last_upper_base_addr
)); /* upper memory addr to $9 */
507 for (int i
= 0; i
!= this_round_count
; i
++) { /* Main code loop */
508 uint32_t upper_base_addr
= UPPER16((addr
+ 0x8000));
509 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper addr in $9 */
510 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 9, upper_base_addr
));
511 last_upper_base_addr
= upper_base_addr
;
514 if (size
== 4) /* load from memory to $8 */
515 pracc_add(&ctx
, 0, MIPS32_LW(ctx
.isa
, 8, LOWER16(addr
), 9));
517 pracc_add(&ctx
, 0, MIPS32_LHU(ctx
.isa
, 8, LOWER16(addr
), 9));
519 pracc_add(&ctx
, 0, MIPS32_LBU(ctx
.isa
, 8, LOWER16(addr
), 9));
521 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ i
* 4, /* store $8 at param out */
522 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
+ i
* 4, 15));
525 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
526 pracc_add_li32(&ctx
, 9, ejtag_info
->reg9
, 0); /* restore $9 */
528 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
529 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
532 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, buf32
, 1);
533 if (ctx
.retval
!= ERROR_OK
)
535 buf32
+= this_round_count
;
537 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, data
, 1);
538 if (ctx
.retval
!= ERROR_OK
)
541 uint32_t *data_p
= data
;
542 for (int i
= 0; i
!= this_round_count
; i
++) {
544 *buf16
++ = *data_p
++;
549 count
-= this_round_count
;
552 pracc_queue_free(&ctx
);
558 int mips32_cp0_read(struct mips_ejtag
*ejtag_info
, uint32_t *val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
560 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
561 pracc_queue_init(&ctx
);
563 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
564 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 8, cp0_reg
, cp0_sel
)); /* move cp0 reg / sel to $8 */
565 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
566 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* store $8 to pracc_out */
567 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
568 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 8, UPPER16(ejtag_info
->reg8
))); /* restore upper 16 bits of $8 */
569 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
570 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 8, LOWER16(ejtag_info
->reg8
))); /* restore lower 16 bits of $8 */
572 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, val
, 1);
573 pracc_queue_free(&ctx
);
577 int mips32_cp0_write(struct mips_ejtag
*ejtag_info
, uint32_t val
, uint32_t cp0_reg
, uint32_t cp0_sel
)
579 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
580 pracc_queue_init(&ctx
);
582 pracc_add_li32(&ctx
, 15, val
, 0); /* Load val to $15 */
584 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, cp0_reg
, cp0_sel
)); /* write $15 to cp0 reg / sel */
585 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
586 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
588 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
589 pracc_queue_free(&ctx
);
594 * \b mips32_pracc_sync_cache
596 * Synchronize Caches to Make Instruction Writes Effective
597 * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set,
598 * Document Number: MD00086, Revision 2.00, June 9, 2003)
600 * When the instruction stream is written, the SYNCI instruction should be used
601 * in conjunction with other instructions to make the newly-written instructions effective.
604 * A program that loads another program into memory is actually writing the D- side cache.
605 * The instructions it has loaded can't be executed until they reach the I-cache.
607 * After the instructions have been written, the loader should arrange
608 * to write back any containing D-cache line and invalidate any locations
609 * already in the I-cache.
611 * If the cache coherency attribute (CCA) is set to zero, it's a write through cache, there is no need
614 * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
615 * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
616 * That is, it arranges a D-cache write-back (if CCA = 3) and an I-cache invalidate.
618 * The line size is obtained with the rdhwr SYNCI_Step in release 2 or from cp0 config 1 register in release 1.
620 static int mips32_pracc_synchronize_cache(struct mips_ejtag
*ejtag_info
,
621 uint32_t start_addr
, uint32_t end_addr
, int cached
, int rel
)
623 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
624 pracc_queue_init(&ctx
);
626 /** Find cache line size in bytes */
628 if (rel
) { /* Release 2 (rel = 1) */
629 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, PRACC_UPPER_BASE_ADDR
)); /* $15 = MIPS32_PRACC_BASE_ADDR */
631 pracc_add(&ctx
, 0, MIPS32_RDHWR(ctx
.isa
, 8, MIPS32_SYNCI_STEP
)); /* load synci_step value to $8 */
633 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
,
634 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
, 15)); /* store $8 to pracc_out */
636 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
638 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
639 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
641 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, &clsiz
, 1);
642 if (ctx
.retval
!= ERROR_OK
)
645 } else { /* Release 1 (rel = 0) */
647 ctx
.retval
= mips32_cp0_read(ejtag_info
, &conf
, 16, 1);
648 if (ctx
.retval
!= ERROR_OK
)
651 uint32_t dl
= (conf
& MIPS32_CONFIG1_DL_MASK
) >> MIPS32_CONFIG1_DL_SHIFT
;
653 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... max dl=6 => 128 bytes cache line size */
660 goto exit
; /* Nothing to do */
662 /* make sure clsiz is power of 2 */
663 if (clsiz
& (clsiz
- 1)) {
664 LOG_DEBUG("clsiz must be power of 2");
665 ctx
.retval
= ERROR_FAIL
;
669 /* make sure start_addr and end_addr have the same offset inside de cache line */
670 start_addr
|= clsiz
- 1;
671 end_addr
|= clsiz
- 1;
677 uint32_t last_upper_base_addr
= UPPER16((start_addr
+ 0x8000));
679 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, last_upper_base_addr
)); /* load upper memory base addr to $15 */
681 while (start_addr
<= end_addr
) { /* main loop */
682 uint32_t upper_base_addr
= UPPER16((start_addr
+ 0x8000));
683 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper addr in $15 */
684 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, upper_base_addr
));
685 last_upper_base_addr
= upper_base_addr
;
687 if (rel
) /* synci instruction, offset($15) */
688 pracc_add(&ctx
, 0, MIPS32_SYNCI(ctx
.isa
, LOWER16(start_addr
), 15));
691 if (cached
== 3) /* cache Hit_Writeback_D, offset($15) */
692 pracc_add(&ctx
, 0, MIPS32_CACHE(ctx
.isa
, MIPS32_CACHE_D_HIT_WRITEBACK
,
693 LOWER16(start_addr
), 15));
694 /* cache Hit_Invalidate_I, offset($15) */
695 pracc_add(&ctx
, 0, MIPS32_CACHE(ctx
.isa
, MIPS32_CACHE_I_HIT_INVALIDATE
,
696 LOWER16(start_addr
), 15));
700 if (count
== 256 && start_addr
<= end_addr
) { /* more ?, then execute code list */
701 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* to start */
702 pracc_add(&ctx
, 0, MIPS32_NOP
); /* nop in delay slot */
704 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
705 if (ctx
.retval
!= ERROR_OK
)
708 ctx
.code_count
= 0; /* reset counters for another loop */
713 pracc_add(&ctx
, 0, MIPS32_SYNC(ctx
.isa
));
714 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
715 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave*/
717 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
719 pracc_queue_free(&ctx
);
723 static int mips32_pracc_write_mem_generic(struct mips_ejtag
*ejtag_info
,
724 uint32_t addr
, int size
, int count
, const void *buf
)
726 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
727 pracc_queue_init(&ctx
);
729 const uint32_t *buf32
= buf
;
730 const uint16_t *buf16
= buf
;
731 const uint8_t *buf8
= buf
;
737 int this_round_count
= (count
> 128) ? 128 : count
;
738 uint32_t last_upper_base_addr
= UPPER16((addr
+ 0x8000));
739 /* load $15 with memory base address */
740 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, last_upper_base_addr
));
742 for (int i
= 0; i
!= this_round_count
; i
++) {
743 uint32_t upper_base_addr
= UPPER16((addr
+ 0x8000));
744 if (last_upper_base_addr
!= upper_base_addr
) { /* if needed, change upper address in $15*/
745 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 15, upper_base_addr
));
746 last_upper_base_addr
= upper_base_addr
;
750 pracc_add_li32(&ctx
, 8, *buf32
, 1); /* load with li32, optimize */
751 pracc_add(&ctx
, 0, MIPS32_SW(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store word to mem */
754 } else if (size
== 2) {
755 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 0, *buf16
)); /* load lower value */
756 pracc_add(&ctx
, 0, MIPS32_SH(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store half word */
760 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 8, 0, *buf8
)); /* load lower value */
761 pracc_add(&ctx
, 0, MIPS32_SB(ctx
.isa
, 8, LOWER16(addr
), 15)); /* store byte */
767 pracc_add_li32(&ctx
, 8, ejtag_info
->reg8
, 0); /* restore $8 */
769 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
770 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 15, 31, 0)); /* restore $15 from DeSave */
772 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
773 if (ctx
.retval
!= ERROR_OK
)
775 count
-= this_round_count
;
778 pracc_queue_free(&ctx
);
782 int mips32_pracc_write_mem(struct mips_ejtag
*ejtag_info
, uint32_t addr
, int size
, int count
, const void *buf
)
784 int retval
= mips32_pracc_write_mem_generic(ejtag_info
, addr
, size
, count
, buf
);
785 if (retval
!= ERROR_OK
)
789 * If we are in the cacheable region and cache is activated,
790 * we must clean D$ (if Cache Coherency Attribute is set to 3) + invalidate I$ after we did the write,
791 * so that changes do not continue to live only in D$ (if CCA = 3), but to be
792 * replicated in I$ also (maybe we wrote the istructions)
797 if ((KSEGX(addr
) == KSEG1
) || ((addr
>= 0xff200000) && (addr
<= 0xff3fffff)))
798 return retval
; /*Nothing to do*/
800 mips32_cp0_read(ejtag_info
, &conf
, 16, 0);
802 switch (KSEGX(addr
)) {
804 cached
= (conf
& MIPS32_CONFIG0_KU_MASK
) >> MIPS32_CONFIG0_KU_SHIFT
;
807 cached
= (conf
& MIPS32_CONFIG0_K0_MASK
) >> MIPS32_CONFIG0_K0_SHIFT
;
811 cached
= (conf
& MIPS32_CONFIG0_K23_MASK
) >> MIPS32_CONFIG0_K23_SHIFT
;
819 * Check cachablitiy bits coherency algorithm
820 * is the region cacheable or uncached.
821 * If cacheable we have to synchronize the cache
823 if (cached
== 3 || cached
== 0) { /* Write back cache or write through cache */
824 uint32_t start_addr
= addr
;
825 uint32_t end_addr
= addr
+ count
* size
;
826 uint32_t rel
= (conf
& MIPS32_CONFIG0_AR_MASK
) >> MIPS32_CONFIG0_AR_SHIFT
;
828 LOG_DEBUG("Unknown release in cache code");
831 retval
= mips32_pracc_synchronize_cache(ejtag_info
, start_addr
, end_addr
, cached
, rel
);
837 int mips32_pracc_write_regs(struct mips_ejtag
*ejtag_info
, uint32_t *regs
)
839 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
840 pracc_queue_init(&ctx
);
842 uint32_t cp0_write_code
[] = {
843 MIPS32_MTC0(ctx
.isa
, 1, 12, 0), /* move $1 to status */
844 MIPS32_MTLO(ctx
.isa
, 1), /* move $1 to lo */
845 MIPS32_MTHI(ctx
.isa
, 1), /* move $1 to hi */
846 MIPS32_MTC0(ctx
.isa
, 1, 8, 0), /* move $1 to badvaddr */
847 MIPS32_MTC0(ctx
.isa
, 1, 13, 0), /* move $1 to cause*/
848 MIPS32_MTC0(ctx
.isa
, 1, 24, 0), /* move $1 to depc (pc) */
851 /* load registers 2 to 31 with li32, optimize */
852 for (int i
= 2; i
< 32; i
++)
853 pracc_add_li32(&ctx
, i
, regs
[i
], 1);
855 for (int i
= 0; i
!= 6; i
++) {
856 pracc_add_li32(&ctx
, 1, regs
[i
+ 32], 0); /* load CPO value in $1 */
857 pracc_add(&ctx
, 0, cp0_write_code
[i
]); /* write value from $1 to CPO register */
859 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, 31, 0)); /* load $15 in DeSave */
860 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 1, UPPER16((regs
[1])))); /* load upper half word in $1 */
861 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
862 pracc_add(&ctx
, 0, MIPS32_ORI(ctx
.isa
, 1, 1, LOWER16((regs
[1])))); /* load lower half word in $1 */
864 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, NULL
, 1);
866 ejtag_info
->reg8
= regs
[8];
867 ejtag_info
->reg9
= regs
[9];
868 pracc_queue_free(&ctx
);
872 int mips32_pracc_read_regs(struct mips_ejtag
*ejtag_info
, uint32_t *regs
)
874 struct pracc_queue_info ctx
= {.ejtag_info
= ejtag_info
};
875 pracc_queue_init(&ctx
);
877 uint32_t cp0_read_code
[] = {
878 MIPS32_MFC0(ctx
.isa
, 8, 12, 0), /* move status to $8 */
879 MIPS32_MFLO(ctx
.isa
, 8), /* move lo to $8 */
880 MIPS32_MFHI(ctx
.isa
, 8), /* move hi to $8 */
881 MIPS32_MFC0(ctx
.isa
, 8, 8, 0), /* move badvaddr to $8 */
882 MIPS32_MFC0(ctx
.isa
, 8, 13, 0), /* move cause to $8 */
883 MIPS32_MFC0(ctx
.isa
, 8, 24, 0), /* move depc (pc) to $8 */
886 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 1, 31, 0)); /* move $1 to COP0 DeSave */
887 pracc_add(&ctx
, 0, MIPS32_LUI(ctx
.isa
, 1, PRACC_UPPER_BASE_ADDR
)); /* $1 = MIP32_PRACC_BASE_ADDR */
889 for (int i
= 2; i
!= 32; i
++) /* store GPR's 2 to 31 */
890 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ (i
* 4),
891 MIPS32_SW(ctx
.isa
, i
, PRACC_OUT_OFFSET
+ (i
* 4), 1));
893 for (int i
= 0; i
!= 6; i
++) {
894 pracc_add(&ctx
, 0, cp0_read_code
[i
]); /* load COP0 needed registers to $8 */
895 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ (i
+ 32) * 4, /* store $8 at PARAM OUT */
896 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
+ (i
+ 32) * 4, 1));
898 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 8, 31, 0)); /* move DeSave to $8, reg1 value */
899 pracc_add(&ctx
, MIPS32_PRACC_PARAM_OUT
+ 4, /* store reg1 value from $8 to param out */
900 MIPS32_SW(ctx
.isa
, 8, PRACC_OUT_OFFSET
+ 4, 1));
902 pracc_add(&ctx
, 0, MIPS32_MFC0(ctx
.isa
, 1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */
903 pracc_add(&ctx
, 0, MIPS32_B(ctx
.isa
, NEG16((ctx
.code_count
+ 1) << ctx
.isa
))); /* jump to start */
904 pracc_add(&ctx
, 0, MIPS32_MTC0(ctx
.isa
, 15, 31, 0)); /* load $15 in DeSave */
906 ctx
.retval
= mips32_pracc_queue_exec(ejtag_info
, &ctx
, regs
, 1);
908 ejtag_info
->reg8
= regs
[8]; /* reg8 is saved but not restored, next called function should restore it */
909 ejtag_info
->reg9
= regs
[9];
910 pracc_queue_free(&ctx
);
914 /* fastdata upload/download requires an initialized working area
915 * to load the download code; it should not be called otherwise
916 * fetch order from the fastdata area
921 int mips32_pracc_fastdata_xfer(struct mips_ejtag
*ejtag_info
, struct working_area
*source
,
922 int write_t
, uint32_t addr
, int count
, uint32_t *buf
)
924 uint32_t isa
= ejtag_info
->isa
? 1 : 0;
925 uint32_t handler_code
[] = {
926 /* r15 points to the start of this code */
927 MIPS32_SW(isa
, 8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
928 MIPS32_SW(isa
, 9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
929 MIPS32_SW(isa
, 10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
930 MIPS32_SW(isa
, 11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
931 /* start of fastdata area in t0 */
932 MIPS32_LUI(isa
, 8, UPPER16(MIPS32_PRACC_FASTDATA_AREA
)),
933 MIPS32_ORI(isa
, 8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA
)),
934 MIPS32_LW(isa
, 9, 0, 8), /* start addr in t1 */
935 MIPS32_LW(isa
, 10, 0, 8), /* end addr to t2 */
937 write_t
? MIPS32_LW(isa
, 11, 0, 8) : MIPS32_LW(isa
, 11, 0, 9), /* from xfer area : from memory */
938 write_t
? MIPS32_SW(isa
, 11, 0, 9) : MIPS32_SW(isa
, 11, 0, 8), /* to memory : to xfer area */
940 MIPS32_BNE(isa
, 10, 9, NEG16(3 << isa
)), /* bne $t2,t1,loop */
941 MIPS32_ADDI(isa
, 9, 9, 4), /* addi t1,t1,4 */
943 MIPS32_LW(isa
, 8, MIPS32_FASTDATA_HANDLER_SIZE
- 4, 15),
944 MIPS32_LW(isa
, 9, MIPS32_FASTDATA_HANDLER_SIZE
- 8, 15),
945 MIPS32_LW(isa
, 10, MIPS32_FASTDATA_HANDLER_SIZE
- 12, 15),
946 MIPS32_LW(isa
, 11, MIPS32_FASTDATA_HANDLER_SIZE
- 16, 15),
948 MIPS32_LUI(isa
, 15, UPPER16(MIPS32_PRACC_TEXT
)),
949 MIPS32_ORI(isa
, 15, 15, LOWER16(MIPS32_PRACC_TEXT
) | isa
), /* isa bit for JR instr */
950 MIPS32_JR(isa
, 15), /* jr start */
951 MIPS32_MFC0(isa
, 15, 31, 0), /* move COP0 DeSave to $15 */
954 if (source
->size
< MIPS32_FASTDATA_HANDLER_SIZE
)
955 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE
;
957 pracc_swap16_array(ejtag_info
, handler_code
, ARRAY_SIZE(handler_code
));
958 /* write program into RAM */
959 if (write_t
!= ejtag_info
->fast_access_save
) {
960 mips32_pracc_write_mem(ejtag_info
, source
->address
, 4, ARRAY_SIZE(handler_code
), handler_code
);
961 /* save previous operation to speed to any consecutive read/writes */
962 ejtag_info
->fast_access_save
= write_t
;
965 LOG_DEBUG("%s using 0x%.8" TARGET_PRIxADDR
" for write handler", __func__
, source
->address
);
967 uint32_t jmp_code
[] = {
968 MIPS32_LUI(isa
, 15, UPPER16(source
->address
)), /* load addr of jump in $15 */
969 MIPS32_ORI(isa
, 15, 15, LOWER16(source
->address
) | isa
), /* isa bit for JR instr */
970 MIPS32_JR(isa
, 15), /* jump to ram program */
971 isa
? MIPS32_XORI(isa
, 15, 15, 1) : MIPS32_NOP
, /* drop isa bit, needed for LW/SW instructions */
974 pracc_swap16_array(ejtag_info
, jmp_code
, ARRAY_SIZE(jmp_code
));
976 /* execute jump code, with no address check */
977 for (unsigned i
= 0; i
< ARRAY_SIZE(jmp_code
); i
++) {
978 int retval
= wait_for_pracc_rw(ejtag_info
);
979 if (retval
!= ERROR_OK
)
982 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_DATA
);
983 mips_ejtag_drscan_32_out(ejtag_info
, jmp_code
[i
]);
985 /* Clear the access pending bit (let the processor eat!) */
986 mips32_pracc_finish(ejtag_info
);
989 /* wait PrAcc pending bit for FASTDATA write, read address */
990 int retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
991 if (retval
!= ERROR_OK
)
994 /* next fetch to dmseg should be in FASTDATA_AREA, check */
995 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_FASTDATA_AREA
)
998 /* Send the load start address */
1000 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1001 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1003 retval
= wait_for_pracc_rw(ejtag_info
);
1004 if (retval
!= ERROR_OK
)
1007 /* Send the load end address */
1008 val
= addr
+ (count
- 1) * 4;
1009 mips_ejtag_set_instr(ejtag_info
, EJTAG_INST_FASTDATA
);
1010 mips_ejtag_fastdata_scan(ejtag_info
, 1, &val
);
1012 unsigned num_clocks
= 0; /* like in legacy code */
1013 if (ejtag_info
->mode
!= 0)
1014 num_clocks
= ((uint64_t)(ejtag_info
->scan_delay
) * jtag_get_speed_khz() + 500000) / 1000000;
1016 for (int i
= 0; i
< count
; i
++) {
1017 jtag_add_clocks(num_clocks
);
1018 mips_ejtag_fastdata_scan(ejtag_info
, write_t
, buf
++);
1021 retval
= jtag_execute_queue();
1022 if (retval
!= ERROR_OK
) {
1023 LOG_ERROR("fastdata load failed");
1027 retval
= mips32_pracc_read_ctrl_addr(ejtag_info
);
1028 if (retval
!= ERROR_OK
)
1031 if (ejtag_info
->pa_addr
!= MIPS32_PRACC_TEXT
)
1032 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)