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

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)