target/mips32: optimize pracc access
[openocd.git] / src / target / mips32_pracc.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 /***************************************************************************
4 * Copyright (C) 2008 by Spencer Oliver *
5 * spen@spen-soft.co.uk *
6 * *
7 * Copyright (C) 2008 by David T.L. Wong *
8 * *
9 * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> *
10 * *
11 * Copyright (C) 2011 by Drasko DRASKOVIC *
12 * drasko.draskovic@gmail.com *
13 ***************************************************************************/
14
15 /*
16 * This version has optimized assembly routines for 32 bit operations:
17 * - read word
18 * - write word
19 * - write array of words
20 *
21 * One thing to be aware of is that the MIPS32 cpu will execute the
22 * instruction after a branch instruction (one delay slot).
23 *
24 * For example:
25 * LW $2, ($5 +10)
26 * B foo
27 * LW $1, ($2 +100)
28 *
29 * The LW $1, ($2 +100) instruction is also executed. If this is
30 * not wanted a NOP can be inserted:
31 *
32 * LW $2, ($5 +10)
33 * B foo
34 * NOP
35 * LW $1, ($2 +100)
36 *
37 * or the code can be changed to:
38 *
39 * B foo
40 * LW $2, ($5 +10)
41 * LW $1, ($2 +100)
42 *
43 * The original code contained NOPs. I have removed these and moved
44 * the branches.
45 *
46 * These changes result in a 35% speed increase when programming an
47 * external flash.
48 *
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.
52 *
53 * Nico Coesel
54 */
55
56 #ifdef HAVE_CONFIG_H
57 #include "config.h"
58 #endif
59
60 #include <helper/align.h>
61 #include <helper/time_support.h>
62 #include <jtag/adapter.h>
63
64 #include "mips_cpu.h"
65 #include "mips32.h"
66 #include "mips32_pracc.h"
67
68 static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info)
69 {
70 int64_t then = timeval_ms();
71
72 /* wait for the PrAcc to become "1" */
73 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
74
75 while (1) {
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)
79 return retval;
80
81 if (ejtag_info->pa_ctrl & EJTAG_CTRL_PRACC)
82 break;
83
84 int64_t timeout = timeval_ms() - then;
85 if (timeout > 1000) {
86 LOG_DEBUG("DEBUGMODULE: No memory access in progress!");
87 return ERROR_JTAG_DEVICE_ERROR;
88 }
89 }
90
91 return ERROR_OK;
92 }
93
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)
96 {
97 int retval = wait_for_pracc_rw(ejtag_info);
98 if (retval != ERROR_OK)
99 return retval;
100
101 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
102
103 ejtag_info->pa_addr = 0;
104 return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->pa_addr);
105 }
106
107 /* Finish processor access */
108 static void mips32_pracc_finish(struct mips_ejtag *ejtag_info)
109 {
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);
113 }
114
115 static int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info)
116 {
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++) {
121 /* Wait for pracc */
122 int retval = wait_for_pracc_rw(ejtag_info);
123 if (retval != ERROR_OK)
124 return retval;
125
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);
130
131 /* finish pa */
132 mips32_pracc_finish(ejtag_info);
133 }
134
135 if (ejtag_info->mode != 0) /* async mode support only for MIPS ... */
136 return ERROR_OK;
137
138 for (int i = 0; i != 2; i++) {
139 int retval = mips32_pracc_read_ctrl_addr(ejtag_info);
140 if (retval != ERROR_OK)
141 return retval;
142
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);
147 } else
148 break;
149 }
150
151 return ERROR_OK;
152 }
153
154 static int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx,
155 uint32_t *param_out, bool check_last)
156 {
157 int code_count = 0;
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;
162 uint32_t instr = 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 */
165 int retval;
166
167 while (1) {
168 if (restart) {
169 if (restart_count < 3) { /* max 3 restarts allowed */
170 retval = mips32_pracc_clean_text_jump(ejtag_info);
171 if (retval != ERROR_OK)
172 return retval;
173 } else
174 return ERROR_JTAG_DEVICE_ERROR;
175 restart_count++;
176 restart = 0;
177 code_count = 0;
178 LOG_DEBUG("restarting code");
179 }
180
181 retval = mips32_pracc_read_ctrl_addr(ejtag_info); /* update current pa info: control and address */
182 if (retval != ERROR_OK)
183 return retval;
184
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 */
191 restart = 1;
192 continue;
193 } else
194 return ERROR_JTAG_DEVICE_ERROR;
195 } else {
196 /* check address */
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;
201 }
202 }
203 /* read data */
204 uint32_t data = 0;
205 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
206 retval = mips_ejtag_drscan_32(ejtag_info, &data);
207 if (retval != ERROR_OK)
208 return retval;
209
210 /* store data at param out, address based offset */
211 param_out[(ejtag_info->pa_addr - MIPS32_PRACC_PARAM_OUT) / 4] = data;
212 store_pending--;
213
214 } else { /* read/fetch access */
215 if (!final_check) { /* executing function code */
216 /* check address */
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);
220
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");
225 restart_count++;
226 code_count = 0;
227 continue;
228 } else if (code_count < 2) {
229 restart = 1;
230 continue;
231 }
232 return ERROR_JTAG_DEVICE_ERROR;
233 }
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;
239 store_pending++;
240 }
241
242 instr = ctx->pracc_list[code_count++].instr;
243 if (code_count == ctx->code_count) /* last instruction, start final check */
244 final_check = 1;
245
246 } else { /* final check after function code shifted out */
247 /* check address */
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 */
251 return ERROR_OK;
252 pass = 1; /* pracc text passed */
253 code_count = 0; /* restart code count */
254 } else {
255 LOG_DEBUG("unexpected second pass through pracc text");
256 return ERROR_JTAG_DEVICE_ERROR;
257 }
258 } else {
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;
264 }
265 }
266 if (!pass) {
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;
270 }
271 } else
272 if (code_count > 10) { /* enough, abandon */
273 LOG_DEBUG("execution abandoned, store pending: %d", store_pending);
274 return ERROR_JTAG_DEVICE_ERROR;
275 }
276 instr = MIPS32_NOP; /* shift out NOPs instructions */
277 code_count++;
278 }
279
280 /* Send instruction out */
281 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
282 mips_ejtag_drscan_32_out(ejtag_info, instr);
283 }
284 /* finish processor access, let the processor eat! */
285 mips32_pracc_finish(ejtag_info);
286
287 if (final_check && !check_last) /* last instr, don't check, execute and exit */
288 return jtag_execute_queue();
289
290 if (store_pending == 0 && pass) { /* store access done, but after passing pracc text */
291 LOG_DEBUG("warning: store access pass pracc text");
292 return ERROR_OK;
293 }
294 }
295 }
296
297 inline void pracc_queue_init(struct pracc_queue_info *ctx)
298 {
299 ctx->retval = ERROR_OK;
300 ctx->code_count = 0;
301 ctx->store_count = 0;
302 ctx->max_code = 0;
303 ctx->pracc_list = NULL;
304 ctx->isa = ctx->ejtag_info->isa ? 1 : 0;
305 }
306
307 void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr)
308 {
309 if (ctx->retval != ERROR_OK) /* On previous out of memory, return */
310 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));
313 if (p) {
314 ctx->max_code += PRACC_BLOCK;
315 ctx->pracc_list = p;
316 } else {
317 ctx->retval = ERROR_FAIL; /* Out of memory */
318 return;
319 }
320 }
321 ctx->pracc_list[ctx->code_count].instr = instr;
322 ctx->pracc_list[ctx->code_count++].addr = addr;
323 if (addr)
324 ctx->store_count++;
325 }
326
327 static void pracc_add_li32(struct pracc_queue_info *ctx, uint32_t reg_num, uint32_t data, bool optimize)
328 {
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 */
333 else {
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)));
336 }
337 }
338
339 inline void pracc_queue_free(struct pracc_queue_info *ctx)
340 {
341 free(ctx->pracc_list);
342 }
343
344 int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx,
345 uint32_t *buf, bool check_last)
346 {
347 if (ctx->retval != ERROR_OK) {
348 LOG_ERROR("Out of memory");
349 return ERROR_FAIL;
350 }
351
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);
355
356 if (ejtag_info->mode == 0)
357 return mips32_pracc_exec(ejtag_info, ctx, buf, check_last);
358
359 union scan_in {
360 uint8_t scan_96[12];
361 struct {
362 uint8_t ctrl[4];
363 uint8_t data[4];
364 uint8_t addr[4];
365 } scan_32;
366
367 } *scan_in = malloc(sizeof(union scan_in) * (ctx->code_count + ctx->store_count));
368 if (!scan_in) {
369 LOG_ERROR("Out of memory");
370 return ERROR_FAIL;
371 }
372
373 unsigned num_clocks =
374 ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000;
375
376 uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
377 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ALL);
378
379 int scan_count = 0;
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);
384
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);
389 }
390 }
391
392 int retval = jtag_execute_queue(); /* execute queued scans */
393 if (retval != ERROR_OK)
394 goto exit;
395
396 uint32_t fetch_addr = MIPS32_PRACC_TEXT; /* start address */
397 scan_count = 0;
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);
404 retval = ERROR_FAIL;
405 goto exit;
406 }
407 if (ejtag_ctrl & EJTAG_CTRL_PRNW) {
408 LOG_ERROR("Not a fetch/read access, count: %d", scan_count);
409 retval = ERROR_FAIL;
410 goto exit;
411 }
412 if (addr != fetch_addr) {
413 LOG_ERROR("Fetch addr mismatch, read: %" PRIx32 " expected: %" PRIx32 " count: %d",
414 addr, fetch_addr, scan_count);
415 retval = ERROR_FAIL;
416 goto exit;
417 }
418 fetch_addr += 4;
419 scan_count++;
420
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);
426
427 if (!(ejtag_ctrl & EJTAG_CTRL_PRNW)) {
428 LOG_ERROR("Not a store/write access, count: %d", scan_count);
429 retval = ERROR_FAIL;
430 goto exit;
431 }
432 if (addr != store_addr) {
433 LOG_ERROR("Store address mismatch, read: %" PRIx32 " expected: %" PRIx32 " count: %d",
434 addr, store_addr, scan_count);
435 retval = ERROR_FAIL;
436 goto exit;
437 }
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);
440 scan_count++;
441 }
442 }
443 exit:
444 free(scan_in);
445 return retval;
446 }
447
448 static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf)
449 {
450 struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
451 pracc_queue_init(&ctx);
452
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 */
463
464 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf, 1);
465 pracc_queue_free(&ctx);
466 return ctx.retval;
467 }
468
469 int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
470 {
471 if (count == 1 && size == 4)
472 return mips32_pracc_read_u32(ejtag_info, addr, (uint32_t *)buf);
473
474 struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
475 pracc_queue_init(&ctx);
476
477 uint32_t *data = NULL;
478 if (size != 4) {
479 data = malloc(256 * sizeof(uint32_t));
480 if (!data) {
481 LOG_ERROR("Out of memory");
482 goto exit;
483 }
484 }
485
486 uint32_t *buf32 = buf;
487 uint16_t *buf16 = buf;
488 uint8_t *buf8 = buf;
489
490 while (count) {
491 ctx.code_count = 0;
492 ctx.store_count = 0;
493
494 int this_round_count = (count > 256) ? 256 : count;
495 uint32_t last_upper_base_addr = UPPER16((addr + 0x8000));
496
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 */
499
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;
505 }
506
507 if (size == 4) /* load from memory to $8 */
508 pracc_add(&ctx, 0, MIPS32_LW(ctx.isa, 8, LOWER16(addr), 9));
509 else if (size == 2)
510 pracc_add(&ctx, 0, MIPS32_LHU(ctx.isa, 8, LOWER16(addr), 9));
511 else
512 pracc_add(&ctx, 0, MIPS32_LBU(ctx.isa, 8, LOWER16(addr), 9));
513
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));
518 addr += size;
519 }
520 pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */
521 pracc_add_li32(&ctx, 9, ejtag_info->reg9, 0); /* restore $9 */
522
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 */
525
526 if (size == 4) {
527 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf32, 1);
528 if (ctx.retval != ERROR_OK)
529 goto exit;
530 buf32 += this_round_count;
531 } else {
532 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, data, 1);
533 if (ctx.retval != ERROR_OK)
534 goto exit;
535
536 uint32_t *data_p = data;
537 for (int i = 0; i != this_round_count; i++) {
538 if (size == 2)
539 *buf16++ = *data_p++;
540 else
541 *buf8++ = *data_p++;
542 }
543 }
544 count -= this_round_count;
545 }
546 exit:
547 pracc_queue_free(&ctx);
548 free(data);
549 return ctx.retval;
550 }
551
552 int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel)
553 {
554 struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
555 pracc_queue_init(&ctx);
556
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 */
567
568 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1);
569 pracc_queue_free(&ctx);
570 return ctx.retval;
571 }
572
573 int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel)
574 {
575 struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
576 pracc_queue_init(&ctx);
577
578 pracc_add_li32(&ctx, 15, val, 0); /* Load val to $15 */
579
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 */
585
586 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
587 pracc_queue_free(&ctx);
588 return ctx.retval;
589 }
590
591 /**
592 * \b mips32_pracc_sync_cache
593 *
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)
597 *
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.
600 *
601 * Explanation :
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.
604 *
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.
608 *
609 * If the cache coherency attribute (CCA) is set to zero, it's a write through cache, there is no need
610 * to write back.
611 *
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.
615 *
616 * The line size is obtained with the rdhwr SYNCI_Step in release 2 or from cp0 config 1 register in release 1.
617 */
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)
620 {
621 struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
622 pracc_queue_init(&ctx);
623
624 /** Find cache line size in bytes */
625 uint32_t clsiz;
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 */
628
629 pracc_add(&ctx, 0, MIPS32_RDHWR(ctx.isa, 8, MIPS32_SYNCI_STEP)); /* load synci_step value to $8 */
630
631 pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT,
632 MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */
633
634 pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */
635
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 */
638
639 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, &clsiz, 1);
640 if (ctx.retval != ERROR_OK)
641 goto exit;
642
643 } else { /* Release 1 (rel = 0) */
644 uint32_t conf;
645 ctx.retval = mips32_cp0_read(ejtag_info, &conf, 16, 1);
646 if (ctx.retval != ERROR_OK)
647 goto exit;
648
649 uint32_t dl = (conf & MIPS32_CONFIG1_DL_MASK) >> MIPS32_CONFIG1_DL_SHIFT;
650
651 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... max dl=6 => 128 bytes cache line size */
652 clsiz = 0x2 << dl;
653 if (dl == 0)
654 clsiz = 0;
655 }
656
657 if (clsiz == 0)
658 goto exit; /* Nothing to do */
659
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;
664 goto exit;
665 }
666
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;
670
671 ctx.code_count = 0;
672 ctx.store_count = 0;
673
674 int count = 0;
675 uint32_t last_upper_base_addr = UPPER16((start_addr + 0x8000));
676
677 pracc_add(&ctx, 0, MIPS32_LUI(ctx.isa, 15, last_upper_base_addr)); /* load upper memory base addr to $15 */
678
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;
684 }
685 if (rel) /* synci instruction, offset($15) */
686 pracc_add(&ctx, 0, MIPS32_SYNCI(ctx.isa, LOWER16(start_addr), 15));
687
688 else {
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));
695 }
696 start_addr += clsiz;
697 count++;
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 */
701
702 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
703 if (ctx.retval != ERROR_OK)
704 goto exit;
705
706 ctx.code_count = 0; /* reset counters for another loop */
707 ctx.store_count = 0;
708 count = 0;
709 }
710 }
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*/
714
715 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
716 exit:
717 pracc_queue_free(&ctx);
718 return ctx.retval;
719 }
720
721 static int mips32_pracc_write_mem_generic(struct mips_ejtag *ejtag_info,
722 uint32_t addr, int size, int count, const void *buf)
723 {
724 struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
725 pracc_queue_init(&ctx);
726
727 const uint32_t *buf32 = buf;
728 const uint16_t *buf16 = buf;
729 const uint8_t *buf8 = buf;
730
731 while (count) {
732 ctx.code_count = 0;
733 ctx.store_count = 0;
734
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));
739
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;
745 }
746
747 if (size == 4) {
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 */
750 buf32++;
751
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 */
755 buf16++;
756
757 } else {
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 */
760 buf8++;
761 }
762 addr += size;
763 }
764
765 pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */
766
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 */
769
770 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
771 if (ctx.retval != ERROR_OK)
772 goto exit;
773 count -= this_round_count;
774 }
775 exit:
776 pracc_queue_free(&ctx);
777 return ctx.retval;
778 }
779
780 int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf)
781 {
782 int retval = mips32_pracc_write_mem_generic(ejtag_info, addr, size, count, buf);
783 if (retval != ERROR_OK)
784 return retval;
785
786 /**
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)
791 */
792 uint32_t conf = 0;
793 int cached = 0;
794
795 if ((KSEGX(addr) == KSEG1) || ((addr >= 0xff200000) && (addr <= 0xff3fffff)))
796 return retval; /*Nothing to do*/
797
798 /* Reads Config0 */
799 mips32_cp0_read(ejtag_info, &conf, 16, 0);
800
801 switch (KSEGX(addr)) {
802 case KUSEG:
803 cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT;
804 break;
805 case KSEG0:
806 cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT;
807 break;
808 case KSEG2:
809 case KSEG3:
810 cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT;
811 break;
812 default:
813 /* what ? */
814 break;
815 }
816
817 /**
818 * Check cacheability bits coherency algorithm
819 * is the region cacheable or uncached.
820 * If cacheable we have to synchronize the cache
821 */
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)");
829 return ERROR_FAIL;
830 }
831 retval = mips32_pracc_synchronize_cache(ejtag_info, start_addr, end_addr, cached, rel);
832 } else {
833 struct pracc_queue_info ctx = {.ejtag_info = ejtag_info};
834
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");
845 retval = ctx.retval;
846 }
847 pracc_queue_free(&ctx);
848 }
849
850 return retval;
851 }
852
853 int mips32_pracc_write_regs(struct mips32_common *mips32)
854 {
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;
859
860 pracc_queue_init(&ctx);
861
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) */
869 };
870
871 uint32_t cp0_write_data[] = {
872 /* status */
873 c0rs[0],
874 /* lo */
875 gprs[32],
876 /* hi */
877 gprs[33],
878 /* badvaddr */
879 c0rs[1],
880 /* cause */
881 c0rs[2],
882 /* depc (pc) */
883 c0rs[3],
884 };
885
886 /* Write CP0 Status Register first, changes on EXL or ERL bits
887 * may lead to different behaviour on writing to other CP0 registers.
888 */
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]);
894 }
895
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);
901
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]))));
906 /* jump to start */
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]))));
910
911 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
912
913 ejtag_info->reg8 = gprs[8];
914 ejtag_info->reg9 = gprs[9];
915 pracc_queue_free(&ctx);
916 return ctx.retval;
917 }
918
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)
921 {
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));
926 }
927
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`.
930 */
931 static void mips32_pracc_store_regs_gpr(struct pracc_queue_info *ctx, unsigned int offset_gpr)
932 {
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));
936 }
937
938 static void mips32_pracc_store_regs_lohi(struct pracc_queue_info *ctx)
939 {
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 */
943 };
944
945 /* store lo & hi */
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));
952 }
953 }
954
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)
957 {
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 */
963 };
964
965 /* store cp0 */
966 for (size_t i = 0; i < ARRAY_SIZE(cp0_read_code); i++) {
967 size_t offset = offset_cp0 + (i * 4);
968
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));
974 }
975 }
976
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.
980 */
981 static void mips32_pracc_store_regs_restore(struct pracc_queue_info *ctx)
982 {
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));
988
989 /* move COP0 DeSave to $1, restore reg1 */
990 pracc_add(ctx, 0, MIPS32_MFC0(ctx->isa, 1, 31, 0));
991 }
992
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`
997 * Saves HI and LO,
998 * Saves necessary cp0 registers.
999 */
1000 static void mips32_pracc_store_regs(struct pracc_queue_info *ctx,
1001 unsigned int offset_gpr, unsigned int offset_cp0)
1002 {
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);
1008 }
1009
1010 int mips32_pracc_read_regs(struct mips32_common *mips32)
1011 {
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;
1017
1018 /*
1019 * This procedure has to be in 2 distinctive steps, because we can
1020 * only know whether FP is enabled after reading CP0.
1021 *
1022 * Step 1: Read everything except CP1 stuff
1023 * Step 2: Read CP1 stuff if FP is implemented
1024 */
1025
1026 pracc_queue_init(&ctx);
1027
1028 mips32_pracc_store_regs(&ctx, offset_gpr, offset_cp0);
1029
1030 /* jump to start */
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));
1034
1035 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, (uint32_t *)&mips32->core_regs, 1);
1036
1037 pracc_queue_free(&ctx);
1038
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];
1042
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 */
1047
1048 return ctx.retval;
1049 }
1050
1051 /**
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
1057 *
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.
1063 *
1064 * @return ERROR_OK on success; error code on failure.
1065 */
1066 static int mips32_pracc_fastdata_xfer_synchronize_cache(struct mips_ejtag *ejtag_info,
1067 uint32_t addr, int size, int count)
1068 {
1069 int retval = ERROR_OK;
1070
1071 if ((KSEGX(addr) == KSEG1) || (addr >= 0xff200000 && addr <= 0xff3fffff)) // DESEG?
1072 return retval; /*Nothing to do*/
1073
1074 int cached = 0;
1075 uint32_t conf = 0;
1076
1077 mips32_cp0_read(ejtag_info, &conf, 16, 0);
1078
1079 switch (KSEGX(addr)) {
1080 case KUSEG:
1081 cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT;
1082 break;
1083 case KSEG0:
1084 cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT;
1085 break;
1086 case KSEG2:
1087 case KSEG3:
1088 cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT;
1089 break;
1090 default:
1091 /* what ? */
1092 break;
1093 }
1094
1095 /**
1096 * Check cacheability bits coherency algorithm
1097 * is the region cacheable or uncached.
1098 * If cacheable we have to synchronize the cache
1099 */
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)");
1107 return ERROR_FAIL;
1108 }
1109 retval = mips32_pracc_synchronize_cache(ejtag_info, start_addr, end_addr, cached, rel);
1110 }
1111
1112 return retval;
1113 }
1114
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
1118 * 1. start addr
1119 * 2. end addr
1120 * 3. data ...
1121 */
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)
1124 {
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 */
1139 /* loop: */
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 */
1142
1143 mips32_cpu_support_sync(ejtag_info) ? MIPS32_SYNC(isa) : MIPS32_NOP, /* barrier for ordering */
1144
1145 MIPS32_BNE(isa, 10, 9, NEG16(4 << isa)), /* bne $t2,t1,loop */
1146 MIPS32_ADDI(isa, 9, 9, 4), /* addi t1,t1,4 */
1147
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),
1152
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 */
1159 };
1160
1161 if (source->size < MIPS32_FASTDATA_HANDLER_SIZE)
1162 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
1163
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;
1170 }
1171
1172 LOG_DEBUG("%s using 0x%.8" TARGET_PRIxADDR " for write handler", __func__, source->address);
1173
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 */
1181 };
1182
1183 pracc_swap16_array(ejtag_info, jmp_code, ARRAY_SIZE(jmp_code));
1184
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)
1189 return retval;
1190
1191 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
1192 mips_ejtag_drscan_32_out(ejtag_info, jmp_code[i]);
1193
1194 /* Clear the access pending bit (let the processor eat!) */
1195 mips32_pracc_finish(ejtag_info);
1196 }
1197
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)
1201 return retval;
1202
1203 /* next fetch to dmseg should be in FASTDATA_AREA, check */
1204 if (ejtag_info->pa_addr != MIPS32_PRACC_FASTDATA_AREA)
1205 return ERROR_FAIL;
1206
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);
1211
1212 retval = wait_for_pracc_rw(ejtag_info);
1213 if (retval != ERROR_OK)
1214 return retval;
1215
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);
1220
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;
1224
1225 for (int i = 0; i < count; i++) {
1226 jtag_add_clocks(num_clocks);
1227 mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++);
1228 }
1229
1230 retval = jtag_execute_queue();
1231 if (retval != ERROR_OK) {
1232 LOG_ERROR("fastdata load failed");
1233 return retval;
1234 }
1235
1236 retval = mips32_pracc_read_ctrl_addr(ejtag_info);
1237 if (retval != ERROR_OK)
1238 return retval;
1239
1240 if (ejtag_info->pa_addr != MIPS32_PRACC_TEXT)
1241 LOG_ERROR("mini program did not return to start");
1242
1243 return mips32_pracc_fastdata_xfer_synchronize_cache(ejtag_info, addr, 4, count);
1244 }

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)