cleanup: rename armv4_5 to arm for readability
[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
39 LW $2, ($5 +10)
40 B foo
41 LW $1, ($2 +100)
42
43 The LW $1, ($2 +100) instruction is also executed. If this is
44 not wanted a NOP can be inserted:
45
46 LW $2, ($5 +10)
47 B foo
48 NOP
49 LW $1, ($2 +100)
50
51 or the code can be changed to:
52
53 B foo
54 LW $2, ($5 +10)
55 LW $1, ($2 +100)
56
57 The original code contained NOPs. I have removed these and moved
58 the branches.
59
60 I also moved the PRACC_STACK to 0xFF204000. This allows
61 the use of 16 bits offsets to get pointers to the input
62 and output area relative to the stack. Note that the stack
63 isn't really a stack (the stack pointer is not 'moving')
64 but a FIFO simulated in software.
65
66 These changes result in a 35% speed increase when programming an
67 external flash.
68
69 More improvement could be gained if the registers do no need
70 to be preserved but in that case the routines should be aware
71 OpenOCD is used as a flash programmer or as a debug tool.
72
73 Nico Coesel
74 */
75
76 #ifdef HAVE_CONFIG_H
77 #include "config.h"
78 #endif
79
80 #include <helper/time_support.h>
81
82 #include "mips32.h"
83 #include "mips32_pracc.h"
84
85 struct mips32_pracc_context
86 {
87 uint32_t *local_iparam;
88 int num_iparam;
89 uint32_t *local_oparam;
90 int num_oparam;
91 const uint32_t *code;
92 int code_len;
93 uint32_t stack[32];
94 int stack_offset;
95 struct mips_ejtag *ejtag_info;
96 };
97
98 static int mips32_pracc_read_mem8(struct mips_ejtag *ejtag_info,
99 uint32_t addr, int count, uint8_t *buf);
100 static int mips32_pracc_read_mem16(struct mips_ejtag *ejtag_info,
101 uint32_t addr, int count, uint16_t *buf);
102 static int mips32_pracc_read_mem32(struct mips_ejtag *ejtag_info,
103 uint32_t addr, int count, uint32_t *buf);
104 static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info,
105 uint32_t addr, uint32_t *buf);
106
107 static int mips32_pracc_write_mem8(struct mips_ejtag *ejtag_info,
108 uint32_t addr, int count, uint8_t *buf);
109 static int mips32_pracc_write_mem16(struct mips_ejtag *ejtag_info,
110 uint32_t addr, int count, uint16_t *buf);
111 static int mips32_pracc_write_mem32(struct mips_ejtag *ejtag_info,
112 uint32_t addr, int count, uint32_t *buf);
113 static int mips32_pracc_write_u32(struct mips_ejtag *ejtag_info,
114 uint32_t addr, uint32_t *buf);
115
116 static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info,
117 uint32_t start_addr, uint32_t end_addr);
118 static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag *ejtag_info,
119 uint32_t start_addr, uint32_t end_addr);
120
121 static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl)
122 {
123 uint32_t ejtag_ctrl;
124 long long then = timeval_ms();
125 int timeout;
126 int retval;
127
128 /* wait for the PrAcc to become "1" */
129 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
130 ejtag_ctrl = ejtag_info->ejtag_ctrl;
131
132 while (1)
133 {
134 retval = mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
135 if (retval != ERROR_OK)
136 return retval;
137
138 if (ejtag_ctrl & EJTAG_CTRL_PRACC)
139 break;
140
141 if ( (timeout = timeval_ms()-then) > 1000 )
142 {
143 LOG_DEBUG("DEBUGMODULE: No memory access in progress!");
144 return ERROR_JTAG_DEVICE_ERROR;
145 }
146 }
147
148 *ctrl = ejtag_ctrl;
149 return ERROR_OK;
150 }
151
152 static int mips32_pracc_exec_read(struct mips32_pracc_context *ctx, uint32_t address)
153 {
154 struct mips_ejtag *ejtag_info = ctx->ejtag_info;
155 int offset;
156 uint32_t ejtag_ctrl, data;
157
158 if ((address >= MIPS32_PRACC_PARAM_IN)
159 && (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4))
160 {
161 offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
162 data = ctx->local_iparam[offset];
163 }
164 else if ((address >= MIPS32_PRACC_PARAM_OUT)
165 && (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4))
166 {
167 offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
168 data = ctx->local_oparam[offset];
169 }
170 else if ((address >= MIPS32_PRACC_TEXT)
171 && (address <= MIPS32_PRACC_TEXT + ctx->code_len * 4))
172 {
173 offset = (address - MIPS32_PRACC_TEXT) / 4;
174 data = ctx->code[offset];
175 }
176 else if (address == MIPS32_PRACC_STACK)
177 {
178 /* save to our debug stack */
179 data = ctx->stack[--ctx->stack_offset];
180 }
181 else
182 {
183 /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back
184 * to start of debug vector */
185
186 LOG_ERROR("Error reading unexpected address 0x%8.8" PRIx32 "", address);
187 return ERROR_JTAG_DEVICE_ERROR;
188 }
189
190 /* Send the data out */
191 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA);
192 mips_ejtag_drscan_32_out(ctx->ejtag_info, data);
193
194 /* Clear the access pending bit (let the processor eat!) */
195 ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
196 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL);
197 mips_ejtag_drscan_32_out(ctx->ejtag_info, ejtag_ctrl);
198
199 return jtag_execute_queue();
200 }
201
202 static int mips32_pracc_exec_write(struct mips32_pracc_context *ctx, uint32_t address)
203 {
204 uint32_t ejtag_ctrl,data;
205 int offset;
206 struct mips_ejtag *ejtag_info = ctx->ejtag_info;
207 int retval;
208
209 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA);
210 retval = mips_ejtag_drscan_32(ctx->ejtag_info, &data);
211 if (retval != ERROR_OK)
212 return retval;
213
214 /* Clear access pending bit */
215 ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
216 mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL);
217 mips_ejtag_drscan_32_out(ctx->ejtag_info, ejtag_ctrl);
218
219 retval = jtag_execute_queue();
220 if (retval != ERROR_OK)
221 return retval;
222
223 if ((address >= MIPS32_PRACC_PARAM_IN)
224 && (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4))
225 {
226 offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
227 ctx->local_iparam[offset] = data;
228 }
229 else if ((address >= MIPS32_PRACC_PARAM_OUT)
230 && (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4))
231 {
232 offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
233 ctx->local_oparam[offset] = data;
234 }
235 else if (address == MIPS32_PRACC_STACK)
236 {
237 /* save data onto our stack */
238 ctx->stack[ctx->stack_offset++] = data;
239 }
240 else
241 {
242 LOG_ERROR("Error writing unexpected address 0x%8.8" PRIx32 "", address);
243 return ERROR_JTAG_DEVICE_ERROR;
244 }
245
246 return ERROR_OK;
247 }
248
249 int mips32_pracc_exec(struct mips_ejtag *ejtag_info, int code_len, const uint32_t *code,
250 int num_param_in, uint32_t *param_in, int num_param_out, uint32_t *param_out, int cycle)
251 {
252 uint32_t ejtag_ctrl;
253 uint32_t address, data;
254 struct mips32_pracc_context ctx;
255 int retval;
256 int pass = 0;
257
258 ctx.local_iparam = param_in;
259 ctx.local_oparam = param_out;
260 ctx.num_iparam = num_param_in;
261 ctx.num_oparam = num_param_out;
262 ctx.code = code;
263 ctx.code_len = code_len;
264 ctx.ejtag_info = ejtag_info;
265 ctx.stack_offset = 0;
266
267 while (1)
268 {
269 if ((retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl)) != ERROR_OK)
270 return retval;
271
272 address = data = 0;
273 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
274 retval = mips_ejtag_drscan_32(ejtag_info, &address);
275 if (retval != ERROR_OK)
276 return retval;
277
278 /* Check for read or write */
279 if (ejtag_ctrl & EJTAG_CTRL_PRNW)
280 {
281 if ((retval = mips32_pracc_exec_write(&ctx, address)) != ERROR_OK)
282 return retval;
283 }
284 else
285 {
286 /* Check to see if its reading at the debug vector. The first pass through
287 * the module is always read at the vector, so the first one we allow. When
288 * the second read from the vector occurs we are done and just exit. */
289 if ((address == MIPS32_PRACC_TEXT) && (pass++))
290 {
291 break;
292 }
293
294 if ((retval = mips32_pracc_exec_read(&ctx, address)) != ERROR_OK)
295 return retval;
296 }
297
298 if (cycle == 0)
299 break;
300 }
301
302 /* stack sanity check */
303 if (ctx.stack_offset != 0)
304 {
305 LOG_DEBUG("Pracc Stack not zero");
306 }
307
308 return ERROR_OK;
309 }
310
311 int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
312 {
313 switch (size)
314 {
315 case 1:
316 return mips32_pracc_read_mem8(ejtag_info, addr, count, (uint8_t*)buf);
317 case 2:
318 return mips32_pracc_read_mem16(ejtag_info, addr, count, (uint16_t*)buf);
319 case 4:
320 if (count == 1)
321 return mips32_pracc_read_u32(ejtag_info, addr, (uint32_t*)buf);
322 else
323 return mips32_pracc_read_mem32(ejtag_info, addr, count, (uint32_t*)buf);
324 }
325
326 return ERROR_OK;
327 }
328
329 static int mips32_pracc_read_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
330 {
331 static const uint32_t code[] = {
332 /* start: */
333 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
334 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
335 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
336 MIPS32_SW(8,0,15), /* sw $8,($15) */
337 MIPS32_SW(9,0,15), /* sw $9,($15) */
338 MIPS32_SW(10,0,15), /* sw $10,($15) */
339 MIPS32_SW(11,0,15), /* sw $11,($15) */
340
341 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
342 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
343 MIPS32_LW(9,0,8), /* $9 = mem[$8]; read addr */
344 MIPS32_LW(10,4,8), /* $10 = mem[$8 + 4]; read count */
345 MIPS32_LUI(11,UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */
346 MIPS32_ORI(11,11,LOWER16(MIPS32_PRACC_PARAM_OUT)),
347 /* loop: */
348 MIPS32_BEQ(0,10,8), /* beq 0, $10, end */
349 MIPS32_NOP,
350
351 MIPS32_LW(8,0,9), /* lw $8,0($9), Load $8 with the word @mem[$9] */
352 MIPS32_SW(8,0,11), /* sw $8,0($11) */
353
354 MIPS32_ADDI(10,10,NEG16(1)), /* $10-- */
355 MIPS32_ADDI(9,9,4), /* $1 += 4 */
356 MIPS32_ADDI(11,11,4), /* $11 += 4 */
357
358 MIPS32_B(NEG16(8)), /* b loop */
359 MIPS32_NOP,
360 /* end: */
361 MIPS32_LW(11,0,15), /* lw $11,($15) */
362 MIPS32_LW(10,0,15), /* lw $10,($15) */
363 MIPS32_LW(9,0,15), /* lw $9,($15) */
364 MIPS32_LW(8,0,15), /* lw $8,($15) */
365 MIPS32_B(NEG16(27)), /* b start */
366 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
367 };
368
369 int retval = ERROR_OK;
370 int blocksize;
371 int bytesread;
372 uint32_t param_in[2];
373
374 bytesread = 0;
375
376 while (count > 0)
377 {
378 blocksize = count;
379 if (count > 0x400)
380 blocksize = 0x400;
381
382 param_in[0] = addr;
383 param_in[1] = blocksize;
384
385 if ((retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
386 ARRAY_SIZE(param_in), param_in, blocksize, &buf[bytesread], 1)) != ERROR_OK)
387 {
388 return retval;
389 }
390
391 count -= blocksize;
392 addr += blocksize;
393 bytesread += blocksize;
394 }
395
396 return retval;
397 }
398
399 static int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf)
400 {
401 static const uint32_t code[] = {
402 /* start: */
403 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
404 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
405 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
406 MIPS32_SW(8,0,15), /* sw $8,($15) */
407
408 MIPS32_LW(8,NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN),15), /* load R8 @ param_in[0] = address */
409
410 MIPS32_LW(8,0,8), /* lw $8,0($8), Load $8 with the word @mem[$8] */
411 MIPS32_SW(8,NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_OUT),15), /* store R8 @ param_out[0] */
412
413 MIPS32_LW(8,0,15), /* lw $8,($15) */
414 MIPS32_B(NEG16(9)), /* b start */
415 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
416 };
417
418 int retval = ERROR_OK;
419 uint32_t param_in[1];
420
421 param_in[0] = addr;
422
423 if ((retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
424 ARRAY_SIZE(param_in), param_in, 1, buf, 1)) != ERROR_OK)
425 {
426 return retval;
427 }
428
429 return retval;
430 }
431
432 static int mips32_pracc_read_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf)
433 {
434 static const uint32_t code[] = {
435 /* start: */
436 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
437 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
438 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
439 MIPS32_SW(8,0,15), /* sw $8,($15) */
440 MIPS32_SW(9,0,15), /* sw $9,($15) */
441 MIPS32_SW(10,0,15), /* sw $10,($15) */
442 MIPS32_SW(11,0,15), /* sw $11,($15) */
443
444 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
445 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
446 MIPS32_LW(9,0,8), /* $9 = mem[$8]; read addr */
447 MIPS32_LW(10,4,8), /* $10 = mem[$8 + 4]; read count */
448 MIPS32_LUI(11,UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */
449 MIPS32_ORI(11,11,LOWER16(MIPS32_PRACC_PARAM_OUT)),
450 /* loop: */
451 MIPS32_BEQ(0,10,8), /* beq 0, $10, end */
452 MIPS32_NOP,
453
454 MIPS32_LHU(8,0,9), /* lw $8,0($9), Load $8 with the halfword @mem[$9] */
455 MIPS32_SW(8,0,11), /* sw $8,0($11) */
456
457 MIPS32_ADDI(10,10,NEG16(1)), /* $10-- */
458 MIPS32_ADDI(9,9,2), /* $9 += 2 */
459 MIPS32_ADDI(11,11,4), /* $11 += 4 */
460 MIPS32_B(NEG16(8)), /* b loop */
461 MIPS32_NOP,
462 /* end: */
463 MIPS32_LW(11,0,15), /* lw $11,($15) */
464 MIPS32_LW(10,0,15), /* lw $10,($15) */
465 MIPS32_LW(9,0,15), /* lw $9,($15) */
466 MIPS32_LW(8,0,15), /* lw $8,($15) */
467 MIPS32_B(NEG16(27)), /* b start */
468 MIPS32_MFC0(15,30,0), /* move COP0 DeSave to $15 */
469 };
470
471 /* TODO remove array */
472 uint32_t *param_out = malloc(count * sizeof(uint32_t));
473 int i;
474
475 int retval = ERROR_OK;
476 int blocksize;
477 uint32_t param_in[2];
478
479 //while (count > 0)
480 {
481 blocksize = count;
482 if (count > 0x400)
483 blocksize = 0x400;
484
485 param_in[0] = addr;
486 param_in[1] = blocksize;
487
488 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
489 ARRAY_SIZE(param_in), param_in, count, param_out, 1);
490
491 // count -= blocksize;
492 // addr += blocksize;
493 }
494
495 for (i = 0; i < count; i++)
496 {
497 buf[i] = param_out[i];
498 }
499
500 free(param_out);
501
502 return retval;
503 }
504
505 static int mips32_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf)
506 {
507 static const uint32_t code[] = {
508 /* start: */
509 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
510 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
511 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
512 MIPS32_SW(8,0,15), /* sw $8,($15) */
513 MIPS32_SW(9,0,15), /* sw $9,($15) */
514 MIPS32_SW(10,0,15), /* sw $10,($15) */
515 MIPS32_SW(11,0,15), /* sw $11,($15) */
516
517 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
518 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
519 MIPS32_LW(9,0,8), /* $9 = mem[$8]; read addr */
520 MIPS32_LW(10,4,8), /* $10 = mem[$8 + 4]; read count */
521 MIPS32_LUI(11,UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */
522 MIPS32_ORI(11,11,LOWER16(MIPS32_PRACC_PARAM_OUT)),
523 /* loop: */
524 MIPS32_BEQ(0,10,8), /* beq 0, $10, end */
525 MIPS32_NOP,
526
527 MIPS32_LBU(8,0,9), /* lw $8,0($9), Load t4 with the byte @mem[t1] */
528 MIPS32_SW(8,0,11), /* sw $8,0($11) */
529
530 MIPS32_ADDI(10,10,NEG16(1)), /* $10-- */
531 MIPS32_ADDI(9,9,1), /* $9 += 1 */
532 MIPS32_ADDI(11,11,4), /* $11 += 4 */
533 MIPS32_B(NEG16(8)), /* b loop */
534 MIPS32_NOP,
535 /* end: */
536 MIPS32_LW(11,0,15), /* lw $11,($15) */
537 MIPS32_LW(10,0,15), /* lw $10,($15) */
538 MIPS32_LW(9,0,15), /* lw $9,($15) */
539 MIPS32_LW(8,0,15), /* lw $8,($15) */
540 MIPS32_B(NEG16(27)), /* b start */
541 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
542 };
543
544 /* TODO remove array */
545 uint32_t *param_out = malloc(count * sizeof(uint32_t));
546 int i;
547
548 int retval = ERROR_OK;
549 int blocksize;
550 uint32_t param_in[2];
551
552 // while (count > 0)
553 {
554 blocksize = count;
555 if (count > 0x400)
556 blocksize = 0x400;
557
558 param_in[0] = addr;
559 param_in[1] = blocksize;
560
561 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
562 ARRAY_SIZE(param_in), param_in, count, param_out, 1);
563
564 // count -= blocksize;
565 // addr += blocksize;
566 }
567
568 for (i = 0; i < count; i++)
569 {
570 buf[i] = param_out[i];
571 }
572
573 free(param_out);
574
575 return retval;
576 }
577
578 int mips32_cp0_read(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t cp0_reg, uint32_t cp0_sel)
579 {
580 /**
581 * Do not make this code static, but regenerate it every time,
582 * as 5th element has to be changed to add parameters
583 */
584 uint32_t code[] = {
585 /* start: */
586 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
587 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
588 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
589 MIPS32_SW(8,0,15), /* sw $8,($15) */
590 MIPS32_SW(9,0,15), /* sw $9,($15) */
591
592 /* 5 */ MIPS32_MFC0(8,0,0), /* move COP0 [cp0_reg select] to $8 */
593
594 MIPS32_LUI(9,UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $11 = MIPS32_PRACC_PARAM_OUT */
595 MIPS32_ORI(9,9,LOWER16(MIPS32_PRACC_PARAM_OUT)),
596 MIPS32_SW(8,0,9), /* sw $8,0($9) */
597
598 MIPS32_LW(9,0,15), /* lw $9,($15) */
599 MIPS32_LW(8,0,15), /* lw $8,($15) */
600 MIPS32_B(NEG16(12)), /* b start */
601 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
602 };
603
604 /**
605 * Note that our input parametes cp0_reg and cp0_sel
606 * are numbers (not gprs) which make part of mfc0 instruction opcode.
607 *
608 * These are not fix, but can be different for each mips32_cp0_read() function call,
609 * and that is why we must insert them directly into opcode,
610 * i.e. we can not pass it on EJTAG microprogram stack (via param_in),
611 * and put them into the gprs later from MIPS32_PRACC_STACK
612 * because mfc0 do not use gpr as a parameter for the cp0_reg and select part,
613 * but plain (immediate) number.
614 *
615 * MIPS32_MTC0 is implemented via MIPS32_R_INST macro.
616 * In order to insert our parameters, we must change rd and funct fields.
617 */
618 code[5] |= (cp0_reg << 11) | cp0_sel; /* change rd and funct of MIPS32_R_INST macro */
619
620 /* TODO remove array */
621 uint32_t *param_out = val;
622 int retval;
623
624 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 0, NULL, 1, param_out, 1);
625
626 return retval;
627 }
628
629 int mips32_cp0_write(struct mips_ejtag *ejtag_info,
630 uint32_t val, uint32_t cp0_reg, uint32_t cp0_sel)
631 {
632 uint32_t code[] = {
633 /* start: */
634 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
635 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
636 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
637 MIPS32_SW(8,0,15), /* sw $8,($15) */
638 MIPS32_SW(9,0,15), /* sw $9,($15) */
639
640 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
641 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
642 MIPS32_LW(9,0,8), /* Load write val to $9 */
643
644 /* 8 */ MIPS32_MTC0(9,0,0), /* move $9 to COP0 [cp0_reg select] */
645
646 MIPS32_LW(9,0,15), /* lw $9,($15) */
647 MIPS32_LW(8,0,15), /* lw $8,($15) */
648 MIPS32_B(NEG16(12)), /* b start */
649 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
650 };
651
652 /**
653 * Note that MIPS32_MTC0 macro is implemented via MIPS32_R_INST macro.
654 * In order to insert our parameters, we must change rd and funct fields.
655 */
656 code[8] |= (cp0_reg << 11) | cp0_sel; /* change rd and funct fields of MIPS32_R_INST macro */
657
658 /* TODO remove array */
659 uint32_t *param_in = malloc(1 * sizeof(uint32_t));
660 int retval;
661 param_in[0] = val;
662
663 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 1, param_in, 0, NULL, 1);
664
665 free(param_in);
666
667 return retval;
668 }
669
670 /**
671 * \b mips32_pracc_sync_cache
672 *
673 * Synchronize Caches to Make Instruction Writes Effective
674 * (ref. doc. MIPS32 Architecture For Programmers Volume II: The MIPS32 Instruction Set,
675 * Document Number: MD00086, Revision 2.00, June 9, 2003)
676 *
677 * When the instruction stream is written, the SYNCI instruction should be used
678 * in conjunction with other instructions to make the newly-written instructions effective.
679 *
680 * Explanation :
681 * A program that loads another program into memory is actually writing the D- side cache.
682 * The instructions it has loaded can't be executed until they reach the I-cache.
683 *
684 * After the instructions have been written, the loader should arrange
685 * to write back any containing D-cache line and invalidate any locations
686 * already in the I-cache.
687 *
688 * You can do that with cache instructions, but those instructions are only available in kernel mode,
689 * and a loader writing instructions for the use of its own process need not be privileged software.
690 *
691 * In the latest MIPS32/64 CPUs, MIPS provides the synci instruction,
692 * which does the whole job for a cache-line-sized chunk of the memory you just loaded:
693 * That is, it arranges a D-cache write-back and an I-cache invalidate.
694 *
695 * To employ synci at user level, you need to know the size of a cache line,
696 * and that can be obtained with a rdhwr SYNCI_Step
697 * from one of the standard “hardware registers”.
698 */
699 static int mips32_pracc_sync_cache(struct mips_ejtag *ejtag_info,
700 uint32_t start_addr, uint32_t end_addr)
701 {
702 static const uint32_t code[] = {
703 /* start: */
704 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
705 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
706 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
707 MIPS32_SW(8,0,15), /* sw $8,($15) */
708 MIPS32_SW(9,0,15), /* sw $9,($15) */
709 MIPS32_SW(10,0,15), /* sw $10,($15) */
710 MIPS32_SW(11,0,15), /* sw $11,($15) */
711
712 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
713 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
714 MIPS32_LW(9,0,8), /* Load write start_addr to $9 */
715 MIPS32_LW(10,4,8), /* Load write end_addr to $10 */
716
717 MIPS32_RDHWR(11, MIPS32_SYNCI_STEP), /* $11 = MIPS32_SYNCI_STEP */
718 MIPS32_BEQ(11,0,6), /* beq $11, $0, end */
719 MIPS32_NOP,
720 /* synci_loop : */
721 MIPS32_SYNCI(0,9), /* synci 0($9) */
722 MIPS32_SLTU(8,10,9), /* sltu $8, $10, $9 # $8 = $10 < $9 ? 1 : 0 */
723 MIPS32_BNE(8,0,NEG16(3)), /* bne $8, $0, synci_loop */
724 MIPS32_ADDU(9, 9, 11), /* $9 += MIPS32_SYNCI_STEP */
725 MIPS32_SYNC,
726 /* end: */
727 MIPS32_LW(11,0,15), /* lw $11,($15) */
728 MIPS32_LW(10,0,15), /* lw $10,($15) */
729 MIPS32_LW(9,0,15), /* lw $9,($15) */
730 MIPS32_LW(8,0,15), /* lw $8,($15) */
731 MIPS32_B(NEG16(24)), /* b start */
732 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
733 };
734
735 /* TODO remove array */
736 uint32_t *param_in = malloc(2 * sizeof(uint32_t));
737 int retval;
738 param_in[0] = start_addr;
739 param_in[1] = end_addr;
740
741 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 2, param_in, 0, NULL, 1);
742
743 free(param_in);
744
745 return retval;
746 }
747
748 /**
749 * \b mips32_pracc_clean_invalidate_cache
750 *
751 * Writeback D$ and Invalidate I$
752 * so that the instructions written can be visible to CPU
753 */
754 static int mips32_pracc_clean_invalidate_cache(struct mips_ejtag *ejtag_info,
755 uint32_t start_addr, uint32_t end_addr)
756 {
757 static const uint32_t code[] = {
758 /* start: */
759 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
760 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
761 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
762 MIPS32_SW(8,0,15), /* sw $8,($15) */
763 MIPS32_SW(9,0,15), /* sw $9,($15) */
764 MIPS32_SW(10,0,15), /* sw $10,($15) */
765 MIPS32_SW(11,0,15), /* sw $11,($15) */
766
767 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
768 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
769 MIPS32_LW(9,0,8), /* Load write start_addr to $9 */
770 MIPS32_LW(10,4,8), /* Load write end_addr to $10 */
771 MIPS32_LW(11,8,8), /* Load write clsiz to $11 */
772
773 /* cache_loop: */
774 MIPS32_SLTU(8,10,9), /* sltu $8, $10, $9 : $8 <- $10 < $9 ? */
775 MIPS32_BGTZ(8,6), /* bgtz $8, end */
776 MIPS32_NOP,
777
778 MIPS32_CACHE(MIPS32_CACHE_D_HIT_WRITEBACK,0,9), /* cache Hit_Writeback_D, 0($9) */
779 MIPS32_CACHE(MIPS32_CACHE_I_HIT_INVALIDATE,0,9), /* cache Hit_Invalidate_I, 0($9) */
780
781 MIPS32_ADDU(9,9,11), /* $9 += $11 */
782
783 MIPS32_B(NEG16(7)), /* b cache_loop */
784 MIPS32_NOP,
785 /* end: */
786 MIPS32_LW(11,0,15), /* lw $11,($15) */
787 MIPS32_LW(10,0,15), /* lw $10,($15) */
788 MIPS32_LW(9,0,15), /* lw $9,($15) */
789 MIPS32_LW(8,0,15), /* lw $8,($15) */
790 MIPS32_B(NEG16(25)), /* b start */
791 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
792 };
793
794 /**
795 * Find cache line size in bytes
796 */
797 uint32_t conf;
798 uint32_t dl, clsiz;
799
800 mips32_cp0_read(ejtag_info, &conf, 16, 1);
801 dl = (conf & MIPS32_CONFIG1_DL_MASK) >> MIPS32_CONFIG1_DL_SHIFT;
802
803 /* dl encoding : dl=1 => 4 bytes, dl=2 => 8 bytes, etc... */
804 clsiz = 0x2 << dl;
805
806 /* TODO remove array */
807 uint32_t *param_in = malloc(3 * sizeof(uint32_t));
808 int retval;
809 param_in[0] = start_addr;
810 param_in[1] = end_addr;
811 param_in[2] = clsiz;
812
813 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code, 3, param_in, 0, NULL, 1);
814
815 free(param_in);
816
817 return retval;
818 }
819
820
821 int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
822 {
823 int retval;
824
825 switch (size)
826 {
827 case 1:
828 retval = mips32_pracc_write_mem8(ejtag_info, addr, count, (uint8_t*)buf);
829 break;
830 case 2:
831 retval = mips32_pracc_write_mem16(ejtag_info, addr, count,(uint16_t*)buf);
832 break;
833 case 4:
834 if (count == 1)
835 {
836 retval = mips32_pracc_write_u32(ejtag_info, addr, (uint32_t*)buf);
837 }
838 else
839 {
840 retval = mips32_pracc_write_mem32(ejtag_info, addr, count, (uint32_t*)buf);
841 }
842 break;
843 default:
844 retval = ERROR_FAIL;
845 }
846
847 /**
848 * If we are in the cachable regoion and cache is activated,
849 * we must clean D$ + invalidate I$ after we did the write,
850 * so that changes do not continue to live only in D$, but to be
851 * replicated in I$ also (maybe we wrote the istructions)
852 */
853 uint32_t conf = 0;
854 int cached = 0;
855
856 mips32_cp0_read(ejtag_info, &conf, 16, 0);
857
858 switch (KSEGX(addr))
859 {
860 case KUSEG:
861 cached = (conf & MIPS32_CONFIG0_KU_MASK) >> MIPS32_CONFIG0_KU_SHIFT;
862 break;
863 case KSEG0 :
864 cached = (conf & MIPS32_CONFIG0_K0_MASK) >> MIPS32_CONFIG0_K0_SHIFT;
865 break;
866 case KSEG1:
867 /* uncachable segment - nothing to do */
868 break;
869 case KSEG2:
870 case KSEG3:
871 cached = (conf & MIPS32_CONFIG0_K23_MASK) >> MIPS32_CONFIG0_K23_SHIFT;
872 break;
873 default:
874 /* what ? */
875 break;
876 }
877
878 /**
879 * Check cachablitiy bits coherency algorithm -
880 * is the region cacheable or uncached.
881 * If cacheable we have to synchronize the cache
882 */
883 if (cached == 0x3)
884 {
885 uint32_t start_addr, end_addr;
886 uint32_t rel;
887
888 start_addr = addr;
889 end_addr = addr + count * size;
890
891 /** select cache synchronisation mechanism based on Architecture Release */
892 rel = (conf & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT;
893 switch (rel)
894 {
895 case MIPS32_ARCH_REL1 :
896 /* MIPS32/64 Release 1 - we must use cache instruction */
897 mips32_pracc_clean_invalidate_cache(ejtag_info, start_addr, end_addr);
898 break;
899 case MIPS32_ARCH_REL2 :
900 /* MIPS32/64 Release 2 - we can use synci instruction */
901 mips32_pracc_sync_cache(ejtag_info, start_addr, end_addr);
902 break;
903 default :
904 /* what ? */
905 break;
906 }
907 }
908
909 return retval;
910 }
911
912 static int mips32_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
913 {
914 static const uint32_t code[] = {
915 /* start: */
916 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
917 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
918 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
919 MIPS32_SW(8,0,15), /* sw $8,($15) */
920 MIPS32_SW(9,0,15), /* sw $9,($15) */
921 MIPS32_SW(10,0,15), /* sw $10,($15) */
922 MIPS32_SW(11,0,15), /* sw $11,($15) */
923
924 MIPS32_ADDI(8,15,NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN)), /* $8= MIPS32_PRACC_PARAM_IN */
925 MIPS32_LW(9,0,8), /* Load write addr to $9 */
926 MIPS32_LW(10,4,8), /* Load write count to $10 */
927 MIPS32_ADDI(8,8,8), /* $8 += 8 beginning of data */
928
929 /* loop: */
930 MIPS32_LW(11,0,8), /* lw $11,0($8), Load $11 with the word @mem[$8] */
931 MIPS32_SW(11,0,9), /* sw $11,0($9) */
932
933 MIPS32_ADDI(9,9,4), /* $9 += 4 */
934 MIPS32_BNE(10,9,NEG16(4)), /* bne $10, $9, loop */
935 MIPS32_ADDI(8,8,4), /* $8 += 4 */
936
937 /* end: */
938 MIPS32_LW(11,0,15), /* lw $11,($15) */
939 MIPS32_LW(10,0,15), /* lw $10,($15) */
940 MIPS32_LW(9,0,15), /* lw $9,($15) */
941 MIPS32_LW(8,0,15), /* lw $8,($15) */
942 MIPS32_B(NEG16(21)), /* b start */
943 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
944 };
945
946 /* TODO remove array */
947 uint32_t *param_in = malloc((count + 2) * sizeof(uint32_t));
948 param_in[0] = addr;
949 param_in[1] = addr + (count * sizeof(uint32_t)); /* last address */
950
951 memcpy(&param_in[2], buf, count * sizeof(uint32_t));
952
953 int retval;
954 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
955 count + 2, param_in, 0, NULL, 1);
956
957 free(param_in);
958
959 return retval;
960 }
961
962 static int mips32_pracc_write_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf)
963 {
964 static const uint32_t code[] = {
965 /* start: */
966 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
967 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
968 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
969 MIPS32_SW(8,0,15), /* sw $8,($15) */
970 MIPS32_SW(9,0,15), /* sw $9,($15) */
971
972 MIPS32_LW(8,NEG16((MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN)-4), 15), /* load R8 @ param_in[1] = data */
973 MIPS32_LW(9,NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN), 15), /* load R9 @ param_in[0] = address */
974
975 MIPS32_SW(8,0,9), /* sw $8,0($9) */
976
977 MIPS32_LW(9,0,15), /* lw $9,($15) */
978 MIPS32_LW(8,0,15), /* lw $8,($15) */
979 MIPS32_B(NEG16(11)), /* b start */
980 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
981 };
982
983 /* TODO remove array */
984 uint32_t param_in[1 + 1];
985 param_in[0] = addr;
986 param_in[1] = *buf;
987
988 return mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
989 ARRAY_SIZE(param_in), param_in, 0, NULL, 1);
990 }
991
992 static int mips32_pracc_write_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf)
993 {
994 static const uint32_t code[] = {
995 /* start: */
996 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
997 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
998 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
999 MIPS32_SW(8,0,15), /* sw $8,($15) */
1000 MIPS32_SW(9,0,15), /* sw $9,($15) */
1001 MIPS32_SW(10,0,15), /* sw $10,($15) */
1002 MIPS32_SW(11,0,15), /* sw $11,($15) */
1003
1004 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
1005 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
1006 MIPS32_LW(9,0,8), /* Load write addr to $9 */
1007 MIPS32_LW(10,4,8), /* Load write count to $10 */
1008 MIPS32_ADDI(8,8,8), /* $8 += 8 */
1009 /* loop: */
1010 MIPS32_BEQ(0,10,8), /* beq $0, $10, end */
1011 MIPS32_NOP,
1012
1013 MIPS32_LW(11,0,8), /* lw $11,0($8), Load $11 with the word @mem[$8] */
1014 MIPS32_SH(11,0,9), /* sh $11,0($9) */
1015
1016 MIPS32_ADDI(10,10,NEG16(1)), /* $10-- */
1017 MIPS32_ADDI(9,9,2), /* $9 += 2 */
1018 MIPS32_ADDI(8,8,4), /* $8 += 4 */
1019
1020 MIPS32_B(NEG16(8)), /* b loop */
1021 MIPS32_NOP,
1022 /* end: */
1023 MIPS32_LW(11,0,15), /* lw $11,($15) */
1024 MIPS32_LW(10,0,15), /* lw $10,($15) */
1025 MIPS32_LW(9,0,15), /* lw $9,($15) */
1026 MIPS32_LW(8,0,15), /* lw $8,($15) */
1027 MIPS32_B(NEG16(26)), /* b start */
1028 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
1029 };
1030
1031 /* TODO remove array */
1032 uint32_t *param_in = malloc((count + 2) * sizeof(uint32_t));
1033 int i;
1034 param_in[0] = addr;
1035 param_in[1] = count;
1036
1037 for (i = 0; i < count; i++)
1038 {
1039 param_in[i + 2] = buf[i];
1040 }
1041
1042 int retval;
1043 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
1044 count + 2, param_in, 0, NULL, 1);
1045
1046 free(param_in);
1047
1048 return retval;
1049 }
1050
1051 static int mips32_pracc_write_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf)
1052 {
1053 static const uint32_t code[] = {
1054 /* start: */
1055 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
1056 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
1057 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
1058 MIPS32_SW(8,0,15), /* sw $8,($15) */
1059 MIPS32_SW(9,0,15), /* sw $9,($15) */
1060 MIPS32_SW(10,0,15), /* sw $10,($15) */
1061 MIPS32_SW(11,0,15), /* sw $11,($15) */
1062
1063 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $8 = MIPS32_PRACC_PARAM_IN */
1064 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
1065 MIPS32_LW(9,0,8), /* Load write addr to $9 */
1066 MIPS32_LW(10,4,8), /* Load write count to $10 */
1067 MIPS32_ADDI(8,8,8), /* $8 += 8 */
1068 /* loop: */
1069 MIPS32_BEQ(0,10,8), /* beq $0, $10, end */
1070 MIPS32_NOP,
1071
1072 MIPS32_LW(11,0,8), /* lw $11,0($8), Load $11 with the word @mem[$8] */
1073 MIPS32_SB(11,0,9), /* sb $11,0($9) */
1074
1075 MIPS32_ADDI(10,10,NEG16(1)), /* $10-- */
1076 MIPS32_ADDI(9,9,1), /* $9 += 1 */
1077 MIPS32_ADDI(8,8,4), /* $8 += 4 */
1078
1079 MIPS32_B(NEG16(8)), /* b loop */
1080 MIPS32_NOP,
1081 /* end: */
1082 MIPS32_LW(11,0,15), /* lw $11,($15) */
1083 MIPS32_LW(10,0,15), /* lw $10,($15) */
1084 MIPS32_LW(9,0,15), /* lw $9,($15) */
1085 MIPS32_LW(8,0,15), /* lw $8,($15) */
1086 MIPS32_B(NEG16(26)), /* b start */
1087 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
1088 };
1089
1090 /* TODO remove array */
1091 uint32_t *param_in = malloc((count + 2) * sizeof(uint32_t));
1092 int retval;
1093 int i;
1094 param_in[0] = addr;
1095 param_in[1] = count;
1096
1097 for (i = 0; i < count; i++)
1098 {
1099 param_in[i + 2] = buf[i];
1100 }
1101
1102 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
1103 count + 2, param_in, 0, NULL, 1);
1104
1105 free(param_in);
1106
1107 return retval;
1108 }
1109
1110 int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
1111 {
1112 static const uint32_t code[] = {
1113 /* start: */
1114 MIPS32_LUI(2,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $2 = MIPS32_PRACC_PARAM_IN */
1115 MIPS32_ORI(2,2,LOWER16(MIPS32_PRACC_PARAM_IN)),
1116 MIPS32_LW(1,1*4,2), /* lw $1,1*4($2) */
1117 MIPS32_LW(15,15*4,2), /* lw $15,15*4($2) */
1118 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
1119 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
1120 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
1121 MIPS32_SW(1,0,15), /* sw $1,($15) */
1122 MIPS32_LUI(1,UPPER16(MIPS32_PRACC_PARAM_IN)), /* $1 = MIPS32_PRACC_PARAM_IN */
1123 MIPS32_ORI(1,1,LOWER16(MIPS32_PRACC_PARAM_IN)),
1124 MIPS32_LW(3,3*4,1), /* lw $3,3*4($1) */
1125 MIPS32_LW(4,4*4,1), /* lw $4,4*4($1) */
1126 MIPS32_LW(5,5*4,1), /* lw $5,5*4($1) */
1127 MIPS32_LW(6,6*4,1), /* lw $6,6*4($1) */
1128 MIPS32_LW(7,7*4,1), /* lw $7,7*4($1) */
1129 MIPS32_LW(8,8*4,1), /* lw $8,8*4($1) */
1130 MIPS32_LW(9,9*4,1), /* lw $9,9*4($1) */
1131 MIPS32_LW(10,10*4,1), /* lw $10,10*4($1) */
1132 MIPS32_LW(11,11*4,1), /* lw $11,11*4($1) */
1133 MIPS32_LW(12,12*4,1), /* lw $12,12*4($1) */
1134 MIPS32_LW(13,13*4,1), /* lw $13,13*4($1) */
1135 MIPS32_LW(14,14*4,1), /* lw $14,14*4($1) */
1136 MIPS32_LW(16,16*4,1), /* lw $16,16*4($1) */
1137 MIPS32_LW(17,17*4,1), /* lw $17,17*4($1) */
1138 MIPS32_LW(18,18*4,1), /* lw $18,18*4($1) */
1139 MIPS32_LW(19,19*4,1), /* lw $19,19*4($1) */
1140 MIPS32_LW(20,20*4,1), /* lw $20,20*4($1) */
1141 MIPS32_LW(21,21*4,1), /* lw $21,21*4($1) */
1142 MIPS32_LW(22,22*4,1), /* lw $22,22*4($1) */
1143 MIPS32_LW(23,23*4,1), /* lw $23,23*4($1) */
1144 MIPS32_LW(24,24*4,1), /* lw $24,24*4($1) */
1145 MIPS32_LW(25,25*4,1), /* lw $25,25*4($1) */
1146 MIPS32_LW(26,26*4,1), /* lw $26,26*4($1) */
1147 MIPS32_LW(27,27*4,1), /* lw $27,27*4($1) */
1148 MIPS32_LW(28,28*4,1), /* lw $28,28*4($1) */
1149 MIPS32_LW(29,29*4,1), /* lw $29,29*4($1) */
1150 MIPS32_LW(30,30*4,1), /* lw $30,30*4($1) */
1151 MIPS32_LW(31,31*4,1), /* lw $31,31*4($1) */
1152
1153 MIPS32_LW(2,32*4,1), /* lw $2,32*4($1) */
1154 MIPS32_MTC0(2,12,0), /* move $2 to status */
1155 MIPS32_LW(2,33*4,1), /* lw $2,33*4($1) */
1156 MIPS32_MTLO(2), /* move $2 to lo */
1157 MIPS32_LW(2,34*4,1), /* lw $2,34*4($1) */
1158 MIPS32_MTHI(2), /* move $2 to hi */
1159 MIPS32_LW(2,35*4,1), /* lw $2,35*4($1) */
1160 MIPS32_MTC0(2,8,0), /* move $2 to badvaddr */
1161 MIPS32_LW(2,36*4,1), /* lw $2,36*4($1) */
1162 MIPS32_MTC0(2,13,0), /* move $2 to cause*/
1163 MIPS32_LW(2,37*4,1), /* lw $2,37*4($1) */
1164 MIPS32_MTC0(2,24,0), /* move $2 to depc (pc) */
1165
1166 MIPS32_LW(2,2*4,1), /* lw $2,2*4($1) */
1167 MIPS32_LW(1,0,15), /* lw $1,($15) */
1168 MIPS32_B(NEG16(53)), /* b start */
1169 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
1170 };
1171
1172 int retval;
1173
1174 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
1175 MIPS32NUMCOREREGS, regs, 0, NULL, 1);
1176
1177 return retval;
1178 }
1179
1180 int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
1181 {
1182 static const uint32_t code[] = {
1183 /* start: */
1184 MIPS32_MTC0(2,31,0), /* move $2 to COP0 DeSave */
1185 MIPS32_LUI(2,UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $2 = MIPS32_PRACC_PARAM_OUT */
1186 MIPS32_ORI(2,2,LOWER16(MIPS32_PRACC_PARAM_OUT)),
1187 MIPS32_SW(0,0*4,2), /* sw $0,0*4($2) */
1188 MIPS32_SW(1,1*4,2), /* sw $1,1*4($2) */
1189 MIPS32_SW(15,15*4,2), /* sw $15,15*4($2) */
1190 MIPS32_MFC0(2,31,0), /* move COP0 DeSave to $2 */
1191 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
1192 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)), /* $15 = MIPS32_PRACC_STACK */
1193 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
1194 MIPS32_SW(1,0,15), /* sw $1,($15) */
1195 MIPS32_SW(2,0,15), /* sw $2,($15) */
1196 MIPS32_LUI(1,UPPER16(MIPS32_PRACC_PARAM_OUT)), /* $1 = MIPS32_PRACC_PARAM_OUT */
1197 MIPS32_ORI(1,1,LOWER16(MIPS32_PRACC_PARAM_OUT)),
1198 MIPS32_SW(2,2*4,1), /* sw $2,2*4($1) */
1199 MIPS32_SW(3,3*4,1), /* sw $3,3*4($1) */
1200 MIPS32_SW(4,4*4,1), /* sw $4,4*4($1) */
1201 MIPS32_SW(5,5*4,1), /* sw $5,5*4($1) */
1202 MIPS32_SW(6,6*4,1), /* sw $6,6*4($1) */
1203 MIPS32_SW(7,7*4,1), /* sw $7,7*4($1) */
1204 MIPS32_SW(8,8*4,1), /* sw $8,8*4($1) */
1205 MIPS32_SW(9,9*4,1), /* sw $9,9*4($1) */
1206 MIPS32_SW(10,10*4,1), /* sw $10,10*4($1) */
1207 MIPS32_SW(11,11*4,1), /* sw $11,11*4($1) */
1208 MIPS32_SW(12,12*4,1), /* sw $12,12*4($1) */
1209 MIPS32_SW(13,13*4,1), /* sw $13,13*4($1) */
1210 MIPS32_SW(14,14*4,1), /* sw $14,14*4($1) */
1211 MIPS32_SW(16,16*4,1), /* sw $16,16*4($1) */
1212 MIPS32_SW(17,17*4,1), /* sw $17,17*4($1) */
1213 MIPS32_SW(18,18*4,1), /* sw $18,18*4($1) */
1214 MIPS32_SW(19,19*4,1), /* sw $19,19*4($1) */
1215 MIPS32_SW(20,20*4,1), /* sw $20,20*4($1) */
1216 MIPS32_SW(21,21*4,1), /* sw $21,21*4($1) */
1217 MIPS32_SW(22,22*4,1), /* sw $22,22*4($1) */
1218 MIPS32_SW(23,23*4,1), /* sw $23,23*4($1) */
1219 MIPS32_SW(24,24*4,1), /* sw $24,24*4($1) */
1220 MIPS32_SW(25,25*4,1), /* sw $25,25*4($1) */
1221 MIPS32_SW(26,26*4,1), /* sw $26,26*4($1) */
1222 MIPS32_SW(27,27*4,1), /* sw $27,27*4($1) */
1223 MIPS32_SW(28,28*4,1), /* sw $28,28*4($1) */
1224 MIPS32_SW(29,29*4,1), /* sw $29,29*4($1) */
1225 MIPS32_SW(30,30*4,1), /* sw $30,30*4($1) */
1226 MIPS32_SW(31,31*4,1), /* sw $31,31*4($1) */
1227
1228 MIPS32_MFC0(2,12,0), /* move status to $2 */
1229 MIPS32_SW(2,32*4,1), /* sw $2,32*4($1) */
1230 MIPS32_MFLO(2), /* move lo to $2 */
1231 MIPS32_SW(2,33*4,1), /* sw $2,33*4($1) */
1232 MIPS32_MFHI(2), /* move hi to $2 */
1233 MIPS32_SW(2,34*4,1), /* sw $2,34*4($1) */
1234 MIPS32_MFC0(2,8,0), /* move badvaddr to $2 */
1235 MIPS32_SW(2,35*4,1), /* sw $2,35*4($1) */
1236 MIPS32_MFC0(2,13,0), /* move cause to $2 */
1237 MIPS32_SW(2,36*4,1), /* sw $2,36*4($1) */
1238 MIPS32_MFC0(2,24,0), /* move depc (pc) to $2 */
1239 MIPS32_SW(2,37*4,1), /* sw $2,37*4($1) */
1240
1241 MIPS32_LW(2,0,15), /* lw $2,($15) */
1242 MIPS32_LW(1,0,15), /* lw $1,($15) */
1243 MIPS32_B(NEG16(58)), /* b start */
1244 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
1245 };
1246
1247 int retval;
1248
1249 retval = mips32_pracc_exec(ejtag_info, ARRAY_SIZE(code), code,
1250 0, NULL, MIPS32NUMCOREREGS, regs, 1);
1251
1252 return retval;
1253 }
1254
1255 /* fastdata upload/download requires an initialized working area
1256 * to load the download code; it should not be called otherwise
1257 * fetch order from the fastdata area
1258 * 1. start addr
1259 * 2. end addr
1260 * 3. data ...
1261 */
1262 int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source,
1263 int write_t, uint32_t addr, int count, uint32_t *buf)
1264 {
1265 uint32_t handler_code[] = {
1266 /* caution when editing, table is modified below */
1267 /* r15 points to the start of this code */
1268 MIPS32_SW(8,MIPS32_FASTDATA_HANDLER_SIZE - 4,15),
1269 MIPS32_SW(9,MIPS32_FASTDATA_HANDLER_SIZE - 8,15),
1270 MIPS32_SW(10,MIPS32_FASTDATA_HANDLER_SIZE - 12,15),
1271 MIPS32_SW(11,MIPS32_FASTDATA_HANDLER_SIZE - 16,15),
1272 /* start of fastdata area in t0 */
1273 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_FASTDATA_AREA)),
1274 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_FASTDATA_AREA)),
1275 MIPS32_LW(9,0,8), /* start addr in t1 */
1276 MIPS32_LW(10,0,8), /* end addr to t2 */
1277 /* loop: */
1278 /* 8 */ MIPS32_LW(11,0,0), /* lw t3,[t8 | r9] */
1279 /* 9 */ MIPS32_SW(11,0,0), /* sw t3,[r9 | r8] */
1280 MIPS32_BNE(10,9,NEG16(3)), /* bne $t2,t1,loop */
1281 MIPS32_ADDI(9,9,4), /* addi t1,t1,4 */
1282
1283 MIPS32_LW(8,MIPS32_FASTDATA_HANDLER_SIZE - 4,15),
1284 MIPS32_LW(9,MIPS32_FASTDATA_HANDLER_SIZE - 8,15),
1285 MIPS32_LW(10,MIPS32_FASTDATA_HANDLER_SIZE - 12,15),
1286 MIPS32_LW(11,MIPS32_FASTDATA_HANDLER_SIZE - 16,15),
1287
1288 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_TEXT)),
1289 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_TEXT)),
1290 MIPS32_JR(15), /* jr start */
1291 MIPS32_MFC0(15,31,0), /* move COP0 DeSave to $15 */
1292 };
1293
1294 uint32_t jmp_code[] = {
1295 MIPS32_MTC0(15,31,0), /* move $15 to COP0 DeSave */
1296 /* 1 */ MIPS32_LUI(15,0), /* addr of working area added below */
1297 /* 2 */ MIPS32_ORI(15,15,0), /* addr of working area added below */
1298 MIPS32_JR(15), /* jump to ram program */
1299 MIPS32_NOP,
1300 };
1301
1302 int retval, i;
1303 uint32_t val, ejtag_ctrl, address;
1304
1305 if (source->size < MIPS32_FASTDATA_HANDLER_SIZE)
1306 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
1307
1308 if (write_t)
1309 {
1310 handler_code[8] = MIPS32_LW(11,0,8); /* load data from probe at fastdata area */
1311 handler_code[9] = MIPS32_SW(11,0,9); /* store data to RAM @ r9 */
1312 }
1313 else
1314 {
1315 handler_code[8] = MIPS32_LW(11,0,9); /* load data from RAM @ r9 */
1316 handler_code[9] = MIPS32_SW(11,0,8); /* store data to probe at fastdata area */
1317 }
1318
1319 /* write program into RAM */
1320 if (write_t != ejtag_info->fast_access_save)
1321 {
1322 mips32_pracc_write_mem32(ejtag_info, source->address, ARRAY_SIZE(handler_code), handler_code);
1323 /* save previous operation to speed to any consecutive read/writes */
1324 ejtag_info->fast_access_save = write_t;
1325 }
1326
1327 LOG_DEBUG("%s using 0x%.8" PRIx32 " for write handler", __func__, source->address);
1328
1329 jmp_code[1] |= UPPER16(source->address);
1330 jmp_code[2] |= LOWER16(source->address);
1331
1332 for (i = 0; i < (int) ARRAY_SIZE(jmp_code); i++)
1333 {
1334 if ((retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl)) != ERROR_OK)
1335 return retval;
1336
1337 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA);
1338 mips_ejtag_drscan_32_out(ejtag_info, jmp_code[i]);
1339
1340 /* Clear the access pending bit (let the processor eat!) */
1341 ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
1342 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL);
1343 mips_ejtag_drscan_32_out(ejtag_info, ejtag_ctrl);
1344 }
1345
1346 if ((retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl)) != ERROR_OK)
1347 return retval;
1348
1349 /* next fetch to dmseg should be in FASTDATA_AREA, check */
1350 address = 0;
1351 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
1352 retval = mips_ejtag_drscan_32(ejtag_info, &address);
1353 if (retval != ERROR_OK)
1354 return retval;
1355
1356 if (address != MIPS32_PRACC_FASTDATA_AREA)
1357 return ERROR_FAIL;
1358
1359 /* wait PrAcc pending bit for FASTDATA write */
1360 if ((retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl)) != ERROR_OK)
1361 return retval;
1362
1363 /* Send the load start address */
1364 val = addr;
1365 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA);
1366 mips_ejtag_fastdata_scan(ejtag_info, 1, &val);
1367
1368 /* Send the load end address */
1369 val = addr + (count - 1) * 4;
1370 mips_ejtag_fastdata_scan(ejtag_info, 1, &val);
1371
1372 for (i = 0; i < count; i++)
1373 {
1374 if ((retval = mips_ejtag_fastdata_scan(ejtag_info, write_t, buf++)) != ERROR_OK)
1375 return retval;
1376 }
1377
1378 if ((retval = jtag_execute_queue()) != ERROR_OK)
1379 {
1380 LOG_ERROR("fastdata load failed");
1381 return retval;
1382 }
1383
1384 if ((retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl)) != ERROR_OK)
1385 return retval;
1386
1387 address = 0;
1388 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS);
1389 retval = mips_ejtag_drscan_32(ejtag_info, &address);
1390 if (retval != ERROR_OK)
1391 return retval;
1392
1393 if (address != MIPS32_PRACC_TEXT)
1394 LOG_ERROR("mini program did not return to start");
1395
1396 return retval;
1397 }

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)