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

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)