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

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)