Extend configure script to check for environ declaration in stdlib.h.
[openocd.git] / 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 }