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