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

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)