mips: remove dynamic arrays - reduces stack usage
[fw/openocd] / 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  *   This program is free software; you can redistribute it and/or modify  *
8  *   it under the terms of the GNU General Public License as published by  *
9  *   the Free Software Foundation; either version 2 of the License, or     *
10  *   (at your option) any later version.                                   *
11  *                                                                         *
12  *   This program is distributed in the hope that it will be useful,       *
13  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
14  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
15  *   GNU General Public License for more details.                          *
16  *                                                                         *
17  *   You should have received a copy of the GNU General Public License     *
18  *   along with this program; if not, write to the                         *
19  *   Free Software Foundation, Inc.,                                       *
20  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
21  ***************************************************************************/
22
23 /*
24 This version has optimized assembly routines for 32 bit operations:
25 - read word
26 - write word
27 - write array of words
28
29 One thing to be aware of is that the MIPS32 cpu will execute the
30 instruction after a branch instruction (one delay slot).
31
32 For example:
33
34
35     LW $2, ($5 +10)
36     B foo
37     LW $1, ($2 +100)
38
39 The LW $1, ($2 +100) instruction is also executed. If this is
40 not wanted a NOP can be inserted:
41
42     LW $2, ($5 +10)
43     B foo
44     NOP
45     LW $1, ($2 +100)
46
47 or the code can be changed to:
48
49     B foo
50     LW $2, ($5 +10)
51     LW $1, ($2 +100)
52
53 The original code contained NOPs. I have removed these and moved
54 the branches.
55
56 I also moved the PRACC_STACK to 0xFF204000. This allows
57 the use of 16 bits offsets to get pointers to the input
58 and output area relative to the stack. Note that the stack
59 isn't really a stack (the stack pointer is not 'moving')
60 but a FIFO simulated in software.
61
62 These changes result in a 35% speed increase when programming an
63 external flash.
64
65 More improvement could be gained if the registers do no need
66 to be preserved but in that case the routines should be aware
67 OpenOCD is used as a flash programmer or as a debug tool.
68
69 Nico Coesel
70 */
71
72
73 #ifdef HAVE_CONFIG_H
74 #include "config.h"
75 #endif
76
77 #include "mips32.h"
78 #include "mips32_pracc.h"
79
80 struct mips32_pracc_context
81 {
82         uint32_t *local_iparam;
83         int num_iparam;
84         uint32_t *local_oparam;
85         int num_oparam;
86         const uint32_t *code;
87         int code_len;
88         uint32_t stack[32];
89         int stack_offset;
90         struct mips_ejtag *ejtag_info;
91 };
92
93 static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl)
94 {
95         uint32_t ejtag_ctrl;
96
97         while (1)
98         {
99                 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_CONTROL, NULL);
100                 ejtag_ctrl = ejtag_info->ejtag_ctrl;
101                 mips_ejtag_drscan_32(ejtag_info, &ejtag_ctrl);
102                 if (ejtag_ctrl & EJTAG_CTRL_PRACC)
103                         break;
104                 LOG_DEBUG("DEBUGMODULE: No memory access in progress!\n");
105                 return ERROR_JTAG_DEVICE_ERROR;
106         }
107
108         *ctrl = ejtag_ctrl;
109         return ERROR_OK;
110 }
111
112 static int mips32_pracc_exec_read(struct mips32_pracc_context *ctx, uint32_t address)
113 {
114         struct mips_ejtag *ejtag_info = ctx->ejtag_info;
115         int offset;
116         uint32_t ejtag_ctrl, data;
117
118         if ((address >= MIPS32_PRACC_PARAM_IN)
119                 && (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4))
120         {
121                 offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
122                 data = ctx->local_iparam[offset];
123         }
124         else if ((address >= MIPS32_PRACC_PARAM_OUT)
125                 && (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4))
126         {
127                 offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
128                 data = ctx->local_oparam[offset];
129         }
130         else if ((address >= MIPS32_PRACC_TEXT)
131                 && (address <= MIPS32_PRACC_TEXT + ctx->code_len*4))
132         {
133                 offset = (address - MIPS32_PRACC_TEXT) / 4;
134                 data = ctx->code[offset];
135         }
136         else if (address == MIPS32_PRACC_STACK)
137         {
138                 /* save to our debug stack */
139                 data = ctx->stack[--ctx->stack_offset];
140         }
141         else
142         {
143                 /* TODO: send JMP 0xFF200000 instruction. Hopefully processor jump back
144                  * to start of debug vector */
145
146                 data = 0;
147                 LOG_ERROR("Error reading unexpected address %8.8" PRIx32 "", address);
148                 return ERROR_JTAG_DEVICE_ERROR;
149         }
150
151         /* Send the data out */
152         mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA, NULL);
153         mips_ejtag_drscan_32(ctx->ejtag_info, &data);
154
155         /* Clear the access pending bit (let the processor eat!) */
156
157         ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
158         mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL, NULL);
159         mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl);
160
161         jtag_add_clocks(5);
162         jtag_execute_queue();
163
164
165         return ERROR_OK;
166 }
167
168 static int mips32_pracc_exec_write(struct mips32_pracc_context *ctx, uint32_t address)
169 {
170         uint32_t ejtag_ctrl,data;
171         int offset;
172         struct mips_ejtag *ejtag_info = ctx->ejtag_info;
173
174         mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_DATA, NULL);
175         mips_ejtag_drscan_32(ctx->ejtag_info, &data);
176
177         /* Clear access pending bit */
178         ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC;
179         mips_ejtag_set_instr(ctx->ejtag_info, EJTAG_INST_CONTROL, NULL);
180         mips_ejtag_drscan_32(ctx->ejtag_info, &ejtag_ctrl);
181
182         jtag_add_clocks(5);
183         jtag_execute_queue();
184
185         if ((address >= MIPS32_PRACC_PARAM_IN)
186                 && (address <= MIPS32_PRACC_PARAM_IN + ctx->num_iparam * 4))
187         {
188                 offset = (address - MIPS32_PRACC_PARAM_IN) / 4;
189                 ctx->local_iparam[offset] = data;
190         }
191         else if ((address >= MIPS32_PRACC_PARAM_OUT)
192                 && (address <= MIPS32_PRACC_PARAM_OUT + ctx->num_oparam * 4))
193         {
194                 offset = (address - MIPS32_PRACC_PARAM_OUT) / 4;
195                 ctx->local_oparam[offset] = data;
196         }
197         else if (address == MIPS32_PRACC_STACK)
198         {
199                 /* save data onto our stack */
200                 ctx->stack[ctx->stack_offset++] = data;
201         }
202         else
203         {
204                 LOG_ERROR("Error writing unexpected address %8.8" PRIx32 "", address);
205                 return ERROR_JTAG_DEVICE_ERROR;
206         }
207
208         return ERROR_OK;
209 }
210
211 int mips32_pracc_exec(struct mips_ejtag *ejtag_info, int code_len, const uint32_t *code, int num_param_in, uint32_t *param_in, int num_param_out, uint32_t *param_out, int cycle)
212 {
213         uint32_t ejtag_ctrl;
214         uint32_t address, data;
215         struct mips32_pracc_context ctx;
216         int retval;
217         int pass = 0;
218
219         ctx.local_iparam = param_in;
220         ctx.local_oparam = param_out;
221         ctx.num_iparam = num_param_in;
222         ctx.num_oparam = num_param_out;
223         ctx.code = code;
224         ctx.code_len = code_len;
225         ctx.ejtag_info = ejtag_info;
226         ctx.stack_offset = 0;
227
228         while (1)
229         {
230                 if ((retval = wait_for_pracc_rw(ejtag_info, &ejtag_ctrl)) != ERROR_OK)
231                         return retval;
232
233                 address = data = 0;
234                 mips_ejtag_set_instr(ejtag_info, EJTAG_INST_ADDRESS, NULL);
235                 mips_ejtag_drscan_32(ejtag_info, &address);
236
237 //              printf("Adres: %.8x\n", address);
238
239                 /* Check for read or write */
240                 if (ejtag_ctrl & EJTAG_CTRL_PRNW)
241                 {
242                         if ((retval = mips32_pracc_exec_write(&ctx, address)) != ERROR_OK)
243                                 return retval;
244                 }
245                 else
246                 {
247                         /* Check to see if its reading at the debug vector. The first pass through
248                          * the module is always read at the vector, so the first one we allow.  When
249                          * the second read from the vector occurs we are done and just exit. */
250                         if ((address == MIPS32_PRACC_TEXT) && (pass++))
251                         {
252                                 break;
253                         }
254
255                         if ((retval = mips32_pracc_exec_read(&ctx, address)) != ERROR_OK)
256                                 return retval;
257
258                 }
259
260                 if (cycle == 0)
261                         break;
262         }
263
264         /* stack sanity check */
265         if (ctx.stack_offset != 0)
266         {
267                 LOG_DEBUG("Pracc Stack not zero");
268         }
269
270         return ERROR_OK;
271 }
272
273 int mips32_pracc_read_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
274 {
275         switch (size)
276         {
277                 case 1:
278                         return mips32_pracc_read_mem8(ejtag_info, addr, count, (uint8_t*)buf);
279                 case 2:
280                         return mips32_pracc_read_mem16(ejtag_info, addr, count, (uint16_t*)buf);
281                 case 4:
282                         if (count == 1)
283                                 return mips32_pracc_read_u32(ejtag_info, addr, (uint32_t*)buf);
284                         else
285                                 return mips32_pracc_read_mem32(ejtag_info, addr, count, (uint32_t*)buf);
286         }
287
288         return ERROR_OK;
289 }
290
291 int mips32_pracc_read_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
292 {
293         static const uint32_t code[] = {
294                                                                                                                         /* start: */
295                 MIPS32_MTC0(15,31,0),                                                           /* move $15 to COP0 DeSave */
296                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),             /* $15 = MIPS32_PRACC_STACK */
297                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
298                 MIPS32_SW(8,0,15),                                                                      /* sw $8,($15) */
299                 MIPS32_SW(9,0,15),                                                                      /* sw $9,($15) */
300                 MIPS32_SW(10,0,15),                                                             /* sw $10,($15) */
301                 MIPS32_SW(11,0,15),                                                             /* sw $11,($15) */
302
303                 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)),           /* $8 = MIPS32_PRACC_PARAM_IN */
304                 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
305                 MIPS32_LW(9,0,8),                                                                       /* $9 = mem[$8]; read addr */
306                 MIPS32_LW(10,4,8),                                                                      /* $10 = mem[$8 + 4]; read count */
307                 MIPS32_LUI(11,UPPER16(MIPS32_PRACC_PARAM_OUT)),         /* $11 = MIPS32_PRACC_PARAM_OUT */
308                 MIPS32_ORI(11,11,LOWER16(MIPS32_PRACC_PARAM_OUT)),
309                 MIPS32_NOP,
310                                                                                                                         /* loop: */
311                 MIPS32_BEQ(0,10,9),                                                                     /* beq 0, $10, end */
312                 MIPS32_NOP,
313
314                 MIPS32_LW(8,0,9),                                                                       /* lw $8,0($9), Load $8 with the word @mem[$9] */
315                 MIPS32_SW(8,0,11),                                                                      /* sw $8,0($11) */
316
317                 MIPS32_ADDI(10,10,NEG16(1)),                                            /* $10-- */
318                 MIPS32_ADDI(9,9,4),                                                             /* $1 += 4 */
319                 MIPS32_ADDI(11,11,4),                                                           /* $11 += 4 */
320
321                 MIPS32_NOP,
322                 MIPS32_B(NEG16(9)),                                                                     /* b loop */
323                 MIPS32_NOP,
324                                                                                                                         /* end: */
325                 MIPS32_LW(11,0,15),                                                             /* lw $11,($15) */
326                 MIPS32_LW(10,0,15),                                                             /* lw $10,($15) */
327                 MIPS32_LW(9,0,15),                                                                      /* lw $9,($15) */
328                 MIPS32_LW(8,0,15),                                                                      /* lw $8,($15) */
329                 MIPS32_MFC0(15,31,0),                                                           /* move COP0 DeSave to $15 */
330                 MIPS32_NOP,
331                 MIPS32_B(NEG16(31)),                                                            /* b start */
332                 MIPS32_NOP,
333         };
334
335         int retval = ERROR_OK;
336         int blocksize;
337         int bytesread;
338         uint32_t param_in[2];
339
340         bytesread = 0;
341
342         while (count > 0)
343         {
344                 blocksize = count;
345                 if (count > 0x400)
346                         blocksize = 0x400;
347
348                 param_in[0] = addr;
349                 param_in[1] = blocksize;
350
351                 if ((retval = mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code,
352                         sizeof(param_in)/sizeof(param_in[0]), param_in, blocksize, &buf[bytesread], 1)) != ERROR_OK)
353                 {
354                         return retval;
355                 }
356
357                 count -= blocksize;
358                 addr += blocksize;
359                 bytesread += blocksize;
360         }
361
362         return retval;
363 }
364
365 int mips32_pracc_read_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf)
366 {
367         static const uint32_t code[] = {
368                                                                                                                         /* start: */
369                 MIPS32_MTC0(15,31,0),                                                           /* move $15 to COP0 DeSave */
370                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),             /* $15 = MIPS32_PRACC_STACK */
371                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
372                 MIPS32_SW(8,0,15),                                                                      /* sw $8,($15) */
373
374                 MIPS32_LW(8,NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN), 15),  //load R8 @ param_in[0] = address
375
376                 MIPS32_LW(8,0,8),                                                                       /* lw $8,0($8), Load $8 with the word @mem[$8] */
377                 MIPS32_SW(8,NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_OUT),15),                                                                       /* sw $8,0($9) */
378
379                 MIPS32_LW(8,0,15),                                                                      /* lw $8,($15) */
380                 MIPS32_B(NEG16(9)),     //was 17                                                        /* b start */
381                 MIPS32_MFC0(15,31,0),   //this instruction will be executed (MIPS executes instruction after jump)                                                      /* move COP0 DeSave to $15 */
382                 MIPS32_NOP,
383         };
384
385         int retval = ERROR_OK;
386         uint32_t param_in[1];
387
388         param_in[0] = addr;
389
390         if ((retval = mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code,
391                 sizeof(param_in)/sizeof(param_in[0]), param_in, sizeof(uint32_t), buf, 1)) != ERROR_OK)
392         {
393                 return retval;
394         }
395
396         return retval;
397 }
398
399 int mips32_pracc_read_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf)
400 {
401         static const uint32_t code[] = {
402                                                                                                                         /* start: */
403                 MIPS32_MTC0(15,31,0),                                                           /* move $15 to COP0 DeSave */
404                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),             /* $15 = MIPS32_PRACC_STACK */
405                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
406                 MIPS32_SW(8,0,15),                                                                      /* sw $8,($15) */
407                 MIPS32_SW(9,0,15),                                                                      /* sw $9,($15) */
408                 MIPS32_SW(10,0,15),                                                             /* sw $10,($15) */
409                 MIPS32_SW(11,0,15),                                                             /* sw $11,($15) */
410
411                 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)),           /* $8 = MIPS32_PRACC_PARAM_IN */
412                 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
413                 MIPS32_LW(9,0,8),                                                                       /* $9 = mem[$8]; read addr */
414                 MIPS32_LW(10,4,8),                                                                      /* $10 = mem[$8 + 4]; read count */
415                 MIPS32_LUI(11,UPPER16(MIPS32_PRACC_PARAM_OUT)),         /* $11 = MIPS32_PRACC_PARAM_OUT */
416                 MIPS32_ORI(11,11,LOWER16(MIPS32_PRACC_PARAM_OUT)),
417                 MIPS32_NOP,
418                                                                                                                         /* loop: */
419                 MIPS32_BEQ(0,10,9),                                                             /* beq 0, $10, end */
420                 MIPS32_NOP,
421
422                 MIPS32_LHU(8,0,9),                                                                      /* lw $8,0($9), Load $8 with the halfword @mem[$9] */
423                 MIPS32_SW(8,0,11),                                                                      /* sw $8,0($11) */
424
425                 MIPS32_ADDI(10,10,NEG16(1)),                                            /* $10-- */
426                 MIPS32_ADDI(9,9,2),                                                             /* $9 += 2 */
427                 MIPS32_ADDI(11,11,4),                                                           /* $11 += 4 */
428                 MIPS32_NOP,
429                 MIPS32_B(NEG16(9)),                                                                     /* b loop */
430                 MIPS32_NOP,
431
432                 MIPS32_LW(11,0,15),                                                             /* lw $11,($15) */
433                 MIPS32_LW(10,0,15),                                                             /* lw $10,($15) */
434                 MIPS32_LW(9,0,15),                                                                      /* lw $9,($15) */
435                 MIPS32_LW(8,0,15),                                                                      /* lw $8,($15) */
436                 MIPS32_MFC0(15,31,0),                                                           /* move COP0 DeSave to $15 */
437                 MIPS32_NOP,
438                 MIPS32_B(NEG16(31)),                                                            /* b start */
439                 MIPS32_NOP,
440         };
441
442 //      /* TODO remove array */
443         uint32_t *param_out = malloc(count * sizeof(uint32_t));
444         int i;
445
446 //      int retval;
447         int blocksize;
448         int bytesread;
449         uint32_t param_in[2];
450
451         bytesread = 0;
452
453         //while (count > 0)
454         {
455                 blocksize = count;
456                 if (count > 0x400)
457                         blocksize = 0x400;
458
459                 param_in[0] = addr;
460                 param_in[1] = blocksize;
461
462                 mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code, \
463                         sizeof(param_in)/sizeof(param_in[0]), param_in, count, param_out, 1);
464
465 //              count -= blocksize;
466 //              addr += blocksize;
467 //              bytesread += blocksize;
468         }
469
470         for (i = 0; i < count; i++)
471         {
472                 buf[i] = param_out[i];
473         }
474
475         free(param_out);
476
477         return ERROR_OK;
478 }
479
480 int mips32_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf)
481 {
482         static const uint32_t code[] = {
483                                                                                                                         /* start: */
484                 MIPS32_MTC0(15,31,0),                                                           /* move $15 to COP0 DeSave */
485                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),             /* $15 = MIPS32_PRACC_STACK */
486                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
487                 MIPS32_SW(8,0,15),                                                                      /* sw $8,($15) */
488                 MIPS32_SW(9,0,15),                                                                      /* sw $9,($15) */
489                 MIPS32_SW(10,0,15),                                                             /* sw $10,($15) */
490                 MIPS32_SW(11,0,15),                                                             /* sw $11,($15) */
491
492                 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)),           /* $8 = MIPS32_PRACC_PARAM_IN */
493                 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
494                 MIPS32_LW(9,0,8),                                                                       /* $9 = mem[$8]; read addr */
495                 MIPS32_LW(10,4,8),                                                                      /* $10 = mem[$8 + 4]; read count */
496                 MIPS32_LUI(11,UPPER16(MIPS32_PRACC_PARAM_OUT)),         /* $11 = MIPS32_PRACC_PARAM_OUT */
497                 MIPS32_ORI(11,11,LOWER16(MIPS32_PRACC_PARAM_OUT)),
498                 MIPS32_NOP,
499                                                                                                                         /* loop: */
500                 MIPS32_BEQ(0,10,9),                                                             /* beq 0, $10, end */
501                 MIPS32_NOP,
502
503                 MIPS32_LBU(8,0,9),                                                                      /* lw $8,0($9), Load t4 with the byte @mem[t1] */
504                 MIPS32_SW(8,0,11),                                                                      /* sw $8,0($11) */
505
506                 MIPS32_ADDI(10,10,NEG16(1)),                                            /* $10-- */
507                 MIPS32_ADDI(9,9,1),                                                             /* $9 += 1 */
508                 MIPS32_ADDI(11,11,4),                                                           /* $11 += 4 */
509                 MIPS32_NOP,
510                 MIPS32_B(NEG16(9)),                                                                     /* b loop */
511                 MIPS32_NOP,
512                                                                                                                         /* end: */
513                 MIPS32_LW(11,0,15),                                                             /* lw $11,($15) */
514                 MIPS32_LW(10,0,15),                                                             /* lw $10,($15) */
515                 MIPS32_LW(9,0,15),                                                                      /* lw $9,($15) */
516                 MIPS32_LW(8,0,15),                                                                      /* lw $8,($15) */
517                 MIPS32_MFC0(15,31,0),                                                           /* move COP0 DeSave to $15 */
518                 MIPS32_NOP,
519                 MIPS32_B(NEG16(31)),                                                            /* b start */
520                 MIPS32_NOP,
521         };
522
523 //      /* TODO remove array */
524         uint32_t *param_out = malloc(count * sizeof(uint32_t));
525         int i;
526
527 //      int retval;
528         int blocksize;
529         int bytesread;
530         uint32_t param_in[2];
531
532         bytesread = 0;
533
534 //      while (count > 0)
535         {
536                 blocksize = count;
537                 if (count > 0x400)
538                         blocksize = 0x400;
539
540                 param_in[0] = addr;
541                 param_in[1] = blocksize;
542
543                 mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code, \
544                         sizeof(param_in)/sizeof(param_in[0]), param_in, count, param_out, 1);
545
546 //              count -= blocksize;
547 //              addr += blocksize;
548 //              bytesread += blocksize;
549         }
550
551         for (i = 0; i < count; i++)
552         {
553                 buf[i] = param_out[i];
554         }
555
556         free(param_out);
557
558         return ERROR_OK;
559 }
560
561 int mips32_pracc_write_mem(struct mips_ejtag *ejtag_info, uint32_t addr, int size, int count, void *buf)
562 {
563         switch (size)
564         {
565                 case 1:
566                         return mips32_pracc_write_mem8(ejtag_info, addr, count, (uint8_t*)buf);
567                 case 2:
568                         return mips32_pracc_write_mem16(ejtag_info, addr, count,(uint16_t*)buf);
569                 case 4:
570                         if (count == 1)
571                                 return mips32_pracc_write_u32(ejtag_info, addr, (uint32_t*)buf);
572                         else
573                                 return mips32_pracc_write_mem32(ejtag_info, addr, count, (uint32_t*)buf);
574         }
575
576         return ERROR_OK;
577 }
578
579 int mips32_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint32_t *buf)
580 {
581
582 //NC: use destination pointer as loop counter (last address is in $10)
583         static const uint32_t code[] = {
584                                                                                                                         /* start: */
585                 MIPS32_MTC0(15,31,0),                                                           /* move $15 to COP0 DeSave */
586                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),             /* $15 = MIPS32_PRACC_STACK */
587                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
588                 MIPS32_SW(8,0,15),                                                                      /* sw $8,($15) */
589                 MIPS32_SW(9,0,15),                                                                      /* sw $9,($15) */
590                 MIPS32_SW(10,0,15),                                                             /* sw $10,($15) */
591                 MIPS32_SW(11,0,15),                                                             /* sw $11,($15) */
592
593                 MIPS32_ADDI(8,15,NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN)),  //$8= MIPS32_PRACC_PARAM_IN
594                 MIPS32_LW(9,0,8),                                                                       /* Load write addr to $9 */
595                 MIPS32_LW(10,4,8),      //last address                                                                  /* Load write count to $10 */
596                 MIPS32_ADDI(8,8,8),     // $8 += 8 beginning of data
597
598 //loop:
599                 MIPS32_LW(11,0,8),                                                                      /* lw $11,0($8), Load $11 with the word @mem[$8] */
600                 MIPS32_SW(11,0,9),                                                                      /* sw $11,0($9) */
601
602                 MIPS32_ADDI(9,9,4),                                                             /* $9 += 4 */
603                 MIPS32_BNE(10,9,NEG16(4)),  //was 9 BNE $10, 9, loop                                                                    /* b loop */
604                 MIPS32_ADDI(8,8,4),  //this instruction is part of the loop (one delay slot)!   /* $8 += 4 */
605                                                                                                                         /* end: */
606                 MIPS32_LW(11,0,15),                                                             /* lw $11,($15) */
607                 MIPS32_LW(10,0,15),                                                             /* lw $10,($15) */
608                 MIPS32_LW(9,0,15),                                                                      /* lw $9,($15) */
609                 MIPS32_LW(8,0,15),                                                                      /* lw $8,($15) */
610                 MIPS32_B(NEG16(21)),     //was 30                                                       /* b start */
611                 MIPS32_MFC0(15,31,0),                                                           /* move COP0 DeSave to $15 */
612                 MIPS32_NOP, //this one will not be executed
613         };
614
615         /* TODO remove array */
616         uint32_t *param_in = malloc((count + 2) * sizeof(uint32_t));
617         param_in[0] = addr;
618         param_in[1] = addr + count * sizeof(uint32_t);  //last address
619
620         memcpy(&param_in[2], buf, count * sizeof(uint32_t));
621
622         mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code, \
623                 sizeof(param_in)/sizeof(param_in[0]),param_in, 0, NULL, 1);
624
625         free(param_in);
626
627         return ERROR_OK;
628 }
629
630 int mips32_pracc_write_u32(struct mips_ejtag *ejtag_info, uint32_t addr, uint32_t *buf)
631 {
632         static const uint32_t code[] = {
633                                                                                                                         /* start: */
634                 MIPS32_MTC0(15,31,0),                                                           /* move $15 to COP0 DeSave */
635                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),             /* $15 = MIPS32_PRACC_STACK */
636                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
637                 MIPS32_SW(8,0,15),                                                                      /* sw $8,($15) */
638                 MIPS32_SW(9,0,15),                                                                      /* sw $9,($15) */
639
640                 MIPS32_LW(8,NEG16((MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN)-4), 15),  //load R8 @ param_in[1] = data
641                 MIPS32_LW(9,NEG16(MIPS32_PRACC_STACK-MIPS32_PRACC_PARAM_IN), 15),  //load R9 @ param_in[0] = address
642
643                 MIPS32_SW(8,0,9),                                                                       /* sw $8,0($9) */
644
645                 MIPS32_LW(9,0,15),                                                                      /* lw $9,($15) */
646                 MIPS32_LW(8,0,15),                                                                      /* lw $8,($15) */
647                 MIPS32_B(NEG16(11)),                                                            /* b start */
648                 MIPS32_MFC0(15,31,0),                                                   /* move COP0 DeSave to $15 */
649                 MIPS32_NOP,
650         };
651
652         /* TODO remove array */
653         uint32_t param_in[1 + 1];
654         param_in[0] = addr;
655         param_in[1] = *buf;
656
657         mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code, \
658                 sizeof(param_in)/sizeof(param_in[0]),param_in, 0, NULL, 1);
659
660         return ERROR_OK;
661 }
662
663 int mips32_pracc_write_mem16(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint16_t *buf)
664 {
665         static const uint32_t code[] = {
666                                                                                                                         /* start: */
667                 MIPS32_MTC0(15,31,0),                                                           /* move $15 to COP0 DeSave */
668                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),             /* $15 = MIPS32_PRACC_STACK */
669                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
670                 MIPS32_SW(8,0,15),                                                                      /* sw $8,($15) */
671                 MIPS32_SW(9,0,15),                                                                      /* sw $9,($15) */
672                 MIPS32_SW(10,0,15),                                                             /* sw $10,($15) */
673                 MIPS32_SW(11,0,15),                                                             /* sw $11,($15) */
674
675                 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)),           /* $8 = MIPS32_PRACC_PARAM_IN */
676                 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
677                 MIPS32_LW(9,0,8),                                                                       /* Load write addr to $9 */
678                 MIPS32_LW(10,4,8),                                                                      /* Load write count to $10 */
679                 MIPS32_ADDI(8,8,8),                                                             /* $8 += 8 */
680                 MIPS32_NOP,
681                                                                                                                         /* loop: */
682                 MIPS32_BEQ(0,10,9),                                                                     /* beq $0, $10, end */
683                 MIPS32_NOP,
684
685                 MIPS32_LW(11,0,8),                                                                      /* lw $11,0($8), Load $11 with the word @mem[$8] */
686                 MIPS32_SH(11,0,9),                                                                      /* sh $11,0($9) */
687
688                 MIPS32_ADDI(10,10,NEG16(1)),                                            /* $10-- */
689                 MIPS32_ADDI(9,9,2),                                                             /* $9 += 2 */
690                 MIPS32_ADDI(8,8,4),                                                             /* $8 += 4 */
691
692                 MIPS32_NOP,
693                 MIPS32_B(NEG16(9)),                                                                     /* b loop */
694                 MIPS32_NOP,
695                                                                                                                         /* end: */
696                 MIPS32_LW(11,0,15),                                                             /* lw $11,($15) */
697                 MIPS32_LW(10,0,15),                                                             /* lw $10,($15) */
698                 MIPS32_LW(9,0,15),                                                                      /* lw $9,($15) */
699                 MIPS32_LW(8,0,15),                                                                      /* lw $8,($15) */
700                 MIPS32_MFC0(15,31,0),                                                           /* move COP0 DeSave to $15 */
701                 MIPS32_NOP,
702                 MIPS32_B(NEG16(30)),                                                            /* b start */
703                 MIPS32_NOP,
704         };
705
706         /* TODO remove array */
707         uint32_t *param_in = malloc((count + 2) * sizeof(uint32_t));
708         int i;
709         param_in[0] = addr;
710         param_in[1] = count;
711
712         for (i = 0; i < count; i++)
713         {
714                 param_in[i + 2] = buf[i];
715         }
716
717         mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code, \
718                 sizeof(param_in)/sizeof(param_in[0]), param_in, 0, NULL, 1);
719
720         free(param_in);
721
722         return ERROR_OK;
723 }
724
725 int mips32_pracc_write_mem8(struct mips_ejtag *ejtag_info, uint32_t addr, int count, uint8_t *buf)
726 {
727         static const uint32_t code[] = {
728                                                                                                                         /* start: */
729                 MIPS32_MTC0(15,31,0),                                                           /* move $15 to COP0 DeSave */
730                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),             /* $15 = MIPS32_PRACC_STACK */
731                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
732                 MIPS32_SW(8,0,15),                                                                      /* sw $8,($15) */
733                 MIPS32_SW(9,0,15),                                                                      /* sw $9,($15) */
734                 MIPS32_SW(10,0,15),                                                             /* sw $10,($15) */
735                 MIPS32_SW(11,0,15),                                                             /* sw $11,($15) */
736
737                 MIPS32_LUI(8,UPPER16(MIPS32_PRACC_PARAM_IN)),           /* $8 = MIPS32_PRACC_PARAM_IN */
738                 MIPS32_ORI(8,8,LOWER16(MIPS32_PRACC_PARAM_IN)),
739                 MIPS32_LW(9,0,8),                                                                       /* Load write addr to $9 */
740                 MIPS32_LW(10,4,8),                                                                      /* Load write count to $10 */
741                 MIPS32_ADDI(8,8,8),                                                             /* $8 += 8 */
742                 MIPS32_NOP,
743                                                                                                                         /* loop: */
744                 MIPS32_BEQ(0,10,9),                                                                     /* beq $0, $10, end */
745                 MIPS32_NOP,
746
747                 MIPS32_LW(11,0,8),                                                                      /* lw $11,0($8), Load $11 with the word @mem[$8] */
748                 MIPS32_SB(11,0,9),                                                                      /* sb $11,0($9) */
749
750                 MIPS32_ADDI(10,10,NEG16(1)),                                            /* $10-- */
751                 MIPS32_ADDI(9,9,1),                                                             /* $9 += 1 */
752                 MIPS32_ADDI(8,8,4),                                                             /* $8 += 4 */
753
754                 MIPS32_NOP,
755                 MIPS32_B(NEG16(9)),                                                                     /* b loop */
756                 MIPS32_NOP,
757                                                                                                                         /* end: */
758                 MIPS32_LW(11,0,15),                                                             /* lw $11,($15) */
759                 MIPS32_LW(10,0,15),                                                             /* lw $10,($15) */
760                 MIPS32_LW(9,0,15),                                                                      /* lw $9,($15) */
761                 MIPS32_LW(8,0,15),                                                                      /* lw $8,($15) */
762                 MIPS32_MFC0(15,31,0),                                                           /* move COP0 DeSave to $15 */
763                 MIPS32_NOP,
764                 MIPS32_B(NEG16(30)),                                                            /* b start */
765                 MIPS32_NOP,
766         };
767
768         /* TODO remove array */
769         uint32_t *param_in = malloc((count + 2) * sizeof(uint32_t));
770         int retval;
771         int i;
772         param_in[0] = addr;
773         param_in[1] = count;
774
775         for (i = 0; i < count; i++)
776         {
777                 param_in[i + 2] = buf[i];
778         }
779
780         retval = mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code, \
781                 sizeof(param_in)/sizeof(param_in[0]), param_in, 0, NULL, 1);
782
783         free(param_in);
784
785         return retval;
786 }
787
788 int mips32_pracc_write_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
789 {
790         static const uint32_t code[] = {
791                                                                                                                 /* start: */
792                 MIPS32_LUI(2,UPPER16(MIPS32_PRACC_PARAM_IN)),   /* $2 = MIPS32_PRACC_PARAM_IN */
793                 MIPS32_ORI(2,2,LOWER16(MIPS32_PRACC_PARAM_IN)),
794                 MIPS32_LW(1,1*4,2),                                                     /* lw $1,1*4($2) */
795                 MIPS32_LW(15,15*4,2),                                                   /* lw $15,15*4($2) */
796                 MIPS32_MTC0(15,31,0),                                                   /* move $15 to COP0 DeSave */
797                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),     /* $15 = MIPS32_PRACC_STACK */
798                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
799                 MIPS32_SW(1,0,15),                                                              /* sw $1,($15) */
800                 MIPS32_LUI(1,UPPER16(MIPS32_PRACC_PARAM_IN)),   /* $1 = MIPS32_PRACC_PARAM_IN */
801                 MIPS32_ORI(1,1,LOWER16(MIPS32_PRACC_PARAM_IN)),
802                 MIPS32_LW(3,3*4,1),                                                     /* lw $3,3*4($1) */
803                 MIPS32_LW(4,4*4,1),                                                     /* lw $4,4*4($1) */
804                 MIPS32_LW(5,5*4,1),                                                     /* lw $5,5*4($1) */
805                 MIPS32_LW(6,6*4,1),                                                     /* lw $6,6*4($1) */
806                 MIPS32_LW(7,7*4,1),                                                     /* lw $7,7*4($1) */
807                 MIPS32_LW(8,8*4,1),                                                     /* lw $8,8*4($1) */
808                 MIPS32_LW(9,9*4,1),                                                     /* lw $9,9*4($1) */
809                 MIPS32_LW(10,10*4,1),                                                   /* lw $10,10*4($1) */
810                 MIPS32_LW(11,11*4,1),                                                   /* lw $11,11*4($1) */
811                 MIPS32_LW(12,12*4,1),                                                   /* lw $12,12*4($1) */
812                 MIPS32_LW(13,13*4,1),                                                   /* lw $13,13*4($1) */
813                 MIPS32_LW(14,14*4,1),                                                   /* lw $14,14*4($1) */
814                 MIPS32_LW(16,16*4,1),                                                   /* lw $16,16*4($1) */
815                 MIPS32_LW(17,17*4,1),                                                   /* lw $17,17*4($1) */
816                 MIPS32_LW(18,18*4,1),                                                   /* lw $18,18*4($1) */
817                 MIPS32_LW(19,19*4,1),                                                   /* lw $19,19*4($1) */
818                 MIPS32_LW(20,20*4,1),                                                   /* lw $20,20*4($1) */
819                 MIPS32_LW(21,21*4,1),                                                   /* lw $21,21*4($1) */
820                 MIPS32_LW(22,22*4,1),                                                   /* lw $22,22*4($1) */
821                 MIPS32_LW(23,23*4,1),                                                   /* lw $23,23*4($1) */
822                 MIPS32_LW(24,24*4,1),                                                   /* lw $24,24*4($1) */
823                 MIPS32_LW(25,25*4,1),                                                   /* lw $25,25*4($1) */
824                 MIPS32_LW(26,26*4,1),                                                   /* lw $26,26*4($1) */
825                 MIPS32_LW(27,27*4,1),                                                   /* lw $27,27*4($1) */
826                 MIPS32_LW(28,28*4,1),                                                   /* lw $28,28*4($1) */
827                 MIPS32_LW(29,29*4,1),                                                   /* lw $29,29*4($1) */
828                 MIPS32_LW(30,30*4,1),                                                   /* lw $30,30*4($1) */
829                 MIPS32_LW(31,31*4,1),                                                   /* lw $31,31*4($1) */
830
831                 MIPS32_LW(2,32*4,1),                                                    /* lw $2,32*4($1) */
832                 MIPS32_MTC0(2,12,0),                                                    /* move $2 to status */
833                 MIPS32_LW(2,33*4,1),                                                    /* lw $2,33*4($1) */
834                 MIPS32_MTLO(2),                                                                 /* move $2 to lo */
835                 MIPS32_LW(2,34*4,1),                                                    /* lw $2,34*4($1) */
836                 MIPS32_MTHI(2),                                                                 /* move $2 to hi */
837                 MIPS32_LW(2,35*4,1),                                                    /* lw $2,35*4($1) */
838                 MIPS32_MTC0(2,8,0),                                                             /* move $2 to badvaddr */
839                 MIPS32_LW(2,36*4,1),                                                    /* lw $2,36*4($1) */
840                 MIPS32_MTC0(2,13,0),                                                    /* move $2 to cause*/
841                 MIPS32_LW(2,37*4,1),                                                    /* lw $2,37*4($1) */
842                 MIPS32_MTC0(2,24,0),                                                    /* move $2 to pc */
843
844                 MIPS32_LW(2,2*4,1),                                                     /* lw $2,2*4($1) */
845                 MIPS32_LW(1,0,15),                                                              /* lw $1,($15) */
846                 MIPS32_MFC0(15,31,0),                                                   /* move COP0 DeSave to $15 */
847                 MIPS32_NOP,
848                 MIPS32_B(NEG16(55)),                                                    /* b start */
849                 MIPS32_NOP,
850         };
851
852         int retval;
853
854         retval = mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code, \
855                 38, regs, 0, NULL, 1);
856
857         return retval;
858 }
859
860 int mips32_pracc_read_regs(struct mips_ejtag *ejtag_info, uint32_t *regs)
861 {
862         static const uint32_t code[] = {
863                                                                                                                 /* start: */
864                 MIPS32_MTC0(2,31,0),                                                    /* move $2 to COP0 DeSave */
865                 MIPS32_LUI(2,UPPER16(MIPS32_PRACC_PARAM_OUT)),  /* $2 = MIPS32_PRACC_PARAM_OUT */
866                 MIPS32_ORI(2,2,LOWER16(MIPS32_PRACC_PARAM_OUT)),
867                 MIPS32_SW(0,0*4,2),                                                             /* sw $0,0*4($2) */
868                 MIPS32_SW(1,1*4,2),                                                     /* sw $1,1*4($2) */
869                 MIPS32_SW(15,15*4,2),                                                   /* sw $15,15*4($2) */
870                 MIPS32_MFC0(2,31,0),                                                    /* move COP0 DeSave to $2 */
871                 MIPS32_MTC0(15,31,0),                                                   /* move $15 to COP0 DeSave */
872                 MIPS32_LUI(15,UPPER16(MIPS32_PRACC_STACK)),     /* $15 = MIPS32_PRACC_STACK */
873                 MIPS32_ORI(15,15,LOWER16(MIPS32_PRACC_STACK)),
874                 MIPS32_SW(1,0,15),                                                              /* sw $1,($15) */
875                 MIPS32_SW(2,0,15),                                                              /* sw $2,($15) */
876                 MIPS32_LUI(1,UPPER16(MIPS32_PRACC_PARAM_OUT)),  /* $1 = MIPS32_PRACC_PARAM_OUT */
877                 MIPS32_ORI(1,1,LOWER16(MIPS32_PRACC_PARAM_OUT)),
878                 MIPS32_SW(2,2*4,1),                                                     /* sw $2,2*4($1) */
879                 MIPS32_SW(3,3*4,1),                                                     /* sw $3,3*4($1) */
880                 MIPS32_SW(4,4*4,1),                                                     /* sw $4,4*4($1) */
881                 MIPS32_SW(5,5*4,1),                                                     /* sw $5,5*4($1) */
882                 MIPS32_SW(6,6*4,1),                                                     /* sw $6,6*4($1) */
883                 MIPS32_SW(7,7*4,1),                                                     /* sw $7,7*4($1) */
884                 MIPS32_SW(8,8*4,1),                                                     /* sw $8,8*4($1) */
885                 MIPS32_SW(9,9*4,1),                                                     /* sw $9,9*4($1) */
886                 MIPS32_SW(10,10*4,1),                                                   /* sw $10,10*4($1) */
887                 MIPS32_SW(11,11*4,1),                                                   /* sw $11,11*4($1) */
888                 MIPS32_SW(12,12*4,1),                                                   /* sw $12,12*4($1) */
889                 MIPS32_SW(13,13*4,1),                                                   /* sw $13,13*4($1) */
890                 MIPS32_SW(14,14*4,1),                                                   /* sw $14,14*4($1) */
891                 MIPS32_SW(16,16*4,1),                                                   /* sw $16,16*4($1) */
892                 MIPS32_SW(17,17*4,1),                                                   /* sw $17,17*4($1) */
893                 MIPS32_SW(18,18*4,1),                                                   /* sw $18,18*4($1) */
894                 MIPS32_SW(19,19*4,1),                                                   /* sw $19,19*4($1) */
895                 MIPS32_SW(20,20*4,1),                                                   /* sw $20,20*4($1) */
896                 MIPS32_SW(21,21*4,1),                                                   /* sw $21,21*4($1) */
897                 MIPS32_SW(22,22*4,1),                                                   /* sw $22,22*4($1) */
898                 MIPS32_SW(23,23*4,1),                                                   /* sw $23,23*4($1) */
899                 MIPS32_SW(24,24*4,1),                                                   /* sw $24,24*4($1) */
900                 MIPS32_SW(25,25*4,1),                                                   /* sw $25,25*4($1) */
901                 MIPS32_SW(26,26*4,1),                                                   /* sw $26,26*4($1) */
902                 MIPS32_SW(27,27*4,1),                                                   /* sw $27,27*4($1) */
903                 MIPS32_SW(28,28*4,1),                                                   /* sw $28,28*4($1) */
904                 MIPS32_SW(29,29*4,1),                                                   /* sw $29,29*4($1) */
905                 MIPS32_SW(30,30*4,1),                                                   /* sw $30,30*4($1) */
906                 MIPS32_SW(31,31*4,1),                                                   /* sw $31,31*4($1) */
907
908                 MIPS32_MFC0(2,12,0),                                                    /* move status to $2 */
909                 MIPS32_SW(2,32*4,1),                                                    /* sw $2,32*4($1) */
910                 MIPS32_MFLO(2),                                                                 /* move lo to $2 */
911                 MIPS32_SW(2,33*4,1),                                                    /* sw $2,33*4($1) */
912                 MIPS32_MFHI(2),                                                                 /* move hi to $2 */
913                 MIPS32_SW(2,34*4,1),                                                    /* sw $2,34*4($1) */
914                 MIPS32_MFC0(2,8,0),                                                             /* move badvaddr to $2 */
915                 MIPS32_SW(2,35*4,1),                                                    /* sw $2,35*4($1) */
916                 MIPS32_MFC0(2,13,0),                                                    /* move cause to $2 */
917                 MIPS32_SW(2,36*4,1),                                                    /* sw $2,36*4($1) */
918                 MIPS32_MFC0(2,24,0),                                                    /* move pc to $2 */
919                 MIPS32_SW(2,37*4,1),                                                    /* sw $2,37*4($1) */
920
921                 MIPS32_LW(2,0,15),                                                              /* lw $2,($15) */
922                 MIPS32_LW(1,0,15),                                                              /* lw $1,($15) */
923                 MIPS32_MFC0(15,31,0),                                                   /* move COP0 DeSave to $15 */
924                 MIPS32_NOP,
925                 MIPS32_B(NEG16(60)),                                                    /* b start */
926                 MIPS32_NOP,
927         };
928
929         int retval;
930
931         retval = mips32_pracc_exec(ejtag_info, sizeof(code)/sizeof(code[0]), code, \
932                 0, NULL, 38, regs, 1);
933
934         return retval;
935 }