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