mips: optimize mips32_pracc_read_regs() code
[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, write to the *
24 * Free Software Foundation, Inc., *
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
26 ***************************************************************************/
27
28 /*
29 * This version has optimized assembly routines for 32 bit operations:
30 * - read word
31 * - write word
32 * - write array of words
33 *
34 * One thing to be aware of is that the MIPS32 cpu will execute the
35 * instruction after a branch instruction (one delay slot).
36 *
37 * For example:
38 * LW $2, ($5 +10)
39 * B foo
40 * LW $1, ($2 +100)
41 *
42 * The LW $1, ($2 +100) instruction is also executed. If this is
43 * not wanted a NOP can be inserted:
44 *
45 * LW $2, ($5 +10)
46 * B foo
47 * NOP
48 * LW $1, ($2 +100)
49 *
50 * or the code can be changed to:
51 *
52 * B foo
53 * LW $2, ($5 +10)
54 * LW $1, ($2 +100)
55 *
56 * The original code contained NOPs. I have removed these and moved
57 * the branches.
58 *
59 * I also moved the PRACC_STACK to 0xFF204000. This allows
60 * the use of 16 bits offsets to get pointers to the input
61 * and output area relative to the stack. Note that the stack
62 * isn't really a stack (the stack pointer is not 'moving')
63 * but a FIFO simulated in software.
64 *
65 * These changes result in a 35% speed increase when programming an
66 * external flash.
67 *
68 * More improvement could be gained if the registers do no need
69 * to be preserved but in that case the routines should be aware
70 * OpenOCD is used as a flash programmer or as a debug tool.
71 *
72 * Nico Coesel
73 */
74
75 #ifdef HAVE_CONFIG_H
76 #include "config.h"
77 #endif
78
79 #include <helper/time_support.h>
80
81 #include "mips32.h"
82 #include "mips32_pracc.h"
83
84 struct mips32_pracc_context {
85 uint32_t *local_iparam;
86 int num_iparam;
87 uint32_t *local_oparam;
88 int num_oparam;
89 const uint32_t *code;
90 int code_len;
91 uint32_t stack[32];
92 int stack_offset;
93 struct mips_ejtag *ejtag_info;
94 };
95
96 static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info,
97 uint32_t start_addr, uint32_t end_addr);
98 static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag *ejtag_info,
99 uint32_t start_addr, uint32_t end_addr);
100
101 static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl)
102 {
103 uint32_t ejtag_ctrl;
104 long long then = timeval_ms();
105 int timeout;
106 int retval;
107
108 /* wait for the PrAcc to become "1" */
109 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
110
111 while (1) {
112 ejtag_ctrl = ejtag_info->ejtag_ctrl;
113 retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
114 if (retval != ERROR_OK)
115 return retval;
116
117 if (ejtag_ctrl & EJTAG_CTRL_PRACC)
118 break;
119
120 timeout = timeval_ms() - then;
121 if (timeout > 1000) {
122 LOG_DEBUG("DEBUGMODULE: No memory access in progress!");
123 return ERROR_JTAG_DEVICE_ERROR;
124 }
125 }
126
127 *ctrl = ejtag_ctrl;
128 return ERROR_OK;
129 }
130
131 static int mips32_pracc_exec_read(struct mips32_pracc_context *ctx, uint32_t address)
132 {
133 struct mips_ejtag *ejtag_info = ctx->ejtag_info;
134 int offset;
135 uint32_t ejtag_ctrl, data;
136
137 if ((address >= MIPS32_PRACC_PARAM_IN)
138 && (address < MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4)) {
139 offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
140 data = ctx->local_iparam[offset];
141 } else if ((address >= MIPS32_PRACC_PARAM_OUT)
142 && (address < MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) {
143 offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
144 data = ctx->local_oparam[offset];
145 } else if ((address >= MIPS32_PRACC_TEXT)
146 && (address < MIPS32_PRACC_TEXT + ctx->code_len * 4)) {
147 offset = (address - MIPS32_PRACC_TEXT) / 4;
148 data = ctx->code[offset];
149 } else if (address == MIPS32_PRACC_STACK) {
150 if (ctx->stack_offset <= 0) {
151 LOG_ERROR("Error: Pracc stack out of bounds");
152 return ERROR_JTAG_DEVICE_ERROR;
153 }
154 /* save to our debug stack */
155 data = ctx->stack[--ctx->stack_offset];
156 } else {
157 /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back
158 * to start of debug vector */
159
160 LOG_ERROR("Error reading unexpected address 0x%8.8" PRIx32 "", address);
161 return ERROR_JTAG_DEVICE_ERROR;
162 }
163
164 /* Send the data out */
165 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA);
166 mips_ejtag_drscan_32_out(ctx->ejtag_info, data);
167
168 /* Clear the access pending bit (let the processor eat!) */
169 ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
170 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL);
171 mips_ejtag_drscan_32_out(ctx->ejtag_info, ejtag_ctrl);
172
173 return jtag_execute_queue();
174 }
175
176 static int mips32_pracc_exec_write(struct mips32_pracc_context *ctx, uint32_t address)
177 {
178 uint32_t ejtag_ctrl, data;
179 int offset;
180 struct mips_ejtag *ejtag_info = ctx->ejtag_info;
181 int retval;
182
183 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA);
184 retval = mips_ejtag_drscan_32(ctx->ejtag_info, &data);
185 if (retval != ERROR_OK)
186 return retval;
187
188 /* Clear access pending bit */
189 ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
190 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL);
191 mips_ejtag_drscan_32_out(ctx->ejtag_info, ejtag_ctrl);
192
193 retval = jtag_execute_queue();
194 if (retval != ERROR_OK)
195 return retval;
196
197 if ((address >= MIPS32_PRACC_PARAM_IN)
198 && (address < MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4)) {
199 offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
200 ctx->local_iparam[offset] = data;
201 } else if ((address >= MIPS32_PRACC_PARAM_OUT)
202 && (address < MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4)) {
203 offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
204 ctx->local_oparam[offset] = data;
205 } else if (address == MIPS32_PRACC_STACK) {
206 if (ctx->stack_offset >= 32) {
207 LOG_ERROR("Error: Pracc stack out of bounds");
208 return ERROR_JTAG_DEVICE_ERROR;
209 }
210 /* save data onto our stack */
211 ctx->stack[ctx->stack_offset++] = data;
212 } else {
213 LOG_ERROR("Error writing unexpected address 0x%8.8" PRIx32 "", address);
214 return ERROR_JTAG_DEVICE_ERROR;
215 }
216
217 return ERROR_OK;
218 }
219
220 int mips32_pracc_exec(struct mips_ejtag *ejtag_info, int code_len, const uint32_t *code,
221 int num_param_in, uint32_t *param_in, int num_param_out, uint32_t *param_out, int cycle)
222 {
223 uint32_t ejtag_ctrl;
224 uint32_t address;
225 struct mips32_pracc_context ctx;
226 int retval;
227 int pass = 0;
228
229 ctx.local_iparam = param_in;
230 ctx.local_oparam = param_out;
231 ctx.num_iparam = num_param_in;
232 ctx.num_oparam = num_param_out;
233 ctx.code = code;
234 ctx.code_len = code_len;
235 ctx.ejtag_info = ejtag_info;
236 ctx.stack_offset = 0;
237
238 while (1) {
239 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
240 if (retval != ERROR_OK)
241 return retval;
242
243 address = 0;
244 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
245 retval = mips_ejtag_drscan_32(ejtag_info, &address);
246 if (retval != ERROR_OK)
247 return retval;
248
249 /* Check for read or write */
250 if (ejtag_ctrl & EJTAG_CTRL_PRNW) {
251 retval = mips32_pracc_exec_write(&ctx, address);
252 if (retval != ERROR_OK)
253 return retval;
254 } else {
255 /* Check to see if its reading at the debug vector. The first pass through
256 * the module is always read at the vector, so the first one we allow. When
257 * the second read from the vector occurs we are done and just exit. */
258 if ((address == MIPS32_PRACC_TEXT) && (pass++))
259 break;
260
261 retval = mips32_pracc_exec_read(&ctx, address);
262 if (retval != ERROR_OK)
263 return retval;
264 }
265
266 if (cycle == 0)
267 break;
268 }
269
270 /* stack sanity check */
271 if (ctx.stack_offset != 0)
272 LOG_DEBUG("Pracc Stack not zero");
273
274 return ERROR_OK;
275 }
276
277 static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf)
278 {
279 uint32_t code[] = {
280 /* start: */
281 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
282 MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR), /* $15 = MIPS32_PRACC_BASE_ADDR */
283 MIPS32_SW(8, PRACC_STACK_OFFSET, 15), /* sw $8,PRACC_STACK_OFFSET($15) */
284
285 MIPS32_LUI(8, UPPER16((addr + 0x8000))), /* load $8 with modified upper address */
286 MIPS32_LW(8, LOWER16(addr), 8), /* lw $8, LOWER16(addr)($8) */
287 MIPS32_SW(8, PRACC_OUT_OFFSET, 15), /* sw $8,PRACC_OUT_OFFSET($15) */
288
289 MIPS32_LW(8, PRACC_STACK_OFFSET, 15), /* lw $8,PRACC_STACK_OFFSET($15) */
290 MIPS32_B(NEG16(8)), /* b start */
291 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
292 };
293
294 return mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 0, NULL, 1, buf, 1);
295 }
296
297 int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
298 {
299 if (count == 1 && size == 4)
300 return mips32_pracc_read_u32(ejtag_info, addr, (uint32_t *)buf);
301
302 int retval = ERROR_FAIL;
303
304 uint32_t *code = NULL;
305 uint32_t *data = NULL;
306
307 code = malloc((256 * 2 + 10) * sizeof(uint32_t));
308 if (code == NULL) {
309 LOG_ERROR("Out of memory");
310 goto exit;
311 }
312
313 if (size != 4) {
314 data = malloc(256 * sizeof(uint32_t));
315 if (data == NULL) {
316 LOG_ERROR("Out of memory");
317 goto exit;
318 }
319 }
320
321 uint32_t *buf32 = buf;
322 uint16_t *buf16 = buf;
323 uint8_t *buf8 = buf;
324
325 int i;
326 uint32_t upper_base_addr, last_upper_base_addr;
327 int this_round_count;
328 int code_len;
329
330 while (count) {
331 this_round_count = (count > 256) ? 256 : count;
332 last_upper_base_addr = UPPER16((addr + 0x8000));
333 uint32_t *code_p = code;
334
335 *code_p++ = MIPS32_MTC0(15, 31, 0); /* save $15 in DeSave */
336 *code_p++ = MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR); /* $15 = MIPS32_PRACC_BASE_ADDR */
337 *code_p++ = MIPS32_SW(8, PRACC_STACK_OFFSET, 15); /* save $8 and $9 to pracc stack */
338 *code_p++ = MIPS32_SW(9, PRACC_STACK_OFFSET, 15);
339 *code_p++ = MIPS32_LUI(9, last_upper_base_addr); /* load the upper memory address in $9*/
340 code_len = 5;
341
342 for (i = 0; i != this_round_count; i++) { /* Main code loop */
343 upper_base_addr = UPPER16((addr + 0x8000));
344 if (last_upper_base_addr != upper_base_addr) {
345 *code_p++ = MIPS32_LUI(9, upper_base_addr); /* if needed, change upper address in $9*/
346 code_len++;
347 last_upper_base_addr = upper_base_addr;
348 }
349
350 if (size == 4)
351 *code_p++ = MIPS32_LW(8, LOWER16(addr), 9); /* load from memory to $8 */
352 else if (size == 2)
353 *code_p++ = MIPS32_LHU(8, LOWER16(addr), 9);
354 else
355 *code_p++ = MIPS32_LBU(8, LOWER16(addr), 9);
356
357 *code_p++ = MIPS32_SW(8, PRACC_OUT_OFFSET + i * 4, 15); /* store $8 at param out */
358
359 code_len += 2;
360 addr += size;
361 }
362
363 *code_p++ = MIPS32_LW(9, PRACC_STACK_OFFSET, 15); /* restore $8 and $9 from pracc stack */
364 *code_p++ = MIPS32_LW(8, PRACC_STACK_OFFSET, 15);
365
366 code_len += 4;
367 *code_p++ = MIPS32_B(NEG16(code_len - 1)); /* jump to start */
368 *code_p = MIPS32_MFC0(15, 31, 0); /* restore $15 from DeSave */
369
370 if (size == 4) {
371 retval = mips32_pracc_exec(ejtag_info, code_len, code, 0, NULL, this_round_count, buf32, 1);
372 if (retval != ERROR_OK)
373 goto exit;
374 buf32 += this_round_count;
375 } else {
376 retval = mips32_pracc_exec(ejtag_info, code_len, code, 0, NULL, this_round_count, data, 1);
377 if (retval != ERROR_OK)
378 goto exit;
379 uint32_t *data_p = data;
380 for (i = 0; i != this_round_count; i++) {
381 if (size == 2)
382 *buf16++ = *data_p++;
383 else
384 *buf8++ = *data_p++;
385 }
386 }
387 count -= this_round_count;
388 }
389
390 exit:
391 if (code)
392 free(code);
393 if (data)
394 free(data);
395 return retval;
396 }
397
398 int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel)
399 {
400 /**
401 * Do not make this code static, but regenerate it every time,
402 * as 3th element has to be changed to add parameters
403 */
404 uint32_t code[] = {
405 /* start: */
406 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
407 MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR), /* $15 = MIPS32_PRACC_BASE_ADDR */
408 MIPS32_SW(8, PRACC_STACK_OFFSET, 15), /* sw $8,PRACC_STACK_OFFSET($15) */
409
410 /* 3 */ MIPS32_MFC0(8, 0, 0), /* move COP0 [cp0_reg select] to $8 */
411 MIPS32_SW(8, PRACC_OUT_OFFSET, 15), /* sw $8,PRACC_OUT_OFFSET($15) */
412
413 MIPS32_LW(8, PRACC_STACK_OFFSET, 15), /* lw $8,PRACC_STACK_OFFSET($15) */
414 MIPS32_B(NEG16(7)), /* b start */
415 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
416 };
417
418 /**
419 * Note that our input parametes cp0_reg and cp0_sel
420 * are numbers (not gprs) which make part of mfc0 instruction opcode.
421 *
422 * These are not fix, but can be different for each mips32_cp0_read() function call,
423 * and that is why we must insert them directly into opcode,
424 * i.e. we can not pass it on EJTAG microprogram stack (via param_in),
425 * and put them into the gprs later from MIPS32_PRACC_STACK
426 * because mfc0 do not use gpr as a parameter for the cp0_reg and select part,
427 * but plain (immediate) number.
428 *
429 * MIPS32_MTC0 is implemented via MIPS32_R_INST macro.
430 * In order to insert our parameters, we must change rd and funct fields.
431 */
432 code[3] |= (cp0_reg << 11) | cp0_sel; /* change rd and funct of MIPS32_R_INST macro */
433
434 return mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 0, NULL, 1, val, 1);
435 }
436
437 int mips32_cp0_write(struct mips_ejtag *ejtag_info, uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel)
438 {
439 uint32_t code[] = {
440 /* start: */
441 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
442 MIPS32_LUI(15, UPPER16(val)), /* Load val to $15 */
443 MIPS32_ORI(15, 15, LOWER16(val)),
444
445 /* 3 */ MIPS32_MTC0(15, 0, 0), /* move $15 to COP0 [cp0_reg select] */
446
447 MIPS32_B(NEG16(5)), /* b start */
448 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
449 };
450
451 /**
452 * Note that MIPS32_MTC0 macro is implemented via MIPS32_R_INST macro.
453 * In order to insert our parameters, we must change rd and funct fields.
454 */
455 code[3] |= (cp0_reg << 11) | cp0_sel; /* change rd and funct fields of MIPS32_R_INST macro */
456
457 return mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 0, NULL, 0, NULL, 1);
458 }
459
460 /**
461 * \b mips32_pracc_sync_cache
462 *
463 * Synchronize Caches to Make Instruction Writes Effective
464 * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set,
465 * Document Number: MD00086, Revision 2.00, June 9, 2003)
466 *
467 * When the instruction stream is written, the SYNCI instruction should be used
468 * in conjunction with other instructions to make the newly-written instructions effective.
469 *
470 * Explanation :
471 * A program that loads another program into memory is actually writing the D- side cache.
472 * The instructions it has loaded can't be executed until they reach the I-cache.
473 *
474 * After the instructions have been written, the loader should arrange
475 * to write back any containing D-cache line and invalidate any locations
476 * already in the I-cache.
477 *
478 * You can do that with cache instructions, but those instructions are only available in kernel mode,
479 * and a loader writing instructions for the use of its own process need not be privileged software.
480 *
481 * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
482 * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
483 * That is, it arranges a D-cache write-back and an I-cache invalidate.
484 *
485 * To employ synci at user level, you need to know the size of a cache line,
486 * and that can be obtained with a rdhwr SYNCI_Step
487 * from one of the standard “hardware registers”.
488 */
489 static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info,
490 uint32_t start_addr, uint32_t end_addr)
491 {
492 static const uint32_t code[] = {
493 /* start: */
494 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
495 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
496 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
497 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
498 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
499 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
500 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
501
502 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
503 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
504 MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */
505 MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */
506
507 MIPS32_RDHWR(11, MIPS32_SYNCI_STEP), /* $11 = MIPS32_SYNCI_STEP */
508 MIPS32_BEQ(11, 0, 6), /* beq $11, $0, end */
509 MIPS32_NOP,
510 /* synci_loop : */
511 MIPS32_SYNCI(0, 9), /* synci 0($9) */
512 MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 # $8 = $10 < $9 ? 1 : 0 */
513 MIPS32_BNE(8, 0, NEG16(3)), /* bne $8, $0, synci_loop */
514 MIPS32_ADDU(9, 9, 11), /* $9 += MIPS32_SYNCI_STEP */
515 MIPS32_SYNC,
516 /* end: */
517 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
518 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
519 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
520 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
521 MIPS32_B(NEG16(24)), /* b start */
522 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
523 };
524
525 /* TODO remove array */
526 uint32_t *param_in = malloc(2 * sizeof(uint32_t));
527 int retval;
528 param_in[0] = start_addr;
529 param_in[1] = end_addr;
530
531 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 2, param_in, 0, NULL, 1);
532
533 free(param_in);
534
535 return retval;
536 }
537
538 /**
539 * \b mips32_pracc_clean_invalidate_cache
540 *
541 * Writeback D$ and Invalidate I$
542 * so that the instructions written can be visible to CPU
543 */
544 static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag *ejtag_info,
545 uint32_t start_addr, uint32_t end_addr)
546 {
547 static const uint32_t code[] = {
548 /* start: */
549 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
550 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
551 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_STACK)),
552 MIPS32_SW(8, 0, 15), /* sw $8,($15) */
553 MIPS32_SW(9, 0, 15), /* sw $9,($15) */
554 MIPS32_SW(10, 0, 15), /* sw $10,($15) */
555 MIPS32_SW(11, 0, 15), /* sw $11,($15) */
556
557 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
558 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_PARAM_IN)),
559 MIPS32_LW(9, 0, 8), /* Load write start_addr to $9 */
560 MIPS32_LW(10, 4, 8), /* Load write end_addr to $10 */
561 MIPS32_LW(11, 8, 8), /* Load write clsiz to $11 */
562
563 /* cache_loop: */
564 MIPS32_SLTU(8, 10, 9), /* sltu $8, $10, $9 : $8 <- $10 < $9 ? */
565 MIPS32_BGTZ(8, 6), /* bgtz $8, end */
566 MIPS32_NOP,
567
568 MIPS32_CACHE(MIPS32_CACHE_D_HIT_WRITEBACK, 0, 9), /* cache Hit_Writeback_D, 0($9) */
569 MIPS32_CACHE(MIPS32_CACHE_I_HIT_INVALIDATE, 0, 9), /* cache Hit_Invalidate_I, 0($9) */
570
571 MIPS32_ADDU(9, 9, 11), /* $9 += $11 */
572
573 MIPS32_B(NEG16(7)), /* b cache_loop */
574 MIPS32_NOP,
575 /* end: */
576 MIPS32_LW(11, 0, 15), /* lw $11,($15) */
577 MIPS32_LW(10, 0, 15), /* lw $10,($15) */
578 MIPS32_LW(9, 0, 15), /* lw $9,($15) */
579 MIPS32_LW(8, 0, 15), /* lw $8,($15) */
580 MIPS32_B(NEG16(25)), /* b start */
581 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
582 };
583
584 /**
585 * Find cache line size in bytes
586 */
587 uint32_t conf;
588 uint32_t dl, clsiz;
589
590 mips32_cp0_read(ejtag_info, &conf, 16, 1);
591 dl = (conf & MIPS32_CONFIG1_DL_MASK) >> MIPS32_CONFIG1_DL_SHIFT;
592
593 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... */
594 clsiz = 0x2 << dl;
595
596 /* TODO remove array */
597 uint32_t *param_in = malloc(3 * sizeof(uint32_t));
598 int retval;
599 param_in[0] = start_addr;
600 param_in[1] = end_addr;
601 param_in[2] = clsiz;
602
603 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 3, param_in, 0, NULL, 1);
604
605 free(param_in);
606
607 return retval;
608 }
609
610 static int mips32_pracc_write_mem_generic(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
611 {
612 uint32_t *code;
613 code = malloc((128 * 3 + 9) * sizeof(uint32_t)); /* alloc memory for the worst case */
614 if (code == NULL) {
615 LOG_ERROR("Out of memory");
616 return ERROR_FAIL;
617 }
618
619 uint32_t *buf32 = buf;
620 uint16_t *buf16 = buf;
621 uint8_t *buf8 = buf;
622
623 int i;
624 int retval = ERROR_FAIL;
625 uint32_t *code_p;
626 uint32_t upper_base_addr, last_upper_base_addr;
627 int this_round_count;
628 int code_len;
629
630 while (count) {
631 this_round_count = (count > 128) ? 128 : count;
632 last_upper_base_addr = UPPER16((addr + 0x8000));
633 code_p = code;
634
635 *code_p++ = MIPS32_MTC0(15, 31, 0); /* save $15 in DeSave */
636 *code_p++ = MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR); /* $15 = MIPS32_PRACC_BASE_ADDR */
637 *code_p++ = MIPS32_SW(8, PRACC_STACK_OFFSET, 15); /* save $8 to pracc stack */
638 *code_p++ = MIPS32_LUI(15, last_upper_base_addr); /* reuse $15 as memory base address */
639 code_len = 4;
640
641 for (i = 0; i != this_round_count; i++) {
642 upper_base_addr = UPPER16((addr + 0x8000));
643 if (last_upper_base_addr != upper_base_addr) {
644 *code_p++ = MIPS32_LUI(15, upper_base_addr); /* if needed, change upper address in $15*/
645 code_len++;
646 last_upper_base_addr = upper_base_addr;
647 }
648
649 if (size == 4) { /* for word write check if one half word is 0 and load it accordingly */
650 if (LOWER16(*buf32) == 0) {
651 *code_p++ = MIPS32_LUI(8, UPPER16(*buf32)); /* load only upper value */
652 code_len++;
653 } else if (UPPER16(*buf32) == 0) {
654 *code_p++ = MIPS32_ORI(8, 0, LOWER16(*buf32)); /* load only lower value */
655 code_len++;
656 } else {
657 *code_p++ = MIPS32_LUI(8, UPPER16(*buf32)); /* load upper and lower */
658 *code_p++ = MIPS32_ORI(8, 8, LOWER16(*buf32));
659 code_len += 2;
660 }
661 *code_p++ = MIPS32_SW(8, LOWER16(addr), 15); /* store word to memory */
662 code_len++;
663 buf32++;
664
665 } else if (size == 2) {
666 *code_p++ = MIPS32_ORI(8, 0, *buf16); /* load lower value */
667 *code_p++ = MIPS32_SH(8, LOWER16(addr), 15); /* store half word to memory */
668 code_len += 2;
669 buf16++;
670
671 } else {
672 *code_p++ = MIPS32_ORI(8, 0, *buf8); /* load lower value */
673 *code_p++ = MIPS32_SB(8, LOWER16(addr), 15); /* store byte to memory */
674 code_len += 2;
675 buf8++;
676 }
677
678 addr += size;
679 }
680
681 *code_p++ = MIPS32_LUI(15, PRACC_UPPER_BASE_ADDR); /* $15 = MIPS32_PRACC_BASE_ADDR */
682 *code_p++ = MIPS32_LW(8, PRACC_STACK_OFFSET, 15); /* restore $8 from pracc stack */
683
684 code_len += 4;
685 *code_p++ = MIPS32_B(NEG16(code_len - 1)); /* jump to start */
686 *code_p = MIPS32_MFC0(15, 31, 0); /* restore $15 from DeSave */
687
688 retval = mips32_pracc_exec(ejtag_info, code_len, code, 0, NULL, 0, NULL, 1);
689 if (retval != ERROR_OK)
690 goto exit;
691
692 count -= this_round_count;
693 }
694
695 exit:
696 free(code);
697 return retval;
698 }
699
700 int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
701 {
702 int retval = mips32_pracc_write_mem_generic(ejtag_info, addr, size, count, buf);
703 if (retval != ERROR_OK)
704 return retval;
705
706 /**
707 * If we are in the cachable regoion and cache is activated,
708 * we must clean D$ + invalidate I$ after we did the write,
709 * so that changes do not continue to live only in D$, but to be
710 * replicated in I$ also (maybe we wrote the istructions)
711 */
712 uint32_t conf = 0;
713 int cached = 0;
714
715 if ((KSEGX(addr) == KSEG1) || ((addr >= 0xff200000) && (addr <= 0xff3fffff)))
716 return retval; /*Nothing to do*/
717
718 mips32_cp0_read(ejtag_info, &conf, 16, 0);
719
720 switch (KSEGX(addr)) {
721 case KUSEG:
722 cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT;
723 break;
724 case KSEG0:
725 cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT;
726 break;
727 case KSEG2:
728 case KSEG3:
729 cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT;
730 break;
731 default:
732 /* what ? */
733 break;
734 }
735
736 /**
737 * Check cachablitiy bits coherency algorithm -
738 * is the region cacheable or uncached.
739 * If cacheable we have to synchronize the cache
740 */
741 if (cached == 0x3) {
742 uint32_t start_addr, end_addr;
743 uint32_t rel;
744
745 start_addr = addr;
746 end_addr = addr + count * size;
747
748 /** select cache synchronisation mechanism based on Architecture Release */
749 rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT;
750 switch (rel) {
751 case MIPS32_ARCH_REL1:
752 /* MIPS32/64 Release 1 - we must use cache instruction */
753 mips32_pracc_clean_invalidate_cache(ejtag_info, start_addr, end_addr);
754 break;
755 case MIPS32_ARCH_REL2:
756 /* MIPS32/64 Release 2 - we can use synci instruction */
757 mips32_pracc_sync_cache(ejtag_info, start_addr, end_addr);
758 break;
759 default:
760 /* what ? */
761 break;
762 }
763 }
764
765 return retval;
766 }
767
768 int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
769 {
770 static const uint32_t cp0_write_code[] = {
771 MIPS32_MTC0(1, 12, 0), /* move $1 to status */
772 MIPS32_MTLO(1), /* move $1 to lo */
773 MIPS32_MTHI(1), /* move $1 to hi */
774 MIPS32_MTC0(1, 8, 0), /* move $1 to badvaddr */
775 MIPS32_MTC0(1, 13, 0), /* move $1 to cause*/
776 MIPS32_MTC0(1, 24, 0), /* move $1 to depc (pc) */
777 };
778
779 uint32_t *code;
780 code = malloc((37 * 2 + 6 + 1) * sizeof(uint32_t)); /* alloc memory for the worst case */
781 if (code == NULL) {
782 LOG_ERROR("Out of memory");
783 return ERROR_FAIL;
784 }
785
786 uint32_t *code_p = code;
787 int code_len = 0;
788 /* load registers 2 to 31 with lui an ori instructions, check if same instructions can be saved */
789 for (int i = 2; i < 32; i++) {
790 if (LOWER16((regs[i])) == 0) {
791 *code_p++ = MIPS32_LUI(i, UPPER16((regs[i]))); /* if lower half word is 0, lui instruction only */
792 code_len++;
793 } else if (UPPER16((regs[i])) == 0) {
794 *code_p++ = MIPS32_ORI(i, 0, LOWER16((regs[i]))); /* if upper half word is 0, ori with $0 only*/
795 code_len++;
796 } else {
797 *code_p++ = MIPS32_LUI(i, UPPER16((regs[i]))); /* default, load with lui and ori instructions */
798 *code_p++ = MIPS32_ORI(i, i, LOWER16((regs[i])));
799 code_len += 2;
800 }
801 }
802
803 for (int i = 0; i != 6; i++) {
804 *code_p++ = MIPS32_LUI(1, UPPER16((regs[i + 32]))); /* load CPO value in $1, with lui and ori */
805 *code_p++ = MIPS32_ORI(1, 1, LOWER16((regs[i + 32])));
806 *code_p++ = cp0_write_code[i]; /* write value from $1 to CPO register */
807 code_len += 3;
808 }
809
810 *code_p++ = MIPS32_LUI(1, UPPER16((regs[1]))); /* load upper half word in $1 */
811 code_len += 3;
812 *code_p++ = MIPS32_B(NEG16(code_len - 1)), /* b start */
813 *code_p = MIPS32_ORI(1, 1, LOWER16((regs[1]))); /* load lower half word in $1 */
814
815 int retval = mips32_pracc_exec(ejtag_info, code_len, code, 0, NULL, 0, NULL, 1);
816 free(code);
817 return retval;
818 }
819
820 int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
821 {
822 static int cp0_read_code[] = {
823 MIPS32_MFC0(2, 12, 0), /* move status to $2 */
824 MIPS32_MFLO(2), /* move lo to $2 */
825 MIPS32_MFHI(2), /* move hi to $2 */
826 MIPS32_MFC0(2, 8, 0), /* move badvaddr to $2 */
827 MIPS32_MFC0(2, 13, 0), /* move cause to $2 */
828 MIPS32_MFC0(2, 24, 0), /* move depc (pc) to $2 */
829 };
830
831 uint32_t *code;
832 code = malloc(49 * sizeof(uint32_t));
833 if (code == NULL) {
834 LOG_ERROR("Out of memory");
835 return ERROR_FAIL;
836 }
837
838 uint32_t *code_p = code;
839
840 *code_p++ = MIPS32_MTC0(1, 31, 0), /* move $1 to COP0 DeSave */
841 *code_p++ = MIPS32_LUI(1, PRACC_UPPER_BASE_ADDR); /* $1 = MIP32_PRACC_BASE_ADDR */
842
843 for (int i = 2; i != 32; i++)
844 *code_p++ = MIPS32_SW(i, PRACC_OUT_OFFSET + (i * 4), 1); /* store GPR's 2 to 31 */
845
846 for (int i = 0; i != 6; i++) {
847 *code_p++ = cp0_read_code[i]; /* load COP0 needed registers to $2 */
848 *code_p++ = MIPS32_SW(2, PRACC_OUT_OFFSET + (i + 32) * 4, 1); /* store COP0 registers from $2 to param out */
849 }
850
851 *code_p++ = MIPS32_MFC0(2, 31, 0), /* move DeSave to $2, reg1 value */
852 *code_p++ = MIPS32_SW(2, PRACC_OUT_OFFSET + 4, 1); /* store reg1 value from $2 to param out */
853
854 *code_p++ = MIPS32_LW(2, PRACC_OUT_OFFSET + 8, 1); /* restore $2 from param out (singularity) */
855 *code_p++ = MIPS32_B(NEG16(48)); /* b start */
856 *code_p = MIPS32_MFC0(1, 31, 0); /* move COP0 DeSave to $1 */
857
858 int retval = mips32_pracc_exec(ejtag_info, 49, code, 0, NULL, MIPS32NUMCOREREGS, regs, 1);
859
860 free(code);
861 return retval;
862 }
863
864 /* fastdata upload/download requires an initialized working area
865 * to load the download code; it should not be called otherwise
866 * fetch order from the fastdata area
867 * 1. start addr
868 * 2. end addr
869 * 3. data ...
870 */
871 int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source,
872 int write_t, uint32_t addr, int count, uint32_t *buf)
873 {
874 uint32_t handler_code[] = {
875 /* caution when editing, table is modified below */
876 /* r15 points to the start of this code */
877 MIPS32_SW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15),
878 MIPS32_SW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15),
879 MIPS32_SW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15),
880 MIPS32_SW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15),
881 /* start of fastdata area in t0 */
882 MIPS32_LUI(8, UPPER16(MIPS32_PRACC_FASTDATA_AREA)),
883 MIPS32_ORI(8, 8, LOWER16(MIPS32_PRACC_FASTDATA_AREA)),
884 MIPS32_LW(9, 0, 8), /* start addr in t1 */
885 MIPS32_LW(10, 0, 8), /* end addr to t2 */
886 /* loop: */
887 /* 8 */ MIPS32_LW(11, 0, 0), /* lw t3,[t8 | r9] */
888 /* 9 */ MIPS32_SW(11, 0, 0), /* sw t3,[r9 | r8] */
889 MIPS32_BNE(10, 9, NEG16(3)), /* bne $t2,t1,loop */
890 MIPS32_ADDI(9, 9, 4), /* addi t1,t1,4 */
891
892 MIPS32_LW(8, MIPS32_FASTDATA_HANDLER_SIZE - 4, 15),
893 MIPS32_LW(9, MIPS32_FASTDATA_HANDLER_SIZE - 8, 15),
894 MIPS32_LW(10, MIPS32_FASTDATA_HANDLER_SIZE - 12, 15),
895 MIPS32_LW(11, MIPS32_FASTDATA_HANDLER_SIZE - 16, 15),
896
897 MIPS32_LUI(15, UPPER16(MIPS32_PRACC_TEXT)),
898 MIPS32_ORI(15, 15, LOWER16(MIPS32_PRACC_TEXT)),
899 MIPS32_JR(15), /* jr start */
900 MIPS32_MFC0(15, 31, 0), /* move COP0 DeSave to $15 */
901 };
902
903 uint32_t jmp_code[] = {
904 MIPS32_MTC0(15, 31, 0), /* move $15 to COP0 DeSave */
905 /* 1 */ MIPS32_LUI(15, 0), /* addr of working area added below */
906 /* 2 */ MIPS32_ORI(15, 15, 0), /* addr of working area added below */
907 MIPS32_JR(15), /* jump to ram program */
908 MIPS32_NOP,
909 };
910
911 int retval, i;
912 uint32_t val, ejtag_ctrl, address;
913
914 if (source->size < MIPS32_FASTDATA_HANDLER_SIZE)
915 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
916
917 if (write_t) {
918 handler_code[8] = MIPS32_LW(11, 0, 8); /* load data from probe at fastdata area */
919 handler_code[9] = MIPS32_SW(11, 0, 9); /* store data to RAM @ r9 */
920 } else {
921 handler_code[8] = MIPS32_LW(11, 0, 9); /* load data from RAM @ r9 */
922 handler_code[9] = MIPS32_SW(11, 0, 8); /* store data to probe at fastdata area */
923 }
924
925 /* write program into RAM */
926 if (write_t != ejtag_info->fast_access_save) {
927 mips32_pracc_write_mem_generic(ejtag_info, source->address, 4, ARRAY_SIZE(handler_code), handler_code);
928 /* save previous operation to speed to any consecutive read/writes */
929 ejtag_info->fast_access_save = write_t;
930 }
931
932 LOG_DEBUG("%s using 0x%.8" PRIx32 " for write handler", __func__, source->address);
933
934 jmp_code[1] |= UPPER16(source->address);
935 jmp_code[2] |= LOWER16(source->address);
936
937 for (i = 0; i < (int) ARRAY_SIZE(jmp_code); i++) {
938 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
939 if (retval != ERROR_OK)
940 return retval;
941
942 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
943 mips_ejtag_drscan_32_out(ejtag_info, jmp_code[i]);
944
945 /* Clear the access pending bit (let the processor eat!) */
946 ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
947 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
948 mips_ejtag_drscan_32_out(ejtag_info, ejtag_ctrl);
949 }
950
951 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
952 if (retval != ERROR_OK)
953 return retval;
954
955 /* next fetch to dmseg should be in FASTDATA_AREA, check */
956 address = 0;
957 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
958 retval = mips_ejtag_drscan_32(ejtag_info, &address);
959 if (retval != ERROR_OK)
960 return retval;
961
962 if (address != MIPS32_PRACC_FASTDATA_AREA)
963 return ERROR_FAIL;
964
965 /* wait PrAcc pending bit for FASTDATA write */
966 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
967 if (retval != ERROR_OK)
968 return retval;
969
970 /* Send the load start address */
971 val = addr;
972 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA);
973 mips_ejtag_fastdata_scan(ejtag_info, 1, &val);
974
975 /* Send the load end address */
976 val = addr + (count - 1) * 4;
977 mips_ejtag_fastdata_scan(ejtag_info, 1, &val);
978
979 for (i = 0; i < count; i++) {
980 retval = mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++);
981 if (retval != ERROR_OK)
982 return retval;
983 }
984
985 retval = jtag_execute_queue();
986 if (retval != ERROR_OK) {
987 LOG_ERROR("fastdata load failed");
988 return retval;
989 }
990
991 retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl);
992 if (retval != ERROR_OK)
993 return retval;
994
995 address = 0;
996 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
997 retval = mips_ejtag_drscan_32(ejtag_info, &address);
998 if (retval != ERROR_OK)
999 return retval;
1000
1001 if (address != MIPS32_PRACC_TEXT)
1002 LOG_ERROR("mini program did not return to start");
1003
1004 return retval;
1005 }

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)