- Added support for reading and writing 64-bit data items
using TCL commands "mem2array" and "array2mem". Until now,
data items only up to 32 bits were supportd.
- Cleaned up functions target_array2mem() and
target_mem2array(), especially data types of variables
and variable declarations (scope).
Change-Id: Ia0ba427804f8fd8d7568f12714ab36984d6d5e24
Signed-off-by: Jan Matyas <matyas@codasip.com>
Reviewed-on: http://openocd.zylin.com/6286
Tested-by: jenkins
Reviewed-by: Marc Schink <dev@zapb.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
@deffn {Command} {$target_name array2mem} arrayname width address count
@deffnx {Command} {$target_name mem2array} arrayname width address count
These provide an efficient script-oriented interface to memory.
@deffn {Command} {$target_name array2mem} arrayname width address count
@deffnx {Command} {$target_name mem2array} arrayname width address count
These provide an efficient script-oriented interface to memory.
-The @code{array2mem} primitive writes bytes, halfwords, or words;
-while @code{mem2array} reads them.
+The @code{array2mem} primitive writes bytes, halfwords, words
+or double-words; while @code{mem2array} reads them.
In both cases, the TCL side uses an array, and
the target side uses raw memory.
In both cases, the TCL side uses an array, and
the target side uses raw memory.
@itemize
@item @var{arrayname} ... is the name of an array variable
@itemize
@item @var{arrayname} ... is the name of an array variable
-@item @var{width} ... is 8/16/32 - indicating the memory access size
+@item @var{width} ... is 8/16/32/64 - indicating the memory access size
@item @var{address} ... is the target memory address
@item @var{count} ... is the number of elements to process
@end itemize
@item @var{address} ... is the target memory address
@item @var{count} ... is the number of elements to process
@end itemize
-static int new_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t val)
+static int new_u64_array_element(Jim_Interp *interp, const char *varname, int idx, uint64_t val)
{
char *namebuf;
Jim_Obj *nameObjPtr, *valObjPtr;
{
char *namebuf;
Jim_Obj *nameObjPtr, *valObjPtr;
return JIM_ERR;
nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
return JIM_ERR;
nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
- valObjPtr = Jim_NewIntObj(interp, val);
+ jim_wide wide_val = val;
+ valObjPtr = Jim_NewWideObj(interp, wide_val);
if (!nameObjPtr || !valObjPtr) {
free(namebuf);
return JIM_ERR;
if (!nameObjPtr || !valObjPtr) {
free(namebuf);
return JIM_ERR;
static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
{
static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
{
- long l;
- jim_wide wide_addr;
- uint32_t width;
- int len;
- target_addr_t addr;
- uint32_t count;
- uint32_t v;
- const char *varname;
- const char *phys;
- bool is_phys;
- int n, e, retval;
- uint32_t i;
- /* argv[1] = name of array to receive the data
- * argv[2] = desired width
- * argv[3] = memory address
- * argv[4] = count of times to read
+ /* argv[0] = name of array to receive the data
+ * argv[1] = desired element width in bits
+ * argv[2] = memory address
+ * argv[3] = count of times to read
+ * argv[4] = optional "phys"
if (argc < 4 || argc > 5) {
Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
return JIM_ERR;
}
if (argc < 4 || argc > 5) {
Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
return JIM_ERR;
}
- varname = Jim_GetString(argv[0], &len);
- /* given "foo" get space for worse case "foo(%d)" .. add 20 */
+ /* Arg 0: Name of the array variable */
+ const char *varname = Jim_GetString(argv[0], NULL);
+
+ /* Arg 1: Bit width of one element */
+ long l;
e = Jim_GetLong(interp, argv[1], &l);
e = Jim_GetLong(interp, argv[1], &l);
if (e != JIM_OK)
return e;
if (e != JIM_OK)
return e;
+ const unsigned int width_bits = l;
+
+ if (width_bits != 8 &&
+ width_bits != 16 &&
+ width_bits != 32 &&
+ width_bits != 64) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp),
+ "Invalid width param. Must be one of: 8, 16, 32 or 64.", NULL);
+ return JIM_ERR;
+ }
+ const unsigned int width = width_bits / 8;
+ /* Arg 2: Memory address */
+ jim_wide wide_addr;
e = Jim_GetWide(interp, argv[2], &wide_addr);
e = Jim_GetWide(interp, argv[2], &wide_addr);
- addr = (target_addr_t)wide_addr;
if (e != JIM_OK)
return e;
if (e != JIM_OK)
return e;
+ target_addr_t addr = (target_addr_t)wide_addr;
+
+ /* Arg 3: Number of elements to read */
e = Jim_GetLong(interp, argv[3], &l);
e = Jim_GetLong(interp, argv[3], &l);
if (e != JIM_OK)
return e;
if (e != JIM_OK)
return e;
+ size_t len = l;
+
+ /* Arg 4: phys */
+ bool is_phys = false;
- phys = Jim_GetString(argv[4], &n);
- if (!strncmp(phys, "phys", n))
+ int str_len = 0;
+ const char *phys = Jim_GetString(argv[4], &str_len);
+ if (!strncmp(phys, "phys", str_len))
is_phys = true;
else
return JIM_ERR;
}
is_phys = true;
else
return JIM_ERR;
}
- switch (width) {
- case 8:
- width = 1;
- break;
- case 16:
- width = 2;
- break;
- case 32:
- width = 4;
- break;
- default:
- Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
- Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL);
- return JIM_ERR;
- }
+
+ /* Argument checks */
if (len == 0) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
if (len == 0) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: zero width read?", NULL);
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
return JIM_ERR;
}
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: addr + len - wraps to zero?", NULL);
return JIM_ERR;
}
- /* absurd transfer size? */
if (len > 65536) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
if (len > 65536) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
- Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: absurd > 64K item request", NULL);
+ Jim_AppendStrings(interp, Jim_GetResult(interp),
+ "mem2array: too large read request, exceeds 64K items", NULL);
return JIM_ERR;
}
if ((width == 1) ||
((width == 2) && ((addr & 1) == 0)) ||
return JIM_ERR;
}
if ((width == 1) ||
((width == 2) && ((addr & 1) == 0)) ||
- ((width == 4) && ((addr & 3) == 0))) {
- /* all is well */
+ ((width == 4) && ((addr & 3) == 0)) ||
+ ((width == 8) && ((addr & 7) == 0))) {
+ /* alignment correct */
} else {
char buf[100];
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
} else {
char buf[100];
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
/* Transfer loop */
/* index counter */
/* Transfer loop */
/* index counter */
- size_t buffersize = 4096;
+ const size_t buffersize = 4096;
uint8_t *buffer = malloc(buffersize);
if (buffer == NULL)
return JIM_ERR;
uint8_t *buffer = malloc(buffersize);
if (buffer == NULL)
return JIM_ERR;
e = JIM_OK;
while (len) {
/* Slurp... in buffer size chunks */
e = JIM_OK;
while (len) {
/* Slurp... in buffer size chunks */
+ const unsigned int max_chunk_len = buffersize / width;
+ const size_t chunk_len = MIN(len, max_chunk_len); /* in elements.. */
- count = len; /* in objects.. */
- if (count > (buffersize / width))
- count = (buffersize / width);
-
- retval = target_read_phys_memory(target, addr, width, count, buffer);
+ retval = target_read_phys_memory(target, addr, width, chunk_len, buffer);
- retval = target_read_memory(target, addr, width, count, buffer);
+ retval = target_read_memory(target, addr, width, chunk_len, buffer);
if (retval != ERROR_OK) {
/* BOO !*/
if (retval != ERROR_OK) {
/* BOO !*/
- LOG_ERROR("mem2array: Read @ " TARGET_ADDR_FMT ", w=%" PRIu32 ", cnt=%" PRIu32 ", failed",
+ LOG_ERROR("mem2array: Read @ " TARGET_ADDR_FMT ", w=%u, cnt=%zu, failed",
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
e = JIM_ERR;
break;
} else {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
e = JIM_ERR;
break;
} else {
- v = 0; /* shut up gcc */
- for (i = 0; i < count ; i++, n++) {
+ for (size_t i = 0; i < chunk_len ; i++, idx++) {
+ uint64_t v = 0;
+ case 8:
+ v = target_buffer_get_u64(target, &buffer[i*width]);
+ break;
case 4:
v = target_buffer_get_u32(target, &buffer[i*width]);
break;
case 4:
v = target_buffer_get_u32(target, &buffer[i*width]);
break;
v = buffer[i] & 0x0ff;
break;
}
v = buffer[i] & 0x0ff;
break;
}
- new_int_array_element(interp, varname, n, v);
+ new_u64_array_element(interp, varname, idx, v);
- len -= count;
- addr += count * width;
+ len -= chunk_len;
+ addr += chunk_len * width;
-static int get_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t *val)
+static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t idx, uint64_t *val)
- char *namebuf;
- Jim_Obj *nameObjPtr, *valObjPtr;
- int result;
- long l;
-
- namebuf = alloc_printf("%s(%d)", varname, idx);
+ char *namebuf = alloc_printf("%s(%zu)", varname, idx);
if (!namebuf)
return JIM_ERR;
if (!namebuf)
return JIM_ERR;
- nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
+ Jim_Obj *nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
if (!nameObjPtr) {
free(namebuf);
return JIM_ERR;
}
Jim_IncrRefCount(nameObjPtr);
if (!nameObjPtr) {
free(namebuf);
return JIM_ERR;
}
Jim_IncrRefCount(nameObjPtr);
- valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
+ Jim_Obj *valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
Jim_DecrRefCount(interp, nameObjPtr);
free(namebuf);
if (valObjPtr == NULL)
return JIM_ERR;
Jim_DecrRefCount(interp, nameObjPtr);
free(namebuf);
if (valObjPtr == NULL)
return JIM_ERR;
- result = Jim_GetLong(interp, valObjPtr, &l);
- /* printf("%s(%d) => 0%08x\n", varname, idx, val); */
- *val = l;
+ jim_wide wide_val;
+ int result = Jim_GetWide(interp, valObjPtr, &wide_val);
+ *val = wide_val;
static int target_array2mem(Jim_Interp *interp, struct target *target,
int argc, Jim_Obj *const *argv)
{
static int target_array2mem(Jim_Interp *interp, struct target *target,
int argc, Jim_Obj *const *argv)
{
- long l;
- jim_wide wide_addr;
- uint32_t width;
- int len;
- target_addr_t addr;
- uint32_t count;
- uint32_t v;
- const char *varname;
- const char *phys;
- bool is_phys;
- int n, e, retval;
- uint32_t i;
- /* argv[1] = name of array to get the data
- * argv[2] = desired width
- * argv[3] = memory address
- * argv[4] = count to write
+ /* argv[0] = name of array from which to read the data
+ * argv[1] = desired element width in bits
+ * argv[2] = memory address
+ * argv[3] = number of elements to write
+ * argv[4] = optional "phys"
*/
if (argc < 4 || argc > 5) {
Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
return JIM_ERR;
}
*/
if (argc < 4 || argc > 5) {
Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
return JIM_ERR;
}
- varname = Jim_GetString(argv[0], &len);
- /* given "foo" get space for worse case "foo(%d)" .. add 20 */
+ /* Arg 0: Name of the array variable */
+ const char *varname = Jim_GetString(argv[0], NULL);
+
+ /* Arg 1: Bit width of one element */
+ long l;
e = Jim_GetLong(interp, argv[1], &l);
e = Jim_GetLong(interp, argv[1], &l);
if (e != JIM_OK)
return e;
if (e != JIM_OK)
return e;
+ const unsigned int width_bits = l;
+
+ if (width_bits != 8 &&
+ width_bits != 16 &&
+ width_bits != 32 &&
+ width_bits != 64) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp),
+ "Invalid width param. Must be one of: 8, 16, 32 or 64.", NULL);
+ return JIM_ERR;
+ }
+ const unsigned int width = width_bits / 8;
+ /* Arg 2: Memory address */
+ jim_wide wide_addr;
e = Jim_GetWide(interp, argv[2], &wide_addr);
e = Jim_GetWide(interp, argv[2], &wide_addr);
- addr = (target_addr_t)wide_addr;
if (e != JIM_OK)
return e;
if (e != JIM_OK)
return e;
+ target_addr_t addr = (target_addr_t)wide_addr;
+
+ /* Arg 3: Number of elements to write */
e = Jim_GetLong(interp, argv[3], &l);
e = Jim_GetLong(interp, argv[3], &l);
if (e != JIM_OK)
return e;
if (e != JIM_OK)
return e;
+ size_t len = l;
+
+ /* Arg 4: Phys */
+ bool is_phys = false;
- phys = Jim_GetString(argv[4], &n);
- if (!strncmp(phys, "phys", n))
+ int str_len = 0;
+ const char *phys = Jim_GetString(argv[4], &str_len);
+ if (!strncmp(phys, "phys", str_len))
is_phys = true;
else
return JIM_ERR;
}
is_phys = true;
else
return JIM_ERR;
}
- switch (width) {
- case 8:
- width = 1;
- break;
- case 16:
- width = 2;
- break;
- case 32:
- width = 4;
- break;
- default:
- Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
- Jim_AppendStrings(interp, Jim_GetResult(interp),
- "Invalid width param, must be 8/16/32", NULL);
- return JIM_ERR;
- }
+
+ /* Argument checks */
if (len == 0) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp),
"array2mem: zero width read?", NULL);
return JIM_ERR;
}
if (len == 0) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp),
"array2mem: zero width read?", NULL);
return JIM_ERR;
}
if ((addr + (len * width)) < addr) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp),
"array2mem: addr + len - wraps to zero?", NULL);
return JIM_ERR;
}
if ((addr + (len * width)) < addr) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp),
"array2mem: addr + len - wraps to zero?", NULL);
return JIM_ERR;
}
- /* absurd transfer size? */
if (len > 65536) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp),
if (len > 65536) {
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp),
- "array2mem: absurd > 64K item request", NULL);
+ "array2mem: too large memory write request, exceeds 64K items", NULL);
return JIM_ERR;
}
if ((width == 1) ||
((width == 2) && ((addr & 1) == 0)) ||
return JIM_ERR;
}
if ((width == 1) ||
((width == 2) && ((addr & 1) == 0)) ||
- ((width == 4) && ((addr & 3) == 0))) {
- /* all is well */
+ ((width == 4) && ((addr & 3) == 0)) ||
+ ((width == 8) && ((addr & 7) == 0))) {
+ /* alignment correct */
} else {
char buf[100];
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
} else {
char buf[100];
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
- /* index counter */
- n = 0;
/* assume ok */
e = JIM_OK;
/* assume ok */
e = JIM_OK;
- size_t buffersize = 4096;
+ const size_t buffersize = 4096;
uint8_t *buffer = malloc(buffersize);
if (buffer == NULL)
return JIM_ERR;
uint8_t *buffer = malloc(buffersize);
if (buffer == NULL)
return JIM_ERR;
+ /* index counter */
+ size_t idx = 0;
+
while (len) {
/* Slurp... in buffer size chunks */
while (len) {
/* Slurp... in buffer size chunks */
+ const unsigned int max_chunk_len = buffersize / width;
- count = len; /* in objects.. */
- if (count > (buffersize / width))
- count = (buffersize / width);
+ const size_t chunk_len = MIN(len, max_chunk_len); /* in elements.. */
- v = 0; /* shut up gcc */
- for (i = 0; i < count; i++, n++) {
- get_int_array_element(interp, varname, n, &v);
+ /* Fill the buffer */
+ for (size_t i = 0; i < chunk_len; i++, idx++) {
+ uint64_t v = 0;
+ if (get_u64_array_element(interp, varname, idx, &v) != JIM_OK) {
+ free(buffer);
+ return JIM_ERR;
+ }
+ case 8:
+ target_buffer_set_u64(target, &buffer[i * width], v);
+ break;
case 4:
target_buffer_set_u32(target, &buffer[i * width], v);
break;
case 4:
target_buffer_set_u32(target, &buffer[i * width], v);
break;
+ /* Write the buffer to memory */
+ int retval;
- retval = target_write_phys_memory(target, addr, width, count, buffer);
+ retval = target_write_phys_memory(target, addr, width, chunk_len, buffer);
- retval = target_write_memory(target, addr, width, count, buffer);
+ retval = target_write_memory(target, addr, width, chunk_len, buffer);
if (retval != ERROR_OK) {
/* BOO !*/
if (retval != ERROR_OK) {
/* BOO !*/
- LOG_ERROR("array2mem: Write @ " TARGET_ADDR_FMT ", w=%" PRIu32 ", cnt=%" PRIu32 ", failed",
+ LOG_ERROR("array2mem: Write @ " TARGET_ADDR_FMT ", w=%u, cnt=%zu, failed",
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL);
e = JIM_ERR;
break;
}
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL);
e = JIM_ERR;
break;
}
+ addr += chunk_len * width;