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

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)