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

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)