Revive tclapi.c from r1650:
[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 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)