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

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)