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

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)