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

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)