- remove target specific variant and use target->variant member
[fw/openocd] / src / helper / tclapi.c
1 /***************************************************************************
2  *   Copyright (C) 2007,2008 Ã˜yvind Harboe                                 *
3  *   Copyright (C) 2008 Duane Ellis                                        *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "replacements.h"
25 #include "target.h"
26 #include "target_request.h"
27
28 #include "log.h"
29 #include "configuration.h"
30 #include "binarybuffer.h"
31 #include "jtag.h"
32 #include "flash.h"
33
34 #include <string.h>
35 #include <stdlib.h>
36 #include <inttypes.h>
37
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <unistd.h>
41 #include <errno.h>
42
43 #include <sys/time.h>
44 #include <time.h>
45
46 #include <time_support.h>
47
48 #include <fileio.h>
49 #include <image.h>
50
51 static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, u32 val)
52 {
53         char *namebuf;
54         Jim_Obj *nameObjPtr, *valObjPtr;
55         int result;
56
57         namebuf = alloc_printf("%s(%d)", varname, idx);
58         if (!namebuf)
59                 return JIM_ERR;
60
61         nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
62         valObjPtr = Jim_NewIntObj(interp, val);
63         if (!nameObjPtr || !valObjPtr)
64         {
65                 free(namebuf);
66                 return JIM_ERR;
67         }
68
69         Jim_IncrRefCount(nameObjPtr);
70         Jim_IncrRefCount(valObjPtr);
71         result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
72         Jim_DecrRefCount(interp, nameObjPtr);
73         Jim_DecrRefCount(interp, valObjPtr);
74         free(namebuf);
75         /* printf("%s(%d) <= 0%08x\n", varname, idx, val); */
76         return result;
77 }
78
79 static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
80 {
81         target_t *target;
82         command_context_t *context;
83         long l;
84         u32 width;
85         u32 len;
86         u32 addr;
87         u32 count;
88         u32 v;
89         const char *varname;
90         u8 buffer[4096];
91         int  i, n, e, retval;
92
93         /* argv[1] = name of array to receive the data
94          * argv[2] = desired width
95          * argv[3] = memory address
96          * argv[4] = count of times to read
97          */
98         if (argc != 5) {
99                 Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
100                 return JIM_ERR;
101         }
102         varname = Jim_GetString(argv[1], &len);
103         /* given "foo" get space for worse case "foo(%d)" .. add 20 */
104
105         e = Jim_GetLong(interp, argv[2], &l);
106         width = l;
107         if (e != JIM_OK) {
108                 return e;
109         }
110
111         e = Jim_GetLong(interp, argv[3], &l);
112         addr = l;
113         if (e != JIM_OK) {
114                 return e;
115         }
116         e = Jim_GetLong(interp, argv[4], &l);
117         len = l;
118         if (e != JIM_OK) {
119                 return e;
120         }
121         switch (width) {
122                 case 8:
123                         width = 1;
124                         break;
125                 case 16:
126                         width = 2;
127                         break;
128                 case 32:
129                         width = 4;
130                         break;
131                 default:
132                         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
133                         Jim_AppendStrings( interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL );
134                         return JIM_ERR;
135         }
136         if (len == 0) {
137                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
138                 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
139                 return JIM_ERR;
140         }
141         if ((addr + (len * width)) < addr) {
142                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
143                 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
144                 return JIM_ERR;
145         }
146         /* absurd transfer size? */
147         if (len > 65536) {
148                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
149                 Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL);
150                 return JIM_ERR;
151         }
152
153         if ((width == 1) ||
154                 ((width == 2) && ((addr & 1) == 0)) ||
155                 ((width == 4) && ((addr & 3) == 0))) {
156                 /* all is well */
157         } else {
158                 char buf[100];
159                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
160                 sprintf(buf, "mem2array address: 0x%08x is not aligned for %d byte reads", addr, width);
161                 Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
162                 return JIM_ERR;
163         }
164
165         context = Jim_GetAssocData(interp, "context");
166         if (context == NULL)
167         {
168                 LOG_ERROR("mem2array: no command context");
169                 return JIM_ERR;
170         }
171         target = get_current_target(context);
172         if (target == NULL)
173         {
174                 LOG_ERROR("mem2array: no current target");
175                 return JIM_ERR;
176         }
177
178         /* Transfer loop */
179
180         /* index counter */
181         n = 0;
182         /* assume ok */
183         e = JIM_OK;
184         while (len) {
185                 /* Slurp... in buffer size chunks */
186
187                 count = len; /* in objects.. */
188                 if (count > (sizeof(buffer)/width)) {
189                         count = (sizeof(buffer)/width);
190                 }
191
192                 retval = target->type->read_memory( target, addr, width, count, buffer );
193                 if (retval != ERROR_OK) {
194                         /* BOO !*/
195                         LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed", addr, width, count);
196                         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
197                         Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
198                         e = JIM_ERR;
199                         len = 0;
200                 } else {
201                         v = 0; /* shut up gcc */
202                         for (i = 0 ;i < count ;i++, n++) {
203                                 switch (width) {
204                                         case 4:
205                                                 v = target_buffer_get_u32(target, &buffer[i*width]);
206                                                 break;
207                                         case 2:
208                                                 v = target_buffer_get_u16(target, &buffer[i*width]);
209                                                 break;
210                                         case 1:
211                                                 v = buffer[i] & 0x0ff;
212                                                 break;
213                                 }
214                                 new_int_array_element(interp, varname, n, v);
215                         }
216                         len -= count;
217                 }
218         }
219
220         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
221
222         return JIM_OK;
223 }
224
225 static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, u32 *val)
226 {
227         char *namebuf;
228         Jim_Obj *nameObjPtr, *valObjPtr;
229         int result;
230         long l;
231
232         namebuf = alloc_printf("%s(%d)", varname, idx);
233         if (!namebuf)
234                 return JIM_ERR;
235
236         nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
237         if (!nameObjPtr)
238         {
239                 free(namebuf);
240                 return JIM_ERR;
241         }
242
243         Jim_IncrRefCount(nameObjPtr);
244         valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
245         Jim_DecrRefCount(interp, nameObjPtr);
246         free(namebuf);
247         if (valObjPtr == NULL)
248                 return JIM_ERR;
249
250         result = Jim_GetLong(interp, valObjPtr, &l);
251         /* printf("%s(%d) => 0%08x\n", varname, idx, val); */
252         *val = l;
253         return result;
254 }
255
256 static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
257 {
258         target_t *target;
259         command_context_t *context;
260         long l;
261         u32 width;
262         u32 len;
263         u32 addr;
264         u32 count;
265         u32 v;
266         const char *varname;
267         u8 buffer[4096];
268         int  i, n, e, retval;
269
270         /* argv[1] = name of array to get the data
271          * argv[2] = desired width
272          * argv[3] = memory address
273          * argv[4] = count to write
274          */
275         if (argc != 5) {
276                 Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems");
277                 return JIM_ERR;
278         }
279         varname = Jim_GetString(argv[1], &len);
280         /* given "foo" get space for worse case "foo(%d)" .. add 20 */
281
282         e = Jim_GetLong(interp, argv[2], &l);
283         width = l;
284         if (e != JIM_OK) {
285                 return e;
286         }
287
288         e = Jim_GetLong(interp, argv[3], &l);
289         addr = l;
290         if (e != JIM_OK) {
291                 return e;
292         }
293         e = Jim_GetLong(interp, argv[4], &l);
294         len = l;
295         if (e != JIM_OK) {
296                 return e;
297         }
298         switch (width) {
299                 case 8:
300                         width = 1;
301                         break;
302                 case 16:
303                         width = 2;
304                         break;
305                 case 32:
306                         width = 4;
307                         break;
308                 default:
309                         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
310                         Jim_AppendStrings( interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL );
311                         return JIM_ERR;
312         }
313         if (len == 0) {
314                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
315                 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: zero width read?", NULL);
316                 return JIM_ERR;
317         }
318         if ((addr + (len * width)) < addr) {
319                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
320                 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: addr + len - wraps to zero?", NULL);
321                 return JIM_ERR;
322         }
323         /* absurd transfer size? */
324         if (len > 65536) {
325                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
326                 Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: absurd > 64K item request", NULL);
327                 return JIM_ERR;
328         }
329
330         if ((width == 1) ||
331                 ((width == 2) && ((addr & 1) == 0)) ||
332                 ((width == 4) && ((addr & 3) == 0))) {
333                 /* all is well */
334         } else {
335                 char buf[100];
336                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
337                 sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads", addr, width);
338                 Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL);
339                 return JIM_ERR;
340         }
341
342         context = Jim_GetAssocData(interp, "context");
343         if (context == NULL)
344         {
345                 LOG_ERROR("array2mem: no command context");
346                 return JIM_ERR;
347         }
348         target = get_current_target(context);
349         if (target == NULL)
350         {
351                 LOG_ERROR("array2mem: no current target");
352                 return JIM_ERR;
353         }
354
355         /* Transfer loop */
356
357         /* index counter */
358         n = 0;
359         /* assume ok */
360         e = JIM_OK;
361         while (len) {
362                 /* Slurp... in buffer size chunks */
363
364                 count = len; /* in objects.. */
365                 if (count > (sizeof(buffer)/width)) {
366                         count = (sizeof(buffer)/width);
367                 }
368
369                 v = 0; /* shut up gcc */
370                 for (i = 0 ;i < count ;i++, n++) {
371                         get_int_array_element(interp, varname, n, &v);
372                         switch (width) {
373                         case 4:
374                                 target_buffer_set_u32(target, &buffer[i*width], v);
375                                 break;
376                         case 2:
377                                 target_buffer_set_u16(target, &buffer[i*width], v);
378                                 break;
379                         case 1:
380                                 buffer[i] = v & 0x0ff;
381                                 break;
382                         }
383                 }
384                 len -= count;
385
386                 retval = target->type->write_memory(target, addr, width, count, buffer);
387                 if (retval != ERROR_OK) {
388                         /* BOO !*/
389                         LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed", addr, width, count);
390                         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
391                         Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
392                         e = JIM_ERR;
393                         len = 0;
394                 }
395         }
396
397         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
398
399         return JIM_OK;
400 }
401
402 int Jim_Command_drscan(Jim_Interp *interp, int argc, Jim_Obj *const *args)
403 {
404         int retval;
405         scan_field_t *fields;
406         int num_fields;
407         int field_count = 0;
408         int i, e;
409         long device;
410
411         /* args[1] = device
412          * args[2] = num_bits
413          * args[3] = hex string
414          * ... repeat num bits and hex string ...
415          */
416         if ((argc < 4) || ((argc % 2)!=0))
417         {
418                 Jim_WrongNumArgs(interp, 1, args, "<device> <num_bits1> <value1> <num_bits2> <value2> ...");
419                 return JIM_ERR;
420         }
421
422         for (i = 2; i < argc; i+=2)
423         {
424                 long bits;
425
426                 e = Jim_GetLong(interp, args[i], &bits);
427                 if (e != JIM_OK)
428                         return e;
429         }
430
431         e = Jim_GetLong(interp, args[1], &device);
432         if (e != JIM_OK)
433                 return e;
434
435         num_fields=(argc-2)/2;
436         fields = malloc(sizeof(scan_field_t) * num_fields);
437         for (i = 2; i < argc; i+=2)
438         {
439                 long bits;
440                 int len;
441                 const char *str;
442
443                 Jim_GetLong(interp, args[i], &bits);
444                 str = Jim_GetString(args[i+1], &len);
445
446                 fields[field_count].device = device;
447                 fields[field_count].num_bits = bits;
448                 fields[field_count].out_value = malloc(CEIL(bits, 8));
449                 str_to_buf(str, len, fields[field_count].out_value, bits, 0);
450                 fields[field_count].out_mask = NULL;
451                 fields[field_count].in_value = fields[field_count].out_value;
452                 fields[field_count].in_check_mask = NULL;
453                 fields[field_count].in_check_value = NULL;
454                 fields[field_count].in_handler = NULL;
455                 fields[field_count++].in_handler_priv = NULL;
456         }
457
458         jtag_add_dr_scan(num_fields, fields, -1);
459         retval = jtag_execute_queue();
460         if (retval != ERROR_OK)
461         {
462                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
463                 Jim_AppendStrings(interp, Jim_GetResult(interp), "drscan: jtag execute failed", NULL);
464                 return JIM_ERR;
465         }
466
467         field_count=0;
468         Jim_Obj *list = Jim_NewListObj(interp, NULL, 0);
469         for (i = 2; i < argc; i+=2)
470         {
471                 long bits;
472                 char *str;
473
474                 Jim_GetLong(interp, args[i], &bits);
475                 str = buf_to_str(fields[field_count].in_value, bits, 16);
476                 free(fields[field_count].out_value);
477
478                 Jim_ListAppendElement(interp, list, Jim_NewStringObj(interp, str, strlen(str)));
479                 free(str);
480                 field_count++;
481         }
482
483         Jim_SetResult(interp, list);
484
485         free(fields);
486
487         return JIM_OK;
488 }
489
490 static int jim_flash_banks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
491 {
492         flash_bank_t *p;
493
494         if (argc != 1) {
495                 Jim_WrongNumArgs(interp, 1, argv, "no arguments to flash_banks command");
496                 return JIM_ERR;
497         }
498
499         if (!flash_banks)
500         {
501                 return JIM_ERR;
502         }
503
504         Jim_Obj *list=Jim_NewListObj(interp, NULL, 0);
505         for (p = flash_banks; p; p = p->next)
506         {
507                 Jim_Obj *elem=Jim_NewListObj(interp, NULL, 0);
508
509                 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "name", -1));
510                 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, p->driver->name, -1));
511                 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "base", -1));
512                 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->base));
513                 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "size", -1));
514                 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->size));
515                 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "bus_width", -1));
516                 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->bus_width));
517                 Jim_ListAppendElement(interp, elem, Jim_NewStringObj(interp, "chip_width", -1));
518                 Jim_ListAppendElement(interp, elem, Jim_NewIntObj(interp, p->chip_width));
519
520                 Jim_ListAppendElement(interp, list, elem);
521         }
522
523         Jim_SetResult(interp, list);
524
525         return JIM_OK;
526 }
527
528 int tclapi_register_commands()
529 {
530         register_jim("ocd_mem2array", jim_mem2array, "read memory and return as a TCL array for script processing");
531         register_jim("ocd_array2mem", jim_array2mem, "convert a TCL array to memory locations and write the values");
532         register_jim("drscan", Jim_Command_drscan, "execute DR scan <device> <num_bits> <value> <num_bits1> <value2> ...");
533         register_jim("ocd_flash_banks", jim_flash_banks, "return information about the flash banks");
534
535 }