73242463888a3db8d145b0026ff32b2e3d94e38d
[openocd.git] / src / target / mips32_pracc.c
1 /***************************************************************************
2 * Copyright (C) 2008 by Spencer Oliver *
3 * spen@spen-soft.co.uk *
4 * *
5 * Copyright (C) 2008 by David T.L. Wong *
6 * *
7 * Copyright (C) 2009 by David N. Claffey <dnclaffey@gmail.com> *
8 * *
9 * Copyright (C) 2011 by Drasko DRASKOVIC *
10 * drasko.draskovic@gmail.com *
11 * *
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. *
16 * *
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. *
21 * *
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 ***************************************************************************/
25
26 /*
27 * This version has optimized assembly routines for 32 bit operations:
28 * - read word
29 * - write word
30 * - write array of words
31 *
32 * One thing to be aware of is that the MIPS32 cpu will execute the
33 * instruction after a branch instruction (one delay slot).
34 *
35 * For example:
36 * LW $2, ($5 +10)
37 * B foo
38 * LW $1, ($2 +100)
39 *
40 * The LW $1, ($2 +100) instruction is also executed. If this is
41 * not wanted a NOP can be inserted:
42 *
43 * LW $2, ($5 +10)
44 * B foo
45 * NOP
46 * LW $1, ($2 +100)
47 *
48 * or the code can be changed to:
49 *
50 * B foo
51 * LW $2, ($5 +10)
52 * LW $1, ($2 +100)
53 *
54 * The original code contained NOPs. I have removed these and moved
55 * the branches.
56 *
57 * These changes result in a 35% speed increase when programming an
58 * external flash.
59 *
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.
63 *
64 * Nico Coesel
65 */
66
67 #ifdef HAVE_CONFIG_H
68 #include "config.h"
69 #endif
70
71 #include <helper/time_support.h>
72
73 #include "mips32.h"
74 #include "mips32_pracc.h"
75
76 static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info)
77 {
78 int64_t then = timeval_ms();
79
80 /* wait for the PrAcc to become "1" */
81 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
82
83 while (1) {
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)
87 return retval;
88
89 if (ejtag_info->pa_ctrl & EJTAG_CTRL_PRACC)
90 break;
91
92 int64_t timeout = timeval_ms() - then;
93 if (timeout > 1000) {
94 LOG_DEBUG("DEBUGMODULE: No memory access in progress!");
95 return ERROR_JTAG_DEVICE_ERROR;
96 }
97 }
98
99 return ERROR_OK;
100 }
101
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)
104 {
105 int retval = wait_for_pracc_rw(ejtag_info);
106 if (retval != ERROR_OK)
107 return retval;
108
109 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
110
111 ejtag_info->pa_addr = 0;
112 return mips_ejtag_drscan_32(ejtag_info, &ejtag_info->pa_addr);
113 }
114
115 /* Finish processor access */
116 static void mips32_pracc_finish(struct mips_ejtag *ejtag_info)
117 {
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);
121 }
122
123 int mips32_pracc_clean_text_jump(struct mips_ejtag *ejtag_info)
124 {
125 uint32_t jt_code = MIPS32_J((0x0FFFFFFF & MIPS32_PRACC_TEXT) >> 2);
126
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++) {
129 /* Wait for pracc */
130 int retval = wait_for_pracc_rw(ejtag_info);
131 if (retval != ERROR_OK)
132 return retval;
133
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);
138
139 /* finish pa */
140 mips32_pracc_finish(ejtag_info);
141 }
142
143 if (ejtag_info->mode != 0) /* async mode support only for MIPS ... */
144 return ERROR_OK;
145
146 for (int i = 0; i != 2; i++) {
147 int retval = mips32_pracc_read_ctrl_addr(ejtag_info);
148 if (retval != ERROR_OK)
149 return retval;
150
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);
155 } else
156 break;
157 }
158
159 return ERROR_OK;
160 }
161
162 int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx,
163 uint32_t *param_out, bool check_last)
164 {
165 int code_count = 0;
166 int store_pending = 0; /* increases with every store instruction 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;
170 uint32_t instr = 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 */
173 int retval;
174
175 while (1) {
176 if (restart) {
177 if (restart_count < 3) { /* max 3 restarts allowed */
178 retval = mips32_pracc_clean_text_jump(ejtag_info);
179 if (retval != ERROR_OK)
180 return retval;
181 } else
182 return ERROR_JTAG_DEVICE_ERROR;
183 restart_count++;
184 restart = 0;
185 code_count = 0;
186 LOG_DEBUG("restarting code");
187 }
188
189 retval = mips32_pracc_read_ctrl_addr(ejtag_info); /* update current pa info: control and address */
190 if (retval != ERROR_OK)
191 return retval;
192
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 */
199 restart = 1;
200 continue;
201 } else
202 return ERROR_JTAG_DEVICE_ERROR;
203 } else {
204 /* check address */
205 if (ejtag_info->pa_addr < MIPS32_PRACC_PARAM_OUT || ejtag_info->pa_addr > max_store_addr) {
206
207 LOG_DEBUG("writing at unexpected address %" PRIx32, ejtag_info->pa_addr);
208 return ERROR_JTAG_DEVICE_ERROR;
209 }
210 }
211 /* read data */
212 uint32_t data = 0;
213 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
214 retval = mips_ejtag_drscan_32(ejtag_info, &data);
215 if (retval != ERROR_OK)
216 return retval;
217
218 /* store data at param out, address based offset */
219 param_out[(ejtag_info->pa_addr - MIPS32_PRACC_PARAM_OUT) / 4] = data;
220 store_pending--;
221
222 } else { /* read/fetch access */
223 if (!final_check) { /* executing function code */
224 /* check address */
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);
228
229 /* restart code execution only in some cases */
230 if (code_count == 1 && ejtag_info->pa_addr == MIPS32_PRACC_TEXT && restart_count == 0) {
231 LOG_DEBUG("restarting, without clean jump");
232 restart_count++;
233 code_count = 0;
234 continue;
235 } else if (code_count < 2) {
236 restart = 1;
237 continue;
238 }
239 return ERROR_JTAG_DEVICE_ERROR;
240 }
241 /* check for store instruction at dmseg */
242 uint32_t store_addr = ctx->pracc_list[code_count].addr;
243 if (store_addr != 0) {
244 if (store_addr > max_store_addr)
245 max_store_addr = store_addr;
246 store_pending++;
247 }
248
249 instr = ctx->pracc_list[code_count++].instr;
250 if (code_count == ctx->code_count) /* last instruction, start final check */
251 final_check = 1;
252
253 } else { /* final check after function code shifted out */
254 /* check address */
255 if (ejtag_info->pa_addr == MIPS32_PRACC_TEXT) {
256 if (!pass) { /* first pass through pracc text */
257 if (store_pending == 0) /* done, normal exit */
258 return ERROR_OK;
259 pass = 1; /* pracc text passed */
260 code_count = 0; /* restart code count */
261 } else {
262 LOG_DEBUG("unexpected second pass through pracc text");
263 return ERROR_JTAG_DEVICE_ERROR;
264 }
265 } else {
266 if (ejtag_info->pa_addr != (MIPS32_PRACC_TEXT + code_count * 4)) {
267 LOG_DEBUG("unexpected read address in final check: %" PRIx32 ", expected: %x",
268 ejtag_info->pa_addr, MIPS32_PRACC_TEXT + code_count * 4);
269 return ERROR_JTAG_DEVICE_ERROR;
270 }
271 }
272 if (!pass) {
273 if ((code_count - ctx->code_count) > 1) { /* allow max 2 instruction delay slot */
274 LOG_DEBUG("failed to jump back to pracc text");
275 return ERROR_JTAG_DEVICE_ERROR;
276 }
277 } else
278 if (code_count > 10) { /* enough, abandone */
279 LOG_DEBUG("execution abandoned, store pending: %d", store_pending);
280 return ERROR_JTAG_DEVICE_ERROR;
281 }
282 instr = MIPS32_NOP; /* shift out NOPs instructions */
283 code_count++;
284 }
285
286 /* Send instruction out */
287 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
288 mips_ejtag_drscan_32_out(ejtag_info, instr);
289 }
290 /* finish processor access, let the processor eat! */
291 mips32_pracc_finish(ejtag_info);
292
293 if (final_check && !check_last) /* last instr, don't check, execute and exit */
294 return jtag_execute_queue();
295
296 if (store_pending == 0 && pass) { /* store access done, but after passing pracc text */
297 LOG_DEBUG("warning: store access pass pracc text");
298 return ERROR_OK;
299 }
300 }
301 }
302
303 inline void pracc_queue_init(struct pracc_queue_info *ctx)
304 {
305 ctx->retval = ERROR_OK;
306 ctx->code_count = 0;
307 ctx->store_count = 0;
308 ctx->max_code = 0;
309 ctx->pracc_list = NULL;
310 }
311
312 void pracc_add(struct pracc_queue_info *ctx, uint32_t addr, uint32_t instr)
313 {
314 if (ctx->retval != ERROR_OK) /* On previous out of memory, return */
315 return;
316 if (ctx->code_count == ctx->max_code) {
317 void *p = realloc(ctx->pracc_list, sizeof(pa_list) * (ctx->max_code + PRACC_BLOCK));
318 if (p) {
319 ctx->max_code += PRACC_BLOCK;
320 ctx->pracc_list = p;
321 } else {
322 ctx->retval = ERROR_FAIL; /* Out of memory */
323 return;
324 }
325 }
326 ctx->pracc_list[ctx->code_count].instr = instr;
327 ctx->pracc_list[ctx->code_count++].addr = addr;
328 if (addr)
329 ctx->store_count++;
330 }
331
332 void pracc_add_li32(struct pracc_queue_info *ctx, uint32_t reg_num, uint32_t data, bool optimize)
333 {
334 if (LOWER16(data) == 0 && optimize)
335 pracc_add(ctx, 0, MIPS32_LUI(reg_num, UPPER16(data))); /* load only upper value */
336 else if (UPPER16(data) == 0 && optimize)
337 pracc_add(ctx, 0, MIPS32_ORI(reg_num, 0, LOWER16(data))); /* load only lower */
338 else {
339 pracc_add(ctx, 0, MIPS32_LUI(reg_num, UPPER16(data))); /* load upper and lower */
340 pracc_add(ctx, 0, MIPS32_ORI(reg_num, reg_num, LOWER16(data)));
341 }
342 }
343
344 inline void pracc_queue_free(struct pracc_queue_info *ctx)
345 {
346 if (ctx->pracc_list != NULL)
347 free(ctx->pracc_list);
348 }
349
350 int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_info *ctx,
351 uint32_t *buf, bool check_last)
352 {
353 if (ctx->retval != ERROR_OK) {
354 LOG_ERROR("Out of memory");
355 return ERROR_FAIL;
356 }
357
358 if (ejtag_info->mode == 0)
359 return mips32_pracc_exec(ejtag_info, ctx, buf, check_last);
360
361 union scan_in {
362 uint8_t scan_96[12];
363 struct {
364 uint8_t ctrl[4];
365 uint8_t data[4];
366 uint8_t addr[4];
367 } scan_32;
368
369 } *scan_in = malloc(sizeof(union scan_in) * (ctx->code_count + ctx->store_count));
370 if (scan_in == NULL) {
371 LOG_ERROR("Out of memory");
372 return ERROR_FAIL;
373 }
374
375 unsigned num_clocks =
376 ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000;
377
378 uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
379 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ALL);
380
381 int scan_count = 0;
382 for (int i = 0; i != ctx->code_count; i++) {
383 jtag_add_clocks(num_clocks);
384 mips_ejtag_add_scan_96(ejtag_info, ejtag_ctrl, ctx->pracc_list[i].instr,
385 scan_in[scan_count++].scan_96);
386
387 /* Check store address from previous instruction, if not the first */
388 if (i > 0 && ctx->pracc_list[i - 1].addr) {
389 jtag_add_clocks(num_clocks);
390 mips_ejtag_add_scan_96(ejtag_info, ejtag_ctrl, 0, scan_in[scan_count++].scan_96);
391 }
392 }
393
394 int retval = jtag_execute_queue(); /* execute queued scans */
395 if (retval != ERROR_OK)
396 goto exit;
397
398 uint32_t fetch_addr = MIPS32_PRACC_TEXT; /* start address */
399 scan_count = 0;
400 for (int i = 0; i != ctx->code_count; i++) { /* verify every pracc access */
401 /* check pracc bit */
402 ejtag_ctrl = buf_get_u32(scan_in[scan_count].scan_32.ctrl, 0, 32);
403 uint32_t addr = buf_get_u32(scan_in[scan_count].scan_32.addr, 0, 32);
404 if (!(ejtag_ctrl & EJTAG_CTRL_PRACC)) {
405 LOG_ERROR("Error: access not pending count: %d", scan_count);
406 retval = ERROR_FAIL;
407 goto exit;
408 }
409 if (ejtag_ctrl & EJTAG_CTRL_PRNW) {
410 LOG_ERROR("Not a fetch/read access, count: %d", scan_count);
411 retval = ERROR_FAIL;
412 goto exit;
413 }
414 if (addr != fetch_addr) {
415 LOG_ERROR("Fetch addr mismatch, read: %" PRIx32 " expected: %" PRIx32 " count: %d",
416 addr, fetch_addr, scan_count);
417 retval = ERROR_FAIL;
418 goto exit;
419 }
420 fetch_addr += 4;
421 scan_count++;
422
423 /* check if previous intrucction is a store instruction at dmesg */
424 if (i > 0 && ctx->pracc_list[i - 1].addr) {
425 uint32_t store_addr = ctx->pracc_list[i - 1].addr;
426 ejtag_ctrl = buf_get_u32(scan_in[scan_count].scan_32.ctrl, 0, 32);
427 addr = buf_get_u32(scan_in[scan_count].scan_32.addr, 0, 32);
428
429 if (!(ejtag_ctrl & EJTAG_CTRL_PRNW)) {
430 LOG_ERROR("Not a store/write access, count: %d", scan_count);
431 retval = ERROR_FAIL;
432 goto exit;
433 }
434 if (addr != store_addr) {
435 LOG_ERROR("Store address mismatch, read: %" PRIx32 " expected: %" PRIx32 " count: %d",
436 addr, store_addr, scan_count);
437 retval = ERROR_FAIL;
438 goto exit;
439 }
440 int buf_index = (addr - MIPS32_PRACC_PARAM_OUT) / 4;
441 buf[buf_index] = buf_get_u32(scan_in[scan_count].scan_32.data, 0, 32);
442 scan_count++;
443 }
444 }
445 exit:
446 free(scan_in);
447 return retval;
448 }
449
450 int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf)
451 {
452 struct pracc_queue_info ctx;
453 pracc_queue_init(&ctx);
454
455 pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */
456 pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16((addr + 0x8000)))); /* load $8 with modified upper address */
457 pracc_add(&ctx, 0, MIPS32_LW(8, LOWER16(addr), 8)); /* lw $8, LOWER16(addr)($8) */
458 pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT,
459 MIPS32_SW(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(NEG16(ctx.code_count + 1))); /* jump to start */
462 pracc_add(&ctx, 0, MIPS32_MFC0(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 uint32_t *data = NULL;
475 struct pracc_queue_info ctx;
476 pracc_queue_init(&ctx);
477
478 if (size != 4) {
479 data = malloc(256 * sizeof(uint32_t));
480 if (data == NULL) {
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 int this_round_count = (count > 256) ? 256 : count;
494 uint32_t last_upper_base_addr = UPPER16((addr + 0x8000));
495
496 pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */
497 pracc_add(&ctx, 0, MIPS32_LUI(9, last_upper_base_addr)); /* load the upper memory address in $9 */
498
499 for (int i = 0; i != this_round_count; i++) { /* Main code loop */
500 uint32_t upper_base_addr = UPPER16((addr + 0x8000));
501 if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper address in $9 */
502 pracc_add(&ctx, 0, MIPS32_LUI(9, upper_base_addr));
503 last_upper_base_addr = upper_base_addr;
504 }
505
506 if (size == 4)
507 pracc_add(&ctx, 0, MIPS32_LW(8, LOWER16(addr), 9)); /* load from memory to $8 */
508 else if (size == 2)
509 pracc_add(&ctx, 0, MIPS32_LHU(8, LOWER16(addr), 9));
510 else
511 pracc_add(&ctx, 0, MIPS32_LBU(8, LOWER16(addr), 9));
512
513 pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + i * 4,
514 MIPS32_SW(8, PRACC_OUT_OFFSET + i * 4, 15)); /* store $8 at param out */
515 addr += size;
516 }
517 pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */
518 pracc_add_li32(&ctx, 9, ejtag_info->reg9, 0); /* restore $9 */
519
520 pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */
521 pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */
522
523 if (size == 4) {
524 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, buf32, 1);
525 if (ctx.retval != ERROR_OK)
526 goto exit;
527 buf32 += this_round_count;
528 } else {
529 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, data, 1);
530 if (ctx.retval != ERROR_OK)
531 goto exit;
532
533 uint32_t *data_p = data;
534 for (int i = 0; i != this_round_count; i++) {
535 if (size == 2)
536 *buf16++ = *data_p++;
537 else
538 *buf8++ = *data_p++;
539 }
540 }
541 count -= this_round_count;
542 }
543 exit:
544 pracc_queue_free(&ctx);
545 if (data != NULL)
546 free(data);
547 return ctx.retval;
548 }
549
550 int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel)
551 {
552 struct pracc_queue_info ctx;
553 pracc_queue_init(&ctx);
554
555 pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */
556 pracc_add(&ctx, 0, MIPS32_MFC0(8, cp0_reg, cp0_sel)); /* move cp0 reg / sel to $8 */
557 pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT,
558 MIPS32_SW(8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */
559 pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */
560 pracc_add(&ctx, 0, MIPS32_LUI(8, UPPER16(ejtag_info->reg8))); /* restore upper 16 bits of $8 */
561 pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */
562 pracc_add(&ctx, 0, MIPS32_ORI(8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 bits of $8 */
563
564 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, val, 1);
565 pracc_queue_free(&ctx);
566 return ctx.retval;
567 }
568
569 int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel)
570 {
571 struct pracc_queue_info ctx;
572 pracc_queue_init(&ctx);
573
574 pracc_add_li32(&ctx, 15, val, 0); /* Load val to $15 */
575
576 pracc_add(&ctx, 0, MIPS32_MTC0(15, cp0_reg, cp0_sel)); /* write $15 to cp0 reg / sel */
577 pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */
578 pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */
579
580 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
581 pracc_queue_free(&ctx);
582 return ctx.retval;
583 }
584
585 /**
586 * \b mips32_pracc_sync_cache
587 *
588 * Synchronize Caches to Make Instruction Writes Effective
589 * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set,
590 * Document Number: MD00086, Revision 2.00, June 9, 2003)
591 *
592 * When the instruction stream is written, the SYNCI instruction should be used
593 * in conjunction with other instructions to make the newly-written instructions effective.
594 *
595 * Explanation :
596 * A program that loads another program into memory is actually writing the D- side cache.
597 * The instructions it has loaded can't be executed until they reach the I-cache.
598 *
599 * After the instructions have been written, the loader should arrange
600 * to write back any containing D-cache line and invalidate any locations
601 * already in the I-cache.
602 *
603 * If the cache coherency attribute (CCA) is set to zero, it's a write through cache, there is no need
604 * to write back.
605 *
606 * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
607 * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
608 * That is, it arranges a D-cache write-back (if CCA = 3) and an I-cache invalidate.
609 *
610 * The line size is obtained with the rdhwr SYNCI_Step in release 2 or from cp0 config 1 register in release 1.
611 */
612 static int mips32_pracc_synchronize_cache(struct mips_ejtag *ejtag_info,
613 uint32_t start_addr, uint32_t end_addr, int cached, int rel)
614 {
615 struct pracc_queue_info ctx;
616 pracc_queue_init(&ctx);
617
618 /** Find cache line size in bytes */
619 uint32_t clsiz;
620 if (rel) { /* Release 2 (rel = 1) */
621 pracc_add(&ctx, 0, MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIPS32_PRACC_BASE_ADDR */
622
623 pracc_add(&ctx, 0, MIPS32_RDHWR(8, MIPS32_SYNCI_STEP)); /* load synci_step value to $8 */
624
625 pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT,
626 MIPS32_SW(8, PRACC_OUT_OFFSET, 15)); /* store $8 to pracc_out */
627
628 pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */
629
630 pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */
631 pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */
632
633 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, &clsiz, 1);
634 if (ctx.retval != ERROR_OK)
635 goto exit;
636
637 } else { /* Release 1 (rel = 0) */
638 uint32_t conf;
639 ctx.retval = mips32_cp0_read(ejtag_info, &conf, 16, 1);
640 if (ctx.retval != ERROR_OK)
641 goto exit;
642
643 uint32_t dl = (conf & MIPS32_CONFIG1_DL_MASK) >> MIPS32_CONFIG1_DL_SHIFT;
644
645 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... max dl=6 => 128 bytes cache line size */
646 clsiz = 0x2 << dl;
647 if (dl == 0)
648 clsiz = 0;
649 }
650
651 if (clsiz == 0)
652 goto exit; /* Nothing to do */
653
654 /* make sure clsiz is power of 2 */
655 if (clsiz & (clsiz - 1)) {
656 LOG_DEBUG("clsiz must be power of 2");
657 ctx.retval = ERROR_FAIL;
658 goto exit;
659 }
660
661 /* make sure start_addr and end_addr have the same offset inside de cache line */
662 start_addr |= clsiz - 1;
663 end_addr |= clsiz - 1;
664
665 ctx.code_count = 0;
666 int count = 0;
667 uint32_t last_upper_base_addr = UPPER16((start_addr + 0x8000));
668
669 pracc_add(&ctx, 0, MIPS32_LUI(15, last_upper_base_addr)); /* load upper memory base address to $15 */
670
671 while (start_addr <= end_addr) { /* main loop */
672 uint32_t upper_base_addr = UPPER16((start_addr + 0x8000));
673 if (last_upper_base_addr != upper_base_addr) { /* if needed, change upper address in $15 */
674 pracc_add(&ctx, 0, MIPS32_LUI(15, upper_base_addr));
675 last_upper_base_addr = upper_base_addr;
676 }
677 if (rel)
678 pracc_add(&ctx, 0, MIPS32_SYNCI(LOWER16(start_addr), 15)); /* synci instruction, offset($15) */
679
680 else {
681 if (cached == 3)
682 pracc_add(&ctx, 0, MIPS32_CACHE(MIPS32_CACHE_D_HIT_WRITEBACK,
683 LOWER16(start_addr), 15)); /* cache Hit_Writeback_D, offset($15) */
684
685 pracc_add(&ctx, 0, MIPS32_CACHE(MIPS32_CACHE_I_HIT_INVALIDATE,
686 LOWER16(start_addr), 15)); /* cache Hit_Invalidate_I, offset($15) */
687 }
688 start_addr += clsiz;
689 count++;
690 if (count == 256 && start_addr <= end_addr) { /* more ?, then execute code list */
691 pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */
692 pracc_add(&ctx, 0, MIPS32_NOP); /* nop in delay slot */
693
694 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
695 if (ctx.retval != ERROR_OK)
696 goto exit;
697
698 ctx.code_count = 0;
699 count = 0;
700 }
701 }
702 pracc_add(&ctx, 0, MIPS32_SYNC);
703 pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */
704 pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave*/
705
706 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
707 exit:
708 pracc_queue_free(&ctx);
709 return ctx.retval;
710 }
711
712 static int mips32_pracc_write_mem_generic(struct mips_ejtag *ejtag_info,
713 uint32_t addr, int size, int count, const void *buf)
714 {
715 struct pracc_queue_info ctx;
716 pracc_queue_init(&ctx);
717
718 const uint32_t *buf32 = buf;
719 const uint16_t *buf16 = buf;
720 const uint8_t *buf8 = buf;
721
722 while (count) {
723 ctx.code_count = 0;
724 ctx.store_count = 0;
725 int this_round_count = (count > 128) ? 128 : count;
726 uint32_t last_upper_base_addr = UPPER16((addr + 0x8000));
727
728 pracc_add(&ctx, 0, MIPS32_LUI(15, last_upper_base_addr)); /* load $15 with memory base address */
729
730 for (int i = 0; i != this_round_count; i++) {
731 uint32_t upper_base_addr = UPPER16((addr + 0x8000));
732 if (last_upper_base_addr != upper_base_addr) {
733 pracc_add(&ctx, 0, MIPS32_LUI(15, upper_base_addr)); /* if needed, change upper address in $15*/
734 last_upper_base_addr = upper_base_addr;
735 }
736
737 if (size == 4) {
738 pracc_add_li32(&ctx, 8, *buf32, 1); /* load with li32, optimize */
739 pracc_add(&ctx, 0, MIPS32_SW(8, LOWER16(addr), 15)); /* store word to memory */
740 buf32++;
741
742 } else if (size == 2) {
743 pracc_add(&ctx, 0, MIPS32_ORI(8, 0, *buf16)); /* load lower value */
744 pracc_add(&ctx, 0, MIPS32_SH(8, LOWER16(addr), 15)); /* store half word to memory */
745 buf16++;
746
747 } else {
748 pracc_add(&ctx, 0, MIPS32_ORI(8, 0, *buf8)); /* load lower value */
749 pracc_add(&ctx, 0, MIPS32_SB(8, LOWER16(addr), 15)); /* store byte to memory */
750 buf8++;
751 }
752 addr += size;
753 }
754
755 pracc_add_li32(&ctx, 8, ejtag_info->reg8, 0); /* restore $8 */
756
757 pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */
758 pracc_add(&ctx, 0, MIPS32_MFC0(15, 31, 0)); /* restore $15 from DeSave */
759
760 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
761 if (ctx.retval != ERROR_OK)
762 goto exit;
763 count -= this_round_count;
764 }
765 exit:
766 pracc_queue_free(&ctx);
767 return ctx.retval;
768 }
769
770 int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, const void *buf)
771 {
772 int retval = mips32_pracc_write_mem_generic(ejtag_info, addr, size, count, buf);
773 if (retval != ERROR_OK)
774 return retval;
775
776 /**
777 * If we are in the cacheable region and cache is activated,
778 * we must clean D$ (if Cache Coherency Attribute is set to 3) + invalidate I$ after we did the write,
779 * so that changes do not continue to live only in D$ (if CCA = 3), but to be
780 * replicated in I$ also (maybe we wrote the istructions)
781 */
782 uint32_t conf = 0;
783 int cached = 0;
784
785 if ((KSEGX(addr) == KSEG1) || ((addr >= 0xff200000) && (addr <= 0xff3fffff)))
786 return retval; /*Nothing to do*/
787
788 mips32_cp0_read(ejtag_info, &conf, 16, 0);
789
790 switch (KSEGX(addr)) {
791 case KUSEG:
792 cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT;
793 break;
794 case KSEG0:
795 cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT;
796 break;
797 case KSEG2:
798 case KSEG3:
799 cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT;
800 break;
801 default:
802 /* what ? */
803 break;
804 }
805
806 /**
807 * Check cachablitiy bits coherency algorithm
808 * is the region cacheable or uncached.
809 * If cacheable we have to synchronize the cache
810 */
811 if (cached == 3 || cached == 0) { /* Write back cache or write through cache */
812 uint32_t start_addr = addr;
813 uint32_t end_addr = addr + count * size;
814 uint32_t rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT;
815 if (rel > 1) {
816 LOG_DEBUG("Unknown release in cache code");
817 return ERROR_FAIL;
818 }
819 retval = mips32_pracc_synchronize_cache(ejtag_info, start_addr, end_addr, cached, rel);
820 }
821
822 return retval;
823 }
824
825 int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
826 {
827 static const uint32_t cp0_write_code[] = {
828 MIPS32_MTC0(1, 12, 0), /* move $1 to status */
829 MIPS32_MTLO(1), /* move $1 to lo */
830 MIPS32_MTHI(1), /* move $1 to hi */
831 MIPS32_MTC0(1, 8, 0), /* move $1 to badvaddr */
832 MIPS32_MTC0(1, 13, 0), /* move $1 to cause*/
833 MIPS32_MTC0(1, 24, 0), /* move $1 to depc (pc) */
834 };
835
836 struct pracc_queue_info ctx;
837 pracc_queue_init(&ctx);
838
839 /* load registers 2 to 31 with li32, optimize */
840 for (int i = 2; i < 32; i++)
841 pracc_add_li32(&ctx, i, regs[i], 1);
842
843 for (int i = 0; i != 6; i++) {
844 pracc_add_li32(&ctx, 1, regs[i + 32], 0); /* load CPO value in $1 */
845 pracc_add(&ctx, 0, cp0_write_code[i]); /* write value from $1 to CPO register */
846 }
847 pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0)); /* load $15 in DeSave */
848 pracc_add(&ctx, 0, MIPS32_LUI(1, UPPER16((regs[1])))); /* load upper half word in $1 */
849 pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */
850 pracc_add(&ctx, 0, MIPS32_ORI(1, 1, LOWER16((regs[1])))); /* load lower half word in $1 */
851
852 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1);
853
854 ejtag_info->reg8 = regs[8];
855 ejtag_info->reg9 = regs[9];
856 pracc_queue_free(&ctx);
857 return ctx.retval;
858 }
859
860 int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
861 {
862 static int cp0_read_code[] = {
863 MIPS32_MFC0(8, 12, 0), /* move status to $8 */
864 MIPS32_MFLO(8), /* move lo to $8 */
865 MIPS32_MFHI(8), /* move hi to $8 */
866 MIPS32_MFC0(8, 8, 0), /* move badvaddr to $8 */
867 MIPS32_MFC0(8, 13, 0), /* move cause to $8 */
868 MIPS32_MFC0(8, 24, 0), /* move depc (pc) to $8 */
869 };
870
871 struct pracc_queue_info ctx;
872 pracc_queue_init(&ctx);
873
874 pracc_add(&ctx, 0, MIPS32_MTC0(1, 31, 0)); /* move $1 to COP0 DeSave */
875 pracc_add(&ctx, 0, MIPS32_LUI(1, PRACC_UPPER_BASE_ADDR)); /* $1 = MIP32_PRACC_BASE_ADDR */
876
877 for (int i = 2; i != 32; i++) /* store GPR's 2 to 31 */
878 pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i * 4),
879 MIPS32_SW(i, PRACC_OUT_OFFSET + (i * 4), 1));
880
881 for (int i = 0; i != 6; i++) {
882 pracc_add(&ctx, 0, cp0_read_code[i]); /* load COP0 needed registers to $8 */
883 pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i + 32) * 4, /* store $8 at PARAM OUT */
884 MIPS32_SW(8, PRACC_OUT_OFFSET + (i + 32) * 4, 1));
885 }
886 pracc_add(&ctx, 0, MIPS32_MFC0(8, 31, 0)); /* move DeSave to $8, reg1 value */
887 pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + 4, /* store reg1 value from $8 to param out */
888 MIPS32_SW(8, PRACC_OUT_OFFSET + 4, 1));
889
890 pracc_add(&ctx, 0, MIPS32_MFC0(1, 31, 0)); /* move COP0 DeSave to $1, restore reg1 */
891 pracc_add(&ctx, 0, MIPS32_B(NEG16(ctx.code_count + 1))); /* jump to start */
892 pracc_add(&ctx, 0, MIPS32_MTC0(15, 31, 0)); /* load $15 in DeSave */
893
894 ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, regs, 1);
895
896 ejtag_info->reg8 = regs[8]; /* reg8 is saved but not restored, next called function should restore it */
897 ejtag_info->reg9 = regs[9];
898 pracc_queue_free(&ctx);
899 return ctx.retval;
900 }
901
902 /* fastdata upload/download requires an initialized working area
903 * to load the download code; it should not be called otherwise
904 * fetch order from the fastdata area
905 * 1. start addr
906 * 2. end addr
907 * 3. data ...
908 */
909 int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source,
910 int write_t, uint32_t addr, int count, uint32_t *buf)
911 {
912 uint32_t handler_code[] = {
913 /* r15 points to the start of this code */
914 MIPS32_SW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15),
915 MIPS32_SW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15),
916 MIPS32_SW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15),
917 MIPS32_SW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15),
918 /* start of fastdata area in t0 */
919 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_FASTDATA_AREA)),
920 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA)),
921 MIPS32_LW(9, 0, 8), /* start addr in t1 */
922 MIPS32_LW(10, 0, 8), /* end addr to t2 */
923 /* loop: */
924 write_t ? MIPS32_LW(11, 0, 8) : MIPS32_LW(11, 0, 9), /* from xfer area : from memory */
925 write_t ? MIPS32_SW(11, 0, 9) : MIPS32_SW(11, 0, 8), /* to memory : to xfer area */
926
927 MIPS32_BNE(10, 9, NEG16(3)), /* bne $t2,t1,loop */
928 MIPS32_ADDI(9, 9, 4), /* addi t1,t1,4 */
929
930 MIPS32_LW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15),
931 MIPS32_LW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15),
932 MIPS32_LW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15),
933 MIPS32_LW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15),
934
935 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_TEXT)),
936 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_TEXT)),
937 MIPS32_JR(15), /* jr start */
938 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
939 };
940
941 if (source->size < MIPS32_FASTDATA_HANDLER_SIZE)
942 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
943
944 /* write program into RAM */
945 if (write_t != ejtag_info->fast_access_save) {
946 mips32_pracc_write_mem(ejtag_info, source->address, 4, ARRAY_SIZE(handler_code), handler_code);
947 /* save previous operation to speed to any consecutive read/writes */
948 ejtag_info->fast_access_save = write_t;
949 }
950
951 LOG_DEBUG("%s using 0x%.8" TARGET_PRIxADDR " for write handler", __func__, source->address);
952
953 uint32_t jmp_code[] = {
954 MIPS32_LUI(15, UPPER16(source->address)), /* load addr of jump in $15 */
955 MIPS32_ORI(15, 15, LOWER16(source->address)),
956 MIPS32_JR(15), /* jump to ram program */
957 MIPS32_NOP,
958 };
959
960 /* execute jump code, with no address check */
961 for (unsigned i = 0; i < ARRAY_SIZE(jmp_code); i++) {
962 int retval = wait_for_pracc_rw(ejtag_info);
963 if (retval != ERROR_OK)
964 return retval;
965
966 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
967 mips_ejtag_drscan_32_out(ejtag_info, jmp_code[i]);
968
969 /* Clear the access pending bit (let the processor eat!) */
970 mips32_pracc_finish(ejtag_info);
971 }
972
973 /* wait PrAcc pending bit for FASTDATA write, read address */
974 int retval = mips32_pracc_read_ctrl_addr(ejtag_info);
975 if (retval != ERROR_OK)
976 return retval;
977
978 /* next fetch to dmseg should be in FASTDATA_AREA, check */
979 if (ejtag_info->pa_addr != MIPS32_PRACC_FASTDATA_AREA)
980 return ERROR_FAIL;
981
982 /* Send the load start address */
983 uint32_t val = addr;
984 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA);
985 mips_ejtag_fastdata_scan(ejtag_info, 1, &val);
986
987 retval = wait_for_pracc_rw(ejtag_info);
988 if (retval != ERROR_OK)
989 return retval;
990
991 /* Send the load end address */
992 val = addr + (count - 1) * 4;
993 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA);
994 mips_ejtag_fastdata_scan(ejtag_info, 1, &val);
995
996 unsigned num_clocks = 0; /* like in legacy code */
997 if (ejtag_info->mode != 0)
998 num_clocks = ((uint64_t)(ejtag_info->scan_delay) * jtag_get_speed_khz() + 500000) / 1000000;
999
1000 for (int i = 0; i < count; i++) {
1001 jtag_add_clocks(num_clocks);
1002 mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++);
1003 }
1004
1005 retval = jtag_execute_queue();
1006 if (retval != ERROR_OK) {
1007 LOG_ERROR("fastdata load failed");
1008 return retval;
1009 }
1010
1011 retval = mips32_pracc_read_ctrl_addr(ejtag_info);
1012 if (retval != ERROR_OK)
1013 return retval;
1014
1015 if (ejtag_info->pa_addr != MIPS32_PRACC_TEXT)
1016 LOG_ERROR("mini program did not return to start");
1017
1018 return retval;
1019 }

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)