From e78b33e3ca2fe05e82f974fcd6e745dbcfa6ca37 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 10 May 2017 14:31:18 +0000 Subject: [PATCH 001/127] telnet_server: drop unused options They're never used, so just drop them. Change-Id: Ie137deed3e7258f9d6af7e0cb508e73df0f53ee0 Signed-off-by: Karl Palsson Reviewed-on: http://openocd.zylin.com/4131 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/server/telnet_server.c | 1 - src/server/telnet_server.h | 3 --- src/target/openrisc/jsp_server.c | 1 - 3 files changed, 5 deletions(-) diff --git a/src/server/telnet_server.c b/src/server/telnet_server.c index e33188b5e..7507afea8 100644 --- a/src/server/telnet_server.c +++ b/src/server/telnet_server.c @@ -222,7 +222,6 @@ static int telnet_new_connection(struct connection *connection) telnet_connection->closed = 0; telnet_connection->line_size = 0; telnet_connection->line_cursor = 0; - telnet_connection->option_size = 0; telnet_connection->prompt = strdup("> "); telnet_connection->state = TELNET_STATE_DATA; diff --git a/src/server/telnet_server.h b/src/server/telnet_server.h index 04ba96570..e43d6bcf8 100644 --- a/src/server/telnet_server.h +++ b/src/server/telnet_server.h @@ -29,7 +29,6 @@ #define TELNET_BUFFER_SIZE (1024) -#define TELNET_OPTION_MAX_SIZE (128) #define TELNET_LINE_HISTORY_SIZE (128) #define TELNET_LINE_MAX_SIZE (256) @@ -51,8 +50,6 @@ struct telnet_connection { char line[TELNET_LINE_MAX_SIZE]; int line_size; int line_cursor; - char option[TELNET_OPTION_MAX_SIZE]; - int option_size; char last_escape; char *history[TELNET_LINE_HISTORY_SIZE]; int next_history; diff --git a/src/target/openrisc/jsp_server.c b/src/target/openrisc/jsp_server.c index e581fb870..2d90114fa 100644 --- a/src/target/openrisc/jsp_server.c +++ b/src/target/openrisc/jsp_server.c @@ -88,7 +88,6 @@ static int jsp_new_connection(struct connection *connection) telnet_connection->closed = 0; telnet_connection->line_size = 0; telnet_connection->line_cursor = 0; - telnet_connection->option_size = 0; telnet_connection->state = TELNET_STATE_DATA; /* negotiate telnet options */ From bf5258d8761c93e4101aa933b90344d854868ff1 Mon Sep 17 00:00:00 2001 From: Karl Palsson Date: Wed, 10 May 2017 14:37:51 +0000 Subject: [PATCH 002/127] telnet_server: increase buffer sizes to allow longer commands. A common use case seen in the wild is echoing a string of commands to an existing openocd instance via netcat. The sequence of ; separated commands can easily run over the line limit of only 256 chars. Increasing this dramatically reduces surprises, at the expense of a tiny amount of extra ram usage. Change-Id: I2389d99d316a96b5fa03f0894b43c412308e12c4 Signed-off-by: Karl Palsson Reviewed-on: http://openocd.zylin.com/4132 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/server/telnet_server.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server/telnet_server.h b/src/server/telnet_server.h index e43d6bcf8..f8fb82689 100644 --- a/src/server/telnet_server.h +++ b/src/server/telnet_server.h @@ -27,10 +27,10 @@ #include -#define TELNET_BUFFER_SIZE (1024) +#define TELNET_BUFFER_SIZE (10*1024) #define TELNET_LINE_HISTORY_SIZE (128) -#define TELNET_LINE_MAX_SIZE (256) +#define TELNET_LINE_MAX_SIZE (10*256) enum telnet_states { TELNET_STATE_DATA, From 83772f32ad0f46d9c21485178c112cc832449a3c Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Sun, 11 Jun 2017 16:18:27 +0300 Subject: [PATCH 003/127] configure: bring back all default JimTcl extensions This partially reverts commit 56d163ce79510c7756567df00ae54155757eaa0f. That change certainly caused more pain than gain. Change-Id: Ifb126abd1e6b89d29db8bf6a7b8af5dfc815c163 Signed-off-by: Paul Fertser Reviewed-on: http://openocd.zylin.com/4159 Tested-by: jenkins Reviewed-by: Karl Palsson Reviewed-by: Spencer Oliver --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index c680bda7a..56109b103 100644 --- a/configure.ac +++ b/configure.ac @@ -571,7 +571,7 @@ AS_IF([test "x$build_buspirate" = "xyes"], [ AS_IF([test "x$use_internal_jimtcl" = "xyes"], [ AS_IF([test -f "$srcdir/jimtcl/configure.ac"], [ - AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim --with-ext="eventloop array clock regexp stdlib tclcompat" --without-ext="default"]) + AX_CONFIG_SUBDIR_OPTION([jimtcl], [--disable-install-jim]) ], [ AC_MSG_ERROR([jimtcl not found, run git submodule init and git submodule update.]) ]) From 1ab0303dbc6d00f8fd0036170dd7a10b32fc8713 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Mon, 21 Aug 2017 20:56:43 +0200 Subject: [PATCH 004/127] helper/options: Add missing #include for MinGW and MSYS2 Change-Id: I3bb295f52706b641661241e3e047306811ca915e Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4201 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/helper/options.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/helper/options.c b/src/helper/options.c index 1cfa55376..12755e010 100644 --- a/src/helper/options.c +++ b/src/helper/options.c @@ -37,6 +37,9 @@ #ifdef HAVE_SYS_SYSCTL_H #include #endif +#if IS_WIN32 && !IS_CYGWIN +#include +#endif static int help_flag, version_flag; From 4dc09d98d0cab5feb189667b189832d5ce519cba Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Fri, 28 Jul 2017 17:34:07 +0200 Subject: [PATCH 005/127] libjaylink: Update to latest Git version Update to latest Git version and bump required libjaylink package version to 0.2.0. This version introduces support for devices with TCP/IP interface (e.g. SEGGER Flasher ARM) and an additional debug level for I/O messages. Change-Id: I030236aa704a91d1bb1843dd30010865947747e0 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4202 Tested-by: jenkins Reviewed-by: Spencer Oliver --- configure.ac | 2 +- src/jtag/drivers/libjaylink | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index 56109b103..fd06a0b3f 100644 --- a/configure.ac +++ b/configure.ac @@ -628,7 +628,7 @@ PKG_CHECK_MODULES([LIBFTDI], [libftdi1], [use_libftdi=yes], [ PKG_CHECK_MODULES([LIBFTDI], [libftdi], [use_libftdi=yes], [use_libftdi=no]) ]) -PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.1], +PKG_CHECK_MODULES([LIBJAYLINK], [libjaylink >= 0.2], [use_libjaylink=yes], [use_libjaylink=no]) m4_define([PROCESS_ADAPTERS], [ diff --git a/src/jtag/drivers/libjaylink b/src/jtag/drivers/libjaylink index 699b7001d..8645845c1 160000 --- a/src/jtag/drivers/libjaylink +++ b/src/jtag/drivers/libjaylink @@ -1 +1 @@ -Subproject commit 699b7001d34a79c8e7064503dde1bede786fd7f0 +Subproject commit 8645845c1abebd004e991ba9a7f808f4fd0c608b From ba24c1fc05c8bb244abab513b880c7e9ec50ea73 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Wed, 26 Jul 2017 23:51:22 +0200 Subject: [PATCH 006/127] jlink: Make use of debug level for I/O messages Change-Id: Iba08c119a80041f9c1b4c9bd7e83bb4f9bbb7199 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4203 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/drivers/jlink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index bd3c5e03c..c05141a1e 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -523,6 +523,9 @@ static int jaylink_log_handler(const struct jaylink_context *ctx, case JAYLINK_LOG_LEVEL_DEBUG: tmp = LOG_LVL_DEBUG; break; + case JAYLINK_LOG_LEVEL_DEBUG_IO: + tmp = LOG_LVL_DEBUG_IO; + break; default: tmp = LOG_LVL_WARNING; } From 7d8d2654e6168a56a8e5e53aa4a8b64a66576c55 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 20 May 2017 14:34:21 +0200 Subject: [PATCH 007/127] jlink: Make libusb optional libusb is now optional for libjaylink because support for TCP/IP devices is always available. Change-Id: I03f2566f8e1703276671ac0f353f72394d21f2f0 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4204 Tested-by: jenkins Reviewed-by: Spencer Oliver --- configure.ac | 2 +- src/jtag/drivers/jlink.c | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index fd06a0b3f..562ec5a7c 100644 --- a/configure.ac +++ b/configure.ac @@ -655,7 +655,7 @@ PROCESS_ADAPTERS([USB0_ADAPTERS], ["x$use_libusb0" = "xyes"], [libusb-0.1]) PROCESS_ADAPTERS([HIDAPI_ADAPTERS], ["x$use_hidapi" = "xyes"], [hidapi]) PROCESS_ADAPTERS([HIDAPI_USB1_ADAPTERS], ["x$use_hidapi" = "xyes" -a "x$use_libusb1" = "xyes"], [hidapi and libusb-1.x]) PROCESS_ADAPTERS([LIBFTDI_ADAPTERS], ["x$use_libftdi" = "xyes"], [libftdi]) -PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_libusb1" = "xyes" -a "x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libusb-1.x or libjaylink-0.1]) +PROCESS_ADAPTERS([LIBJAYLINK_ADAPTERS], ["x$use_internal_libjaylink" = "xyes" -o "x$use_libjaylink" = "xyes"], [libjaylink-0.1]) AS_IF([test "x$build_openjtag" = "xyes"], [ AS_IF([test "x$use_libusb1" != "xyes" -a "x$use_libusb0" != "xyes"], [ diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index c05141a1e..893d43ec4 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -551,6 +551,11 @@ static int jlink_init(void) LOG_DEBUG("Using libjaylink %s (compiled with %s).", jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); + if (!jaylink_library_has_cap(JAYLINK_CAP_HIF_USB) && use_usb_address) { + LOG_ERROR("J-Link driver does not support USB devices."); + return ERROR_JTAG_INIT_FAILED; + } + ret = jaylink_init(&jayctx); if (ret != JAYLINK_OK) { @@ -610,7 +615,9 @@ static int jlink_init(void) if (use_usb_address) { ret = jaylink_device_get_usb_address(devs[i], &address); - if (ret != JAYLINK_OK) { + if (ret == JAYLINK_ERR_NOT_SUPPORTED) { + continue; + } else if (ret != JAYLINK_OK) { LOG_WARNING("jaylink_device_get_usb_address() failed: %s.", jaylink_strerror_name(ret)); continue; From f981730fe76c1b8341f84f2ab004bedc0082f99e Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 2 Sep 2017 09:50:44 +0200 Subject: [PATCH 008/127] jlink: Use error description in log messages Use a human-readable error description rather than just the error name in log messages. Change-Id: Iab4ff7a7e4d9993983a07eab9f462820d4ee8190 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4212 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/drivers/jlink.c | 77 ++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 42 deletions(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 893d43ec4..955adf8aa 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -322,7 +322,7 @@ static int jlink_speed(int speed) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_speeds() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_JTAG_DEVICE_ERROR; } @@ -349,7 +349,7 @@ static int jlink_speed(int speed) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_set_speed() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_JTAG_DEVICE_ERROR; } @@ -378,7 +378,7 @@ static bool read_device_config(struct device_config *cfg) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_read_raw_config() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return false; } @@ -409,7 +409,7 @@ static int select_interface(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_available_interfaces() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } @@ -422,7 +422,7 @@ static int select_interface(void) if (ret < 0) { LOG_ERROR("jaylink_select_interface() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } @@ -442,8 +442,7 @@ static int jlink_register(void) ret = jaylink_register(devh, &conn, connlist, &count); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_register() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_register() failed: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -482,7 +481,7 @@ static bool adjust_swd_buffer_size(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_free_memory() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return false; } @@ -559,8 +558,7 @@ static int jlink_init(void) ret = jaylink_init(&jayctx); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_init() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_init() failed: %s.", jaylink_strerror(ret)); return ERROR_JTAG_INIT_FAILED; } @@ -568,7 +566,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_log_set_callback() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } @@ -577,7 +575,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_discovery_scan() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } @@ -585,8 +583,7 @@ static int jlink_init(void) ret = jaylink_get_devices(jayctx, &devs, NULL); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_devices() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_get_devices() failed: %s.", jaylink_strerror(ret)); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; } @@ -604,7 +601,7 @@ static int jlink_init(void) continue; } else if (ret != JAYLINK_OK) { LOG_WARNING("jaylink_device_get_serial_number() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); continue; } @@ -619,7 +616,7 @@ static int jlink_init(void) continue; } else if (ret != JAYLINK_OK) { LOG_WARNING("jaylink_device_get_usb_address() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); continue; } @@ -634,7 +631,7 @@ static int jlink_init(void) break; } - LOG_ERROR("Failed to open device: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("Failed to open device: %s.", jaylink_strerror(ret)); } jaylink_free_devices(devs, true); @@ -654,7 +651,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_firmware_version() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -669,7 +666,7 @@ static int jlink_init(void) ret = jaylink_get_caps(devh, caps); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_get_caps() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_get_caps() failed: %s.", jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -680,7 +677,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_extended_caps() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -694,7 +691,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("Failed to retrieve hardware version: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -735,7 +732,7 @@ static int jlink_init(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_hardware_status() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); jaylink_close(devh); jaylink_exit(jayctx); return ERROR_JTAG_INIT_FAILED; @@ -796,8 +793,7 @@ static int jlink_quit(void) ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) - LOG_ERROR("jaylink_swo_stop() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret)); } if (jaylink_has_cap(caps, JAYLINK_DEV_CAP_REGISTER)) { @@ -805,7 +801,7 @@ static int jlink_quit(void) if (ret != JAYLINK_OK) LOG_ERROR("jaylink_unregister() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); } jaylink_close(devh); @@ -954,7 +950,7 @@ COMMAND_HANDLER(jlink_serial_command) return ERROR_FAIL; } else if (ret != JAYLINK_OK) { command_print(CMD_CTX, "jaylink_parse_serial_number() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -973,7 +969,7 @@ COMMAND_HANDLER(jlink_handle_hwstatus_command) if (ret != JAYLINK_OK) { command_print(CMD_CTX, "jaylink_get_hardware_status() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1005,7 +1001,7 @@ COMMAND_HANDLER(jlink_handle_free_memory_command) if (ret != JAYLINK_OK) { command_print(CMD_CTX, "jaylink_get_free_memory() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1087,7 +1083,7 @@ COMMAND_HANDLER(jlink_handle_target_power_command) if (ret != JAYLINK_OK) { command_print(CMD_CTX, "jaylink_set_target_power() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1193,7 +1189,7 @@ static int poll_trace(uint8_t *buf, size_t *size) ret = jaylink_swo_read(devh, buf, &length); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swo_read() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_swo_read() failed: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1214,7 +1210,7 @@ static uint32_t calculate_trace_buffer_size(void) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_free_memory() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1278,7 +1274,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, ret = jaylink_swo_stop(devh); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_swo_stop() failed: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1304,7 +1300,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_swo_get_speeds() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1320,8 +1316,7 @@ static int config_trace(bool enabled, enum tpio_pin_protocol pin_protocol, buffer_size); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_start_swo() failed: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_start_swo() failed: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1580,7 +1575,7 @@ COMMAND_HANDLER(jlink_handle_config_write_command) if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_write_raw_config() failed: %s.", - jaylink_strerror_name(ret)); + jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1665,8 +1660,7 @@ COMMAND_HANDLER(jlink_handle_emucom_write_command) LOG_ERROR("Channel not supported by the device."); return ERROR_FAIL; } else if (ret != JAYLINK_OK) { - LOG_ERROR("Failed to write to channel: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("Failed to write to channel: %s.", jaylink_strerror(ret)); return ERROR_FAIL; } @@ -1714,8 +1708,7 @@ COMMAND_HANDLER(jlink_handle_emucom_read_command) free(buf); return ERROR_FAIL; } else if (ret != JAYLINK_OK) { - LOG_ERROR("Failed to read from channel: %s.", - jaylink_strerror_name(ret)); + LOG_ERROR("Failed to read from channel: %s.", jaylink_strerror(ret)); free(buf); return ERROR_FAIL; } @@ -1982,7 +1975,7 @@ static int jlink_flush(void) tap_length, jtag_command_version); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_jtag_io() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_jtag_io() failed: %s.", jaylink_strerror(ret)); jlink_tap_init(); return ERROR_JTAG_QUEUE_FAILED; } @@ -2088,7 +2081,7 @@ static int jlink_swd_run_queue(void) ret = jaylink_swd_io(devh, tms_buffer, tdi_buffer, tdo_buffer, tap_length); if (ret != JAYLINK_OK) { - LOG_ERROR("jaylink_swd_io() failed: %s.", jaylink_strerror_name(ret)); + LOG_ERROR("jaylink_swd_io() failed: %s.", jaylink_strerror(ret)); goto skip; } From 98e63cdc86243cf91fc0da56479acef240313d19 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 2 Sep 2017 10:10:00 +0200 Subject: [PATCH 009/127] jlink: Disable automatic device selection If multiple devices are attached, do not automatically use the first device found. Otherwise, a user may unintentionally operate on the wrong device. Change-Id: I08c4110b82e911e9e3e744d41830ffc6c56c44bf Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4213 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/drivers/jlink.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index 955adf8aa..ac6e997ef 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -546,6 +546,7 @@ static int jlink_init(void) struct jaylink_hardware_status hwstatus; enum jaylink_usb_address address; size_t length; + size_t num_devices; LOG_DEBUG("Using libjaylink %s (compiled with %s).", jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); @@ -580,7 +581,7 @@ static int jlink_init(void) return ERROR_JTAG_INIT_FAILED; } - ret = jaylink_get_devices(jayctx, &devs, NULL); + ret = jaylink_get_devices(jayctx, &devs, &num_devices); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_get_devices() failed: %s.", jaylink_strerror(ret)); @@ -588,10 +589,14 @@ static int jlink_init(void) return ERROR_JTAG_INIT_FAILED; } - found_device = false; + if (!use_serial_number && !use_usb_address && num_devices > 1) { + LOG_ERROR("Multiple devices found, specify the desired device."); + jaylink_free_devices(devs, true); + jaylink_exit(jayctx); + return ERROR_JTAG_INIT_FAILED; + } - if (!use_serial_number && !use_usb_address) - LOG_INFO("No device selected, using first device."); + found_device = false; for (i = 0; devs[i]; i++) { if (use_serial_number) { From b0dcff5e345cf255d0ccdc5b473dff408af4b5ed Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sat, 2 Sep 2017 10:16:41 +0200 Subject: [PATCH 010/127] jlink: Disable TCP/IP discovery If no serial number is specified, disable TCP/IP device discovery to ensure that a user does not unintentionally operate on a remote device. Change-Id: I6a7e913b8b679fae003825468cd86d2014849b29 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4214 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/jtag/drivers/jlink.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/jtag/drivers/jlink.c b/src/jtag/drivers/jlink.c index ac6e997ef..132ef06e9 100644 --- a/src/jtag/drivers/jlink.c +++ b/src/jtag/drivers/jlink.c @@ -547,6 +547,7 @@ static int jlink_init(void) enum jaylink_usb_address address; size_t length; size_t num_devices; + uint32_t host_interfaces; LOG_DEBUG("Using libjaylink %s (compiled with %s).", jaylink_version_package_get_string(), JAYLINK_VERSION_PACKAGE_STRING); @@ -572,7 +573,12 @@ static int jlink_init(void) return ERROR_JTAG_INIT_FAILED; } - ret = jaylink_discovery_scan(jayctx, 0); + host_interfaces = JAYLINK_HIF_USB; + + if (use_serial_number) + host_interfaces |= JAYLINK_HIF_TCP; + + ret = jaylink_discovery_scan(jayctx, host_interfaces); if (ret != JAYLINK_OK) { LOG_ERROR("jaylink_discovery_scan() failed: %s.", From 18a94a1a8a37c38fda98aceae39e652f9df9bdd9 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 9 Jun 2016 09:23:10 -0700 Subject: [PATCH 011/127] Fix typo in comment. Change-Id: I6567f85f399315e1dac98881765dfaa6eab5facb Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4238 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/helper/log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helper/log.c b/src/helper/log.c index 49b9bd98f..c8a3a6c55 100644 --- a/src/helper/log.c +++ b/src/helper/log.c @@ -104,7 +104,7 @@ static void log_forward(const char *file, unsigned line, const char *function, c } } -/* The log_puts() serves to somewhat different goals: +/* The log_puts() serves two somewhat different goals: * * - logging * - feeding low-level info to the user in GDB or Telnet From 5fd8eaadf919f867b95682373d8e60da417f4556 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 24 Aug 2017 17:42:28 +0200 Subject: [PATCH 012/127] stm32f2x: Fix left shift of negative value MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use unsigned constant for left shift operation in order to avoid the following error with GCC >= 6.0: ../src/flash/nor/stm32f2x.c: In function ‘stm32x_handle_unlock_command’: ../src/flash/nor/stm32f2x.c:1324:67: error: left shift of negative value [-Werror=shift-negative-value] stm32x_info->option_bytes.optcr2_pcrop = OPTCR2_PCROP_RDP | (~1 << bank->num_sectors); Change-Id: I0ac082bd0dbb8dc2f61ffff8fdf486ab7962d2e0 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4207 Tested-by: jenkins Reviewed-by: Andreas Bolsch Reviewed-by: Spencer Oliver Reviewed-by: Anton Fosselius Reviewed-by: Esben Haabendal --- src/flash/nor/stm32f2x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 0e4abb533..65cb212b6 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -1321,7 +1321,7 @@ COMMAND_HANDLER(stm32x_handle_unlock_command) * this will also force a device unlock if set */ stm32x_info->option_bytes.RDP = 0xAA; if (stm32x_info->has_optcr2_pcrop) { - stm32x_info->option_bytes.optcr2_pcrop = OPTCR2_PCROP_RDP | (~1 << bank->num_sectors); + stm32x_info->option_bytes.optcr2_pcrop = OPTCR2_PCROP_RDP | (~1U << bank->num_sectors); } if (stm32x_write_options(bank) != ERROR_OK) { From e8b6aaa8e59208aea6cead31760895d67c1226ee Mon Sep 17 00:00:00 2001 From: Fabio Utzig Date: Fri, 11 Aug 2017 13:17:03 -0300 Subject: [PATCH 013/127] Add missing break MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: Ie1de679fe6ab5ace05fc3e156c71f34b296b3d3b Signed-off-by: Fabio Utzig Reviewed-on: http://openocd.zylin.com/4200 Tested-by: jenkins Reviewed-by: Andreas Färber Reviewed-by: Spencer Oliver Reviewed-by: Esben Haabendal --- src/target/armv7a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/armv7a.c b/src/target/armv7a.c index 6021def4e..db72afd21 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -355,7 +355,7 @@ int armv7a_mmu_translate_va_pa(struct target *target, uint32_t va, break; case 7: LOG_INFO("inner: Write-Back, no Write-Allocate"); - + break; default: LOG_INFO("inner: %" PRIx32 " ???", INNER); } From f95f8b70fbd0f7e9c91a2d9006b1abb2dd07ebf2 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Sun, 27 Aug 2017 19:12:21 +0100 Subject: [PATCH 014/127] tcl/interface/ftdi/sheevaplug: Fix FTDI channel configuration The migration from the old ft2232 driver to the new generic ftdi driver ended up breaking support for the SheevaPlug device. The old driver defaulted to channel 1, but numbered the channels 1 to 4. The new driver starts at 0. The SheevaPlug JTAG is on interface A (interface B is the serial console), so it should be using channel 0. Fix this. Confirmed as working; serial console remains available and a new u-boot image can be transferred across using the JTAG link. See also Debian Bug#837989; https://bugs.debian.org/837989 Change-Id: I4ac2bfeb0d1e7e99d70fa47dc55f186e6af2c542 Signed-off-by: Jonathan McDowell Reviewed-on: http://openocd.zylin.com/4206 Reviewed-by: Paul Fertser Tested-by: jenkins --- tcl/interface/ftdi/sheevaplug.cfg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tcl/interface/ftdi/sheevaplug.cfg b/tcl/interface/ftdi/sheevaplug.cfg index f299f27a9..625aad398 100644 --- a/tcl/interface/ftdi/sheevaplug.cfg +++ b/tcl/interface/ftdi/sheevaplug.cfg @@ -7,7 +7,7 @@ interface ftdi ftdi_device_desc "SheevaPlug JTAGKey FT2232D B" ftdi_vid_pid 0x9e88 0x9e8f -ftdi_channel 1 +ftdi_channel 0 ftdi_layout_init 0x0608 0x0f1b ftdi_layout_signal nTRST -data 0x0200 From 10a3b24daf379162caf84fe757f849d7ba48c379 Mon Sep 17 00:00:00 2001 From: Andrea Merello Date: Wed, 1 Mar 2017 11:32:07 +0100 Subject: [PATCH 015/127] flash: efm32: add support for EFR-familty (e.g. bluegecko) This patch adds support for Blue Gecko and Mighty Gecko chips from Silabs. They have different EFM32_MSC_REGBASE and LOCK register offset. Based on the original patch from Andreas Kemnade. Change-Id: I166c14960ced7c880b68083badd1b31372fefabe Cc: Andreas Kemnade Signed-off-by: Andrea Merello Reviewed-on: http://openocd.zylin.com/4034 Reviewed-by: Jonas Norling Tested-by: jenkins Reviewed-by: Fredrik Hederstierna Reviewed-by: Spencer Oliver Reviewed-by: chrysn --- contrib/loaders/flash/efm32.S | 4 -- src/flash/nor/efm32.c | 99 +++++++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 32 deletions(-) diff --git a/contrib/loaders/flash/efm32.S b/contrib/loaders/flash/efm32.S index 25d63010a..c5de55c27 100644 --- a/contrib/loaders/flash/efm32.S +++ b/contrib/loaders/flash/efm32.S @@ -44,11 +44,7 @@ #define EFM32_MSC_ADDRB_OFFSET 0x010 #define EFM32_MSC_WDATA_OFFSET 0x018 #define EFM32_MSC_STATUS_OFFSET 0x01c -#define EFM32_MSC_LOCK_OFFSET 0x03c - /* unlock MSC */ - ldr r6, =#0x1b71 - str r6, [r0, #EFM32_MSC_LOCK_OFFSET] /* set WREN to 1 */ movs r6, #1 str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] diff --git a/src/flash/nor/efm32.c b/src/flash/nor/efm32.c index 117cd8a1b..b8453e1dd 100644 --- a/src/flash/nor/efm32.c +++ b/src/flash/nor/efm32.c @@ -49,6 +49,8 @@ #define EZR_FAMILY_ID_WONDER_GECKO 120 #define EZR_FAMILY_ID_LEOPARD_GECKO 121 #define EZR_FAMILY_ID_HAPPY_GECKO 122 +#define EFR_FAMILY_ID_MIGHTY_GECKO 16 +#define EFR_FAMILY_ID_BLUE_GECKO 20 #define EFM32_FLASH_ERASE_TMO 100 #define EFM32_FLASH_WDATAREADY_TMO 100 @@ -72,27 +74,31 @@ #define EFM32_MSC_DI_PROD_REV (EFM32_MSC_DEV_INFO+0x1ff) #define EFM32_MSC_REGBASE 0x400c0000 -#define EFM32_MSC_WRITECTRL (EFM32_MSC_REGBASE+0x008) +#define EFR32_MSC_REGBASE 0x400e0000 +#define EFM32_MSC_REG_WRITECTRL 0x008 #define EFM32_MSC_WRITECTRL_WREN_MASK 0x1 -#define EFM32_MSC_WRITECMD (EFM32_MSC_REGBASE+0x00c) +#define EFM32_MSC_REG_WRITECMD 0x00c #define EFM32_MSC_WRITECMD_LADDRIM_MASK 0x1 #define EFM32_MSC_WRITECMD_ERASEPAGE_MASK 0x2 #define EFM32_MSC_WRITECMD_WRITEONCE_MASK 0x8 -#define EFM32_MSC_ADDRB (EFM32_MSC_REGBASE+0x010) -#define EFM32_MSC_WDATA (EFM32_MSC_REGBASE+0x018) -#define EFM32_MSC_STATUS (EFM32_MSC_REGBASE+0x01c) +#define EFM32_MSC_REG_ADDRB 0x010 +#define EFM32_MSC_REG_WDATA 0x018 +#define EFM32_MSC_REG_STATUS 0x01c #define EFM32_MSC_STATUS_BUSY_MASK 0x1 #define EFM32_MSC_STATUS_LOCKED_MASK 0x2 #define EFM32_MSC_STATUS_INVADDR_MASK 0x4 #define EFM32_MSC_STATUS_WDATAREADY_MASK 0x8 #define EFM32_MSC_STATUS_WORDTIMEOUT_MASK 0x10 #define EFM32_MSC_STATUS_ERASEABORTED_MASK 0x20 -#define EFM32_MSC_LOCK (EFM32_MSC_REGBASE+0x03c) +#define EFM32_MSC_REG_LOCK 0x03c +#define EFR32_MSC_REG_LOCK 0x040 #define EFM32_MSC_LOCK_LOCKKEY 0x1b71 struct efm32x_flash_bank { int probed; uint32_t lb_page[LOCKBITS_PAGE_SZ/4]; + uint32_t reg_base; + uint32_t reg_lock; }; struct efm32_info { @@ -132,11 +138,30 @@ static int efm32x_get_prod_rev(struct flash_bank *bank, uint8_t *prev) return target_read_u8(bank->target, EFM32_MSC_DI_PROD_REV, prev); } +static int efm32x_read_reg_u32(struct flash_bank *bank, target_addr_t offset, + uint32_t *value) +{ + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + uint32_t base = efm32x_info->reg_base; + + return target_read_u32(bank->target, base + offset, value); +} + +static int efm32x_write_reg_u32(struct flash_bank *bank, target_addr_t offset, + uint32_t value) +{ + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + uint32_t base = efm32x_info->reg_base; + + return target_write_u32(bank->target, base + offset, value); +} + static int efm32x_read_info(struct flash_bank *bank, struct efm32_info *efm32_info) { int ret; uint32_t cpuid = 0; + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; memset(efm32_info, 0, sizeof(struct efm32_info)); @@ -175,6 +200,15 @@ static int efm32x_read_info(struct flash_bank *bank, if (ERROR_OK != ret) return ret; + if (EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || + EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { + efm32x_info->reg_base = EFR32_MSC_REGBASE; + efm32x_info->reg_lock = EFR32_MSC_REG_LOCK; + } else { + efm32x_info->reg_base = EFM32_MSC_REGBASE; + efm32x_info->reg_lock = EFM32_MSC_REG_LOCK; + } + if (EFM_FAMILY_ID_GECKO == efm32_info->part_family || EFM_FAMILY_ID_TINY_GECKO == efm32_info->part_family) efm32_info->page_size = 512; @@ -208,7 +242,9 @@ static int efm32x_read_info(struct flash_bank *bank, } } else if (EFM_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || EZR_FAMILY_ID_WONDER_GECKO == efm32_info->part_family || - EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family) { + EZR_FAMILY_ID_LEOPARD_GECKO == efm32_info->part_family || + EFR_FAMILY_ID_BLUE_GECKO == efm32_info->part_family || + EFR_FAMILY_ID_MIGHTY_GECKO == efm32_info->part_family) { uint8_t pg_size = 0; ret = target_read_u8(bank->target, EFM32_MSC_DI_PAGE_SIZE, &pg_size); @@ -241,6 +277,10 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) case EZR_FAMILY_ID_HAPPY_GECKO: printed = snprintf(buf, buf_size, "EZR32 "); break; + case EFR_FAMILY_ID_MIGHTY_GECKO: + case EFR_FAMILY_ID_BLUE_GECKO: + printed = snprintf(buf, buf_size, "EFR32 "); + break; default: printed = snprintf(buf, buf_size, "EFM32 "); } @@ -276,6 +316,12 @@ static int efm32x_decode_info(struct efm32_info *info, char *buf, int buf_size) case EZR_FAMILY_ID_HAPPY_GECKO: printed = snprintf(buf, buf_size, "Happy Gecko"); break; + case EFR_FAMILY_ID_BLUE_GECKO: + printed = snprintf(buf, buf_size, "Blue Gecko"); + break; + case EFR_FAMILY_ID_MIGHTY_GECKO: + printed = snprintf(buf, buf_size, "Mighty Gecko"); + break; } buf += printed; @@ -319,7 +365,7 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, int ret = 0; uint32_t reg_val = 0; - ret = target_read_u32(bank->target, reg, ®_val); + ret = efm32x_read_reg_u32(bank, reg, ®_val); if (ERROR_OK != ret) return ret; @@ -328,18 +374,19 @@ static int efm32x_set_reg_bits(struct flash_bank *bank, uint32_t reg, else reg_val &= ~bitmask; - return target_write_u32(bank->target, reg, reg_val); + return efm32x_write_reg_u32(bank, reg, reg_val); } static int efm32x_set_wren(struct flash_bank *bank, int write_enable) { - return efm32x_set_reg_bits(bank, EFM32_MSC_WRITECTRL, + return efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECTRL, EFM32_MSC_WRITECTRL_WREN_MASK, write_enable); } static int efm32x_msc_lock(struct flash_bank *bank, int lock) { - return target_write_u32(bank->target, EFM32_MSC_LOCK, + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; + return efm32x_write_reg_u32(bank, efm32x_info->reg_lock, (lock ? 0 : EFM32_MSC_LOCK_LOCKKEY)); } @@ -350,7 +397,7 @@ static int efm32x_wait_status(struct flash_bank *bank, int timeout, uint32_t status = 0; while (1) { - ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); + ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ERROR_OK != ret) break; @@ -389,16 +436,16 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) LOG_DEBUG("erasing flash page at 0x%08" PRIx32, addr); - ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr); + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); if (ERROR_OK != ret) return ret; - ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, + ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ERROR_OK != ret) return ret; - ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); + ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ERROR_OK != ret) return ret; @@ -412,7 +459,7 @@ static int efm32x_erase_page(struct flash_bank *bank, uint32_t addr) return ERROR_FAIL; } - ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, + ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_ERASEPAGE_MASK, 1); if (ERROR_OK != ret) return ret; @@ -589,6 +636,7 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, uint32_t address = bank->base + offset; struct reg_param reg_params[5]; struct armv7m_algorithm armv7m_info; + struct efm32x_flash_bank *efm32x_info = bank->driver_priv; int ret = ERROR_OK; /* see contrib/loaders/flash/efm32.S for src */ @@ -598,10 +646,7 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, /* #define EFM32_MSC_ADDRB_OFFSET 0x010 */ /* #define EFM32_MSC_WDATA_OFFSET 0x018 */ /* #define EFM32_MSC_STATUS_OFFSET 0x01c */ - /* #define EFM32_MSC_LOCK_OFFSET 0x03c */ - 0x15, 0x4e, /* ldr r6, =#0x1b71 */ - 0xc6, 0x63, /* str r6, [r0, #EFM32_MSC_LOCK_OFFSET] */ 0x01, 0x26, /* movs r6, #1 */ 0x86, 0x60, /* str r6, [r0, #EFM32_MSC_WRITECTRL_OFFSET] */ @@ -660,11 +705,9 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, /* exit: */ 0x30, 0x46, /* mov r0, r6 */ 0x00, 0xbe, /* bkpt #0 */ - - /* LOCKKEY */ - 0x71, 0x1b, 0x00, 0x00 }; + /* flash write code */ if (target_alloc_working_area(target, sizeof(efm32x_flash_write_code), &write_algorithm) != ERROR_OK) { @@ -697,7 +740,7 @@ static int efm32x_write_block(struct flash_bank *bank, const uint8_t *buf, init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[4], "r4", 32, PARAM_IN_OUT); /* target address */ - buf_set_u32(reg_params[0].value, 0, 32, EFM32_MSC_REGBASE); + buf_set_u32(reg_params[0].value, 0, 32, efm32x_info->reg_base); buf_set_u32(reg_params[1].value, 0, 32, count); buf_set_u32(reg_params[2].value, 0, 32, source->address); buf_set_u32(reg_params[3].value, 0, 32, source->address + source->size); @@ -762,16 +805,16 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, /* if not called, GDB errors will be reported during large writes */ keep_alive(); - ret = target_write_u32(bank->target, EFM32_MSC_ADDRB, addr); + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_ADDRB, addr); if (ERROR_OK != ret) return ret; - ret = efm32x_set_reg_bits(bank, EFM32_MSC_WRITECMD, + ret = efm32x_set_reg_bits(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_LADDRIM_MASK, 1); if (ERROR_OK != ret) return ret; - ret = target_read_u32(bank->target, EFM32_MSC_STATUS, &status); + ret = efm32x_read_reg_u32(bank, EFM32_MSC_REG_STATUS, &status); if (ERROR_OK != ret) return ret; @@ -792,13 +835,13 @@ static int efm32x_write_word(struct flash_bank *bank, uint32_t addr, return ret; } - ret = target_write_u32(bank->target, EFM32_MSC_WDATA, val); + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WDATA, val); if (ERROR_OK != ret) { LOG_ERROR("WDATA write failed"); return ret; } - ret = target_write_u32(bank->target, EFM32_MSC_WRITECMD, + ret = efm32x_write_reg_u32(bank, EFM32_MSC_REG_WRITECMD, EFM32_MSC_WRITECMD_WRITEONCE_MASK); if (ERROR_OK != ret) { LOG_ERROR("WRITECMD write failed"); From 5a6f0495db71ef1c05a912cd87e52e3d62e641a3 Mon Sep 17 00:00:00 2001 From: Diego Herranz Date: Thu, 3 Aug 2017 07:37:41 +0100 Subject: [PATCH 016/127] tcl/interface/ftdi: improve minimodule config - Tested on a real FT2232H MiniModule, so warning removed. - Every pin initially set to high impedance except TCK, TDI, TDO and TMS: Safest values given it's an evaluation board and the rest of pins might be connected to something else. - Reset is now initially de-asserted (it was asserted which is not recommended). - nRST pin choice is arbitrary so comment added (wondering if it should be an "echo"). - "-oe" option added to NRST signal so it can be set as high impedance (tri-stated). Change-Id: I967ab0c7bbccf72dbf6d6d78b3180b74e016e0d6 Signed-off-by: Diego Herranz Reviewed-on: http://openocd.zylin.com/4185 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/interface/ftdi/minimodule.cfg | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tcl/interface/ftdi/minimodule.cfg b/tcl/interface/ftdi/minimodule.cfg index 57249dfc1..7df096d9c 100644 --- a/tcl/interface/ftdi/minimodule.cfg +++ b/tcl/interface/ftdi/minimodule.cfg @@ -4,14 +4,13 @@ # http://www.ftdichip.com/Support/Documents/DataSheets/Modules/DS_FT2232H_Mini_Module.pdf # -echo "WARNING!" -echo "This file was not tested with real interface, it is based on code in ft2232.c." -echo "Please report your experience with this file to openocd-devel mailing list," -echo "so it could be marked as working or fixed." - interface ftdi ftdi_device_desc "FT2232H MiniModule" ftdi_vid_pid 0x0403 0x6010 -ftdi_layout_init 0x0018 0x05fb -ftdi_layout_signal nSRST -data 0x0020 +# Every pin set as high impedance except TCK, TDI, TDO and TMS +ftdi_layout_init 0x0008 0x000b + +# nSRST defined on pin CN2-13 of the MiniModule (pin ADBUS5 [AD5] on the FT2232H chip) +# This choice is arbitrary. Use other GPIO pin if desired. +ftdi_layout_signal nSRST -data 0x0020 -oe 0x0020 From f712098323c46213a7658f6b91b3775055bc6d6a Mon Sep 17 00:00:00 2001 From: Robert Foss Date: Wed, 7 Jun 2017 16:49:29 -0400 Subject: [PATCH 017/127] server: Add port number to socket bind error Make this error message more useful by providing the port number that we tried to bind to. Change-Id: Ieb18adf0725a6ae99c77ebfaadc49d64ed407bbe Signed-off-by: Robert Foss Reviewed-on: http://openocd.zylin.com/4157 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/server/server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/server.c b/src/server/server.c index 8009d408f..517d62a79 100644 --- a/src/server/server.c +++ b/src/server/server.c @@ -273,7 +273,7 @@ int add_service(char *name, c->sin.sin_port = htons(c->portnumber); if (bind(c->fd, (struct sockaddr *)&c->sin, sizeof(c->sin)) == -1) { - LOG_ERROR("couldn't bind %s to socket: %s", name, strerror(errno)); + LOG_ERROR("couldn't bind %s to socket on port %d: %s", name, c->portnumber, strerror(errno)); close_socket(c->fd); free_service(c); return ERROR_FAIL; From f441f58ad6e58aefd3045810371d432acbd5b0f8 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 6 Aug 2017 07:58:31 +0200 Subject: [PATCH 018/127] board: tp-link_tl-mr3020: add ath79 support Finally we can use this driver by default! Change-Id: I09d215d1bd1dc16873a7379637e6869af65ad8f1 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4193 Tested-by: jenkins Reviewed-by: Dmytro Reviewed-by: Spencer Oliver --- tcl/board/tp-link_tl-mr3020.cfg | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tcl/board/tp-link_tl-mr3020.cfg b/tcl/board/tp-link_tl-mr3020.cfg index b7d8d5b61..7e040b325 100644 --- a/tcl/board/tp-link_tl-mr3020.cfg +++ b/tcl/board/tp-link_tl-mr3020.cfg @@ -42,3 +42,5 @@ $_TARGETNAME configure -event reset-init { set ram_boot_address 0xa0000000 $_TARGETNAME configure -work-area-phys 0xa1FFE000 -work-area-size 0x1000 + +flash bank flash0 ath79 0 0 0 0 $_TARGETNAME cs0 From e548d17f627666c7bd87dd114133de020a5da48d Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 15 Jul 2017 17:52:01 +0200 Subject: [PATCH 019/127] target: add atheros_ar9344.cfg Change-Id: I005b4c78ccb0fec8d38a25430cb49c580dcd8df5 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4191 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/target/atheros_ar9344.cfg | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tcl/target/atheros_ar9344.cfg diff --git a/tcl/target/atheros_ar9344.cfg b/tcl/target/atheros_ar9344.cfg new file mode 100644 index 000000000..f273fb05d --- /dev/null +++ b/tcl/target/atheros_ar9344.cfg @@ -0,0 +1,16 @@ +if { [info exists CHIPNAME] } { + set _CHIPNAME $_CHIPNAME +} else { + set _CHIPNAME ar9344 +} + +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + set _CPUTAPID 0x00000001 +} + +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME From ffa745b8350d88e8c45c6100f18b2ea81786480f Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sat, 15 Jul 2017 17:53:37 +0200 Subject: [PATCH 020/127] board: add TP-Link WDR4300 config tested on TP-Link WDR4300 v1.7 Change-Id: If2b456afac835ab3a3987d434d20824c7ba75b93 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4192 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/board/tp-link_wdr4300.cfg | 160 ++++++++++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 tcl/board/tp-link_wdr4300.cfg diff --git a/tcl/board/tp-link_wdr4300.cfg b/tcl/board/tp-link_wdr4300.cfg new file mode 100644 index 000000000..c31791620 --- /dev/null +++ b/tcl/board/tp-link_wdr4300.cfg @@ -0,0 +1,160 @@ +source [find target/atheros_ar9344.cfg] + +reset_config trst_only separate + +proc ar9344_40mhz_pll_init {} { + # QCA_PLL_SRIF_CPU_DPLL2_REG + mww 0xb81161C4 0x13210f00 + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x03000000 + # QCA_PLL_SRIF_DDR_DPLL2_REG + mww 0xb8116244 0x13210f00 + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x03000000 + # QCA_PLL_SRIF_BB_DPLL_BASE_REG + mww 0xb8116188 0x03000000 + + # QCA_PLL_CPU_DDR_CLK_CTRL_REG + mww 0xb8050008 0x0130001C + mww 0xb8050008 0x0130001C + mww 0xb8050008 0x0130001C + + # QCA_PLL_CPU_PLL_CFG_REG + mww 0xb8050000 0x40021380 + # QCA_PLL_DDR_PLL_CFG_REG + mww 0xb8050004 0x40815800 + # QCA_PLL_CPU_DDR_CLK_CTRL_REG + mww 0xb8050008 0x0130801C + + # QCA_PLL_SRIF_CPU_DPLL2_REG + mww 0xb81161C4 0x10810F00 + mww 0xb81161C0 0x41C00000 + # QCA_PLL_SRIF_CPU_DPLL2_REG + mww 0xb81161C4 0xD0810F00 + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x03000000 + # QCA_PLL_SRIF_CPU_DPLL2_REG + mww 0xb81161C4 0xD0800F00 + + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x03000000 + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x43000000 + # QCA_PLL_SRIF_CPU_DPLL3_REG + mww 0xb81161C8 0x030003E8 + + # QCA_PLL_SRIF_DDR_DPLL2_REG + mww 0xb8116244 0x10810F00 + mww 0xb8116240 0x41680000 + # QCA_PLL_SRIF_DDR_DPLL2_REG + mww 0xb8116244 0xD0810F00 + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x03000000 + # QCA_PLL_SRIF_DDR_DPLL2_REG + mww 0xb8116244 0xD0800F00 + + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x03000000 + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x43000000 + # QCA_PLL_SRIF_DDR_DPLL3_REG + mww 0xb8116248 0x03000718 + + # QCA_PLL_CPU_DDR_CLK_CTRL_REG + mww 0xb8050008 0x01308018 + mww 0xb8050008 0x01308010 + mww 0xb8050008 0x01308000 + + # QCA_PLL_DDR_PLL_DITHER_REG + mww 0xb8050044 0x78180200 + # QCA_PLL_CPU_PLL_DITHER_REG + mww 0xb8050048 0x41C00000 + +} + +proc ar9344_ddr_init {} { + # QCA_DDR_CTRL_CFG_REG + mww 0xb8000108 0x40 + # QCA_DDR_RD_DATA_THIS_CYCLE_REG + mww 0xb8000018 0xFF + # QCA_DDR_BURST_REG + mww 0xb80000C4 0x74444444 + # QCA_DDR_BURST2_REG + mww 0xb80000C8 0x0222 + # QCA_AHB_MASTER_TOUT_MAX_REG + mww 0xb80000CC 0xFFFFF + + # QCA_DDR_CFG_REG + mww 0xb8000000 0xC7D48CD0 + # QCA_DDR_CFG2_REG + mww 0xb8000004 0x9DD0E6A8 + + # QCA_DDR_DDR2_CFG_REG + mww 0xb80000B8 0x0E59 + # QCA_DDR_CFG2_REG + mww 0xb8000004 0x9DD0E6A8 + + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x08 + mww 0xb8000010 0x08 + mww 0xb8000010 0x10 + mww 0xb8000010 0x20 + # QCA_DDR_EMR_REG + mww 0xb800000C 0x02 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x02 + + # QCA_DDR_MR_REG + mww 0xb8000008 0x0133 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x1 + mww 0xb8000010 0x8 + mww 0xb8000010 0x8 + mww 0xb8000010 0x4 + mww 0xb8000010 0x4 + + # QCA_DDR_MR_REG + mww 0xb8000008 0x33 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x1 + + # QCA_DDR_EMR_REG + mww 0xb800000C 0x0382 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x2 + # QCA_DDR_EMR_REG + mww 0xb800000C 0x0402 + # QCA_DDR_CTRL_REG + mww 0xb8000010 0x2 + + # QCA_DDR_REFRESH_REG + mww 0xb8000014 0x4270 + + # QCA_DDR_TAP_CTRL_0_REG + mww 0xb800001C 0x0e + # QCA_DDR_TAP_CTRL_1_REG + mww 0xb8000020 0x0e + # QCA_DDR_TAP_CTRL_2_REG + mww 0xb8000024 0x0e + # QCA_DDR_TAP_CTRL_3_REG + mww 0xb8000028 0x0e +} + +$_TARGETNAME configure -event reset-init { + + # mww 0xb806001c 0x1000000 + ar9344_40mhz_pll_init + sleep 100 + + # flash remap + # SPI_CONTROL_ADDR + mww 0xbF000004 0x43 + + ar9344_ddr_init + sleep 100 +} + +set ram_boot_address 0xa0000000 +$_TARGETNAME configure -work-area-phys 0x1d000000 -work-area-size 0x1000 + +flash bank flash0 ath79 0 0 0 0 $_TARGETNAME cs0 From 5384d2c20929d7217d884070e505ae38108c1a21 Mon Sep 17 00:00:00 2001 From: Oleksij Rempel Date: Sun, 6 Aug 2017 09:50:05 +0200 Subject: [PATCH 021/127] target: atheros_ar9344: add simple uart0 test in some cases we need something to test if uart is actually properly connected. Change-Id: I5a16b053164b34bb30ae8370753be12887a85c51 Signed-off-by: Oleksij Rempel Reviewed-on: http://openocd.zylin.com/4194 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/target/atheros_ar9344.cfg | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tcl/target/atheros_ar9344.cfg b/tcl/target/atheros_ar9344.cfg index f273fb05d..b698f2503 100644 --- a/tcl/target/atheros_ar9344.cfg +++ b/tcl/target/atheros_ar9344.cfg @@ -14,3 +14,26 @@ jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME mips_m4k -endian big -chain-position $_TARGETNAME + +proc test_ar9344_uart0_tx {} { + echo "configuring uart0.." + mww 0xb802000c 0x87 + mww 0xb8020000 0x15 + mww 0xb8020004 0 + mww 0xb802000c 7 + mww 0xb8020004 0 + + echo "send message: hallo world" + mww 0xb8020000 0x68 + mww 0xb8020000 0x65 + mww 0xb8020000 0x6c + mww 0xb8020000 0x6c + mww 0xb8020000 0x6f + mww 0xb8020000 0x20 + mww 0xb8020000 0x77 + mww 0xb8020000 0x6f + mww 0xb8020000 0x72 + mww 0xb8020000 0x6c + mww 0xb8020000 0x64 + mww 0xb8020000 0x0a +} From 9bbe299b35be0e086fdafb9c44669b1c36f935f9 Mon Sep 17 00:00:00 2001 From: Uwe Bonnes Date: Mon, 14 Nov 2016 19:12:38 +0100 Subject: [PATCH 022/127] stm32lx.c: Read IDcode at appropriate address. Trying to read the L0 idcode at the L1 idcode address 0xE0042000 often resulted in an uncatched error. Reading at the right L0 address 0x40015800 afterwards results in reading 0. So access to the device is denied.. Change-Id: I6de92cf99a5d5d46c72f9ba055613cbc5753a951 Signed-off-by: Uwe Bonnes Reviewed-on: http://openocd.zylin.com/3883 Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/flash/nor/stm32lx.c | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/flash/nor/stm32lx.c b/src/flash/nor/stm32lx.c index 0c2fddc92..fdfaad4cf 100644 --- a/src/flash/nor/stm32lx.c +++ b/src/flash/nor/stm32lx.c @@ -726,16 +726,13 @@ reset_pg_and_lock: static int stm32lx_read_id_code(struct target *target, uint32_t *id) { - /* read stm32 device id register */ - int retval = target_read_u32(target, DBGMCU_IDCODE, id); - if (retval != ERROR_OK) - return retval; - - /* STM32L0 parts will have 0 there, try reading the L0's location for - * DBG_IDCODE in case this is an L0 part. */ - if (*id == 0) + struct armv7m_common *armv7m = target_to_armv7m(target); + int retval; + if (armv7m->arm.is_armv6m == true) retval = target_read_u32(target, DBGMCU_IDCODE_L0, id); - + else + /* read stm32 device id register */ + retval = target_read_u32(target, DBGMCU_IDCODE, id); return retval; } From 52885d2b538dcd4184aae14cf2706fb97acccbd9 Mon Sep 17 00:00:00 2001 From: Slowcoder Date: Thu, 31 Aug 2017 20:53:57 +0200 Subject: [PATCH 023/127] nrf51: Refactor device-list This cleans up the list of supported nrf51 chips considerably. Change-Id: Ic74685657bb72a8703c0a49df4c48c54604ec2a7 Signed-off-by: Slowcoder Reviewed-on: http://openocd.zylin.com/4208 Tested-by: jenkins Reviewed-by: Fredrik Hederstierna Reviewed-by: Spencer Oliver --- src/flash/nor/nrf51.c | 304 +++++++----------------------------------- 1 file changed, 45 insertions(+), 259 deletions(-) diff --git a/src/flash/nor/nrf51.c b/src/flash/nor/nrf51.c index 7b7acf479..350957c90 100644 --- a/src/flash/nor/nrf51.c +++ b/src/flash/nor/nrf51.c @@ -126,6 +126,15 @@ struct nrf51_device_spec { unsigned int flash_size_kb; }; +#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \ +{ \ +.hwid = (id), \ +.part = pt, \ +.variant = var, \ +.build_code = bcode, \ +.flash_size_kb = (fsize), \ +} + /* The known devices table below is derived from the "nRF51 Series * Compatibility Matrix" document, which can be found by searching for * ATTN-51 on the Nordic Semi website: @@ -140,279 +149,56 @@ struct nrf51_device_spec { */ static const struct nrf51_device_spec nrf51_known_devices_table[] = { /* nRF51822 Devices (IC rev 1). */ - { - .hwid = 0x001D, - .part = "51822", - .variant = "QFAA", - .build_code = "CA/C0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0026, - .part = "51822", - .variant = "QFAB", - .build_code = "AA", - .flash_size_kb = 128, - }, - { - .hwid = 0x0027, - .part = "51822", - .variant = "QFAB", - .build_code = "A0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0020, - .part = "51822", - .variant = "CEAA", - .build_code = "BA", - .flash_size_kb = 256, - }, - { - .hwid = 0x002F, - .part = "51822", - .variant = "CEAA", - .build_code = "B0", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), + NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), + NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), + NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), + NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), /* nRF51822 Devices (IC rev 2). */ - { - .hwid = 0x002A, - .part = "51822", - .variant = "QFAA", - .build_code = "FA0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0044, - .part = "51822", - .variant = "QFAA", - .build_code = "GC0", - .flash_size_kb = 256, - }, - { - .hwid = 0x003C, - .part = "51822", - .variant = "QFAA", - .build_code = "G0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0057, - .part = "51822", - .variant = "QFAA", - .build_code = "G2", - .flash_size_kb = 256, - }, - { - .hwid = 0x0058, - .part = "51822", - .variant = "QFAA", - .build_code = "G3", - .flash_size_kb = 256, - }, - { - .hwid = 0x004C, - .part = "51822", - .variant = "QFAB", - .build_code = "B0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0040, - .part = "51822", - .variant = "CEAA", - .build_code = "CA0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0047, - .part = "51822", - .variant = "CEAA", - .build_code = "DA0", - .flash_size_kb = 256, - }, - { - .hwid = 0x004D, - .part = "51822", - .variant = "CEAA", - .build_code = "D00", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), + NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), + NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), + NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), + NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), + NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), + NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), + NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), + NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), /* nRF51822 Devices (IC rev 3). */ - { - .hwid = 0x0072, - .part = "51822", - .variant = "QFAA", - .build_code = "H0", - .flash_size_kb = 256, - }, - { - .hwid = 0x007B, - .part = "51822", - .variant = "QFAB", - .build_code = "C0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0083, - .part = "51822", - .variant = "QFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0084, - .part = "51822", - .variant = "QFAC", - .build_code = "A1", - .flash_size_kb = 256, - }, - { - .hwid = 0x007D, - .part = "51822", - .variant = "CDAB", - .build_code = "A0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0079, - .part = "51822", - .variant = "CEAA", - .build_code = "E0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0087, - .part = "51822", - .variant = "CFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, - { - .hwid = 0x008F, - .part = "51822", - .variant = "QFAA", - .build_code = "H1", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), + NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), + NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), + NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), + NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), + NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), + NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), /* nRF51422 Devices (IC rev 1). */ - { - .hwid = 0x001E, - .part = "51422", - .variant = "QFAA", - .build_code = "CA", - .flash_size_kb = 256, - }, - { - .hwid = 0x0024, - .part = "51422", - .variant = "QFAA", - .build_code = "C0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0031, - .part = "51422", - .variant = "CEAA", - .build_code = "A0A", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), + NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), + NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), /* nRF51422 Devices (IC rev 2). */ - { - .hwid = 0x002D, - .part = "51422", - .variant = "QFAA", - .build_code = "DAA", - .flash_size_kb = 256, - }, - { - .hwid = 0x002E, - .part = "51422", - .variant = "QFAA", - .build_code = "E0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0061, - .part = "51422", - .variant = "QFAB", - .build_code = "A00", - .flash_size_kb = 128, - }, - { - .hwid = 0x0050, - .part = "51422", - .variant = "CEAA", - .build_code = "B0", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), + NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), + NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), + NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), /* nRF51422 Devices (IC rev 3). */ - { - .hwid = 0x0073, - .part = "51422", - .variant = "QFAA", - .build_code = "F0", - .flash_size_kb = 256, - }, - { - .hwid = 0x007C, - .part = "51422", - .variant = "QFAB", - .build_code = "B0", - .flash_size_kb = 128, - }, - { - .hwid = 0x0085, - .part = "51422", - .variant = "QFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0086, - .part = "51422", - .variant = "QFAC", - .build_code = "A1", - .flash_size_kb = 256, - }, - { - .hwid = 0x007E, - .part = "51422", - .variant = "CDAB", - .build_code = "A0", - .flash_size_kb = 128, - }, - { - .hwid = 0x007A, - .part = "51422", - .variant = "CEAA", - .build_code = "C0", - .flash_size_kb = 256, - }, - { - .hwid = 0x0088, - .part = "51422", - .variant = "CFAC", - .build_code = "A0", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), + NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), + NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), + NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), + NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), + NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), + NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards with built-in jlink seem to use engineering samples not listed in the nRF51 Series Compatibility Matrix V1.0. */ - { - .hwid = 0x0071, - .part = "51822", - .variant = "QFAC", - .build_code = "AB", - .flash_size_kb = 256, - }, + NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), }; static int nrf51_bank_is_probed(struct flash_bank *bank) From d43308af7513fa98f6ef1cae75393c8766bd370d Mon Sep 17 00:00:00 2001 From: Slowcoder Date: Thu, 31 Aug 2017 21:09:42 +0200 Subject: [PATCH 024/127] nrf51: Rename to nrf5 Renaming of all nrf51 NOR flash code to nrf5, as to prepare the code for being able to flash nrf51 and nrf52 chips. The nrf51 command is retained for backwards compatability. "nRF5" is also the name Nordic Semiconductor uses to describe both the nrf51 and nrf52 chips. Change-Id: I5f4e3f1ec780184b28ad44f735a746e68908c502 Signed-off-by: Slowcoder Reviewed-on: http://openocd.zylin.com/4209 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Spencer Oliver --- doc/openocd.texi | 10 +- src/flash/nor/Makefile.am | 2 +- src/flash/nor/drivers.c | 2 + src/flash/nor/{nrf51.c => nrf5.c} | 578 ++++++++++++++++-------------- 4 files changed, 310 insertions(+), 282 deletions(-) rename src/flash/nor/{nrf51.c => nrf5.c} (61%) diff --git a/doc/openocd.texi b/doc/openocd.texi index 89ee5eb45..39b81ea85 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5767,17 +5767,19 @@ Show information about flash driver. @end deffn -@deffn {Flash Driver} nrf51 +@deffn {Flash Driver} nrf5 All members of the nRF51 microcontroller families from Nordic Semiconductor include internal flash and use ARM Cortex-M0 core. +Also, the nRF52832 microcontroller from Nordic Semiconductor, which include +internal flash and use an ARM Cortex-M4F core. @example -flash bank $_FLASHNAME nrf51 0 0x00000000 0 0 $_TARGETNAME +flash bank $_FLASHNAME nrf5 0 0x00000000 0 0 $_TARGETNAME @end example -Some nrf51-specific commands are defined: +Some nrf5-specific commands are defined: -@deffn Command {nrf51 mass_erase} +@deffn Command {nrf5 mass_erase} Erases the contents of the code memory and user information configuration registers as well. It must be noted that this command works only for chips that do not have factory pre-programmed region 0 diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 5a992feef..4dac110c4 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -36,7 +36,7 @@ NOR_DRIVERS = \ %D%/mrvlqspi.c \ %D%/niietcm4.c \ %D%/non_cfi.c \ - %D%/nrf51.c \ + %D%/nrf5.c \ %D%/numicro.c \ %D%/ocl.c \ %D%/pic32mx.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 4ad1d92b9..9594ed9a3 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -48,6 +48,7 @@ extern struct flash_driver lpcspifi_flash; extern struct flash_driver mdr_flash; extern struct flash_driver mrvlqspi_flash; extern struct flash_driver niietcm4_flash; +extern struct flash_driver nrf5_flash; extern struct flash_driver nrf51_flash; extern struct flash_driver numicro_flash; extern struct flash_driver ocl_flash; @@ -101,6 +102,7 @@ static struct flash_driver *flash_drivers[] = { &mdr_flash, &mrvlqspi_flash, &niietcm4_flash, + &nrf5_flash, &nrf51_flash, &numicro_flash, &ocl_flash, diff --git a/src/flash/nor/nrf51.c b/src/flash/nor/nrf5.c similarity index 61% rename from src/flash/nor/nrf51.c rename to src/flash/nor/nrf5.c index 350957c90..8441c2a07 100644 --- a/src/flash/nor/nrf51.c +++ b/src/flash/nor/nrf5.c @@ -28,97 +28,97 @@ #include enum { - NRF51_FLASH_BASE = 0x00000000, + NRF5_FLASH_BASE = 0x00000000, }; -enum nrf51_ficr_registers { - NRF51_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ +enum nrf5_ficr_registers { + NRF5_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */ -#define NRF51_FICR_REG(offset) (NRF51_FICR_BASE + offset) +#define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + offset) - NRF51_FICR_CODEPAGESIZE = NRF51_FICR_REG(0x010), - NRF51_FICR_CODESIZE = NRF51_FICR_REG(0x014), - NRF51_FICR_CLENR0 = NRF51_FICR_REG(0x028), - NRF51_FICR_PPFC = NRF51_FICR_REG(0x02C), - NRF51_FICR_NUMRAMBLOCK = NRF51_FICR_REG(0x034), - NRF51_FICR_SIZERAMBLOCK0 = NRF51_FICR_REG(0x038), - NRF51_FICR_SIZERAMBLOCK1 = NRF51_FICR_REG(0x03C), - NRF51_FICR_SIZERAMBLOCK2 = NRF51_FICR_REG(0x040), - NRF51_FICR_SIZERAMBLOCK3 = NRF51_FICR_REG(0x044), - NRF51_FICR_CONFIGID = NRF51_FICR_REG(0x05C), - NRF51_FICR_DEVICEID0 = NRF51_FICR_REG(0x060), - NRF51_FICR_DEVICEID1 = NRF51_FICR_REG(0x064), - NRF51_FICR_ER0 = NRF51_FICR_REG(0x080), - NRF51_FICR_ER1 = NRF51_FICR_REG(0x084), - NRF51_FICR_ER2 = NRF51_FICR_REG(0x088), - NRF51_FICR_ER3 = NRF51_FICR_REG(0x08C), - NRF51_FICR_IR0 = NRF51_FICR_REG(0x090), - NRF51_FICR_IR1 = NRF51_FICR_REG(0x094), - NRF51_FICR_IR2 = NRF51_FICR_REG(0x098), - NRF51_FICR_IR3 = NRF51_FICR_REG(0x09C), - NRF51_FICR_DEVICEADDRTYPE = NRF51_FICR_REG(0x0A0), - NRF51_FICR_DEVICEADDR0 = NRF51_FICR_REG(0x0A4), - NRF51_FICR_DEVICEADDR1 = NRF51_FICR_REG(0x0A8), - NRF51_FICR_OVERRIDEN = NRF51_FICR_REG(0x0AC), - NRF51_FICR_NRF_1MBIT0 = NRF51_FICR_REG(0x0B0), - NRF51_FICR_NRF_1MBIT1 = NRF51_FICR_REG(0x0B4), - NRF51_FICR_NRF_1MBIT2 = NRF51_FICR_REG(0x0B8), - NRF51_FICR_NRF_1MBIT3 = NRF51_FICR_REG(0x0BC), - NRF51_FICR_NRF_1MBIT4 = NRF51_FICR_REG(0x0C0), - NRF51_FICR_BLE_1MBIT0 = NRF51_FICR_REG(0x0EC), - NRF51_FICR_BLE_1MBIT1 = NRF51_FICR_REG(0x0F0), - NRF51_FICR_BLE_1MBIT2 = NRF51_FICR_REG(0x0F4), - NRF51_FICR_BLE_1MBIT3 = NRF51_FICR_REG(0x0F8), - NRF51_FICR_BLE_1MBIT4 = NRF51_FICR_REG(0x0FC), + NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010), + NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014), + NRF5_FICR_CLENR0 = NRF5_FICR_REG(0x028), + NRF5_FICR_PPFC = NRF5_FICR_REG(0x02C), + NRF5_FICR_NUMRAMBLOCK = NRF5_FICR_REG(0x034), + NRF5_FICR_SIZERAMBLOCK0 = NRF5_FICR_REG(0x038), + NRF5_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C), + NRF5_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040), + NRF5_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044), + NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C), + NRF5_FICR_DEVICEID0 = NRF5_FICR_REG(0x060), + NRF5_FICR_DEVICEID1 = NRF5_FICR_REG(0x064), + NRF5_FICR_ER0 = NRF5_FICR_REG(0x080), + NRF5_FICR_ER1 = NRF5_FICR_REG(0x084), + NRF5_FICR_ER2 = NRF5_FICR_REG(0x088), + NRF5_FICR_ER3 = NRF5_FICR_REG(0x08C), + NRF5_FICR_IR0 = NRF5_FICR_REG(0x090), + NRF5_FICR_IR1 = NRF5_FICR_REG(0x094), + NRF5_FICR_IR2 = NRF5_FICR_REG(0x098), + NRF5_FICR_IR3 = NRF5_FICR_REG(0x09C), + NRF5_FICR_DEVICEADDRTYPE = NRF5_FICR_REG(0x0A0), + NRF5_FICR_DEVICEADDR0 = NRF5_FICR_REG(0x0A4), + NRF5_FICR_DEVICEADDR1 = NRF5_FICR_REG(0x0A8), + NRF5_FICR_OVERRIDEN = NRF5_FICR_REG(0x0AC), + NRF5_FICR_NRF_1MBIT0 = NRF5_FICR_REG(0x0B0), + NRF5_FICR_NRF_1MBIT1 = NRF5_FICR_REG(0x0B4), + NRF5_FICR_NRF_1MBIT2 = NRF5_FICR_REG(0x0B8), + NRF5_FICR_NRF_1MBIT3 = NRF5_FICR_REG(0x0BC), + NRF5_FICR_NRF_1MBIT4 = NRF5_FICR_REG(0x0C0), + NRF5_FICR_BLE_1MBIT0 = NRF5_FICR_REG(0x0EC), + NRF5_FICR_BLE_1MBIT1 = NRF5_FICR_REG(0x0F0), + NRF5_FICR_BLE_1MBIT2 = NRF5_FICR_REG(0x0F4), + NRF5_FICR_BLE_1MBIT3 = NRF5_FICR_REG(0x0F8), + NRF5_FICR_BLE_1MBIT4 = NRF5_FICR_REG(0x0FC), }; -enum nrf51_uicr_registers { - NRF51_UICR_BASE = 0x10001000, /* User Information +enum nrf5_uicr_registers { + NRF5_UICR_BASE = 0x10001000, /* User Information * Configuration Regsters */ - NRF51_UICR_SIZE = 0x100, + NRF5_UICR_SIZE = 0x100, -#define NRF51_UICR_REG(offset) (NRF51_UICR_BASE + offset) +#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset) - NRF51_UICR_CLENR0 = NRF51_UICR_REG(0x000), - NRF51_UICR_RBPCONF = NRF51_UICR_REG(0x004), - NRF51_UICR_XTALFREQ = NRF51_UICR_REG(0x008), - NRF51_UICR_FWID = NRF51_UICR_REG(0x010), + NRF5_UICR_CLENR0 = NRF5_UICR_REG(0x000), + NRF5_UICR_RBPCONF = NRF5_UICR_REG(0x004), + NRF5_UICR_XTALFREQ = NRF5_UICR_REG(0x008), + NRF5_UICR_FWID = NRF5_UICR_REG(0x010), }; -enum nrf51_nvmc_registers { - NRF51_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory +enum nrf5_nvmc_registers { + NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory * Controller Regsters */ -#define NRF51_NVMC_REG(offset) (NRF51_NVMC_BASE + offset) +#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset) - NRF51_NVMC_READY = NRF51_NVMC_REG(0x400), - NRF51_NVMC_CONFIG = NRF51_NVMC_REG(0x504), - NRF51_NVMC_ERASEPAGE = NRF51_NVMC_REG(0x508), - NRF51_NVMC_ERASEALL = NRF51_NVMC_REG(0x50C), - NRF51_NVMC_ERASEUICR = NRF51_NVMC_REG(0x514), + NRF5_NVMC_READY = NRF5_NVMC_REG(0x400), + NRF5_NVMC_CONFIG = NRF5_NVMC_REG(0x504), + NRF5_NVMC_ERASEPAGE = NRF5_NVMC_REG(0x508), + NRF5_NVMC_ERASEALL = NRF5_NVMC_REG(0x50C), + NRF5_NVMC_ERASEUICR = NRF5_NVMC_REG(0x514), }; -enum nrf51_nvmc_config_bits { - NRF51_NVMC_CONFIG_REN = 0x00, - NRF51_NVMC_CONFIG_WEN = 0x01, - NRF51_NVMC_CONFIG_EEN = 0x02, +enum nrf5_nvmc_config_bits { + NRF5_NVMC_CONFIG_REN = 0x00, + NRF5_NVMC_CONFIG_WEN = 0x01, + NRF5_NVMC_CONFIG_EEN = 0x02, }; -struct nrf51_info { +struct nrf5_info { uint32_t code_page_size; struct { bool probed; int (*write) (struct flash_bank *bank, - struct nrf51_info *chip, + struct nrf5_info *chip, const uint8_t *buffer, uint32_t offset, uint32_t count); } bank[2]; struct target *target; }; -struct nrf51_device_spec { +struct nrf5_device_spec { uint16_t hwid; const char *part; const char *variant; @@ -126,7 +126,7 @@ struct nrf51_device_spec { unsigned int flash_size_kb; }; -#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \ +#define NRF5_DEVICE_DEF(id, pt, var, bcode, fsize) \ { \ .hwid = (id), \ .part = pt, \ @@ -147,71 +147,71 @@ struct nrf51_device_spec { * shown as Gx0, Bx0, etc. In these cases the HWID in the matrix is * for x==0, x!=0 means different (unspecified) HWIDs. */ -static const struct nrf51_device_spec nrf51_known_devices_table[] = { +static const struct nrf5_device_spec nrf5_known_devices_table[] = { /* nRF51822 Devices (IC rev 1). */ - NRF51_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), - NRF51_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), - NRF51_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), - NRF51_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), - NRF51_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), + NRF5_DEVICE_DEF(0x001D, "51822", "QFAA", "CA/C0", 256), + NRF5_DEVICE_DEF(0x0026, "51822", "QFAB", "AA", 128), + NRF5_DEVICE_DEF(0x0027, "51822", "QFAB", "A0", 128), + NRF5_DEVICE_DEF(0x0020, "51822", "CEAA", "BA", 256), + NRF5_DEVICE_DEF(0x002F, "51822", "CEAA", "B0", 256), /* nRF51822 Devices (IC rev 2). */ - NRF51_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), - NRF51_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), - NRF51_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), - NRF51_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), - NRF51_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), - NRF51_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), - NRF51_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), - NRF51_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), - NRF51_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), + NRF5_DEVICE_DEF(0x002A, "51822", "QFAA", "FA0", 256), + NRF5_DEVICE_DEF(0x0044, "51822", "QFAA", "GC0", 256), + NRF5_DEVICE_DEF(0x003C, "51822", "QFAA", "G0", 256), + NRF5_DEVICE_DEF(0x0057, "51822", "QFAA", "G2", 256), + NRF5_DEVICE_DEF(0x0058, "51822", "QFAA", "G3", 256), + NRF5_DEVICE_DEF(0x004C, "51822", "QFAB", "B0", 128), + NRF5_DEVICE_DEF(0x0040, "51822", "CEAA", "CA0", 256), + NRF5_DEVICE_DEF(0x0047, "51822", "CEAA", "DA0", 256), + NRF5_DEVICE_DEF(0x004D, "51822", "CEAA", "D00", 256), /* nRF51822 Devices (IC rev 3). */ - NRF51_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), - NRF51_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), - NRF51_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), - NRF51_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), - NRF51_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), - NRF51_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), - NRF51_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0072, "51822", "QFAA", "H0", 256), + NRF5_DEVICE_DEF(0x007B, "51822", "QFAB", "C0", 128), + NRF5_DEVICE_DEF(0x0083, "51822", "QFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0084, "51822", "QFAC", "A1", 256), + NRF5_DEVICE_DEF(0x007D, "51822", "CDAB", "A0", 128), + NRF5_DEVICE_DEF(0x0079, "51822", "CEAA", "E0", 256), + NRF5_DEVICE_DEF(0x0087, "51822", "CFAC", "A0", 256), /* nRF51422 Devices (IC rev 1). */ - NRF51_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), - NRF51_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), - NRF51_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), + NRF5_DEVICE_DEF(0x001E, "51422", "QFAA", "CA", 256), + NRF5_DEVICE_DEF(0x0024, "51422", "QFAA", "C0", 256), + NRF5_DEVICE_DEF(0x0031, "51422", "CEAA", "A0A", 256), /* nRF51422 Devices (IC rev 2). */ - NRF51_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), - NRF51_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), - NRF51_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), - NRF51_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), + NRF5_DEVICE_DEF(0x002D, "51422", "QFAA", "DAA", 256), + NRF5_DEVICE_DEF(0x002E, "51422", "QFAA", "E0", 256), + NRF5_DEVICE_DEF(0x0061, "51422", "QFAB", "A00", 128), + NRF5_DEVICE_DEF(0x0050, "51422", "CEAA", "B0", 256), /* nRF51422 Devices (IC rev 3). */ - NRF51_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), - NRF51_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), - NRF51_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), - NRF51_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), - NRF51_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), - NRF51_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), - NRF51_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0073, "51422", "QFAA", "F0", 256), + NRF5_DEVICE_DEF(0x007C, "51422", "QFAB", "B0", 128), + NRF5_DEVICE_DEF(0x0085, "51422", "QFAC", "A0", 256), + NRF5_DEVICE_DEF(0x0086, "51422", "QFAC", "A1", 256), + NRF5_DEVICE_DEF(0x007E, "51422", "CDAB", "A0", 128), + NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), + NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards with built-in jlink seem to use engineering samples not listed in the nRF51 Series Compatibility Matrix V1.0. */ - NRF51_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), + NRF5_DEVICE_DEF(0x0071, "51822", "QFAC", "AB", 256), }; -static int nrf51_bank_is_probed(struct flash_bank *bank) +static int nrf5_bank_is_probed(struct flash_bank *bank) { - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; assert(chip != NULL); return chip->bank[bank->bank_number].probed; } -static int nrf51_probe(struct flash_bank *bank); +static int nrf5_probe(struct flash_bank *bank); -static int nrf51_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf51_info **chip) +static int nrf5_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf5_info **chip) { if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); @@ -220,23 +220,23 @@ static int nrf51_get_probed_chip_if_halted(struct flash_bank *bank, struct nrf51 *chip = bank->driver_priv; - int probed = nrf51_bank_is_probed(bank); + int probed = nrf5_bank_is_probed(bank); if (probed < 0) return probed; else if (!probed) - return nrf51_probe(bank); + return nrf5_probe(bank); else return ERROR_OK; } -static int nrf51_wait_for_nvmc(struct nrf51_info *chip) +static int nrf5_wait_for_nvmc(struct nrf5_info *chip) { uint32_t ready; int res; int timeout = 100; do { - res = target_read_u32(chip->target, NRF51_NVMC_READY, &ready); + res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready); if (res != ERROR_OK) { LOG_ERROR("Couldn't read NVMC_READY register"); return res; @@ -252,12 +252,12 @@ static int nrf51_wait_for_nvmc(struct nrf51_info *chip) return ERROR_FLASH_BUSY; } -static int nrf51_nvmc_erase_enable(struct nrf51_info *chip) +static int nrf5_nvmc_erase_enable(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, - NRF51_NVMC_CONFIG, - NRF51_NVMC_CONFIG_EEN); + NRF5_NVMC_CONFIG, + NRF5_NVMC_CONFIG_EEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable erase operation"); @@ -268,19 +268,19 @@ static int nrf51_nvmc_erase_enable(struct nrf51_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Erase enable did not complete"); return res; } -static int nrf51_nvmc_write_enable(struct nrf51_info *chip) +static int nrf5_nvmc_write_enable(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, - NRF51_NVMC_CONFIG, - NRF51_NVMC_CONFIG_WEN); + NRF5_NVMC_CONFIG, + NRF5_NVMC_CONFIG_WEN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable write operation"); @@ -291,19 +291,19 @@ static int nrf51_nvmc_write_enable(struct nrf51_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Write enable did not complete"); return res; } -static int nrf51_nvmc_read_only(struct nrf51_info *chip) +static int nrf5_nvmc_read_only(struct nrf5_info *chip) { int res; res = target_write_u32(chip->target, - NRF51_NVMC_CONFIG, - NRF51_NVMC_CONFIG_REN); + NRF5_NVMC_CONFIG, + NRF5_NVMC_CONFIG_REN); if (res != ERROR_OK) { LOG_ERROR("Failed to enable read-only operation"); @@ -313,19 +313,19 @@ static int nrf51_nvmc_read_only(struct nrf51_info *chip) According to NVMC examples in Nordic SDK busy status must be checked after writing to NVMC_CONFIG */ - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) LOG_ERROR("Read only enable did not complete"); return res; } -static int nrf51_nvmc_generic_erase(struct nrf51_info *chip, +static int nrf5_nvmc_generic_erase(struct nrf5_info *chip, uint32_t erase_register, uint32_t erase_value) { int res; - res = nrf51_nvmc_erase_enable(chip); + res = nrf5_nvmc_erase_enable(chip); if (res != ERROR_OK) goto error; @@ -335,34 +335,34 @@ static int nrf51_nvmc_generic_erase(struct nrf51_info *chip, if (res != ERROR_OK) goto set_read_only; - res = nrf51_wait_for_nvmc(chip); + res = nrf5_wait_for_nvmc(chip); if (res != ERROR_OK) goto set_read_only; - return nrf51_nvmc_read_only(chip); + return nrf5_nvmc_read_only(chip); set_read_only: - nrf51_nvmc_read_only(chip); + nrf5_nvmc_read_only(chip); error: LOG_ERROR("Failed to erase reg: 0x%08"PRIx32" val: 0x%08"PRIx32, erase_register, erase_value); return ERROR_FAIL; } -static int nrf51_protect_check(struct flash_bank *bank) +static int nrf5_protect_check(struct flash_bank *bank) { int res; uint32_t clenr0; /* UICR cannot be write protected so just return early */ - if (bank->base == NRF51_UICR_BASE) + if (bank->base == NRF5_UICR_BASE) return ERROR_OK; - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; assert(chip != NULL); - res = target_read_u32(chip->target, NRF51_FICR_CLENR0, + res = target_read_u32(chip->target, NRF5_FICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[FICR]"); @@ -370,7 +370,7 @@ static int nrf51_protect_check(struct flash_bank *bank) } if (clenr0 == 0xFFFFFFFF) { - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + res = target_read_u32(chip->target, NRF5_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -385,17 +385,17 @@ static int nrf51_protect_check(struct flash_bank *bank) return ERROR_OK; } -static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) +static int nrf5_protect(struct flash_bank *bank, int set, int first, int last) { int res; uint32_t clenr0, ppfc; - struct nrf51_info *chip; + struct nrf5_info *chip; /* UICR cannot be write protected so just bail out early */ - if (bank->base == NRF51_UICR_BASE) + if (bank->base == NRF5_UICR_BASE) return ERROR_FAIL; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -404,7 +404,7 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF51_FICR_PPFC, + res = target_read_u32(chip->target, NRF5_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -416,7 +416,7 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) return ERROR_FAIL; } - res = target_read_u32(chip->target, NRF51_UICR_CLENR0, + res = target_read_u32(chip->target, NRF5_UICR_CLENR0, &clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code region 0 size[UICR]"); @@ -424,7 +424,7 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) } if (clenr0 == 0xFFFFFFFF) { - res = target_write_u32(chip->target, NRF51_UICR_CLENR0, + res = target_write_u32(chip->target, NRF5_UICR_CLENR0, clenr0); if (res != ERROR_OK) { LOG_ERROR("Couldn't write code region 0 size[UICR]"); @@ -435,18 +435,18 @@ static int nrf51_protect(struct flash_bank *bank, int set, int first, int last) LOG_ERROR("You need to perform chip erase before changing the protection settings"); } - nrf51_protect_check(bank); + nrf5_protect_check(bank); return ERROR_OK; } -static int nrf51_probe(struct flash_bank *bank) +static int nrf5_probe(struct flash_bank *bank) { uint32_t hwid; int res; - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; - res = target_read_u32(chip->target, NRF51_FICR_CONFIGID, &hwid); + res = target_read_u32(chip->target, NRF5_FICR_CONFIGID, &hwid); if (res != ERROR_OK) { LOG_ERROR("Couldn't read CONFIGID register"); return res; @@ -455,10 +455,10 @@ static int nrf51_probe(struct flash_bank *bank) hwid &= 0xFFFF; /* HWID is stored in the lower two * bytes of the CONFIGID register */ - const struct nrf51_device_spec *spec = NULL; - for (size_t i = 0; i < ARRAY_SIZE(nrf51_known_devices_table); i++) { - if (hwid == nrf51_known_devices_table[i].hwid) { - spec = &nrf51_known_devices_table[i]; + const struct nrf5_device_spec *spec = NULL; + for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) { + if (hwid == nrf5_known_devices_table[i].hwid) { + spec = &nrf5_known_devices_table[i]; break; } } @@ -472,9 +472,9 @@ static int nrf51_probe(struct flash_bank *bank) LOG_WARNING("Unknown device (HWID 0x%08" PRIx32 ")", hwid); } - if (bank->base == NRF51_FLASH_BASE) { - /* The value stored in NRF51_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ - res = target_read_u32(chip->target, NRF51_FICR_CODEPAGESIZE, + if (bank->base == NRF5_FLASH_BASE) { + /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */ + res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE, &chip->code_page_size); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code page size"); @@ -482,9 +482,9 @@ static int nrf51_probe(struct flash_bank *bank) } /* Note the register name is misleading, - * NRF51_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ + * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */ uint32_t num_sectors; - res = target_read_u32(chip->target, NRF51_FICR_CODESIZE, &num_sectors); + res = target_read_u32(chip->target, NRF5_FICR_CODESIZE, &num_sectors); if (res != ERROR_OK) { LOG_ERROR("Couldn't read code memory size"); return res; @@ -501,7 +501,7 @@ static int nrf51_probe(struct flash_bank *bank) if (!bank->sectors) return ERROR_FLASH_BANK_NOT_PROBED; - /* Fill out the sector information: all NRF51 sectors are the same size and + /* Fill out the sector information: all NRF5 sectors are the same size and * there is always a fixed number of them. */ for (int i = 0; i < bank->num_sectors; i++) { bank->sectors[i].size = chip->code_page_size; @@ -512,11 +512,11 @@ static int nrf51_probe(struct flash_bank *bank) bank->sectors[i].is_protected = -1; } - nrf51_protect_check(bank); + nrf5_protect_check(bank); chip->bank[0].probed = true; } else { - bank->size = NRF51_UICR_SIZE; + bank->size = NRF5_UICR_SIZE; bank->num_sectors = 1; bank->sectors = calloc(bank->num_sectors, sizeof((bank->sectors)[0])); @@ -536,21 +536,21 @@ static int nrf51_probe(struct flash_bank *bank) return ERROR_OK; } -static int nrf51_auto_probe(struct flash_bank *bank) +static int nrf5_auto_probe(struct flash_bank *bank) { - int probed = nrf51_bank_is_probed(bank); + int probed = nrf5_bank_is_probed(bank); if (probed < 0) return probed; else if (probed) return ERROR_OK; else - return nrf51_probe(bank); + return nrf5_probe(bank); } -static struct flash_sector *nrf51_find_sector_by_address(struct flash_bank *bank, uint32_t address) +static struct flash_sector *nrf5_find_sector_by_address(struct flash_bank *bank, uint32_t address) { - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; for (int i = 0; i < bank->num_sectors; i++) if (bank->sectors[i].offset <= address && @@ -559,16 +559,16 @@ static struct flash_sector *nrf51_find_sector_by_address(struct flash_bank *bank return NULL; } -static int nrf51_erase_all(struct nrf51_info *chip) +static int nrf5_erase_all(struct nrf5_info *chip) { LOG_DEBUG("Erasing all non-volatile memory"); - return nrf51_nvmc_generic_erase(chip, - NRF51_NVMC_ERASEALL, + return nrf5_nvmc_generic_erase(chip, + NRF5_NVMC_ERASEALL, 0x00000001); } -static int nrf51_erase_page(struct flash_bank *bank, - struct nrf51_info *chip, +static int nrf5_erase_page(struct flash_bank *bank, + struct nrf5_info *chip, struct flash_sector *sector) { int res; @@ -579,9 +579,9 @@ static int nrf51_erase_page(struct flash_bank *bank, return ERROR_FAIL; } - if (bank->base == NRF51_UICR_BASE) { + if (bank->base == NRF5_UICR_BASE) { uint32_t ppfc; - res = target_read_u32(chip->target, NRF51_FICR_PPFC, + res = target_read_u32(chip->target, NRF5_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -599,14 +599,14 @@ static int nrf51_erase_page(struct flash_bank *bank, return ERROR_FAIL; } - res = nrf51_nvmc_generic_erase(chip, - NRF51_NVMC_ERASEUICR, + res = nrf5_nvmc_generic_erase(chip, + NRF5_NVMC_ERASEUICR, 0x00000001); } else { - res = nrf51_nvmc_generic_erase(chip, - NRF51_NVMC_ERASEPAGE, + res = nrf5_nvmc_generic_erase(chip, + NRF5_NVMC_ERASEPAGE, sector->offset); } @@ -616,7 +616,7 @@ static int nrf51_erase_page(struct flash_bank *bank, return res; } -static const uint8_t nrf51_flash_write_code[] = { +static const uint8_t nrf5_flash_write_code[] = { /* See contrib/loaders/flash/cortex-m0.S */ /* : */ 0x0d, 0x68, /* ldr r5, [r1, #0] */ @@ -641,13 +641,13 @@ static const uint8_t nrf51_flash_write_code[] = { /* Start a low level flash write for the specified region */ -static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) +static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes) { struct target *target = chip->target; uint32_t buffer_size = 8192; struct working_area *write_algorithm; struct working_area *source; - uint32_t address = NRF51_FLASH_BASE + offset; + uint32_t address = NRF5_FLASH_BASE + offset; struct reg_param reg_params[4]; struct armv7m_algorithm armv7m_info; int retval = ERROR_OK; @@ -657,7 +657,7 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const assert(bytes % 4 == 0); /* allocate working area with flash programming code */ - if (target_alloc_working_area(target, sizeof(nrf51_flash_write_code), + if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code), &write_algorithm) != ERROR_OK) { LOG_WARNING("no working area available, falling back to slow memory writes"); @@ -666,7 +666,7 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const if (retval != ERROR_OK) return retval; - retval = nrf51_wait_for_nvmc(chip); + retval = nrf5_wait_for_nvmc(chip); if (retval != ERROR_OK) return retval; @@ -679,11 +679,11 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const LOG_WARNING("using fast async flash loader. This is currently supported"); LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add"); - LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg to disable it"); + LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it"); retval = target_write_buffer(target, write_algorithm->address, - sizeof(nrf51_flash_write_code), - nrf51_flash_write_code); + sizeof(nrf5_flash_write_code), + nrf5_flash_write_code); if (retval != ERROR_OK) return retval; @@ -734,10 +734,10 @@ static int nrf51_ll_flash_write(struct nrf51_info *chip, uint32_t offset, const /* Check and erase flash sectors in specified range then start a low level page write. start/end must be sector aligned. */ -static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer) +static int nrf5_write_pages(struct flash_bank *bank, uint32_t start, uint32_t end, const uint8_t *buffer) { int res = ERROR_FAIL; - struct nrf51_info *chip = bank->driver_priv; + struct nrf5_info *chip = bank->driver_priv; struct flash_sector *sector; uint32_t offset; @@ -746,7 +746,7 @@ static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t e /* Erase all sectors */ for (offset = start; offset < end; offset += chip->code_page_size) { - sector = nrf51_find_sector_by_address(bank, offset); + sector = nrf5_find_sector_by_address(bank, offset); if (!sector) { LOG_ERROR("Invalid sector @ 0x%08"PRIx32, offset); return ERROR_FLASH_SECTOR_INVALID; @@ -758,7 +758,7 @@ static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t e } if (sector->is_erased != 1) { /* 1 = erased, 0= not erased, -1 = unknown */ - res = nrf51_erase_page(bank, chip, sector); + res = nrf5_erase_page(bank, chip, sector); if (res != ERROR_OK) { LOG_ERROR("Failed to erase sector @ 0x%08"PRIx32, sector->offset); goto error; @@ -767,41 +767,41 @@ static int nrf51_write_pages(struct flash_bank *bank, uint32_t start, uint32_t e sector->is_erased = 0; } - res = nrf51_nvmc_write_enable(chip); + res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) goto error; - res = nrf51_ll_flash_write(chip, start, buffer, (end - start)); + res = nrf5_ll_flash_write(chip, start, buffer, (end - start)); if (res != ERROR_OK) goto set_read_only; - return nrf51_nvmc_read_only(chip); + return nrf5_nvmc_read_only(chip); set_read_only: - nrf51_nvmc_read_only(chip); + nrf5_nvmc_read_only(chip); error: - LOG_ERROR("Failed to write to nrf51 flash"); + LOG_ERROR("Failed to write to nrf5 flash"); return res; } -static int nrf51_erase(struct flash_bank *bank, int first, int last) +static int nrf5_erase(struct flash_bank *bank, int first, int last) { int res; - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; /* For each sector to be erased */ for (int s = first; s <= last && res == ERROR_OK; s++) - res = nrf51_erase_page(bank, chip, &bank->sectors[s]); + res = nrf5_erase_page(bank, chip, &bank->sectors[s]); return res; } -static int nrf51_code_flash_write(struct flash_bank *bank, - struct nrf51_info *chip, +static int nrf5_code_flash_write(struct flash_bank *bank, + struct nrf5_info *chip, const uint8_t *buffer, uint32_t offset, uint32_t count) { @@ -848,58 +848,58 @@ static int nrf51_code_flash_write(struct flash_bank *bank, return res; } - return nrf51_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash); + return nrf5_write_pages(bank, first_page_offset, last_page_offset, buffer_to_flash); } -static int nrf51_uicr_flash_write(struct flash_bank *bank, - struct nrf51_info *chip, +static int nrf5_uicr_flash_write(struct flash_bank *bank, + struct nrf5_info *chip, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; - uint8_t uicr[NRF51_UICR_SIZE]; + uint8_t uicr[NRF5_UICR_SIZE]; struct flash_sector *sector = &bank->sectors[0]; - if ((offset + count) > NRF51_UICR_SIZE) + if ((offset + count) > NRF5_UICR_SIZE) return ERROR_FAIL; res = target_read_memory(bank->target, - NRF51_UICR_BASE, + NRF5_UICR_BASE, 1, - NRF51_UICR_SIZE, + NRF5_UICR_SIZE, uicr); if (res != ERROR_OK) return res; if (sector->is_erased != 1) { - res = nrf51_erase_page(bank, chip, sector); + res = nrf5_erase_page(bank, chip, sector); if (res != ERROR_OK) return res; } - res = nrf51_nvmc_write_enable(chip); + res = nrf5_nvmc_write_enable(chip); if (res != ERROR_OK) return res; memcpy(&uicr[offset], buffer, count); - res = nrf51_ll_flash_write(chip, NRF51_UICR_BASE, uicr, NRF51_UICR_SIZE); + res = nrf5_ll_flash_write(chip, NRF5_UICR_BASE, uicr, NRF5_UICR_SIZE); if (res != ERROR_OK) { - nrf51_nvmc_read_only(chip); + nrf5_nvmc_read_only(chip); return res; } - return nrf51_nvmc_read_only(chip); + return nrf5_nvmc_read_only(chip); } -static int nrf51_write(struct flash_bank *bank, const uint8_t *buffer, +static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { int res; - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -907,15 +907,15 @@ static int nrf51_write(struct flash_bank *bank, const uint8_t *buffer, } -FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) +FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command) { - static struct nrf51_info *chip; + static struct nrf5_info *chip; switch (bank->base) { - case NRF51_FLASH_BASE: + case NRF5_FLASH_BASE: bank->bank_number = 0; break; - case NRF51_UICR_BASE: + case NRF5_UICR_BASE: bank->bank_number = 1; break; default: @@ -933,11 +933,11 @@ FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) } switch (bank->base) { - case NRF51_FLASH_BASE: - chip->bank[bank->bank_number].write = nrf51_code_flash_write; + case NRF5_FLASH_BASE: + chip->bank[bank->bank_number].write = nrf5_code_flash_write; break; - case NRF51_UICR_BASE: - chip->bank[bank->bank_number].write = nrf51_uicr_flash_write; + case NRF5_UICR_BASE: + chip->bank[bank->bank_number].write = nrf5_uicr_flash_write; break; } @@ -947,27 +947,27 @@ FLASH_BANK_COMMAND_HANDLER(nrf51_flash_bank_command) return ERROR_OK; } -COMMAND_HANDLER(nrf51_handle_mass_erase_command) +COMMAND_HANDLER(nrf5_handle_mass_erase_command) { int res; struct flash_bank *bank = NULL; struct target *target = get_current_target(CMD_CTX); - res = get_flash_bank_by_addr(target, NRF51_FLASH_BASE, true, &bank); + res = get_flash_bank_by_addr(target, NRF5_FLASH_BASE, true, &bank); if (res != ERROR_OK) return res; assert(bank != NULL); - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; uint32_t ppfc; - res = target_read_u32(target, NRF51_FICR_PPFC, + res = target_read_u32(target, NRF5_FICR_PPFC, &ppfc); if (res != ERROR_OK) { LOG_ERROR("Couldn't read PPFC register"); @@ -980,23 +980,23 @@ COMMAND_HANDLER(nrf51_handle_mass_erase_command) return ERROR_FAIL; } - res = nrf51_erase_all(chip); + res = nrf5_erase_all(chip); if (res != ERROR_OK) { LOG_ERROR("Failed to erase the chip"); - nrf51_protect_check(bank); + nrf5_protect_check(bank); return res; } for (int i = 0; i < bank->num_sectors; i++) bank->sectors[i].is_erased = 1; - res = nrf51_protect_check(bank); + res = nrf5_protect_check(bank); if (res != ERROR_OK) { LOG_ERROR("Failed to check chip's write protection"); return res; } - res = get_flash_bank_by_addr(target, NRF51_UICR_BASE, true, &bank); + res = get_flash_bank_by_addr(target, NRF5_UICR_BASE, true, &bank); if (res != ERROR_OK) return res; @@ -1005,13 +1005,13 @@ COMMAND_HANDLER(nrf51_handle_mass_erase_command) return ERROR_OK; } -static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size) +static int nrf5_info(struct flash_bank *bank, char *buf, int buf_size) { int res; - struct nrf51_info *chip; + struct nrf5_info *chip; - res = nrf51_get_probed_chip_if_halted(bank, &chip); + res = nrf5_get_probed_chip_if_halted(bank, &chip); if (res != ERROR_OK) return res; @@ -1019,45 +1019,45 @@ static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size) const uint32_t address; uint32_t value; } ficr[] = { - { .address = NRF51_FICR_CODEPAGESIZE }, - { .address = NRF51_FICR_CODESIZE }, - { .address = NRF51_FICR_CLENR0 }, - { .address = NRF51_FICR_PPFC }, - { .address = NRF51_FICR_NUMRAMBLOCK }, - { .address = NRF51_FICR_SIZERAMBLOCK0 }, - { .address = NRF51_FICR_SIZERAMBLOCK1 }, - { .address = NRF51_FICR_SIZERAMBLOCK2 }, - { .address = NRF51_FICR_SIZERAMBLOCK3 }, - { .address = NRF51_FICR_CONFIGID }, - { .address = NRF51_FICR_DEVICEID0 }, - { .address = NRF51_FICR_DEVICEID1 }, - { .address = NRF51_FICR_ER0 }, - { .address = NRF51_FICR_ER1 }, - { .address = NRF51_FICR_ER2 }, - { .address = NRF51_FICR_ER3 }, - { .address = NRF51_FICR_IR0 }, - { .address = NRF51_FICR_IR1 }, - { .address = NRF51_FICR_IR2 }, - { .address = NRF51_FICR_IR3 }, - { .address = NRF51_FICR_DEVICEADDRTYPE }, - { .address = NRF51_FICR_DEVICEADDR0 }, - { .address = NRF51_FICR_DEVICEADDR1 }, - { .address = NRF51_FICR_OVERRIDEN }, - { .address = NRF51_FICR_NRF_1MBIT0 }, - { .address = NRF51_FICR_NRF_1MBIT1 }, - { .address = NRF51_FICR_NRF_1MBIT2 }, - { .address = NRF51_FICR_NRF_1MBIT3 }, - { .address = NRF51_FICR_NRF_1MBIT4 }, - { .address = NRF51_FICR_BLE_1MBIT0 }, - { .address = NRF51_FICR_BLE_1MBIT1 }, - { .address = NRF51_FICR_BLE_1MBIT2 }, - { .address = NRF51_FICR_BLE_1MBIT3 }, - { .address = NRF51_FICR_BLE_1MBIT4 }, + { .address = NRF5_FICR_CODEPAGESIZE }, + { .address = NRF5_FICR_CODESIZE }, + { .address = NRF5_FICR_CLENR0 }, + { .address = NRF5_FICR_PPFC }, + { .address = NRF5_FICR_NUMRAMBLOCK }, + { .address = NRF5_FICR_SIZERAMBLOCK0 }, + { .address = NRF5_FICR_SIZERAMBLOCK1 }, + { .address = NRF5_FICR_SIZERAMBLOCK2 }, + { .address = NRF5_FICR_SIZERAMBLOCK3 }, + { .address = NRF5_FICR_CONFIGID }, + { .address = NRF5_FICR_DEVICEID0 }, + { .address = NRF5_FICR_DEVICEID1 }, + { .address = NRF5_FICR_ER0 }, + { .address = NRF5_FICR_ER1 }, + { .address = NRF5_FICR_ER2 }, + { .address = NRF5_FICR_ER3 }, + { .address = NRF5_FICR_IR0 }, + { .address = NRF5_FICR_IR1 }, + { .address = NRF5_FICR_IR2 }, + { .address = NRF5_FICR_IR3 }, + { .address = NRF5_FICR_DEVICEADDRTYPE }, + { .address = NRF5_FICR_DEVICEADDR0 }, + { .address = NRF5_FICR_DEVICEADDR1 }, + { .address = NRF5_FICR_OVERRIDEN }, + { .address = NRF5_FICR_NRF_1MBIT0 }, + { .address = NRF5_FICR_NRF_1MBIT1 }, + { .address = NRF5_FICR_NRF_1MBIT2 }, + { .address = NRF5_FICR_NRF_1MBIT3 }, + { .address = NRF5_FICR_NRF_1MBIT4 }, + { .address = NRF5_FICR_BLE_1MBIT0 }, + { .address = NRF5_FICR_BLE_1MBIT1 }, + { .address = NRF5_FICR_BLE_1MBIT2 }, + { .address = NRF5_FICR_BLE_1MBIT3 }, + { .address = NRF5_FICR_BLE_1MBIT4 }, }, uicr[] = { - { .address = NRF51_UICR_CLENR0, }, - { .address = NRF51_UICR_RBPCONF }, - { .address = NRF51_UICR_XTALFREQ }, - { .address = NRF51_UICR_FWID }, + { .address = NRF5_UICR_CLENR0, }, + { .address = NRF5_UICR_RBPCONF }, + { .address = NRF5_UICR_XTALFREQ }, + { .address = NRF5_UICR_FWID }, }; for (size_t i = 0; i < ARRAY_SIZE(ficr); i++) { @@ -1129,38 +1129,62 @@ static int nrf51_info(struct flash_bank *bank, char *buf, int buf_size) return ERROR_OK; } -static const struct command_registration nrf51_exec_command_handlers[] = { +static const struct command_registration nrf5_exec_command_handlers[] = { { .name = "mass_erase", - .handler = nrf51_handle_mass_erase_command, + .handler = nrf5_handle_mass_erase_command, .mode = COMMAND_EXEC, .help = "Erase all flash contents of the chip.", }, COMMAND_REGISTRATION_DONE }; -static const struct command_registration nrf51_command_handlers[] = { +static const struct command_registration nrf5_command_handlers[] = { + { + .name = "nrf5", + .mode = COMMAND_ANY, + .help = "nrf5 flash command group", + .usage = "", + .chain = nrf5_exec_command_handlers, + }, { .name = "nrf51", .mode = COMMAND_ANY, .help = "nrf51 flash command group", .usage = "", - .chain = nrf51_exec_command_handlers, + .chain = nrf5_exec_command_handlers, }, COMMAND_REGISTRATION_DONE }; +struct flash_driver nrf5_flash = { + .name = "nrf5", + .commands = nrf5_command_handlers, + .flash_bank_command = nrf5_flash_bank_command, + .info = nrf5_info, + .erase = nrf5_erase, + .protect = nrf5_protect, + .write = nrf5_write, + .read = default_flash_read, + .probe = nrf5_probe, + .auto_probe = nrf5_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = nrf5_protect_check, +}; + +/* We need to retain the flash-driver name as well as the commands + * for backwards compatability */ struct flash_driver nrf51_flash = { .name = "nrf51", - .commands = nrf51_command_handlers, - .flash_bank_command = nrf51_flash_bank_command, - .info = nrf51_info, - .erase = nrf51_erase, - .protect = nrf51_protect, - .write = nrf51_write, + .commands = nrf5_command_handlers, + .flash_bank_command = nrf5_flash_bank_command, + .info = nrf5_info, + .erase = nrf5_erase, + .protect = nrf5_protect, + .write = nrf5_write, .read = default_flash_read, - .probe = nrf51_probe, - .auto_probe = nrf51_auto_probe, + .probe = nrf5_probe, + .auto_probe = nrf5_auto_probe, .erase_check = default_flash_blank_check, - .protect_check = nrf51_protect_check, + .protect_check = nrf5_protect_check, }; From 2168c475ff7ca0f2914bee39700952600014ac40 Mon Sep 17 00:00:00 2001 From: Slowcoder Date: Thu, 31 Aug 2017 22:34:16 +0200 Subject: [PATCH 025/127] nrf5: Add nRF52832-QFAA support Change-Id: Ica9e34e873cac182662b1e32a9b3164dbc0c935f Signed-off-by: Slowcoder Reviewed-on: http://openocd.zylin.com/4210 Reviewed-by: Tomas Vanek Tested-by: jenkins Reviewed-by: Spencer Oliver --- src/flash/nor/nrf5.c | 3 +++ tcl/target/nrf52.cfg | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c index 8441c2a07..11e57291c 100644 --- a/src/flash/nor/nrf5.c +++ b/src/flash/nor/nrf5.c @@ -195,6 +195,9 @@ static const struct nrf5_device_spec nrf5_known_devices_table[] = { NRF5_DEVICE_DEF(0x007A, "51422", "CEAA", "C0", 256), NRF5_DEVICE_DEF(0x0088, "51422", "CFAC", "A0", 256), + /* nRF52832 Devices */ + NRF5_DEVICE_DEF(0x00C7, "52832", "QFAA", "B0", 512), + /* Some early nRF51-DK (PCA10028) & nRF51-Dongle (PCA10031) boards with built-in jlink seem to use engineering samples not listed in the nRF51 Series Compatibility Matrix V1.0. */ diff --git a/tcl/target/nrf52.cfg b/tcl/target/nrf52.cfg index c1cbf1a21..e73017503 100644 --- a/tcl/target/nrf52.cfg +++ b/tcl/target/nrf52.cfg @@ -10,6 +10,14 @@ if { [info exists CHIPNAME] } { set _CHIPNAME nrf52 } +# Work-area is a space in RAM used for flash programming +# By default use 16kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x4000 +} + if { [info exists CPUTAPID] } { set _CPUTAPID $CPUTAPID } else { @@ -21,8 +29,13 @@ swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID set _TARGETNAME $_CHIPNAME.cpu target create $_TARGETNAME cortex_m -chain-position $_TARGETNAME -adapter_khz 10000 +adapter_khz 1000 + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 if { ![using_hla] } { cortex_m reset_config sysresetreq } + +flash bank $_CHIPNAME.flash nrf5 0x00000000 0 1 1 $_TARGETNAME +flash bank $_CHIPNAME.uicr nrf5 0x10001000 0 1 1 $_TARGETNAME From 7aafd6195327e6d17747bf0d4f40b79d030ad24f Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 6 Oct 2017 13:55:52 -0700 Subject: [PATCH 026/127] Clean up this JTAG debug code. Change-Id: Ie7c773b98271d11085d5e50c40b64990710de387 --- src/jtag/core.c | 72 +++++++------------------------------------------ 1 file changed, 10 insertions(+), 62 deletions(-) diff --git a/src/jtag/core.c b/src/jtag/core.c index e21d47644..71a731de1 100644 --- a/src/jtag/core.c +++ b/src/jtag/core.c @@ -838,108 +838,57 @@ int default_interface_jtag_execute_queue(void) int result = jtag->execute_queue(); -#if 0 - // TODO: I like these better than some of the other JTAG debug statements, - // but having both is silly. struct jtag_command *cmd = jtag_command_queue; while (debug_level >= LOG_LVL_DEBUG && cmd) { switch (cmd->type) { case JTAG_SCAN: -#if 0 - LOG_DEBUG("JTAG %s SCAN to %s", + DEBUG_JTAG_IO("JTAG %s SCAN to %s", cmd->cmd.scan->ir_scan ? "IR" : "DR", tap_state_name(cmd->cmd.scan->end_state)); for (int i = 0; i < cmd->cmd.scan->num_fields; i++) { struct scan_field *field = cmd->cmd.scan->fields + i; if (field->out_value) { char *str = buf_to_str(field->out_value, field->num_bits, 16); - LOG_DEBUG(" %db out: %s", field->num_bits, str); + DEBUG_JTAG_IO(" %db out: %s", field->num_bits, str); free(str); } if (field->in_value) { char *str = buf_to_str(field->in_value, field->num_bits, 16); - LOG_DEBUG(" %db in: %s", field->num_bits, str); + DEBUG_JTAG_IO(" %db in: %s", field->num_bits, str); free(str); } - if (field->check_value) { - char *str = buf_to_str(field->check_value, field->num_bits, 16); - LOG_DEBUG(" %db check: %s", field->num_bits, str); - free(str); - } - if (field->check_mask) { - char *str = buf_to_str(field->check_mask, field->num_bits, 16); - LOG_DEBUG(" %db mask: %s", field->num_bits, str); - free(str); - } - } -#endif - { - uint8_t *buf = NULL; - int scan_bits = jtag_build_buffer(cmd->cmd.scan, &buf); - char *str_out = buf_to_str(buf, scan_bits, 16); - free(buf); - LOG_DEBUG("vvv jtag_scan(%d, %d, %d'h%s, %d); // %s", - cmd->cmd.scan->ir_scan, - scan_bits, - scan_bits, str_out, - cmd->cmd.scan->end_state, tap_state_name(cmd->cmd.scan->end_state)); - free(str_out); - - struct scan_field *last_field = cmd->cmd.scan->fields + cmd->cmd.scan->num_fields - 1; - if (last_field->in_value) { - char *str_in = buf_to_str(last_field->in_value, last_field->num_bits, 16); - LOG_DEBUG("vvv jtag_check_tdo(%d, %d'h%s);", - last_field->num_bits, - last_field->num_bits, str_in); - free(str_in); - } } break; case JTAG_TLR_RESET: -#if 0 - LOG_DEBUG("JTAG TLR RESET to %s", - tap_state_name(cmd->cmd.statemove->end_state)); -#endif - LOG_DEBUG("vvv jtag_tlr_reset(%d); // %s", - cmd->cmd.statemove->end_state, + DEBUG_JTAG_IO("JTAG TLR RESET to %s", tap_state_name(cmd->cmd.statemove->end_state)); break; case JTAG_RUNTEST: -#if 0 - LOG_DEBUG("JTAG RUNTEST %d cycles to %s", + DEBUG_JTAG_IO("JTAG RUNTEST %d cycles to %s", cmd->cmd.runtest->num_cycles, tap_state_name(cmd->cmd.runtest->end_state)); -#endif - LOG_DEBUG("vvv jtag_runtest(%d, %d); // %s", - cmd->cmd.runtest->num_cycles, - cmd->cmd.runtest->end_state, - tap_state_name(cmd->cmd.runtest->end_state)); break; case JTAG_RESET: { -#if 0 const char *reset_str[3] = { "leave", "deassert", "assert" }; - LOG_DEBUG("JTAG RESET %s TRST, %s SRST", + DEBUG_JTAG_IO("JTAG RESET %s TRST, %s SRST", reset_str[cmd->cmd.reset->trst + 1], reset_str[cmd->cmd.reset->srst + 1]); -#endif - LOG_DEBUG("vvv jtag_reset(%d, %d);", - cmd->cmd.reset->trst, cmd->cmd.reset->srst); } break; case JTAG_PATHMOVE: - LOG_DEBUG("JTAG PATHMOVE (TODO)"); + DEBUG_JTAG_IO("JTAG PATHMOVE (TODO)"); break; case JTAG_SLEEP: - LOG_DEBUG("JTAG SLEEP (TODO)"); + DEBUG_JTAG_IO("JTAG SLEEP (TODO)"); break; case JTAG_STABLECLOCKS: - LOG_DEBUG("JTAG STABLECLOCKS (TODO)"); + DEBUG_JTAG_IO("JTAG STABLECLOCKS (TODO)"); break; case JTAG_TMS: - LOG_DEBUG("JTAG STABLECLOCKS (TODO)"); + DEBUG_JTAG_IO("JTAG STABLECLOCKS (TODO)"); break; default: LOG_ERROR("Unknown JTAG command: %d", cmd->type); @@ -947,7 +896,6 @@ int default_interface_jtag_execute_queue(void) } cmd = cmd->next; } -#endif return result; } From 77802af655fef154a1eff30d59e699c11917ecd2 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 10 Oct 2017 16:27:51 -0700 Subject: [PATCH 027/127] Remove duplicate progbuf size variable. Change-Id: I662ff84d13ecfc7faae51406a4df57a3643116f0 --- src/target/riscv/riscv-013.c | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index f17ef72e6..f8fd7e67e 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -32,7 +32,6 @@ static void riscv013_on_step_or_resume(struct target *target, bool step); static void riscv013_step_or_resume_current_hart(struct target *target, bool step); static riscv_addr_t riscv013_progbuf_addr(struct target *target); -static riscv_addr_t riscv013_progbuf_size(struct target *target); static riscv_addr_t riscv013_data_size(struct target *target); static riscv_addr_t riscv013_data_addr(struct target *target); static void riscv013_set_autoexec(struct target *target, unsigned index, @@ -176,7 +175,7 @@ typedef struct { bool need_strict_step; // Some memoized values - int progbuf_size, progbuf_addr, data_addr, data_size; + int progbuf_addr, data_addr, data_size; bool abstract_read_csr_supported; bool abstract_write_csr_supported; @@ -908,7 +907,7 @@ static int init_target(struct command_context *cmd_ctx, return ERROR_FAIL; riscv013_info_t *info = get_info(target); - info->progbuf_size = -1; + info->progsize = -1; info->progbuf_addr = -1; info->data_size = -1; info->data_addr = -1; @@ -1078,7 +1077,7 @@ static int examine(struct target *target) /* Without knowing anything else we can at least mess with the * program buffer. */ - r->debug_buffer_size[i] = riscv013_progbuf_size(target); + r->debug_buffer_size[i] = info->progsize; /* Guess this is a 32-bit system, we're probing it. */ r->xlen[i] = 32; @@ -1874,15 +1873,17 @@ void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *pr void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { - if (index >= riscv013_progbuf_size(target)) - return dmi_write(target, DMI_DATA0 + index - riscv013_progbuf_size(target), data); + RISCV013_INFO(info); + if (index >= info->progsize) + return dmi_write(target, DMI_DATA0 + index - info->progsize, data); return dmi_write(target, DMI_PROGBUF0 + index, data); } riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { - if (index >= riscv013_progbuf_size(target)) - return dmi_read(target, DMI_DATA0 + index - riscv013_progbuf_size(target)); + RISCV013_INFO(info); + if (index >= info->progsize) + return dmi_read(target, DMI_DATA0 + index - info->progsize); return dmi_read(target, DMI_PROGBUF0 + index); } @@ -1998,16 +1999,6 @@ riscv_addr_t riscv013_progbuf_addr(struct target *target) return info->progbuf_addr; } -riscv_addr_t riscv013_progbuf_size(struct target *target) -{ - RISCV013_INFO(info); - if (info->progbuf_size == -1) { - uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); - info->progbuf_size = get_field(acs, DMI_ABSTRACTCS_PROGSIZE); - } - return info->progbuf_size; -} - riscv_addr_t riscv013_data_size(struct target *target) { RISCV013_INFO(info); @@ -2030,12 +2021,13 @@ riscv_addr_t riscv013_data_addr(struct target *target) void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled) { - if (index >= riscv013_progbuf_size(target)) { + RISCV013_INFO(info); + if (index >= info->progsize) { LOG_DEBUG("setting bit %d in AUTOEXECDATA to %d", index, enabled); uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO); uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA); - aa_aed &= ~(1 << (index - riscv013_progbuf_size(target))); - aa_aed |= (enabled << (index - riscv013_progbuf_size(target))); + aa_aed &= ~(1 << (index - info->progsize)); + aa_aed |= (enabled << (index - info->progsize)); aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA, aa_aed); dmi_write(target, DMI_ABSTRACTAUTO, aa); } else { From 94e82507134610180843d70c8b244d98de26171a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 12 Oct 2017 11:45:52 -0700 Subject: [PATCH 028/127] WIP; doesn't work. Change-Id: Ia407e82ccbd2044ad61e0845d285dd5765154476 --- src/target/riscv/program.c | 71 ------------------- src/target/riscv/program.h | 16 ----- src/target/riscv/riscv-013.c | 129 +++++++++++++++-------------------- src/target/riscv/riscv.c | 9 --- src/target/riscv/riscv.h | 4 -- 5 files changed, 55 insertions(+), 174 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index d052574d4..2fc80419b 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -100,77 +100,6 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) return ERROR_OK; } -riscv_addr_t riscv_program_alloc_data(struct riscv_program *p, size_t bytes) -{ - riscv_addr_t addr = - riscv_debug_buffer_addr(p->target) - + riscv_debug_buffer_size(p->target) * sizeof(p->debug_buffer[0]) - - p->data_count * sizeof(p->debug_buffer[0]) - - bytes; - while (addr % bytes != 0) addr--; - - riscv_addr_t ptop = - riscv_debug_buffer_addr(p->target) - + p->instruction_count * sizeof(p->debug_buffer[0]); - - if (addr <= ptop) { - LOG_ERROR("unable to allocate %d bytes", (int)bytes); - return RISCV_PROGRAM_ALLOC_FAIL; - } - - p->data_count = - + riscv_debug_buffer_size(p->target) - - (addr - riscv_debug_buffer_addr(p->target)) / sizeof(p->debug_buffer[0]); - return addr; -} - -riscv_addr_t riscv_program_alloc_x(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, p->target_xlen / 8); -} - -riscv_addr_t riscv_program_alloc_d(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, 8); -} - -riscv_addr_t riscv_program_alloc_w(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, 4); -} - -riscv_addr_t riscv_program_alloc_h(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, 2); -} - -riscv_addr_t riscv_program_alloc_b(struct riscv_program *p) -{ - return riscv_program_alloc_data(p, 1); -} - -riscv_insn_t riscv_program_read_ram(struct riscv_program *p, riscv_addr_t addr) -{ - if (addr < riscv_debug_buffer_addr(p->target)) - return -1; - if ((size_t)addr > riscv_debug_buffer_addr(p->target) + (riscv_debug_buffer_size(p->target) * sizeof(p->debug_buffer[0]))) - return -1; - - int off = (addr - riscv_debug_buffer_addr(p->target)) / sizeof(p->debug_buffer[0]); - return p->debug_buffer[off]; -} - -void riscv_program_write_ram(struct riscv_program *p, riscv_addr_t addr, uint64_t d) -{ - if (addr < riscv_debug_buffer_addr(p->target)) - return; - if ((size_t)addr > riscv_debug_buffer_addr(p->target) + (riscv_debug_buffer_size(p->target) * sizeof(p->debug_buffer[0]))) - return; - - int off = (addr - riscv_debug_buffer_addr(p->target)) / sizeof(p->debug_buffer[0]); - p->debug_buffer[off] = d; -} - int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { p->writes_memory = 1; diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index ac1127ed9..82e9b5e99 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -60,22 +60,6 @@ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i); * memory. */ int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_save); -/* Allocates data of various sizes. Either returns the absolute physical - * address or RISCV_PROGRAM_ALLOC_FAIL on failure. */ -riscv_addr_t riscv_program_alloc_data(struct riscv_program *p, size_t bytes); -riscv_addr_t riscv_program_alloc_x(struct riscv_program *p); -riscv_addr_t riscv_program_alloc_d(struct riscv_program *p); -riscv_addr_t riscv_program_alloc_w(struct riscv_program *p); -riscv_addr_t riscv_program_alloc_h(struct riscv_program *p); -riscv_addr_t riscv_program_alloc_b(struct riscv_program *p); -#define RISCV_PROGRAM_ALLOC_FAIL ((riscv_addr_t)(-1)) - -/* Reads a word of memory from this program's internal view of the debug RAM. - * This is what you want to use to get data back from the program after it - * executes. */ -riscv_insn_t riscv_program_read_ram(struct riscv_program *p, riscv_addr_t addr); -void riscv_program_write_ram(struct riscv_program *p, riscv_addr_t a, uint64_t d); - /* Helpers to assembly various instructions. Return 0 on success. These might * assembly into a multi-instruction sequence that overwrites some other * register, but those will be properly saved and restored. */ diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index f8fd7e67e..483c5237b 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -31,13 +31,13 @@ static void riscv013_on_step_or_resume(struct target *target, bool step); static void riscv013_step_or_resume_current_hart(struct target *target, bool step); -static riscv_addr_t riscv013_progbuf_addr(struct target *target); -static riscv_addr_t riscv013_data_size(struct target *target); -static riscv_addr_t riscv013_data_addr(struct target *target); -static void riscv013_set_autoexec(struct target *target, unsigned index, - bool enabled); -static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); -static void riscv013_clear_abstract_error(struct target *target); +//static riscv_addr_t riscv013_progbuf_addr(struct target *target); +//static riscv_addr_t riscv013_data_size(struct target *target); +//static riscv_addr_t riscv013_data_addr(struct target *target); +//static void riscv013_set_autoexec(struct target *target, unsigned index, + //bool enabled); +//static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); +//static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ static riscv_reg_t riscv013_get_register(struct target *target, int hartid, int regid); @@ -517,6 +517,7 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value) } } +#if 0 static void increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); @@ -525,6 +526,7 @@ static void increase_ac_busy_delay(struct target *target) info->dtmcontrol_idle, info->dmi_busy_delay, info->ac_busy_delay); } +#endif uint32_t abstract_register_size(unsigned width) { @@ -769,6 +771,8 @@ static int register_write_direct(struct target *target, unsigned number, riscv_program_init(&program, target); + assert(0); +#if 0 riscv_addr_t input = riscv_program_alloc_d(&program); riscv_program_write_ram(&program, input + 4, value >> 32); riscv_program_write_ram(&program, input, value); @@ -794,6 +798,7 @@ static int register_write_direct(struct target *target, unsigned number, } return ERROR_OK; +#endif } /** Actually read registers from the target right now. */ @@ -805,6 +810,22 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t if (result != ERROR_OK) { struct riscv_program program; riscv_program_init(&program, target); + assert(0); + assert(number != GDB_REGNO_S0); + + uint64_t s0; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + // Write program to move data into s0. + // Execute program. + // Read S0 + if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + // Restore S0. + if (register_write_direct(target, GDB_REGNO_S0, &s0) != ERROR_OK) + return ERROR_FAIL; +#if 0 riscv_addr_t output = riscv_program_alloc_d(&program); riscv_program_write_ram(&program, output + 4, 0); riscv_program_write_ram(&program, output, 0); @@ -833,6 +854,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t *value = 0; *value |= ((uint64_t)(riscv_program_read_ram(&program, output + 4))) << 32; *value |= riscv_program_read_ram(&program, output); +#endif } LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), @@ -1080,77 +1102,19 @@ static int examine(struct target *target) r->debug_buffer_size[i] = info->progsize; /* Guess this is a 32-bit system, we're probing it. */ - r->xlen[i] = 32; - - /* First find the low 32 bits of the program buffer. This is - * used to check for alignment. */ - struct riscv_program program32; - riscv_program_init(&program32, target); - riscv_program_csrrw(&program32, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); - riscv_program_insert(&program32, auipc(GDB_REGNO_S0)); - riscv_program_insert(&program32, sw(GDB_REGNO_S0, GDB_REGNO_S0, -4)); - riscv_program_csrrw(&program32, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); - riscv_program_fence(&program32); - riscv_program_exec(&program32, target); - - riscv_addr_t progbuf_addr = dmi_read(target, DMI_PROGBUF0) - 4; - if (get_field(dmi_read(target, DMI_ABSTRACTCS), DMI_ABSTRACTCS_CMDERR) != 0) { - LOG_ERROR("Unable to find the address of the program buffer on hart %d", i); - r->xlen[i] = -1; - continue; - } - r->debug_buffer_addr[i] = progbuf_addr; - - /* Check to see if the core can execute 64 bit instructions. - * In order to make this work we first need to */ - int offset = (progbuf_addr % 8 == 0) ? -4 : 0; - - /* This program uses a temporary register. If the core can not - * execute 64 bit instruction, the original value of temporary - * register (s0) will not be restored due to an exception. - * So we have to save it and restore manually in that case. - * If the core can execute 64 bit instruction, the saved value - * is wrong, because it was read with 32 bit lw instruction, - * but the value of s0 will be restored by the reverse swap - * of s0 and dscratch registers. */ - uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0); - - struct riscv_program program64; - riscv_program_init(&program64, target); - riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); - riscv_program_insert(&program64, auipc(GDB_REGNO_S0)); - riscv_program_insert(&program64, sd(GDB_REGNO_S0, GDB_REGNO_S0, offset)); - riscv_program_csrrw(&program64, GDB_REGNO_S0, GDB_REGNO_S0, GDB_REGNO_DSCRATCH); - riscv_program_fence(&program64); - int result = riscv_program_exec(&program64, target); + // >>> r->xlen[i] = 32; + uint64_t value; + int result = register_read_abstract(target, &value, GDB_REGNO_S0, 64); if (result == ERROR_OK) { - r->debug_buffer_addr[i] = - (dmi_read(target, DMI_PROGBUF0 + (8 + offset) / 4) << 32) - + dmi_read(target, DMI_PROGBUF0 + (4 + offset) / 4) - - 4; r->xlen[i] = 64; } else { - riscv_set_register(target, GDB_REGNO_S0, s0); + r->xlen[i] = 32; } /* Display this as early as possible to help people who are using * really slow simulators. */ - LOG_DEBUG(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64, i, - r->xlen[i], r->debug_buffer_addr[i]); - - if (riscv_program_gah(&program64, r->debug_buffer_addr[i])) { - LOG_ERROR("This implementation will not work with hart %d with debug_buffer_addr of 0x%lx", i, - (long)r->debug_buffer_addr[i]); - abort(); - } - - /* Check to see if we can use the data words as an extended - * program buffer or not. */ - if (r->debug_buffer_addr[i] + (4 * r->debug_buffer_size[i]) == riscv013_data_addr(target)) { - r->debug_buffer_size[i] += riscv013_data_size(target); - LOG_DEBUG("extending the debug buffer using data words, total size %d", r->debug_buffer_size[i]); - } + LOG_DEBUG(" hart %d: XLEN=%d", i, r->xlen[i]); } /* Then we check the number of triggers availiable to each hart. */ @@ -1172,8 +1136,7 @@ static int examine(struct target *target) riscv_count_harts(target)); for (int i = 0; i < riscv_count_harts(target); ++i) { if (riscv_hart_enabled(target, i)) { - LOG_INFO(" hart %d: XLEN=%d, program buffer at 0x%" PRIx64 - ", %d triggers", i, r->xlen[i], r->debug_buffer_addr[i], + LOG_INFO(" hart %d: XLEN=%d, %d triggers", i, r->xlen[i], r->trigger_count[i]); } else { LOG_INFO(" hart %d: currently disabled", i); @@ -1296,6 +1259,7 @@ static int deassert_reset(struct target *target) return ERROR_OK; } +#if 0 static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) { switch (size) { @@ -1316,6 +1280,7 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) assert(false); } } +#endif /** * Read the requested memory, taking care to execute every read exactly once, @@ -1324,7 +1289,7 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - RISCV013_INFO(info); + //RISCV013_INFO(info); LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); @@ -1342,6 +1307,8 @@ static int read_memory(struct target *target, target_addr_t address, struct riscv_program program; riscv_program_init(&program, target); + assert(0); +#if 0 riscv_addr_t r_data = riscv_program_alloc_w(&program); riscv_addr_t r_addr = riscv_program_alloc_x(&program); riscv_program_fence(&program); @@ -1496,6 +1463,7 @@ static int read_memory(struct target *target, target_addr_t address, riscv_addr_t addr = cur_addr - size; write_to_buf(buffer + addr - address, value, size); LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); +#endif riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); @@ -1505,7 +1473,7 @@ static int read_memory(struct target *target, target_addr_t address, static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - RISCV013_INFO(info); + //RISCV013_INFO(info); LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); @@ -1522,6 +1490,8 @@ static int write_memory(struct target *target, target_addr_t address, struct riscv_program program; riscv_program_init(&program, target); + assert(0); +#if 0 riscv_addr_t r_data = riscv_program_alloc_w(&program); riscv_addr_t r_addr = riscv_program_alloc_x(&program); riscv_program_fence(&program); @@ -1682,6 +1652,7 @@ static int write_memory(struct target *target, target_addr_t address, } riscv013_set_autoexec(target, d_data, 0); +#endif riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); return ERROR_OK; @@ -1992,13 +1963,16 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste abort(); } +#if 0 riscv_addr_t riscv013_progbuf_addr(struct target *target) { RISCV013_INFO(info); assert(info->progbuf_addr != -1); return info->progbuf_addr; } +#endif +#if 0 riscv_addr_t riscv013_data_size(struct target *target) { RISCV013_INFO(info); @@ -2008,7 +1982,9 @@ riscv_addr_t riscv013_data_size(struct target *target) } return info->data_size; } +#endif +#if 0 riscv_addr_t riscv013_data_addr(struct target *target) { RISCV013_INFO(info); @@ -2018,7 +1994,9 @@ riscv_addr_t riscv013_data_addr(struct target *target) } return info->data_addr; } +#endif +#if 0 void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled) { RISCV013_INFO(info); @@ -2040,7 +2018,9 @@ void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled) dmi_write(target, DMI_ABSTRACTAUTO, aa); } } +#endif +#if 0 int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) { if (addr >= riscv013_data_addr(target)) @@ -2069,3 +2049,4 @@ void riscv013_clear_abstract_error(struct target *target) // Clear the error status. dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR); } +#endif diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a8fc4378c..80ecfff77 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1235,7 +1235,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r) for (size_t h = 0; h < RISCV_MAX_HARTS; ++h) { r->xlen[h] = -1; - r->debug_buffer_addr[h] = -1; for (size_t e = 0; e < RISCV_MAX_REGISTERS; ++e) r->valid_saved_registers[h][e] = false; @@ -1483,14 +1482,6 @@ size_t riscv_debug_buffer_size(struct target *target) return r->debug_buffer_size[riscv_current_hartid(target)]; } -riscv_addr_t riscv_debug_buffer_addr(struct target *target) -{ - RISCV_INFO(r); - riscv_addr_t out = r->debug_buffer_addr[riscv_current_hartid(target)]; - assert((out & 3) == 0); - return out; -} - int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program) { RISCV_INFO(r); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 1197cbfbc..192d5c9fa 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -72,9 +72,6 @@ typedef struct { * target controls, while otherwise only a single hart is controlled. */ int trigger_unique_id[RISCV_MAX_HWBPS]; - /* The address of the debug RAM buffer. */ - riscv_addr_t debug_buffer_addr[RISCV_MAX_HARTS]; - /* The number of entries in the debug buffer. */ int debug_buffer_size[RISCV_MAX_HARTS]; @@ -213,7 +210,6 @@ int riscv_count_triggers_of_hart(struct target *target, int hartid); /* These helper functions let the generic program interface get target-specific * information. */ size_t riscv_debug_buffer_size(struct target *target); -riscv_addr_t riscv_debug_buffer_addr(struct target *target); int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program); int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program); From e7bb815e87ff36e58ef4e5a5b8d7cc3e4518ec23 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 12 Oct 2017 14:38:52 -0700 Subject: [PATCH 029/127] Register read/write might be working. Change-Id: I6c51d6157dde56d8cd666b4d30ec7bbc7a4bef9f --- src/target/riscv/program.c | 3 +- src/target/riscv/riscv-013.c | 136 +++++++++++++++++------------------ 2 files changed, 67 insertions(+), 72 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 2fc80419b..36e3f3910 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -40,6 +40,7 @@ int riscv_program_init(struct riscv_program *p, struct target *target) return ERROR_OK; } +/** Add ebreak and execute the program. */ int riscv_program_exec(struct riscv_program *p, struct target *t) { keep_alive(); @@ -258,7 +259,7 @@ int riscv_program_sb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t add int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr) { - assert(csr >= GDB_REGNO_CSR0); + assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); return riscv_program_insert(p, csrrs(d, GDB_REGNO_X0, csr - GDB_REGNO_CSR0)); } diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 483c5237b..0ff104d97 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -37,7 +37,7 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste //static void riscv013_set_autoexec(struct target *target, unsigned index, //bool enabled); //static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); -//static void riscv013_clear_abstract_error(struct target *target); +static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ static riscv_reg_t riscv013_get_register(struct target *target, int hartid, int regid); @@ -62,6 +62,7 @@ static void riscv013_fill_dmi_write_u64(struct target *target, char *buf, int a, static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); static int riscv013_dmi_write_u64_bits(struct target *target); static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); +static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -771,21 +772,21 @@ static int register_write_direct(struct target *target, unsigned number, riscv_program_init(&program, target); - assert(0); -#if 0 - riscv_addr_t input = riscv_program_alloc_d(&program); - riscv_program_write_ram(&program, input + 4, value >> 32); - riscv_program_write_ram(&program, input, value); + uint64_t s0; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; - assert(GDB_REGNO_XPR0 == 0); - if (number <= GDB_REGNO_XPR31) { - riscv_program_lx(&program, number, input); - } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - riscv_program_flx(&program, number, input); + if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { + riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); + } else { + riscv_program_insert(&program, fmv_x_s(S0, number - GDB_REGNO_FPR0)); + } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - enum gdb_regno temp = riscv_program_gettemp(&program); - riscv_program_lx(&program, temp, input); - riscv_program_csrw(&program, temp, number); + riscv_program_csrw(&program, S0, number); } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); abort(); @@ -797,8 +798,11 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_FAIL; } + // Restore S0. + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; -#endif } /** Actually read registers from the target right now. */ @@ -810,7 +814,6 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t if (result != ERROR_OK) { struct riscv_program program; riscv_program_init(&program, target); - assert(0); assert(number != GDB_REGNO_S0); uint64_t s0; @@ -818,43 +821,34 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return ERROR_FAIL; // Write program to move data into s0. - // Execute program. - // Read S0 - if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; - // Restore S0. - if (register_write_direct(target, GDB_REGNO_S0, &s0) != ERROR_OK) - return ERROR_FAIL; -#if 0 - riscv_addr_t output = riscv_program_alloc_d(&program); - riscv_program_write_ram(&program, output + 4, 0); - riscv_program_write_ram(&program, output, 0); - - assert(GDB_REGNO_XPR0 == 0); - if (number <= GDB_REGNO_XPR31) { - riscv_program_sx(&program, number, output); - } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - riscv_program_fsx(&program, number, output); + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + // TODO: Possibly set F in mstatus. + // TODO: Fully support D extension on RV32. + if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { + riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); + } else { + riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); + } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - LOG_DEBUG("reading CSR index=0x%03x", number - GDB_REGNO_CSR0); - enum gdb_regno temp = riscv_program_gettemp(&program); - riscv_program_csrr(&program, temp, number); - riscv_program_sx(&program, temp, output); + riscv_program_csrr(&program, S0, number); } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); abort(); } + // Execute program. int exec_out = riscv_program_exec(&program, target); if (exec_out != ERROR_OK) { riscv013_clear_abstract_error(target); return ERROR_FAIL; } - *value = 0; - *value |= ((uint64_t)(riscv_program_read_ram(&program, output + 4))) << 32; - *value |= riscv_program_read_ram(&program, output); -#endif + // Read S0 + if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + // Restore S0. + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; } LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), @@ -1539,14 +1533,14 @@ static int write_memory(struct target *target, target_addr_t address, } switch (riscv_xlen(target)) { - case 64: - riscv_program_write_ram(&program, r_addr + 4, (uint64_t)address >> 32); - case 32: - riscv_program_write_ram(&program, r_addr, address); - break; - default: - LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); - return ERROR_FAIL; + case 64: + riscv_program_write_ram(&program, r_addr + 4, (uint64_t)address >> 32); + case 32: + riscv_program_write_ram(&program, r_addr, address); + break; + default: + LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); + return ERROR_FAIL; } riscv_program_write_ram(&program, r_data, value); @@ -1582,9 +1576,9 @@ static int write_memory(struct target *target, target_addr_t address, riscv_addr_t start = (cur_addr - address) / size; assert (cur_addr > address); struct riscv_batch *batch = riscv_batch_alloc( - target, - 32, - info->dmi_busy_delay + info->ac_busy_delay); + target, + 32, + info->dmi_busy_delay + info->ac_busy_delay); for (riscv_addr_t i = start; i < count; ++i) { riscv_addr_t offset = size*i; @@ -1613,9 +1607,9 @@ static int write_memory(struct target *target, target_addr_t address, LOG_DEBUG("M[0x%08lx] writes 0x%08x", (long)t_addr, value); riscv_batch_add_dmi_write( - batch, - riscv013_debug_buffer_register(target, r_data), - value); + batch, + riscv013_debug_buffer_register(target, r_data), + value); if (riscv_batch_full(batch)) break; } @@ -1633,21 +1627,21 @@ static int write_memory(struct target *target, target_addr_t address, abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); switch (info->cmderr) { - case CMDERR_NONE: - LOG_DEBUG("successful (partial?) memory write"); - break; - case CMDERR_BUSY: - LOG_DEBUG("memory write resulted in busy response"); - riscv013_clear_abstract_error(target); - increase_ac_busy_delay(target); - break; - default: - LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_set_autoexec(target, d_data, 0); - riscv013_clear_abstract_error(target); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - return ERROR_FAIL; + case CMDERR_NONE: + LOG_DEBUG("successful (partial?) memory write"); + break; + case CMDERR_BUSY: + LOG_DEBUG("memory write resulted in busy response"); + riscv013_clear_abstract_error(target); + increase_ac_busy_delay(target); + break; + default: + LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); + riscv013_set_autoexec(target, d_data, 0); + riscv013_clear_abstract_error(target); + riscv_set_register(target, GDB_REGNO_S0, s0); + riscv_set_register(target, GDB_REGNO_S1, s1); + return ERROR_FAIL; } } @@ -2028,6 +2022,7 @@ int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) else return DMI_PROGBUF0 + (addr - riscv013_progbuf_addr(target)) / 4; } +#endif void riscv013_clear_abstract_error(struct target *target) { @@ -2049,4 +2044,3 @@ void riscv013_clear_abstract_error(struct target *target) // Clear the error status. dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR); } -#endif From 7ec7bc32fe01f632bdfa02649d92cdad9019e28e Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 13 Oct 2017 12:50:02 -0700 Subject: [PATCH 030/127] At least some memory writes work. Change-Id: I6fcf261341f10ec34df01bb844744439d02471a8 --- src/target/riscv/program.c | 23 ++-- src/target/riscv/program.h | 3 + src/target/riscv/riscv-013.c | 196 ++++++++++++++--------------------- 3 files changed, 93 insertions(+), 129 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 36e3f3910..8981ea33f 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -40,6 +40,17 @@ int riscv_program_init(struct riscv_program *p, struct target *target) return ERROR_OK; } +int riscv_program_write(struct riscv_program *program) +{ + for (unsigned i = 0; i < riscv_debug_buffer_size(program->target); ++i) { + LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", program, i, program->debug_buffer[i]); + if (riscv_write_debug_buffer(program->target, i, + program->debug_buffer[i]) != ERROR_OK) + return ERROR_FAIL; + } + return ERROR_OK; +} + /** Add ebreak and execute the program. */ int riscv_program_exec(struct riscv_program *p, struct target *t) { @@ -74,16 +85,8 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) return ERROR_FAIL; } - for (unsigned i = 0; i < riscv_debug_buffer_size(p->target); ++i) { - if (i < p->instruction_count) { - LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", p, i, p->debug_buffer[i]); - riscv_write_debug_buffer(t, i, p->debug_buffer[i]); - } - if (i >= riscv_debug_buffer_size(p->target) - p->data_count) { - LOG_DEBUG("%p: debug_buffer[%02x] = 0x%08x", p, i, p->debug_buffer[i]); - riscv_write_debug_buffer(t, i, p->debug_buffer[i]); - } - } + if (riscv_program_write(p) != ERROR_OK) + return ERROR_FAIL; if (riscv_execute_debug_buffer(t) != ERROR_OK) { LOG_ERROR("Unable to execute program %p", p); diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index 82e9b5e99..e5f6c29e2 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -40,6 +40,9 @@ struct riscv_program { /* Initializes a program with the header. */ int riscv_program_init(struct riscv_program *p, struct target *t); +/* Write the program to the program buffer. */ +int riscv_program_write(struct riscv_program *program); + /* Executes a program, returning 0 if the program successfully executed. Note * that this may cause registers to be saved or restored, which could result to * calls to things like riscv_save_register which itself could require a diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 0ff104d97..ec921dcff 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -34,8 +34,6 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste //static riscv_addr_t riscv013_progbuf_addr(struct target *target); //static riscv_addr_t riscv013_data_size(struct target *target); //static riscv_addr_t riscv013_data_addr(struct target *target); -//static void riscv013_set_autoexec(struct target *target, unsigned index, - //bool enabled); //static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); static void riscv013_clear_abstract_error(struct target *target); @@ -518,7 +516,6 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value) } } -#if 0 static void increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); @@ -527,7 +524,6 @@ static void increase_ac_busy_delay(struct target *target) info->dtmcontrol_idle, info->dmi_busy_delay, info->ac_busy_delay); } -#endif uint32_t abstract_register_size(unsigned width) { @@ -1467,30 +1463,26 @@ static int read_memory(struct target *target, target_addr_t address, static int write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - //RISCV013_INFO(info); + RISCV013_INFO(info); LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); + /* + * s0 holds the next address to write to + * s1 holds the next data value to write + */ + select_dmi(target); - /* This program uses two temporary registers. A word of data and the - * associated address are stored at some location in memory. The - * program stores the word to that address and then increments the - * address. The debugger is expected to feed the memory word-by-word - * into the chip with AUTOEXEC set in order to trigger program - * execution on every word. */ - uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0); - uint64_t s1 = riscv_get_register(target, GDB_REGNO_S1); + uint64_t s0, s1; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + // Write the program (store, increment) struct riscv_program program; riscv_program_init(&program, target); - assert(0); -#if 0 - riscv_addr_t r_data = riscv_program_alloc_w(&program); - riscv_addr_t r_addr = riscv_program_alloc_x(&program); - riscv_program_fence(&program); - riscv_program_lx(&program, GDB_REGNO_S0, r_addr); - riscv_program_lw(&program, GDB_REGNO_S1, r_data); switch (size) { case 1: @@ -1508,83 +1500,35 @@ static int write_memory(struct target *target, target_addr_t address, } riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); - riscv_program_sx(&program, GDB_REGNO_S0, r_addr); - /* The first round through the program's execution we use the regular - * program execution mechanism. */ - uint32_t value; - switch (size) { - case 1: - value = buffer[0]; - break; - case 2: - value = buffer[0] - | ((uint32_t) buffer[1] << 8); - break; - case 4: - value = buffer[0] - | ((uint32_t) buffer[1] << 8) - | ((uint32_t) buffer[2] << 16) - | ((uint32_t) buffer[3] << 24); - break; - default: - LOG_ERROR("unsupported access size: %d", size); - return ERROR_FAIL; - } - - switch (riscv_xlen(target)) { - case 64: - riscv_program_write_ram(&program, r_addr + 4, (uint64_t)address >> 32); - case 32: - riscv_program_write_ram(&program, r_addr, address); - break; - default: - LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); - return ERROR_FAIL; - } - riscv_program_write_ram(&program, r_data, value); - - LOG_DEBUG("M[0x%08lx] writes 0x%08x", (long)address, value); - - if (riscv_program_exec(&program, target) != ERROR_OK) { - uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); - LOG_ERROR("failed to execute program, abstractcs=0x%08x", acs); - riscv013_clear_abstract_error(target); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - LOG_ERROR(" exiting with ERROR_FAIL"); + if (riscv_debug_buffer_leave(target, &program) != ERROR_OK) return ERROR_FAIL; - } - /* The rest of this program is designed to be fast so it reads various - * DMI registers directly. */ - int d_data = (r_data - riscv_debug_buffer_addr(target)) / 4; - int d_addr = (r_addr - riscv_debug_buffer_addr(target)) / 4; + riscv_program_write(&program); - riscv013_set_autoexec(target, d_data, 1); + if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) + return ERROR_FAIL; - /* Copying memory might fail because we're going too quickly, in which - * case we need to back off a bit and try again. There's two - * termination conditions to this loop: a non-BUSY error message, or - * the data was all copied. */ - riscv_addr_t cur_addr = 0xbadbeef; + riscv_addr_t cur_addr = address; riscv_addr_t fin_addr = address + (count * size); + bool setup_needed = true; LOG_DEBUG("writing until final address 0x%016" PRIx64, fin_addr); - while ((cur_addr = riscv_read_debug_buffer_x(target, d_addr)) < fin_addr) { + while (cur_addr < fin_addr) { LOG_DEBUG("transferring burst starting at address 0x%016" PRIx64, cur_addr); - riscv_addr_t start = (cur_addr - address) / size; - assert (cur_addr > address); + struct riscv_batch *batch = riscv_batch_alloc( target, 32, info->dmi_busy_delay + info->ac_busy_delay); - for (riscv_addr_t i = start; i < count; ++i) { - riscv_addr_t offset = size*i; - riscv_addr_t t_addr = address + offset; + /* To write another word, we put it in S1 and execute the program. */ + unsigned start = (cur_addr - address) / size; + for (unsigned i = start; i < count; ++i) { + unsigned offset = size*i; const uint8_t *t_buffer = buffer + offset; + uint32_t value; switch (size) { case 1: value = t_buffer[0]; @@ -1604,14 +1548,44 @@ static int write_memory(struct target *target, target_addr_t address, return ERROR_FAIL; } - LOG_DEBUG("M[0x%08lx] writes 0x%08x", (long)t_addr, value); + LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value); - riscv_batch_add_dmi_write( - batch, - riscv013_debug_buffer_register(target, r_data), - value); - if (riscv_batch_full(batch)) - break; + if (setup_needed) { + // Write value. + dmi_write(target, DMI_DATA0, value); + + // Write and execute command that moves value into S0 and + // executes program buffer. + uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); + switch (size) { + case 32: + command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2); + break; + case 64: + command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); + break; + default: + LOG_ERROR("Unsupported abstract register read size: %d", size); + return ERROR_FAIL; + } + command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 1); + command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1); + command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1); + command = set_field(command, AC_ACCESS_REGISTER_REGNO, + 0x1000 + GDB_REGNO_S1 - GDB_REGNO_XPR0); + int result = execute_abstract_command(target, command); + if (result != ERROR_OK) + return result; + + // Turn on autoexec + dmi_write(target, DMI_ABSTRACTAUTO, + 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + } else { + riscv_batch_add_dmi_write(batch, DMI_DATA0, value); + if (riscv_batch_full(batch)) + break; + } + cur_addr += size; } riscv_batch_run(batch); @@ -1619,8 +1593,7 @@ static int write_memory(struct target *target, target_addr_t address, // Note that if the scan resulted in a Busy DMI response, it // is this read to abstractcs that will cause the dmi_busy_delay - // to be incremented if necessary. The loop condition above - // catches the case where no writes went through at all. + // to be incremented if necessary. uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) @@ -1634,10 +1607,16 @@ static int write_memory(struct target *target, target_addr_t address, LOG_DEBUG("memory write resulted in busy response"); riscv013_clear_abstract_error(target); increase_ac_busy_delay(target); + + dmi_write(target, DMI_ABSTRACTAUTO, 0); + if (register_read_direct(target, &cur_addr, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + setup_needed = true; break; + default: LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_set_autoexec(target, d_data, 0); + dmi_write(target, DMI_ABSTRACTAUTO, 0); riscv013_clear_abstract_error(target); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); @@ -1645,10 +1624,13 @@ static int write_memory(struct target *target, target_addr_t address, } } - riscv013_set_autoexec(target, d_data, 0); -#endif - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); + dmi_write(target, DMI_ABSTRACTAUTO, 0); + + if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) + return ERROR_FAIL; + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; } @@ -1990,30 +1972,6 @@ riscv_addr_t riscv013_data_addr(struct target *target) } #endif -#if 0 -void riscv013_set_autoexec(struct target *target, unsigned index, bool enabled) -{ - RISCV013_INFO(info); - if (index >= info->progsize) { - LOG_DEBUG("setting bit %d in AUTOEXECDATA to %d", index, enabled); - uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO); - uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA); - aa_aed &= ~(1 << (index - info->progsize)); - aa_aed |= (enabled << (index - info->progsize)); - aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECDATA, aa_aed); - dmi_write(target, DMI_ABSTRACTAUTO, aa); - } else { - LOG_DEBUG("setting bit %d in AUTOEXECPROGBUF to %d", index, enabled); - uint32_t aa = dmi_read(target, DMI_ABSTRACTAUTO); - uint32_t aa_aed = get_field(aa, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF); - aa_aed &= ~(1 << index); - aa_aed |= (enabled << index); - aa = set_field(aa, DMI_ABSTRACTAUTO_AUTOEXECPROGBUF, aa_aed); - dmi_write(target, DMI_ABSTRACTAUTO, aa); - } -} -#endif - #if 0 int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) { From 0e02fe40c64ad7488aeb351641723e1eb9ae49cb Mon Sep 17 00:00:00 2001 From: Peter Griffin Date: Mon, 12 Jun 2017 16:28:03 +0100 Subject: [PATCH 031/127] tcl: add hi3798 target and Tocoding Poplar board config This config covers the 4x Cortex A53 CPUs. A custom connector is required from J14 to standard ARM JTAG on v1 boards. However v2 hardware should have a standard FTSH-105-01-L-DV connector. Pinmuxing code to enable JTAG pins is included in l-loader-poplar repository, so board is flashed with open source code, JTAG is available at very early boot. Alternatively the following pokes can be issued from U-Boot to enable JTAG (e.g. to debug hisilicon SDK). mw 0xf8a210ec 0x130; mw 0xf8a210f0 0x130; mw 0xf8a210f4 0x130; mw 0xf8a210f8 0x130; mw 0xf8a210fc 0x130; mw 0xf8a21100 0x130; Change-Id: I2b83dfcb3dc5461c1620f94dd99aa7b31fdda59b Signed-off-by: Peter Griffin Reviewed-on: http://openocd.zylin.com/4161 Tested-by: jenkins Reviewed-by: Jiri Kastner Reviewed-by: Paul Fertser --- tcl/board/tocoding_poplar.cfg | 28 ++++++++++++++++++++ tcl/target/hi3798.cfg | 49 +++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tcl/board/tocoding_poplar.cfg create mode 100644 tcl/target/hi3798.cfg diff --git a/tcl/board/tocoding_poplar.cfg b/tcl/board/tocoding_poplar.cfg new file mode 100644 index 000000000..fd6615605 --- /dev/null +++ b/tcl/board/tocoding_poplar.cfg @@ -0,0 +1,28 @@ +# +# board configuration for Tocoding Poplar +# + +# board does not feature anything but JTAG +transport select jtag + +adapter_khz 10000 + +# SRST-only reset configuration +reset_config srst_only srst_push_pull + +source [find tcl/target/hi3798.cfg] + +# halt the cores when gdb attaches +${_TARGETNAME}0 configure -event gdb-attach "halt" + +# make sure the default target is the boot core +targets ${_TARGETNAME}0 + +proc core_up { args } { + global _TARGETNAME + + # examine remaining cores + foreach _core [set args] { + ${_TARGETNAME}$_core arp_examine + } +} diff --git a/tcl/target/hi3798.cfg b/tcl/target/hi3798.cfg new file mode 100644 index 000000000..9eda15035 --- /dev/null +++ b/tcl/target/hi3798.cfg @@ -0,0 +1,49 @@ +# Hisilicon Hi3798 Target + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME hi3798 +} + +# +# Main DAP +# +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x5ba00477 +} + +# declare the one JTAG tap to access the DAP +jtag newtap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable + +# declare the 4 main application cores +set _TARGETNAME $_CHIPNAME.cpu +set _smp_command "" + +set $_TARGETNAME.cti(0) 0x80020000 +set $_TARGETNAME.cti(1) 0x80120000 +set $_TARGETNAME.cti(2) 0x80220000 +set $_TARGETNAME.cti(3) 0x80320000 + +set _cores 4 +for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + + set _command "target create ${_TARGETNAME}$_core aarch64 \ + -chain-position $_CHIPNAME.dap -coreid $_core -ctibase [set $_TARGETNAME.cti($_core)]" + + if { $_core != 0 } { + # non-boot core examination may fail + #set _command "$_command -defer-examine" + set _smp_command "$_smp_command ${_TARGETNAME}$_core" + } else { + # uncomment when "hawt" rtos is merged + # set _command "$_command -rtos hawt" + set _smp_command "target smp ${_TARGETNAME}$_core" + } + + eval $_command +} + +eval $_smp_command From d94b38279a10f7e9d012a225be8d78cd8e5f1e39 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 16 Oct 2017 20:38:35 -0700 Subject: [PATCH 032/127] Memtest{16,32} pass. Change-Id: I15c2a4fd2bb9a7b30762d07f3b3a74d2f477746b --- src/target/riscv/program.c | 19 +-- src/target/riscv/riscv-013.c | 303 ++++++++++++++--------------------- src/target/riscv/riscv.c | 14 -- src/target/riscv/riscv.h | 5 - 4 files changed, 125 insertions(+), 216 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 8981ea33f..7175fa344 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -32,17 +32,12 @@ int riscv_program_init(struct riscv_program *p, struct target *target) for(size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i) p->debug_buffer[i] = -1; - if (riscv_debug_buffer_enter(target, p) != ERROR_OK) { - LOG_ERROR("unable to write progam buffer enter code"); - return ERROR_FAIL; - } - return ERROR_OK; } int riscv_program_write(struct riscv_program *program) { - for (unsigned i = 0; i < riscv_debug_buffer_size(program->target); ++i) { + for (unsigned i = 0; i < program->instruction_count; ++i) { LOG_DEBUG("%p: debug_buffer[%02x] = DASM(0x%08x)", program, i, program->debug_buffer[i]); if (riscv_write_debug_buffer(program->target, i, program->debug_buffer[i]) != ERROR_OK) @@ -56,11 +51,6 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) { keep_alive(); - if (riscv_debug_buffer_leave(t, p) != ERROR_OK) { - LOG_ERROR("unable to write program buffer exit code"); - return ERROR_FAIL; - } - riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1]; for (size_t i = GDB_REGNO_XPR0 + 1; i <= GDB_REGNO_XPR31; ++i) { if (p->writes_xreg[i]) { @@ -290,6 +280,11 @@ int riscv_program_fence(struct riscv_program *p) int riscv_program_ebreak(struct riscv_program *p) { + if (p->instruction_count == riscv_debug_buffer_size(p->target)) { + // TODO: Check for impebreak bit. + // There's an implicit ebreak here, so no need for us to add one. + return ERROR_OK; + } return riscv_program_insert(p, ebreak()); } @@ -441,7 +436,7 @@ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); LOG_ERROR(" data_count =%d", (int)p->data_count); LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); - return ERROR_FAIL; + abort(); } p->debug_buffer[p->instruction_count] = i; diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index ec921dcff..a34bda07b 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -49,8 +49,6 @@ static void riscv013_on_step(struct target *target); static void riscv013_on_resume(struct target *target); static bool riscv013_is_halted(struct target *target); static enum riscv_halt_reason riscv013_halt_reason(struct target *target); -static void riscv013_debug_buffer_enter(struct target *target, struct riscv_program *p); -static void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *p); static void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t d); static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned @@ -637,11 +635,12 @@ static int write_abstract_arg(struct target *target, unsigned index, return ERROR_OK; } -static int register_read_abstract(struct target *target, uint64_t *value, - uint32_t number, unsigned size) +/** + * @size in bits + */ +static uint32_t access_register_command(uint32_t number, unsigned size, + uint32_t flags) { - RISCV013_INFO(r); - uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); switch (size) { case 32: @@ -651,38 +650,50 @@ static int register_read_abstract(struct target *target, uint64_t *value, command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); break; default: - LOG_ERROR("Unsupported abstract register read size: %d", size); - return ERROR_FAIL; + assert(0); } - command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0); - command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1); - command = set_field(command, AC_ACCESS_REGISTER_WRITE, 0); if (number <= GDB_REGNO_XPR31) { command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0x1000 + number - GDB_REGNO_XPR0); } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (!r->abstract_read_fpr_supported) - return ERROR_FAIL; command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0x1020 + number - GDB_REGNO_FPR0); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - if (!r->abstract_read_csr_supported) - return ERROR_FAIL; command = set_field(command, AC_ACCESS_REGISTER_REGNO, number - GDB_REGNO_CSR0); } else { - return ERROR_FAIL; + assert(0); } + command |= flags; + + return command; +} + +static int register_read_abstract(struct target *target, uint64_t *value, + uint32_t number, unsigned size) +{ + RISCV013_INFO(info); + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + !info->abstract_read_fpr_supported) + return ERROR_FAIL; + if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && + !info->abstract_read_csr_supported) + return ERROR_FAIL; + + uint32_t command = access_register_command(number, size, + AC_ACCESS_REGISTER_TRANSFER); + int result = execute_abstract_command(target, command); if (result != ERROR_OK) { - if (r->cmderr == CMDERR_NOT_SUPPORTED) { + if (info->cmderr == CMDERR_NOT_SUPPORTED) { if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - r->abstract_read_fpr_supported = false; + info->abstract_read_fpr_supported = false; LOG_INFO("Disabling abstract command reads from FPRs."); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - r->abstract_read_csr_supported = false; + info->abstract_read_csr_supported = false; LOG_INFO("Disabling abstract command reads from CSRs."); } } @@ -699,38 +710,16 @@ static int register_write_abstract(struct target *target, uint32_t number, { RISCV013_INFO(info); - uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); - switch (size) { - case 32: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2); - break; - case 64: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); - break; - default: - LOG_ERROR("Unsupported abstract register read size: %d", size); - return ERROR_FAIL; - } - command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 0); - command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1); - command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1); - - if (number <= GDB_REGNO_XPR31) { - command = set_field(command, AC_ACCESS_REGISTER_REGNO, - 0x1000 + number - GDB_REGNO_XPR0); - } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (!info->abstract_read_fpr_supported) - return ERROR_FAIL; - command = set_field(command, AC_ACCESS_REGISTER_REGNO, - 0x1020 + number - GDB_REGNO_FPR0); - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - if (!info->abstract_read_csr_supported) - return ERROR_FAIL; - command = set_field(command, AC_ACCESS_REGISTER_REGNO, - number - GDB_REGNO_CSR0); - } else { + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + !info->abstract_write_fpr_supported) return ERROR_FAIL; - } + if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && + !info->abstract_write_csr_supported) + return ERROR_FAIL; + + uint32_t command = access_register_command(number, size, + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_WRITE); if (write_abstract_arg(target, 0, value) != ERROR_OK) { return ERROR_FAIL; @@ -905,8 +894,6 @@ static int init_target(struct command_context *cmd_ctx, generic_info->on_resume = &riscv013_on_resume; generic_info->on_step = &riscv013_on_step; generic_info->halt_reason = &riscv013_halt_reason; - generic_info->debug_buffer_enter = &riscv013_debug_buffer_enter; - generic_info->debug_buffer_leave = &riscv013_debug_buffer_leave; generic_info->read_debug_buffer = &riscv013_read_debug_buffer; generic_info->write_debug_buffer = &riscv013_write_debug_buffer; generic_info->execute_debug_buffer = &riscv013_execute_debug_buffer; @@ -1249,7 +1236,9 @@ static int deassert_reset(struct target *target) return ERROR_OK; } -#if 0 +/** + * @size in bytes + */ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) { switch (size) { @@ -1270,7 +1259,6 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) assert(false); } } -#endif /** * Read the requested memory, taking care to execute every read exactly once, @@ -1279,30 +1267,27 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) static int read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - //RISCV013_INFO(info); + RISCV013_INFO(info); LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); select_dmi(target); - /* This program uses two temporary registers. A word of data and the - * associated address are stored at some location in memory. The - * program loads the word from that address and then increments the - * address. The debugger is expected to pull the memory word-by-word - * from the chip with AUTOEXEC set in order to trigger program - * execution on every word. */ - uint64_t s0 = riscv_get_register(target, GDB_REGNO_S0); - uint64_t s1 = riscv_get_register(target, GDB_REGNO_S1); + /* s0 holds the next address to write to + * s1 holds the next data value to write + */ + uint64_t s0, s1; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + // Write the program (load, increment) struct riscv_program program; riscv_program_init(&program, target); - assert(0); -#if 0 - riscv_addr_t r_data = riscv_program_alloc_w(&program); - riscv_addr_t r_addr = riscv_program_alloc_x(&program); - riscv_program_fence(&program); - riscv_program_lx(&program, GDB_REGNO_S0, r_addr); + + // TODO: riscv_program_fence(&program); switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); @@ -1318,70 +1303,43 @@ static int read_memory(struct target *target, target_addr_t address, return ERROR_FAIL; } riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); - riscv_program_sw(&program, GDB_REGNO_S1, r_data); - riscv_program_sx(&program, GDB_REGNO_S0, r_addr); - /* The first round through the program's execution we use the regular - * program execution mechanism. */ - switch (riscv_xlen(target)) { - case 64: - riscv_program_write_ram(&program, r_addr + 4, ((riscv_addr_t) address) >> 32); - case 32: - riscv_program_write_ram(&program, r_addr, (riscv_addr_t) address); - break; - default: - LOG_ERROR("unknown XLEN %d", riscv_xlen(target)); + if (riscv_program_ebreak(&program) != ERROR_OK) return ERROR_FAIL; - } + riscv_program_write(&program); - if (riscv_program_exec(&program, target) != ERROR_OK) { - uint32_t acs = dmi_read(target, DMI_ABSTRACTCS); - LOG_ERROR("failed to execute program, abstractcs=0x%08x", acs); - riscv013_clear_abstract_error(target); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - LOG_ERROR(" exiting with ERROR_FAIL"); + // Write address to S0, and execute buffer. + if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) + return ERROR_FAIL; + if (execute_abstract_command(target, + access_register_command(GDB_REGNO_S1, riscv_xlen(target), + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_POSTEXEC)) != ERROR_OK) return ERROR_FAIL; - } - // Program has been executed once. d_addr contains address+size, and d_data - // contains *address. - - /* The rest of this program is designed to be fast so it reads various - * DMI registers directly. */ - int d_data = (r_data - riscv_debug_buffer_addr(target)) / 4; - int d_addr = (r_addr - riscv_debug_buffer_addr(target)) / 4; - - riscv013_set_autoexec(target, d_data, 1); + dmi_write(target, DMI_ABSTRACTAUTO, + 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); /* Copying memory might fail because we're going too quickly, in which - * case we need to back off a bit and try again. There's two - * termination conditions to this loop: a non-BUSY error message, or - * the data was all copied. */ - riscv_addr_t cur_addr = riscv_read_debug_buffer_x(target, d_addr); + * case we need to back off a bit and try again. */ + riscv_addr_t cur_addr = address; riscv_addr_t fin_addr = address + (count * size); LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr); - while (cur_addr < fin_addr) { + while (cur_addr < fin_addr - size) { // Invariant: - // d_data contains *addr - // d_addr contains addr + size + // s0 contains the next address to read + // s1 contains the data read at the previous address unsigned start = (cur_addr - address) / size; LOG_DEBUG("creating burst to read address 0x%" TARGET_PRIxADDR " up to 0x%" TARGET_PRIxADDR "; start=0x%d", cur_addr, fin_addr, start); assert(cur_addr >= address && cur_addr < fin_addr); - struct riscv_batch *batch = riscv_batch_alloc( - target, - 32, - info->dmi_busy_delay + info->ac_busy_delay); + struct riscv_batch *batch = riscv_batch_alloc(target, 32, + info->dmi_busy_delay + info->ac_busy_delay); size_t reads = 0; - for (riscv_addr_t addr = cur_addr; addr < fin_addr; addr += size) { - size_t const index = - riscv_batch_add_dmi_read( - batch, - riscv013_debug_buffer_register(target, r_data)); - assert(index == reads); + for (riscv_addr_t addr = cur_addr; addr < fin_addr - size; addr += size) { + riscv_batch_add_dmi_read(batch, DMI_DATA0); reads++; if (riscv_batch_full(batch)) @@ -1397,37 +1355,37 @@ static int read_memory(struct target *target, target_addr_t address, abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); + riscv_addr_t next_addr; switch (info->cmderr) { - case CMDERR_NONE: - LOG_DEBUG("successful (partial?) memory read"); - break; - case CMDERR_BUSY: - LOG_DEBUG("memory read resulted in busy response"); - increase_ac_busy_delay(target); - riscv013_clear_abstract_error(target); - break; - default: - LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); - riscv013_set_autoexec(target, d_data, 0); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - riscv013_clear_abstract_error(target); - riscv_batch_free(batch); - return ERROR_FAIL; - } + case CMDERR_NONE: + LOG_DEBUG("successful (partial?) memory read"); + next_addr = cur_addr + reads * size; + break; + case CMDERR_BUSY: + LOG_DEBUG("memory read resulted in busy response"); + increase_ac_busy_delay(target); + riscv013_clear_abstract_error(target); - // Figure out how far we managed to read. - riscv_addr_t next_addr = riscv_read_debug_buffer_x(target, d_addr); - LOG_DEBUG("Batch read [0x%" TARGET_PRIxADDR ", 0x%" TARGET_PRIxADDR - "); reads=%d", cur_addr, next_addr, (unsigned) reads); - assert(next_addr >= address && next_addr <= fin_addr); - assert(info->cmderr != CMDERR_NONE || - next_addr == cur_addr + reads * size); + dmi_write(target, DMI_ABSTRACTAUTO, 0); + if (register_read_direct(target, &next_addr, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + next_addr -= size; + dmi_write(target, DMI_ABSTRACTAUTO, + 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + break; + default: + LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); + dmi_write(target, DMI_ABSTRACTAUTO, 0); + riscv_set_register(target, GDB_REGNO_S0, s0); + riscv_set_register(target, GDB_REGNO_S1, s1); + riscv013_clear_abstract_error(target); + riscv_batch_free(batch); + return ERROR_FAIL; + } // Now read whatever we got out of the batch. unsigned rereads = 0; - for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size; - addr += size) { + for (riscv_addr_t addr = cur_addr; addr < next_addr; addr += size) { riscv_addr_t offset = addr - address; uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); @@ -1443,17 +1401,14 @@ static int read_memory(struct target *target, target_addr_t address, cur_addr = next_addr; } - riscv013_set_autoexec(target, d_data, 0); + dmi_write(target, DMI_ABSTRACTAUTO, 0); // Read the last word. - - // Access debug buffer without executing a program. This - // address logic was taken from program.c. - uint32_t value = riscv013_read_debug_buffer(target, d_data); - riscv_addr_t addr = cur_addr - size; - write_to_buf(buffer + addr - address, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); -#endif + uint64_t value; + if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) + return ERROR_FAIL; + write_to_buf(buffer + cur_addr - address, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, cur_addr, value); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); @@ -1467,13 +1422,12 @@ static int write_memory(struct target *target, target_addr_t address, LOG_DEBUG("writing %d words of %d bytes to 0x%08lx", count, size, (long)address); - /* - * s0 holds the next address to write to + select_dmi(target); + + /* s0 holds the next address to write to * s1 holds the next data value to write */ - select_dmi(target); - uint64_t s0, s1; if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; @@ -1501,14 +1455,10 @@ static int write_memory(struct target *target, target_addr_t address, riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); - if (riscv_debug_buffer_leave(target, &program) != ERROR_OK) + if (riscv_program_ebreak(&program) != ERROR_OK) return ERROR_FAIL; - riscv_program_write(&program); - if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) - return ERROR_FAIL; - riscv_addr_t cur_addr = address; riscv_addr_t fin_addr = address + (count * size); bool setup_needed = true; @@ -1551,28 +1501,19 @@ static int write_memory(struct target *target, target_addr_t address, LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value); if (setup_needed) { + if (register_write_direct(target, GDB_REGNO_S0, + address + offset) != ERROR_OK) + return ERROR_FAIL; + // Write value. dmi_write(target, DMI_DATA0, value); // Write and execute command that moves value into S0 and // executes program buffer. - uint32_t command = set_field(0, DMI_COMMAND_CMDTYPE, 0); - switch (size) { - case 32: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 2); - break; - case 64: - command = set_field(command, AC_ACCESS_REGISTER_SIZE, 3); - break; - default: - LOG_ERROR("Unsupported abstract register read size: %d", size); - return ERROR_FAIL; - } - command = set_field(command, AC_ACCESS_REGISTER_POSTEXEC, 1); - command = set_field(command, AC_ACCESS_REGISTER_TRANSFER, 1); - command = set_field(command, AC_ACCESS_REGISTER_WRITE, 1); - command = set_field(command, AC_ACCESS_REGISTER_REGNO, - 0x1000 + GDB_REGNO_S1 - GDB_REGNO_XPR0); + uint32_t command = access_register_command(GDB_REGNO_S1, 32, + AC_ACCESS_REGISTER_POSTEXEC | + AC_ACCESS_REGISTER_TRANSFER | + AC_ACCESS_REGISTER_WRITE); int result = execute_abstract_command(target, command); if (result != ERROR_OK) return result; @@ -1810,14 +1751,6 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) abort(); } -void riscv013_debug_buffer_enter(struct target *target, struct riscv_program *program) -{ -} - -void riscv013_debug_buffer_leave(struct target *target, struct riscv_program *program) -{ -} - void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { RISCV013_INFO(info); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 80ecfff77..820094da3 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1482,20 +1482,6 @@ size_t riscv_debug_buffer_size(struct target *target) return r->debug_buffer_size[riscv_current_hartid(target)]; } -int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program) -{ - RISCV_INFO(r); - r->debug_buffer_enter(target, program); - return ERROR_OK; -} - -int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program) -{ - RISCV_INFO(r); - r->debug_buffer_leave(target, program); - return ERROR_OK; -} - int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn) { RISCV_INFO(r); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 192d5c9fa..e7b0ea2db 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -92,8 +92,6 @@ typedef struct { void (*on_resume)(struct target *target); void (*on_step)(struct target *target); enum riscv_halt_reason (*halt_reason)(struct target *target); - void (*debug_buffer_enter)(struct target *target, struct riscv_program *program); - void (*debug_buffer_leave)(struct target *target, struct riscv_program *program); void (*write_debug_buffer)(struct target *target, unsigned index, riscv_insn_t d); riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index); @@ -211,9 +209,6 @@ int riscv_count_triggers_of_hart(struct target *target, int hartid); * information. */ size_t riscv_debug_buffer_size(struct target *target); -int riscv_debug_buffer_enter(struct target *target, struct riscv_program *program); -int riscv_debug_buffer_leave(struct target *target, struct riscv_program *program); - riscv_insn_t riscv_read_debug_buffer(struct target *target, int index); riscv_addr_t riscv_read_debug_buffer_x(struct target *target, int index); int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn); From fbe2980eb737fa3083ad35c94acdda32579f1929 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 17 Oct 2017 11:15:51 -0700 Subject: [PATCH 033/127] MemTest64 passes. Change-Id: I75996b71c3f31025c89ef596a08e01d191405336 --- src/target/riscv/batch.c | 3 +-- src/target/riscv/riscv-013.c | 19 +++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index 1e6a4be92..1e6db42b8 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -49,13 +49,12 @@ void riscv_batch_run(struct riscv_batch *batch) return; } - keep_alive(); + keep_alive(); LOG_DEBUG("running a batch of %ld scans", (long)batch->used_scans); riscv_batch_add_nop(batch); for (size_t i = 0; i < batch->used_scans; ++i) { - dump_field(batch->fields + i); jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); if (batch->idle_count > 0) jtag_add_runtest(batch->idle_count, TAP_IDLE); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index a34bda07b..71be76df1 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1316,6 +1316,7 @@ static int read_memory(struct target *target, target_addr_t address, AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC)) != ERROR_OK) return ERROR_FAIL; + // First read has just triggered. Result is in s1. dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); @@ -1329,6 +1330,7 @@ static int read_memory(struct target *target, target_addr_t address, // Invariant: // s0 contains the next address to read // s1 contains the data read at the previous address + // dmdata0 contains the data read at the previous previous address unsigned start = (cur_addr - address) / size; LOG_DEBUG("creating burst to read address 0x%" TARGET_PRIxADDR @@ -1385,7 +1387,10 @@ static int read_memory(struct target *target, target_addr_t address, // Now read whatever we got out of the batch. unsigned rereads = 0; - for (riscv_addr_t addr = cur_addr; addr < next_addr; addr += size) { + for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size; addr += size) { + if (addr < address) + continue; + riscv_addr_t offset = addr - address; uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); @@ -1403,6 +1408,14 @@ static int read_memory(struct target *target, target_addr_t address, dmi_write(target, DMI_ABSTRACTAUTO, 0); + if (count > 1) { + // Read the penultimate word. + uint64_t value = dmi_read(target, DMI_DATA0); + write_to_buf(buffer + cur_addr - size - address, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, cur_addr - + size, value); + } + // Read the last word. uint64_t value; if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) @@ -1508,7 +1521,7 @@ static int write_memory(struct target *target, target_addr_t address, // Write value. dmi_write(target, DMI_DATA0, value); - // Write and execute command that moves value into S0 and + // Write and execute command that moves value into S1 and // executes program buffer. uint32_t command = access_register_command(GDB_REGNO_S1, 32, AC_ACCESS_REGISTER_POSTEXEC | @@ -1521,6 +1534,8 @@ static int write_memory(struct target *target, target_addr_t address, // Turn on autoexec dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); + + setup_needed = false; } else { riscv_batch_add_dmi_write(batch, DMI_DATA0, value); if (riscv_batch_full(batch)) From 65be0776d8301daddee9c517e7a7a2c154313dd2 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 17 Oct 2017 11:52:07 -0700 Subject: [PATCH 034/127] Memory read/write works if the core can keep up. Change-Id: Ieca50ece266fbc9d2ff16a5cc2e6b4b926ad5e6f --- src/target/riscv/riscv-013.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 71be76df1..15102907a 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1388,18 +1388,15 @@ static int read_memory(struct target *target, target_addr_t address, // Now read whatever we got out of the batch. unsigned rereads = 0; for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size; addr += size) { - if (addr < address) - continue; - - riscv_addr_t offset = addr - address; - - uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); - uint32_t value = get_field(dmi_out, DTM_DMI_DATA); - write_to_buf(buffer + offset, value, size); + if (addr >= address) { + riscv_addr_t offset = addr - address; + uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); + uint32_t value = get_field(dmi_out, DTM_DMI_DATA); + write_to_buf(buffer + offset, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); + } rereads++; - - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); } riscv_batch_free(batch); @@ -1512,6 +1509,7 @@ static int write_memory(struct target *target, target_addr_t address, } LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value); + cur_addr += size; if (setup_needed) { if (register_write_direct(target, GDB_REGNO_S0, @@ -1541,7 +1539,6 @@ static int write_memory(struct target *target, target_addr_t address, if (riscv_batch_full(batch)) break; } - cur_addr += size; } riscv_batch_run(batch); From a0623b2fa83eeeef91b83f193c98a1354d5963f9 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 17 Oct 2017 11:58:51 -0700 Subject: [PATCH 035/127] Don't crash when encountering RV64. Change-Id: Ie915ce830c3499919e4918ad443a5e225cf8c4d9 --- src/target/riscv/riscv-013.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 15102907a..8e7a2f01c 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -700,7 +700,8 @@ static int register_read_abstract(struct target *target, uint64_t *value, return result; } - *value = read_abstract_arg(target, 0); + if (value) + *value = read_abstract_arg(target, 0); return ERROR_OK; } @@ -1078,11 +1079,7 @@ static int examine(struct target *target) * program buffer. */ r->debug_buffer_size[i] = info->progsize; - /* Guess this is a 32-bit system, we're probing it. */ - // >>> r->xlen[i] = 32; - - uint64_t value; - int result = register_read_abstract(target, &value, GDB_REGNO_S0, 64); + int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); if (result == ERROR_OK) { r->xlen[i] = 64; } else { @@ -1371,7 +1368,6 @@ static int read_memory(struct target *target, target_addr_t address, dmi_write(target, DMI_ABSTRACTAUTO, 0); if (register_read_direct(target, &next_addr, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - next_addr -= size; dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); break; From 1356be121ef97509a3318c62380930689b0b3f76 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Sun, 8 Oct 2017 12:03:25 -0700 Subject: [PATCH 036/127] Document `struct reg` fields. Change-Id: I286316079e2e4d4f09427a4ffbecadb48c5dc9d9 Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4250 Tested-by: jenkins Reviewed-by: Liviu Ionescu Reviewed-by: Andreas Fritiofson --- src/target/register.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/target/register.h b/src/target/register.h index d3b2c31c2..dc18e9a89 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -114,17 +114,32 @@ struct reg_data_type { }; struct reg { + /* Canonical name of the register. */ const char *name; + /* Number that gdb uses to access this register. */ uint32_t number; + /* TODO. This should probably be const. */ struct reg_feature *feature; + /* TODO: When true, the caller will save this register before running any algorithm. */ bool caller_save; + /* Pointer to place where the value is stored, in the format understood by + * the binarybuffer.h functions. */ void *value; + /* The stored value needs to be written to the target. */ bool dirty; + /* When true, value is valid. */ bool valid; + /* When false, the register doesn't actually exist in the target. */ bool exist; + /* Size of the register in bits. */ uint32_t size; + /* Used for generating XML description of registers. Can be set to NULL for + * targets that don't use that. */ struct reg_data_type *reg_data_type; + /* Used for generating XML description of registers. Can be set to NULL for + * targets that don't use that. */ const char *group; + /* Pointer to architecture-specific info for this register. */ void *arch_info; const struct reg_arch_type *type; }; From 1662508911bdf8f86a4f19f6b9eb701c58e9d328 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 6 Oct 2017 14:36:34 -0700 Subject: [PATCH 037/127] Differentiate "target not halted" messages. Change-Id: I8728fa007289d7af5c6791142e76eb5777c83ca4 Signed-off-by: Tim Newsome Reviewed-on: http://openocd.zylin.com/4244 Tested-by: jenkins Reviewed-by: Liviu Ionescu Reviewed-by: Andreas Fritiofson --- src/target/target.c | 16 ++++++++-------- src/target/target_type.h | 1 + 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/target/target.c b/src/target/target.c index 8f9766694..07fe453d9 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -1098,7 +1098,7 @@ int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if ((target->state != TARGET_HALTED) && (breakpoint->type != BKPT_HARD)) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_breakpoint(target, breakpoint); @@ -1108,7 +1108,7 @@ int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add context breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_context_breakpoint(target, breakpoint); @@ -1118,7 +1118,7 @@ int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add hybrid breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_hybrid_breakpoint(target, breakpoint); @@ -1134,7 +1134,7 @@ int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add watchpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_watchpoint(target, watchpoint); @@ -1148,7 +1148,7 @@ int target_hit_watchpoint(struct target *target, struct watchpoint **hit_watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target->cmd_name); + LOG_WARNING("target %s is not halted (hit watchpoint)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } @@ -1177,7 +1177,7 @@ int target_step(struct target *target, int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target->cmd_name); + LOG_WARNING("target %s is not halted (gdb fileio)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } return target->type->get_gdb_fileio_info(target, fileio_info); @@ -1186,7 +1186,7 @@ int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fi int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target->cmd_name); + LOG_WARNING("target %s is not halted (gdb fileio end)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } return target->type->gdb_fileio_end(target, retcode, fileio_errno, ctrl_c); @@ -1196,7 +1196,7 @@ int target_profiling(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target->cmd_name); + LOG_WARNING("target %s is not halted (profiling)", target->cmd_name); return ERROR_TARGET_NOT_HALTED; } return target->type->profiling(target, samples, max_num_samples, diff --git a/src/target/target_type.h b/src/target/target_type.h index 34e2778ad..0960e6d59 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -53,6 +53,7 @@ struct target_type { /* halt will log a warning, but return ERROR_OK if the target is already halted. */ int (*halt)(struct target *target); + /* See target.c target_resume() for documentation. */ int (*resume)(struct target *target, int current, target_addr_t address, int handle_breakpoints, int debug_execution); int (*step)(struct target *target, int current, target_addr_t address, From 7edd9b17862570352c4c70729f2f141ec06f8325 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 Oct 2017 11:27:28 -0700 Subject: [PATCH 038/127] Fix FPR access. Change-Id: I1379de87904f1cf40b45d1a5490249e3ba90d7d0 --- src/target/riscv/riscv-013.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 8e7a2f01c..70531e9ad 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -767,9 +767,9 @@ static int register_write_direct(struct target *target, unsigned number, if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { - riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); + riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); } else { - riscv_program_insert(&program, fmv_x_s(S0, number - GDB_REGNO_FPR0)); + riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrw(&program, S0, number); @@ -811,9 +811,9 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t // TODO: Possibly set F in mstatus. // TODO: Fully support D extension on RV32. if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { - riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); + riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); } else { - riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); + riscv_program_insert(&program, fmv_x_s(S0, number - GDB_REGNO_FPR0)); } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrr(&program, S0, number); @@ -1086,9 +1086,12 @@ static int examine(struct target *target) r->xlen[i] = 32; } + r->misa = riscv_get_register_on_hart(target, i, GDB_REGNO_MISA); + /* Display this as early as possible to help people who are using * really slow simulators. */ - LOG_DEBUG(" hart %d: XLEN=%d", i, r->xlen[i]); + LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, i, r->xlen[i], + r->misa); } /* Then we check the number of triggers availiable to each hart. */ From 5d3f5c35d285fe7dc684fcbd94d3c5a8b4e8b8e1 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 Oct 2017 12:32:41 -0700 Subject: [PATCH 039/127] Still restore registers if an access failed. Change-Id: I11571f0926f69a34f95b4929f633fdecd3a4e810 --- src/target/riscv/riscv-013.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 70531e9ad..5495516b0 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -781,14 +781,13 @@ static int register_write_direct(struct target *target, unsigned number, int exec_out = riscv_program_exec(&program, target); if (exec_out != ERROR_OK) { riscv013_clear_abstract_error(target); - return ERROR_FAIL; } // Restore S0. if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; - return ERROR_OK; + return exec_out; } /** Actually read registers from the target right now. */ @@ -798,6 +797,8 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t riscv_xlen(target)); if (result != ERROR_OK) { + result = ERROR_OK; + struct riscv_program program; riscv_program_init(&program, target); assert(number != GDB_REGNO_S0); @@ -823,10 +824,9 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t } // Execute program. - int exec_out = riscv_program_exec(&program, target); - if (exec_out != ERROR_OK) { + result = riscv_program_exec(&program, target); + if (result != ERROR_OK) { riscv013_clear_abstract_error(target); - return ERROR_FAIL; } // Read S0 @@ -837,9 +837,12 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return ERROR_FAIL; } - LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), - number, *value); - return ERROR_OK; + if (result == ERROR_OK) { + LOG_DEBUG("[%d] reg[0x%x] = 0x%" PRIx64, riscv_current_hartid(target), + number, *value); + } + + return result; } /*** OpenOCD target functions. ***/ From 85bfab36ad549aa53e5054bb5b850d11f8f80386 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 Oct 2017 12:43:03 -0700 Subject: [PATCH 040/127] Remove unused functionality. Change-Id: I0c1464e2e6aa12d0cb1025ed0a7c1c483e7403b7 --- src/target/riscv/program.c | 63 ++------------------------------------ src/target/riscv/program.h | 13 +------- 2 files changed, 3 insertions(+), 73 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 7175fa344..b4f2b55ad 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -21,7 +21,6 @@ int riscv_program_init(struct riscv_program *p, struct target *target) memset(p, 0, sizeof(*p)); p->target = target; p->instruction_count = 0; - p->data_count = 0; p->writes_memory = 0; p->target_xlen = riscv_xlen(target); for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) { @@ -84,7 +83,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) } for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) - if (i >= riscv_debug_buffer_size(p->target) - p->data_count) + if (i >= riscv_debug_buffer_size(p->target)) p->debug_buffer[i] = riscv_read_debug_buffer(t, i); for (size_t i = GDB_REGNO_XPR0; i <= GDB_REGNO_XPR31; ++i) @@ -298,56 +297,6 @@ int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno return riscv_program_insert(p, addi(d, s, u)); } -int riscv_program_fsx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - assert(d >= GDB_REGNO_FPR0); - assert(d <= GDB_REGNO_FPR31); - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - uint32_t instruction; - switch (p->target->reg_cache->reg_list[GDB_REGNO_FPR0].size) { - case 64: - instruction = fsd(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr)); - break; - case 32: - instruction = fsw(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr)); - break; - default: - return ERROR_FAIL; - } - if (riscv_program_insert(p, instruction) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - -int riscv_program_flx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - assert(d >= GDB_REGNO_FPR0); - assert(d <= GDB_REGNO_FPR31); - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - uint32_t instruction; - switch (p->target->reg_cache->reg_list[GDB_REGNO_FPR0].size) { - case 64: - instruction = fld(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr)); - break; - case 32: - instruction = flw(d - GDB_REGNO_FPR0, t, riscv_program_gal(p, addr)); - break; - default: - return ERROR_FAIL; - } - if (riscv_program_insert(p, instruction) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c) { if (riscv_program_lui(p, d, c >> 12) != ERROR_OK) @@ -371,13 +320,6 @@ int riscv_program_do_restore_register(struct riscv_program *p, enum gdb_regno r) return ERROR_OK; } -void riscv_program_reserve_register(struct riscv_program *p, enum gdb_regno r) -{ - assert(r < RISCV_REGISTER_COUNT); - assert(p->in_use[r] == 0); - p->in_use[r] = 1; -} - enum gdb_regno riscv_program_gettemp(struct riscv_program *p) { for (size_t i = GDB_REGNO_S0; i <= GDB_REGNO_XPR31; ++i) { @@ -431,10 +373,9 @@ int riscv_program_lal(struct riscv_program *p, enum gdb_regno d, riscv_addr_t ad int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) { - if (p->instruction_count + p->data_count + 1 > riscv_debug_buffer_size(p->target)) { + if (p->instruction_count >= riscv_debug_buffer_size(p->target)) { LOG_ERROR("Unable to insert instruction:"); LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); - LOG_ERROR(" data_count =%d", (int)p->data_count); LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); abort(); } diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index e5f6c29e2..56a1a9a0a 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -15,11 +15,8 @@ struct riscv_program { uint32_t debug_buffer[RISCV_MAX_DEBUG_BUFFER_SIZE]; - /* The debug buffer is allocated in two directions: instructions go at - * the start, while data goes at the end. When they meet in the middle - * this blows up. */ + /* Number of 32-bit instructions in the program. */ size_t instruction_count; - size_t data_count; /* Side effects of executing this program. These must be accounted for * in order to maintain correct executing of the target system. */ @@ -29,10 +26,6 @@ struct riscv_program { /* When a register is used it will be set in this array. */ bool in_use[RISCV_REGISTER_COUNT]; - /* Remembers the registers that have been saved into dscratch - * registers. These are restored */ - enum gdb_regno dscratch_saved[RISCV_DSCRATCH_COUNT]; - /* XLEN on the target. */ int target_xlen; }; @@ -101,9 +94,6 @@ int riscv_program_ebreak(struct riscv_program *p); int riscv_program_lui(struct riscv_program *p, enum gdb_regno d, int32_t u); int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i); -int riscv_program_fsx(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_flx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); - /* Assembler macros. */ int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c); int riscv_program_la(struct riscv_program *p, enum gdb_regno d, riscv_addr_t a); @@ -113,7 +103,6 @@ int riscv_program_la(struct riscv_program *p, enum gdb_regno d, riscv_addr_t a); * reserving registers -- it's expected that this has been called as the first * thing in the program's execution to reserve registers that can't be touched * by the program's execution. */ -void riscv_program_reserve_register(struct riscv_program *p, enum gdb_regno r); enum gdb_regno riscv_program_gettemp(struct riscv_program *p); void riscv_program_puttemp(struct riscv_program *p, enum gdb_regno r); From a3a137062d518308bbb9bdbae291cfd3d28d1bc6 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 18 Oct 2017 14:21:23 -0700 Subject: [PATCH 041/127] Pay attention to impebreak. This required updating debug_defines.h, which caused a few other small cleanups as well. Change-Id: I3c2cb418d7eff3093d7664c5563b2af5e8b530eb --- src/target/riscv/debug_defines.h | 127 ++++++++++++++++++------------- src/target/riscv/program.c | 7 +- src/target/riscv/riscv-013.c | 22 +++--- src/target/riscv/riscv.h | 3 + 4 files changed, 95 insertions(+), 64 deletions(-) diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index 6e88a55ec..6067dbec0 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -173,12 +173,6 @@ #define CSR_DCSR_EBREAKM_LENGTH 1 #define CSR_DCSR_EBREAKM (0x1U << CSR_DCSR_EBREAKM_OFFSET) /* -* When 1, {\tt ebreak} instructions in Hypervisor Mode enter Debug Mode. - */ -#define CSR_DCSR_EBREAKH_OFFSET 14 -#define CSR_DCSR_EBREAKH_LENGTH 1 -#define CSR_DCSR_EBREAKH (0x1U << CSR_DCSR_EBREAKH_OFFSET) -/* * When 1, {\tt ebreak} instructions in Supervisor Mode enter Debug Mode. */ #define CSR_DCSR_EBREAKS_OFFSET 13 @@ -207,9 +201,10 @@ /* * 0: Increment counters as usual. * -* 1: Don't increment any counters while in Debug Mode. This includes -* the {\tt cycle} and {\tt instret} CSRs. This is preferred for most -* debugging scenarios. +* 1: Don't increment any counters while in Debug Mode or on {\tt +* ebreak} instructions that cause entry into Debug Mode. These +* counters include the {\tt cycle} and {\tt instret} CSRs. This is +* preferred for most debugging scenarios. * * An implementation may choose not to support writing to this bit. * The debugger must read back the value it writes to check whether @@ -312,9 +307,9 @@ * * This bit is only writable from Debug Mode. */ -#define CSR_TDATA1_HMODE_OFFSET XLEN-5 -#define CSR_TDATA1_HMODE_LENGTH 1 -#define CSR_TDATA1_HMODE (0x1ULL << CSR_TDATA1_HMODE_OFFSET) +#define CSR_TDATA1_DMODE_OFFSET XLEN-5 +#define CSR_TDATA1_DMODE_LENGTH 1 +#define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET) /* * Trigger-specific data. */ @@ -390,7 +385,7 @@ * 0: Raise a breakpoint exception. (Used when software wants to use * the trigger module without an external debugger attached.) * -* 1: Enter Debug Mode. (Only supported when \Fhmode is 1.) +* 1: Enter Debug Mode. (Only supported when \Fdmode is 1.) * * 2: Start tracing. * @@ -532,7 +527,7 @@ * 0: Raise a breakpoint exception. (Used when software wants to use the * trigger module without an external debugger attached.) * -* 1: Enter Debug Mode. (Only supported when \Fhmode is 1.) +* 1: Enter Debug Mode. (Only supported when \Fdmode is 1.) * * 2: Start tracing. * @@ -549,6 +544,30 @@ #define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET) #define DMI_DMSTATUS 0x11 /* +* If 1, then there is an implicit {\tt ebreak} instruction at the +* non-existent word immediately after the Program Buffer. This saves +* the debugger from having to write the {\tt ebreak} itself, and +* allows the Program Buffer to be one word smaller. +* +* This must be 1 when \Fprogbufsize is 1. + */ +#define DMI_DMSTATUS_IMPEBREAK_OFFSET 22 +#define DMI_DMSTATUS_IMPEBREAK_LENGTH 1 +#define DMI_DMSTATUS_IMPEBREAK (0x1U << DMI_DMSTATUS_IMPEBREAK_OFFSET) +/* +* Gets set if the Debug Module was accessed incorrectly. +* +* 0 (none): No error. +* +* 1 (badaddr): There was an access to an unimplemented Debug Module +* address. +* +* 7 (other): An access failed for another reason. + */ +#define DMI_DMSTATUS_DMERR_OFFSET 18 +#define DMI_DMSTATUS_DMERR_LENGTH 3 +#define DMI_DMSTATUS_DMERR (0x7U << DMI_DMSTATUS_DMERR_OFFSET) +/* * This field is 1 when all currently selected harts have acknowledged the previous \Fresumereq. */ #define DMI_DMSTATUS_ALLRESUMEACK_OFFSET 17 @@ -629,6 +648,13 @@ #define DMI_DMSTATUS_AUTHBUSY_OFFSET 6 #define DMI_DMSTATUS_AUTHBUSY_LENGTH 1 #define DMI_DMSTATUS_AUTHBUSY (0x1U << DMI_DMSTATUS_AUTHBUSY_OFFSET) +/* +* 0: \Rdevtreeaddrzero--\Rdevtreeaddrthree hold information which +* is not relevant to the Device Tree. +* +* 1: \Rdevtreeaddrzero--\Rdevtreeaddrthree registers hold the address of the +* Device Tree. + */ #define DMI_DMSTATUS_DEVTREEVALID_OFFSET 4 #define DMI_DMSTATUS_DEVTREEVALID_LENGTH 1 #define DMI_DMSTATUS_DEVTREEVALID (0x1U << DMI_DMSTATUS_DEVTREEVALID_OFFSET) @@ -654,7 +680,6 @@ * * Writing 1 or 0 has no effect on a hart which is already halted, but * the bit should be cleared to 0 before the hart is resumed. -* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior. * * Writes apply to the new value of \Fhartsel and \Fhasel. */ @@ -664,7 +689,8 @@ /* * Resume request signal for all currently selected harts. When set to 1, * each selected hart will resume if it is currently halted. -* Setting both \Fhaltreq and \Fresumereq leads to undefined behavior. +* +* This bit is ignored while \Fhaltreq is set. * * Writes apply to the new value of \Fhartsel and \Fhasel. */ @@ -710,11 +736,12 @@ #define DMI_DMCONTROL_HARTSEL (0x3ffU << DMI_DMCONTROL_HARTSEL_OFFSET) /* * This bit controls the reset signal from the DM to the rest of the -* system. To perform a system reset the debugger writes 1, +* system. The signal should reset every part of the system, including +* every hart, except for the DM and any logic required to access the +* DM. +* To perform a system reset the debugger writes 1, * and then writes 0 -* to deassert the reset. This bit must not reset the Debug Module -* registers. What it does reset is platform-specific (it may -* reset nothing). +* to deassert the reset. */ #define DMI_DMCONTROL_NDMRESET_OFFSET 1 #define DMI_DMCONTROL_NDMRESET_LENGTH 1 @@ -778,7 +805,7 @@ * shadowing the {\tt data} registers. * * If \Fdataaccess is 1: Signed address of RAM where the {\tt data} -* registers are shadowed. +* registers are shadowed, to be used to access relative to \Rzero. */ #define DMI_HARTINFO_DATAADDR_OFFSET 0 #define DMI_HARTINFO_DATAADDR_LENGTH 12 @@ -891,13 +918,10 @@ #define DMI_ABSTRACTCS 0x16 /* * Size of the Program Buffer, in 32-bit words. Valid sizes are 0 - 16. -* -* TODO: Explain what can be done with each size of the buffer, to suggest -* why you would want more or less words. */ -#define DMI_ABSTRACTCS_PROGSIZE_OFFSET 24 -#define DMI_ABSTRACTCS_PROGSIZE_LENGTH 5 -#define DMI_ABSTRACTCS_PROGSIZE (0x1fU << DMI_ABSTRACTCS_PROGSIZE_OFFSET) +#define DMI_ABSTRACTCS_PROGBUFSIZE_OFFSET 24 +#define DMI_ABSTRACTCS_PROGBUFSIZE_LENGTH 5 +#define DMI_ABSTRACTCS_PROGBUFSIZE (0x1fU << DMI_ABSTRACTCS_PROGBUFSIZE_OFFSET) /* * 1: An abstract command is currently being executed. * @@ -1013,24 +1037,22 @@ * * 4: 128-bit * -* If an unsupported system bus access size is written here, -* the DM may not perform the access, or may perform the access -* with any access size. +* If an unsupported system bus access size is written here, the DM +* does not perform the access and sberror is set to 3. */ #define DMI_SBCS_SBACCESS_OFFSET 17 #define DMI_SBCS_SBACCESS_LENGTH 3 #define DMI_SBCS_SBACCESS (0x7U << DMI_SBCS_SBACCESS_OFFSET) /* -* When 1, the internal address value (used by the system bus master) -* is incremented by the access size (in bytes) selected in \Fsbaccess -* after every system bus access. +* When 1, {\tt sbaddress} is incremented by the access size (in +* bytes) selected in \Fsbaccess after every system bus access. */ #define DMI_SBCS_SBAUTOINCREMENT_OFFSET 16 #define DMI_SBCS_SBAUTOINCREMENT_LENGTH 1 #define DMI_SBCS_SBAUTOINCREMENT (0x1U << DMI_SBCS_SBAUTOINCREMENT_OFFSET) /* -* When 1, every read from \Rsbdatazero automatically triggers a system -* bus read at the new address. +* When 1, every read from \Rsbdatazero automatically triggers a +* system bus read at the (possibly auto-incremented) address. */ #define DMI_SBCS_SBAUTOREAD_OFFSET 15 #define DMI_SBCS_SBAUTOREAD_LENGTH 1 @@ -1052,8 +1074,7 @@ * * 4: The system bus master was busy when one of the * {\tt sbaddress} or {\tt sbdata} registers was written, -* or the {\tt sbdata} register was read when it had -* stale data. +* or \Rsbdatazero was read when it had stale data. */ #define DMI_SBCS_SBERROR_OFFSET 12 #define DMI_SBCS_SBERROR_LENGTH 3 @@ -1097,54 +1118,54 @@ #define DMI_SBCS_SBACCESS8 (0x1U << DMI_SBCS_SBACCESS8_OFFSET) #define DMI_SBADDRESS0 0x39 /* -* Accesses bits 31:0 of the internal address. +* Accesses bits 31:0 of the physical address in {\tt sbaddress}. */ #define DMI_SBADDRESS0_ADDRESS_OFFSET 0 #define DMI_SBADDRESS0_ADDRESS_LENGTH 32 #define DMI_SBADDRESS0_ADDRESS (0xffffffffU << DMI_SBADDRESS0_ADDRESS_OFFSET) #define DMI_SBADDRESS1 0x3a /* -* Accesses bits 63:32 of the internal address (if the system address -* bus is that wide). +* Accesses bits 63:32 of the physical address in {\tt sbaddress} (if +* the system address bus is that wide). */ #define DMI_SBADDRESS1_ADDRESS_OFFSET 0 #define DMI_SBADDRESS1_ADDRESS_LENGTH 32 #define DMI_SBADDRESS1_ADDRESS (0xffffffffU << DMI_SBADDRESS1_ADDRESS_OFFSET) #define DMI_SBADDRESS2 0x3b /* -* Accesses bits 95:64 of the internal address (if the system address -* bus is that wide). +* Accesses bits 95:64 of the physical address in {\tt sbaddress} (if +* the system address bus is that wide). */ #define DMI_SBADDRESS2_ADDRESS_OFFSET 0 #define DMI_SBADDRESS2_ADDRESS_LENGTH 32 #define DMI_SBADDRESS2_ADDRESS (0xffffffffU << DMI_SBADDRESS2_ADDRESS_OFFSET) #define DMI_SBDATA0 0x3c /* -* Accesses bits 31:0 of the internal data. +* Accesses bits 31:0 of {\tt sbdata}. */ #define DMI_SBDATA0_DATA_OFFSET 0 #define DMI_SBDATA0_DATA_LENGTH 32 #define DMI_SBDATA0_DATA (0xffffffffU << DMI_SBDATA0_DATA_OFFSET) #define DMI_SBDATA1 0x3d /* -* Accesses bits 63:32 of the internal data (if the system bus is -* that wide). +* Accesses bits 63:32 of {\tt sbdata} (if the system bus is that +* wide). */ #define DMI_SBDATA1_DATA_OFFSET 0 #define DMI_SBDATA1_DATA_LENGTH 32 #define DMI_SBDATA1_DATA (0xffffffffU << DMI_SBDATA1_DATA_OFFSET) #define DMI_SBDATA2 0x3e /* -* Accesses bits 95:64 of the internal data (if the system bus is -* that wide). +* Accesses bits 95:64 of {\tt sbdata} (if the system bus is that +* wide). */ #define DMI_SBDATA2_DATA_OFFSET 0 #define DMI_SBDATA2_DATA_LENGTH 32 #define DMI_SBDATA2_DATA (0xffffffffU << DMI_SBDATA2_DATA_OFFSET) #define DMI_SBDATA3 0x3f /* -* Accesses bits 127:96 of the internal data (if the system bus is -* that wide). +* Accesses bits 127:96 of {\tt sbdata} (if the system bus is that +* wide). */ #define DMI_SBDATA3_DATA_OFFSET 0 #define DMI_SBDATA3_DATA_LENGTH 32 @@ -1188,6 +1209,9 @@ * 0: Don't do the operation specified by \Fwrite. * * 1: Do the operation specified by \Fwrite. +* +* This bit can be used to just execute the Program Buffer without +* having to worry about placing valid values into \Fsize or \Fregno. */ #define AC_ACCESS_REGISTER_TRANSFER_OFFSET 17 #define AC_ACCESS_REGISTER_TRANSFER_LENGTH 1 @@ -1223,8 +1247,9 @@ /* * Contains the privilege level the hart was operating in when Debug * Mode was entered. The encoding is described in Table -* \ref{tab:privlevel}. A user can write this value to change the -* hart's privilege level when exiting Debug Mode. +* \ref{tab:privlevel}, and matches the privilege level encoding from +* the RISC-V Privileged ISA Specification. A user can write this +* value to change the hart's privilege level when exiting Debug Mode. */ #define VIRT_PRIV_PRV_OFFSET 0 #define VIRT_PRIV_PRV_LENGTH 2 diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index b4f2b55ad..f02e4ea58 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -279,9 +279,10 @@ int riscv_program_fence(struct riscv_program *p) int riscv_program_ebreak(struct riscv_program *p) { - if (p->instruction_count == riscv_debug_buffer_size(p->target)) { - // TODO: Check for impebreak bit. - // There's an implicit ebreak here, so no need for us to add one. + struct target *target = p->target; + RISCV_INFO(r); + if (p->instruction_count == riscv_debug_buffer_size(p->target) && + r->impebreak) { return ERROR_OK; } return riscv_program_insert(p, ebreak()); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 5495516b0..b05110cd3 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -137,7 +137,7 @@ typedef struct { /* Number of abstract command data registers. */ unsigned datacount; /* Number of words in the Program Buffer. */ - unsigned progsize; + unsigned progbufsize; /* Number of Program Buffer registers. */ /* Number of words in Debug RAM. */ uint64_t tselect; @@ -200,6 +200,7 @@ static void decode_dmi(char *text, unsigned address, unsigned data) { DMI_DMCONTROL, DMI_DMCONTROL_NDMRESET, "ndmreset" }, { DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE, "dmactive" }, + { DMI_DMSTATUS, DMI_DMSTATUS_IMPEBREAK, "impebreak" }, { DMI_DMSTATUS, DMI_DMSTATUS_ALLRESUMEACK, "allresumeack" }, { DMI_DMSTATUS, DMI_DMSTATUS_ANYRESUMEACK, "anyresumeack" }, { DMI_DMSTATUS, DMI_DMSTATUS_ALLNONEXISTENT, "allnonexistent" }, @@ -215,7 +216,7 @@ static void decode_dmi(char *text, unsigned address, unsigned data) { DMI_DMSTATUS, DMI_DMSTATUS_DEVTREEVALID, "devtreevalid" }, { DMI_DMSTATUS, DMI_DMSTATUS_VERSION, "version" }, - { DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGSIZE, "progsize" }, + { DMI_ABSTRACTCS, DMI_ABSTRACTCS_PROGBUFSIZE, "progbufsize" }, { DMI_ABSTRACTCS, DMI_ABSTRACTCS_BUSY, "busy" }, { DMI_ABSTRACTCS, DMI_ABSTRACTCS_CMDERR, "cmderr" }, { DMI_ABSTRACTCS, DMI_ABSTRACTCS_DATACOUNT, "datacount" }, @@ -910,7 +911,7 @@ static int init_target(struct command_context *cmd_ctx, return ERROR_FAIL; riscv013_info_t *info = get_info(target); - info->progsize = -1; + info->progbufsize = -1; info->progbuf_addr = -1; info->data_size = -1; info->data_addr = -1; @@ -1043,10 +1044,12 @@ static int examine(struct target *target) // Check that abstract data registers are accessible. uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); - info->progsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGSIZE); + info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); /* Before doing anything else we must first enumerate the harts. */ RISCV_INFO(r); + r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); + int original_coreid = target->coreid; for (int i = 0; i < RISCV_MAX_HARTS; ++i) { /* Fake being a non-RTOS targeted to this core so we can see if @@ -1080,7 +1083,7 @@ static int examine(struct target *target) /* Without knowing anything else we can at least mess with the * program buffer. */ - r->debug_buffer_size[i] = info->progsize; + r->debug_buffer_size[i] = info->progbufsize; int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); if (result == ERROR_OK) { @@ -1768,16 +1771,16 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { RISCV013_INFO(info); - if (index >= info->progsize) - return dmi_write(target, DMI_DATA0 + index - info->progsize, data); + if (index >= info->progbufsize) + return dmi_write(target, DMI_DATA0 + index - info->progbufsize, data); return dmi_write(target, DMI_PROGBUF0 + index, data); } riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { RISCV013_INFO(info); - if (index >= info->progsize) - return dmi_read(target, DMI_DATA0 + index - info->progsize); + if (index >= info->progbufsize) + return dmi_read(target, DMI_DATA0 + index - info->progbufsize); return dmi_read(target, DMI_PROGBUF0 + index); } @@ -1835,7 +1838,6 @@ static void riscv013_on_step_or_resume(struct target *target, bool step) uint64_t dcsr = riscv_get_register(target, GDB_REGNO_DCSR); dcsr = set_field(dcsr, CSR_DCSR_STEP, step); dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKH, 1); dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1); dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1); riscv_set_register(target, GDB_REGNO_DCSR, dcsr); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index e7b0ea2db..f19f06c4c 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -78,6 +78,9 @@ typedef struct { /* This avoids invalidating the register cache too often. */ bool registers_initialized; + /* This hart contains an implicit ebreak at the end of the program buffer. */ + bool impebreak; + /* Helper functions that target the various RISC-V debug spec * implementations. */ riscv_reg_t (*get_register)(struct target *, int hartid, int regid); From ef49b34b2af5bae85e5ee887c49eed02eb227feb Mon Sep 17 00:00:00 2001 From: Andreas Fritiofson Date: Wed, 28 Dec 2016 23:43:53 +0100 Subject: [PATCH 042/127] arm: semihosting: set command line arguments Add "arm semihosting_cmdline [argv0 argv1 ...]" for setting the command line arguments for the debuggee. [andreas.fritiofson@gmail.com]: Dynamic allocation, empty default Change-Id: I831ddd161d602f251940e29608a154e9590fdee1 Signed-off-by: Christian Groessler Signed-off-by: Andreas Fritiofson Reviewed-on: http://openocd.zylin.com/3106 Tested-by: jenkins --- doc/openocd.texi | 14 ++++++++++++ src/target/arm.h | 3 +++ src/target/arm_semihosting.c | 2 +- src/target/armv4_5.c | 43 ++++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 1 deletion(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 39b81ea85..e452fa3b3 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -7604,6 +7604,20 @@ requests by using a special SVC instruction that is trapped at the Supervisor Call vector by OpenOCD. @end deffn +@deffn Command {arm semihosting_cmdline} [@option{enable}|@option{disable}] +@cindex ARM semihosting +Set the command line to be passed to the debuggee. + +@example +arm semihosting_cmdline argv0 argv1 argv2 ... +@end example + +This option lets one set the command line arguments to be passed to +the program. The first argument (argv0) is the program name in a +standard C environment (argv[0]). Depending on the program (not much +programs look at argv[0]), argv0 is ignored and can be any string. +@end deffn + @deffn Command {arm semihosting_fileio} [@option{enable}|@option{disable}] @cindex ARM semihosting Display status of semihosting fileio, after optionally changing that diff --git a/src/target/arm.h b/src/target/arm.h index d63ead215..f89aa6884 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -157,6 +157,9 @@ struct arm { int (*setup_semihosting)(struct target *target, int enable); + /** Semihosting command line. */ + char *semihosting_cmdline; + /** Backpointer to the target. */ struct target *target; diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 252511962..f31f901f0 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -465,7 +465,7 @@ static int do_semihosting(struct target *target) else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); - char *arg = "foobar"; + char *arg = arm->semihosting_cmdline != NULL ? arm->semihosting_cmdline : ""; uint32_t s = strlen(arg) + 1; if (l < s) arm->semihosting_result = -1; diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 2029ca92a..48050b078 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -1091,6 +1091,42 @@ COMMAND_HANDLER(handle_arm_semihosting_fileio_command) return ERROR_OK; } +COMMAND_HANDLER(handle_arm_semihosting_cmdline) +{ + struct target *target = get_current_target(CMD_CTX); + unsigned int i; + + if (target == NULL) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct arm *arm = target_to_arm(target); + + if (!is_arm(arm)) { + command_print(CMD_CTX, "current target isn't an ARM"); + return ERROR_FAIL; + } + + if (!arm->setup_semihosting) { + command_print(CMD_CTX, "semihosting not supported for current target"); + return ERROR_FAIL; + } + + free(arm->semihosting_cmdline); + arm->semihosting_cmdline = CMD_ARGC > 0 ? strdup(CMD_ARGV[0]) : NULL; + + for (i = 1; i < CMD_ARGC; i++) { + char *cmdline = alloc_printf("%s %s", arm->semihosting_cmdline, CMD_ARGV[i]); + if (cmdline == NULL) + break; + free(arm->semihosting_cmdline); + arm->semihosting_cmdline = cmdline; + } + + return ERROR_OK; +} + static const struct command_registration arm_exec_command_handlers[] = { { .name = "reg", @@ -1133,6 +1169,13 @@ static const struct command_registration arm_exec_command_handlers[] = { .usage = "['enable'|'disable']", .help = "activate support for semihosting operations", }, + { + "semihosting_cmdline", + .handler = handle_arm_semihosting_cmdline, + .mode = COMMAND_EXEC, + .usage = "arguments", + .help = "command line arguments to be passed to program", + }, { "semihosting_fileio", .handler = handle_arm_semihosting_fileio_command, From 9364b0dba451c3cee653f985b96b9f0535997346 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Thu, 29 Jun 2017 23:48:19 +0200 Subject: [PATCH 043/127] Fix GCC7 warnings about switch-case fallthroughs GCC7 with -Wextra warns about switch-case blocks which fallthrough with "this statement may fall through [-Werror=implicit-fallthrough=]". This can be fixed by adding "special" comments: "/* fallthrough */". See https://gcc.gnu.org/gcc-7/changes.html Change-Id: Iba0be791dbdd86984489b2d9a0592bb59828da1e Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/4174 Tested-by: jenkins --- src/flash/mflash.c | 4 ++-- src/flash/nand/mx3.c | 1 + src/flash/nor/kinetis.c | 1 + src/helper/command.c | 2 +- src/jtag/drivers/ftdi.c | 1 + src/jtag/drivers/kitprog.c | 1 + src/svf/svf.c | 2 ++ src/target/arm_adi_v5.c | 6 ++++++ src/target/arm_disassembler.c | 1 + src/target/target.c | 2 +- 10 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/flash/mflash.c b/src/flash/mflash.c index b69995542..4c95d216c 100644 --- a/src/flash/mflash.c +++ b/src/flash/mflash.c @@ -259,11 +259,11 @@ static int mg_dsk_wait(mg_io_type_wait wait_local, uint32_t time_var) case mg_io_wait_rdy: if (status & mg_io_rbit_status_ready) return ERROR_OK; - + /* fallthrough */ case mg_io_wait_drq: if (status & mg_io_rbit_status_data_req) return ERROR_OK; - + /* fallthrough */ default: break; } diff --git a/src/flash/nand/mx3.c b/src/flash/nand/mx3.c index b61e47535..5fdc92305 100644 --- a/src/flash/nand/mx3.c +++ b/src/flash/nand/mx3.c @@ -281,6 +281,7 @@ static int imx31_command(struct nand_device *nand, uint8_t command) * offset == one half of page size */ in_sram_address = MX3_NF_MAIN_BUFFER0 + (nand->page_size >> 1); + break; default: in_sram_address = MX3_NF_MAIN_BUFFER0; } diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 4ef438507..455e7b1b0 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -2126,6 +2126,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX1: /* errata 7534 - should be K63 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX2: /* errata 7534 - should be K64 */ subfamid += 2; /* errata 7534 fix */ + /* fallthrough */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX3: /* K63FN1M0 */ case KINETIS_SDID_FAMILYID_K6X | KINETIS_SDID_SUBFAMID_KX4: diff --git a/src/helper/command.c b/src/helper/command.c index 5deaee859..40e8b0582 100644 --- a/src/helper/command.c +++ b/src/helper/command.c @@ -1456,8 +1456,8 @@ COMMAND_HELPER(handle_command_parse_bool, bool *out, const char *label) LOG_ERROR("%s: argument '%s' is not valid", CMD_NAME, in); return ERROR_COMMAND_SYNTAX_ERROR; } - /* fall through */ } + /* fallthrough */ case 0: LOG_INFO("%s is %s", label, *out ? "enabled" : "disabled"); break; diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 342e32102..75a3ce43e 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -855,6 +855,7 @@ COMMAND_HANDLER(ftdi_handle_set_signal_command) ftdi_set_signal(sig, *CMD_ARGV[1]); break; } + /* fallthrough */ default: LOG_ERROR("unknown signal level '%s', use 0, 1 or z", CMD_ARGV[1]); return ERROR_COMMAND_SYNTAX_ERROR; diff --git a/src/jtag/drivers/kitprog.c b/src/jtag/drivers/kitprog.c index c689848c8..584da8c94 100644 --- a/src/jtag/drivers/kitprog.c +++ b/src/jtag/drivers/kitprog.c @@ -657,6 +657,7 @@ static int kitprog_swd_switch_seq(enum swd_special_seq seq) LOG_DEBUG("JTAG to SWD not supported"); /* Fall through to fix target reset issue */ } + /* fallthrough */ case LINE_RESET: LOG_DEBUG("SWD line reset"); if (kitprog_swd_seq(SEQUENCE_LINE_RESET) != ERROR_OK) diff --git a/src/svf/svf.c b/src/svf/svf.c index e7e815c10..1d686ba61 100644 --- a/src/svf/svf.c +++ b/src/svf/svf.c @@ -661,11 +661,13 @@ static int svf_read_command_from_file(FILE *fd) if (svf_getline(&svf_read_line, &svf_read_line_size, svf_fd) <= 0) return ERROR_FAIL; i = -1; + /* fallthrough */ case '\r': slash = 0; /* Don't save '\r' and '\n' if no data is parsed */ if (!cmd_pos) break; + /* fallthrough */ default: /* The parsing code currently expects a space * before parentheses -- "TDI (123)". Also a diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index eafc2ddc0..88491196d 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -346,8 +346,10 @@ static int mem_ap_write(struct adiv5_ap *ap, const uint8_t *buffer, uint32_t siz case 4: outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); + /* fallthrough */ case 2: outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); + /* fallthrough */ case 1: outvalue |= (uint32_t)*buffer++ << 8 * (address++ & 3); } @@ -509,8 +511,10 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint case 4: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); + /* fallthrough */ case 2: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); + /* fallthrough */ case 1: *buffer++ = *read_ptr >> 8 * (3 - (address++ & 3)); } @@ -519,8 +523,10 @@ static int mem_ap_read(struct adiv5_ap *ap, uint8_t *buffer, uint32_t size, uint case 4: *buffer++ = *read_ptr >> 8 * (address++ & 3); *buffer++ = *read_ptr >> 8 * (address++ & 3); + /* fallthrough */ case 2: *buffer++ = *read_ptr >> 8 * (address++ & 3); + /* fallthrough */ case 1: *buffer++ = *read_ptr >> 8 * (address++ & 3); } diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 5277b94d8..3f1daca4d 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -3299,6 +3299,7 @@ static int t2ev_data_immed(uint32_t opcode, uint32_t address, case 0x10: case 0x12: is_signed = true; + /* fallthrough */ case 0x18: case 0x1a: /* signed/unsigned saturated add */ diff --git a/src/target/target.c b/src/target/target.c index 07fe453d9..36318d88e 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -3684,7 +3684,7 @@ COMMAND_HANDLER(handle_bp_command) addr = 0; return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); } - + /* fallthrough */ case 4: hw = BKPT_HARD; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); From 079d78f7de917e33b58c5ea6147c818e573b3dc4 Mon Sep 17 00:00:00 2001 From: Freddie Chopin Date: Thu, 29 Jun 2017 23:49:03 +0200 Subject: [PATCH 044/127] Fix GCC7 warnings about string truncation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GCC7 with -Wall warns about possible string truncation with snprint()-type functions with "directive output may be truncated writing 1 byte into a region of size between 0 and 9 [-Werror=format-truncation=]" + "note: ‘snprintf’ output between 5 and 14 bytes into a destination of size 12" (or similar). Fix this by increasing sizes of buffers. See https://gcc.gnu.org/gcc-7/changes.html Change-Id: Ib848f2a56dd658783534158947ae1be7c0e99d45 Signed-off-by: Freddie Chopin Reviewed-on: http://openocd.zylin.com/4175 Reviewed-by: Andreas Fritiofson Tested-by: jenkins Reviewed-by: Andreas Bolsch --- src/flash/nor/kinetis.c | 2 +- src/flash/nor/xmc4xxx.c | 4 ++-- src/target/arm_adi_v5.c | 2 +- src/target/nds32_cmd.c | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c index 455e7b1b0..5c0ffbd6f 100644 --- a/src/flash/nor/kinetis.c +++ b/src/flash/nor/kinetis.c @@ -1959,7 +1959,7 @@ static int kinetis_probe_chip(struct kinetis_chip *k_chip) unsigned cpu_mhz = 120; unsigned idx; bool use_nvm_marking = false; - char flash_marking[8], nvm_marking[2]; + char flash_marking[11], nvm_marking[2]; char name[40]; k_chip->probed = false; diff --git a/src/flash/nor/xmc4xxx.c b/src/flash/nor/xmc4xxx.c index 02df46a3f..5677ef0f1 100644 --- a/src/flash/nor/xmc4xxx.c +++ b/src/flash/nor/xmc4xxx.c @@ -931,13 +931,13 @@ static int xmc4xxx_get_info_command(struct flash_bank *bank, char *buf, int buf_ /* If OTP Write protection is enabled (User 2), list each * sector that has it enabled */ - char otp_str[8]; + char otp_str[14]; if (otp_enabled) { strcat(prot_str, "\nOTP Protection is enabled for sectors:\n"); for (int i = 0; i < bank->num_sectors; i++) { if (fb->write_prot_otp[i]) { snprintf(otp_str, sizeof(otp_str), "- %d\n", i); - strncat(prot_str, otp_str, ARRAY_SIZE(otp_str)); + strncat(prot_str, otp_str, sizeof(prot_str) - strlen(prot_str) - 1); } } } diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 88491196d..200629023 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -1059,7 +1059,7 @@ static int dap_rom_display(struct command_context *cmd_ctx, int retval; uint64_t pid; uint32_t cid; - char tabs[7] = ""; + char tabs[16] = ""; if (depth > 16) { command_print(cmd_ctx, "\tTables too deep"); diff --git a/src/target/nds32_cmd.c b/src/target/nds32_cmd.c index edb4872e4..500651dbc 100644 --- a/src/target/nds32_cmd.c +++ b/src/target/nds32_cmd.c @@ -816,7 +816,7 @@ static int jim_nds32_bulk_read(Jim_Interp *interp, int argc, Jim_Obj * const *ar uint32_t *data = malloc(count * sizeof(uint32_t)); int result; result = target_read_buffer(target, address, count * 4, (uint8_t *)data); - char data_str[11]; + char data_str[12]; jim_wide i; Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); From 5425c871c97b5a80c8552a0bc3dca963761a2f03 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 23 Oct 2017 14:13:46 -0700 Subject: [PATCH 045/127] Properly fix memory read when encountering busy. Change-Id: I377054495e860076edc2f38d1cc0f11c23f98d3b --- src/target/riscv/riscv-013.c | 135 ++++++++++++++++++++++++++--------- 1 file changed, 100 insertions(+), 35 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index b05110cd3..5c81c5512 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1317,36 +1317,42 @@ static int read_memory(struct target *target, target_addr_t address, // Write address to S0, and execute buffer. if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) return ERROR_FAIL; - if (execute_abstract_command(target, - access_register_command(GDB_REGNO_S1, riscv_xlen(target), + uint32_t command = access_register_command(GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | - AC_ACCESS_REGISTER_POSTEXEC)) != ERROR_OK) + AC_ACCESS_REGISTER_POSTEXEC); + if (execute_abstract_command(target, command) != ERROR_OK) return ERROR_FAIL; + // First read has just triggered. Result is in s1. dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); - /* Copying memory might fail because we're going too quickly, in which - * case we need to back off a bit and try again. */ - riscv_addr_t cur_addr = address; + // read_addr is the next address that the hart will read from, which is the + // value in s0. + riscv_addr_t read_addr = address + size; + // The next address that we need to receive data for. + riscv_addr_t receive_addr = address; riscv_addr_t fin_addr = address + (count * size); - LOG_DEBUG("reading until final address 0x%" PRIx64, fin_addr); - while (cur_addr < fin_addr - size) { - // Invariant: - // s0 contains the next address to read - // s1 contains the data read at the previous address - // dmdata0 contains the data read at the previous previous address + unsigned skip = 1; + while (read_addr < fin_addr) { + LOG_DEBUG("read_addr=0x%" PRIx64 ", receive_addr=0x%" PRIx64 + ", fin_addr=0x%" PRIx64, read_addr, receive_addr, fin_addr); + // The pipeline looks like this: + // memory -> s1 -> dm_data0 -> debugger + // It advances every time the debugger reads dmdata0. + // So at any time the debugger has just read mem[s0 - 3*size], + // dm_data0 contains mem[s0 - 2*size] + // s1 contains mem[s0-size] - unsigned start = (cur_addr - address) / size; - LOG_DEBUG("creating burst to read address 0x%" TARGET_PRIxADDR - " up to 0x%" TARGET_PRIxADDR "; start=0x%d", cur_addr, fin_addr, start); - assert(cur_addr >= address && cur_addr < fin_addr); + LOG_DEBUG("creating burst to read from 0x%" TARGET_PRIxADDR + " up to 0x%" TARGET_PRIxADDR, read_addr, fin_addr); + assert(read_addr >= address && read_addr < fin_addr); struct riscv_batch *batch = riscv_batch_alloc(target, 32, info->dmi_busy_delay + info->ac_busy_delay); size_t reads = 0; - for (riscv_addr_t addr = cur_addr; addr < fin_addr - size; addr += size) { + for (riscv_addr_t addr = read_addr; addr < fin_addr; addr += size) { riscv_batch_add_dmi_read(batch, DMI_DATA0); reads++; @@ -1363,20 +1369,62 @@ static int read_memory(struct target *target, target_addr_t address, abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->cmderr = get_field(abstractcs, DMI_ABSTRACTCS_CMDERR); - riscv_addr_t next_addr; + unsigned cmderr = info->cmderr; + riscv_addr_t next_read_addr; + uint32_t dmi_data0 = -1; switch (info->cmderr) { case CMDERR_NONE: LOG_DEBUG("successful (partial?) memory read"); - next_addr = cur_addr + reads * size; + next_read_addr = read_addr + reads * size; break; case CMDERR_BUSY: LOG_DEBUG("memory read resulted in busy response"); + + /* + * If you want to exercise this code path, apply the following patch to spike: +--- a/riscv/debug_module.cc ++++ b/riscv/debug_module.cc +@@ -1,3 +1,5 @@ ++#include ++ + #include + + #include "debug_module.h" +@@ -398,6 +400,15 @@ bool debug_module_t::perform_abstract_command() + // Since the next instruction is what we will use, just use nother NOP + // to get there. + write32(debug_abstract, 1, addi(ZERO, ZERO, 0)); ++ ++ if (abstractauto.autoexecdata && ++ program_buffer[0] == 0x83 && ++ program_buffer[1] == 0x24 && ++ program_buffer[2] == 0x04 && ++ program_buffer[3] == 0 && ++ rand() < RAND_MAX / 10) { ++ usleep(1000000); ++ } + } else { + write32(debug_abstract, 1, ebreak()); + } + */ increase_ac_busy_delay(target); riscv013_clear_abstract_error(target); dmi_write(target, DMI_ABSTRACTAUTO, 0); - if (register_read_direct(target, &next_addr, GDB_REGNO_S0) != ERROR_OK) + + // This is definitely a good version of the value that we + // attempted to read when we discovered that the target was + // busy. + dmi_data0 = dmi_read(target, DMI_DATA0); + + // Clobbers DMI_DATA0. + if (register_read_direct(target, &next_read_addr, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; + // Restore the command, and execute it. + // Now DMI_DATA0 contains the next value just as it would if no + // error had occurred. + dmi_write(target, DMI_COMMAND, command); + dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); break; @@ -1391,21 +1439,37 @@ static int read_memory(struct target *target, target_addr_t address, } // Now read whatever we got out of the batch. - unsigned rereads = 0; - for (riscv_addr_t addr = cur_addr - size; addr < next_addr - size; addr += size) { - if (addr >= address) { - riscv_addr_t offset = addr - address; - uint64_t dmi_out = riscv_batch_get_dmi_read(batch, rereads); - uint32_t value = get_field(dmi_out, DTM_DMI_DATA); - write_to_buf(buffer + offset, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", addr, value); + for (size_t i = 0; i < reads; i++) { + if (read_addr >= next_read_addr) { + break; } - rereads++; + read_addr += size; + + if (skip > 0) { + skip--; + continue; + } + + riscv_addr_t offset = receive_addr - address; + uint64_t dmi_out = riscv_batch_get_dmi_read(batch, i); + uint32_t value = get_field(dmi_out, DTM_DMI_DATA); + write_to_buf(buffer + offset, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", receive_addr, + value); + + receive_addr += size; } riscv_batch_free(batch); - cur_addr = next_addr; + if (cmderr == CMDERR_BUSY) { + riscv_addr_t offset = receive_addr - address; + write_to_buf(buffer + offset, dmi_data0, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", receive_addr, + dmi_data0); + read_addr += size; + receive_addr += size; + } } dmi_write(target, DMI_ABSTRACTAUTO, 0); @@ -1413,17 +1477,18 @@ static int read_memory(struct target *target, target_addr_t address, if (count > 1) { // Read the penultimate word. uint64_t value = dmi_read(target, DMI_DATA0); - write_to_buf(buffer + cur_addr - size - address, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, cur_addr - - size, value); + write_to_buf(buffer + receive_addr - address, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value); + receive_addr += size; } // Read the last word. uint64_t value; if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; - write_to_buf(buffer + cur_addr - address, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, cur_addr, value); + write_to_buf(buffer + receive_addr - address, value, size); + LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value); + receive_addr += size; riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); From 3ba6d46fc29c4ee7b6b5f90423a3cf734f0a04e3 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 23 Oct 2017 14:18:09 -0700 Subject: [PATCH 046/127] Remove unused functionality. Change-Id: Ic70cebd62bbd04f7ae5566504fbb279a11de57f0 --- src/target/riscv/program.c | 225 ------------------------------------- src/target/riscv/program.h | 43 ------- 2 files changed, 268 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index f02e4ea58..e7238ddce 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -11,21 +11,15 @@ #include "asm.h" #include "encoding.h" -riscv_addr_t riscv_program_gal(struct riscv_program *p, riscv_addr_t addr); -int riscv_program_lah(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_lal(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); - /* Program interface. */ int riscv_program_init(struct riscv_program *p, struct target *target) { memset(p, 0, sizeof(*p)); p->target = target; p->instruction_count = 0; - p->writes_memory = 0; p->target_xlen = riscv_xlen(target); for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) { p->writes_xreg[i] = 0; - p->in_use[i] = 0; } for(size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i) @@ -58,14 +52,6 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) } } - if (p->writes_memory && (riscv_program_fence(p) != ERROR_OK)) { - LOG_ERROR("Unable to write fence"); - for(size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) - LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]); - abort(); - return ERROR_FAIL; - } - if (riscv_program_ebreak(p) != ERROR_OK) { LOG_ERROR("Unable to write ebreak"); for(size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) @@ -95,160 +81,34 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, sw(d, b, offset)); } int riscv_program_shr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, sh(d, b, offset)); } int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, sb(d, b, offset)); } int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, lw(d, b, offset)); } int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, lh(d, b, offset)); } int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) { - p->writes_memory = 1; return riscv_program_insert(p, lb(d, b, offset)); } -int riscv_program_lx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - switch (p->target_xlen) { - case 64: return riscv_program_ld(p, d, addr); - case 32: return riscv_program_lw(p, d, addr); - } - - LOG_ERROR("unknown xlen %d", p->target_xlen); - abort(); - return -1; -} - -int riscv_program_ld(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, d, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, ld(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_lw(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, d, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, lw(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_lh(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, d, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, lh(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_lb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 ? GDB_REGNO_X0 : d; - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, lb(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_sx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - switch (p->target_xlen) { - case 64: return riscv_program_sd(p, d, addr); - case 32: return riscv_program_sw(p, d, addr); - } - - LOG_ERROR("unknown xlen %d", p->target_xlen); - abort(); - return -1; -} - -int riscv_program_sd(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, sd(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - -int riscv_program_sw(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, sw(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - -int riscv_program_sh(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, sh(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - -int riscv_program_sb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - enum gdb_regno t = riscv_program_gah(p, addr) == 0 - ? GDB_REGNO_X0 - : riscv_program_gettemp(p); - if (riscv_program_lah(p, t, addr) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_insert(p, sb(d, t, riscv_program_gal(p, addr))) != ERROR_OK) - return ERROR_FAIL; - riscv_program_puttemp(p, t); - p->writes_memory = true; - return ERROR_OK; -} - int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); @@ -261,12 +121,6 @@ int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno return riscv_program_insert(p, csrrw(GDB_REGNO_X0, s, csr - GDB_REGNO_CSR0)); } -int riscv_program_csrrw(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, enum gdb_regno csr) -{ - assert(csr >= GDB_REGNO_CSR0); - return riscv_program_insert(p, csrrw(d, s, csr - GDB_REGNO_CSR0)); -} - int riscv_program_fence_i(struct riscv_program *p) { return riscv_program_insert(p, fence_i()); @@ -288,90 +142,11 @@ int riscv_program_ebreak(struct riscv_program *p) return riscv_program_insert(p, ebreak()); } -int riscv_program_lui(struct riscv_program *p, enum gdb_regno d, int32_t u) -{ - return riscv_program_insert(p, lui(d, u)); -} - int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t u) { return riscv_program_insert(p, addi(d, s, u)); } -int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c) -{ - if (riscv_program_lui(p, d, c >> 12) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_addi(p, d, d, c & 0xFFF) != ERROR_OK) - return ERROR_FAIL; - return ERROR_OK; -} - -int riscv_program_dont_restore_register(struct riscv_program *p, enum gdb_regno r) -{ - assert(r < RISCV_REGISTER_COUNT); - p->writes_xreg[r] = 0; - return ERROR_OK; -} - -int riscv_program_do_restore_register(struct riscv_program *p, enum gdb_regno r) -{ - assert(r < RISCV_REGISTER_COUNT); - p->writes_xreg[r] = 1; - return ERROR_OK; -} - -enum gdb_regno riscv_program_gettemp(struct riscv_program *p) -{ - for (size_t i = GDB_REGNO_S0; i <= GDB_REGNO_XPR31; ++i) { - if (p->in_use[i]) continue; - - riscv_program_do_restore_register(p, i); - p->in_use[i] = 1; - return i; - } - - LOG_ERROR("You've run out of temporary registers. This is impossible."); - abort(); -} - -void riscv_program_puttemp(struct riscv_program *p, enum gdb_regno r) -{ - assert(r < RISCV_REGISTER_COUNT); - p->in_use[r] = 0; -} - -/* Helper functions. */ -riscv_addr_t riscv_program_gah(struct riscv_program *p, riscv_addr_t addr) -{ - return addr >> 12; -} - -riscv_addr_t riscv_program_gal(struct riscv_program *p, riscv_addr_t addr) -{ - if (addr > 0) { - return (addr & 0x7FF); - } else { - return 0; - } -} - -int riscv_program_lah(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - riscv_addr_t ah = riscv_program_gah(p, addr); - if (ah == 0) - return ERROR_OK; - return riscv_program_lui(p, d, ah); -} - -int riscv_program_lal(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr) -{ - riscv_addr_t al = riscv_program_gal(p, addr); - if (al == 0) - return ERROR_OK; - return riscv_program_addi(p, d, d, al); -} - int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) { if (p->instruction_count >= riscv_debug_buffer_size(p->target)) { diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index 56a1a9a0a..d641be1be 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -21,10 +21,6 @@ struct riscv_program { /* Side effects of executing this program. These must be accounted for * in order to maintain correct executing of the target system. */ bool writes_xreg[RISCV_REGISTER_COUNT]; - bool writes_memory; - - /* When a register is used it will be set in this array. */ - bool in_use[RISCV_REGISTER_COUNT]; /* XLEN on the target. */ int target_xlen; @@ -59,60 +55,21 @@ int riscv_program_save_to_dscratch(struct riscv_program *p, enum gdb_regno to_sa /* Helpers to assembly various instructions. Return 0 on success. These might * assembly into a multi-instruction sequence that overwrites some other * register, but those will be properly saved and restored. */ -int riscv_program_lx(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_ld(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_lw(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_lh(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); -int riscv_program_lb(struct riscv_program *p, enum gdb_regno d, riscv_addr_t addr); - -int riscv_program_sx(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_sd(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_sw(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_sh(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); -int riscv_program_sb(struct riscv_program *p, enum gdb_regno s, riscv_addr_t addr); - -int riscv_program_lxr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); -int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); -int riscv_program_sxr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); -int riscv_program_sdr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr); int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr); -int riscv_program_csrrw(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, enum gdb_regno csr); int riscv_program_fence_i(struct riscv_program *p); int riscv_program_fence(struct riscv_program *p); int riscv_program_ebreak(struct riscv_program *p); -int riscv_program_lui(struct riscv_program *p, enum gdb_regno d, int32_t u); int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i); -/* Assembler macros. */ -int riscv_program_li(struct riscv_program *p, enum gdb_regno d, riscv_reg_t c); -int riscv_program_la(struct riscv_program *p, enum gdb_regno d, riscv_addr_t a); - -/* Register allocation. The user is expected to have obtained temporary - * registers using these fuctions. Additionally, there is an interface for - * reserving registers -- it's expected that this has been called as the first - * thing in the program's execution to reserve registers that can't be touched - * by the program's execution. */ -enum gdb_regno riscv_program_gettemp(struct riscv_program *p); -void riscv_program_puttemp(struct riscv_program *p, enum gdb_regno r); - -/* Executing a program usually causes the registers that get overwritten to be - * saved and restored. Calling this prevents the given register from actually - * being restored as a result of all activity in this program. */ -int riscv_program_dont_restore_register(struct riscv_program *p, enum gdb_regno r); -int riscv_program_do_restore_register(struct riscv_program *p, enum gdb_regno r); - -/* Addressing functions. */ -riscv_addr_t riscv_program_gah(struct riscv_program *p, riscv_addr_t addr); - #endif From 8432b7cf3da8cf6862d8c86d46812f8b24af8bdf Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 24 Oct 2017 11:34:48 -0700 Subject: [PATCH 047/127] Remove more unused code. Change-Id: Id91237c163d86e8f4d039503ca33b4ad7571ecd1 --- src/target/riscv/riscv-013.c | 54 ++++-------------------------------- 1 file changed, 6 insertions(+), 48 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 5c81c5512..d536a2dcc 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -31,10 +31,6 @@ static void riscv013_on_step_or_resume(struct target *target, bool step); static void riscv013_step_or_resume_current_hart(struct target *target, bool step); -//static riscv_addr_t riscv013_progbuf_addr(struct target *target); -//static riscv_addr_t riscv013_data_size(struct target *target); -//static riscv_addr_t riscv013_data_addr(struct target *target); -//static int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr); static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ @@ -1293,7 +1289,12 @@ static int read_memory(struct target *target, target_addr_t address, struct riscv_program program; riscv_program_init(&program, target); - // TODO: riscv_program_fence(&program); + riscv_program_fence(&program); + if (riscv_program_exec(&program, target) != ERROR_OK) + LOG_ERROR("Unable to execute fence"); + + // New program. + riscv_program_init(&program, target); switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); @@ -1953,49 +1954,6 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste abort(); } -#if 0 -riscv_addr_t riscv013_progbuf_addr(struct target *target) -{ - RISCV013_INFO(info); - assert(info->progbuf_addr != -1); - return info->progbuf_addr; -} -#endif - -#if 0 -riscv_addr_t riscv013_data_size(struct target *target) -{ - RISCV013_INFO(info); - if (info->data_size == -1) { - uint32_t acs = dmi_read(target, DMI_HARTINFO); - info->data_size = get_field(acs, DMI_HARTINFO_DATASIZE); - } - return info->data_size; -} -#endif - -#if 0 -riscv_addr_t riscv013_data_addr(struct target *target) -{ - RISCV013_INFO(info); - if (info->data_addr == -1) { - uint32_t acs = dmi_read(target, DMI_HARTINFO); - info->data_addr = get_field(acs, DMI_HARTINFO_DATAACCESS) ? get_field(acs, DMI_HARTINFO_DATAADDR) : 0; - } - return info->data_addr; -} -#endif - -#if 0 -int riscv013_debug_buffer_register(struct target *target, riscv_addr_t addr) -{ - if (addr >= riscv013_data_addr(target)) - return DMI_DATA0 + (addr - riscv013_data_addr(target)) / 4; - else - return DMI_PROGBUF0 + (addr - riscv013_progbuf_addr(target)) / 4; -} -#endif - void riscv013_clear_abstract_error(struct target *target) { // Wait for busy to go away. From 59a03402610bb92c1298586fcef212c17c5d0644 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 24 Oct 2017 11:38:39 -0700 Subject: [PATCH 048/127] Remove more unused code. Change-Id: I962660f58d948f85df6e073065e15e5d8f4a02b6 --- src/target/riscv/riscv-013.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index d536a2dcc..e9c545878 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -167,9 +167,6 @@ typedef struct { bool need_strict_step; - // Some memoized values - int progbuf_addr, data_addr, data_size; - bool abstract_read_csr_supported; bool abstract_write_csr_supported; bool abstract_read_fpr_supported; @@ -908,9 +905,6 @@ static int init_target(struct command_context *cmd_ctx, riscv013_info_t *info = get_info(target); info->progbufsize = -1; - info->progbuf_addr = -1; - info->data_size = -1; - info->data_addr = -1; info->dmi_busy_delay = 0; info->ac_busy_delay = 0; From dbecbfee997bf7d5aa2daef17f0ef7f30ebdaa6b Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 24 Oct 2017 12:15:25 -0700 Subject: [PATCH 049/127] Add a fence after memory writes. Change-Id: I5137479b685f735aa573cec5d40170016c40f597 --- src/target/riscv/riscv-013.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index e9c545878..f47428a6b 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1256,6 +1256,16 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) } } +static int execute_fence(struct target *target) { + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_fence(&program); + int result = riscv_program_exec(&program, target); + if (result != ERROR_OK) + LOG_ERROR("Unable to execute fence"); + return result; +} + /** * Read the requested memory, taking care to execute every read exactly once, * even if cmderr=busy is encountered. @@ -1279,16 +1289,12 @@ static int read_memory(struct target *target, target_addr_t address, if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + // Write the program (load, increment) struct riscv_program program; riscv_program_init(&program, target); - - riscv_program_fence(&program); - if (riscv_program_exec(&program, target) != ERROR_OK) - LOG_ERROR("Unable to execute fence"); - - // New program. - riscv_program_init(&program, target); switch (size) { case 1: riscv_program_lbr(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0); @@ -1649,6 +1655,9 @@ static int write_memory(struct target *target, target_addr_t address, if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; + if (execute_fence(target) != ERROR_OK) + return ERROR_FAIL; + return ERROR_OK; } From 23bd6d08c9444ef36789f0355e78833dc45fc3f5 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 24 Oct 2017 15:11:33 -0700 Subject: [PATCH 050/127] Remove more unused functionality. Change-Id: I43283b9556c959f891a587fb39bdd1ab9206e8af --- src/target/riscv/riscv-013.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index f47428a6b..5ff4a6ffe 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1839,17 +1839,11 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { - RISCV013_INFO(info); - if (index >= info->progbufsize) - return dmi_write(target, DMI_DATA0 + index - info->progbufsize, data); return dmi_write(target, DMI_PROGBUF0 + index, data); } riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index) { - RISCV013_INFO(info); - if (index >= info->progbufsize) - return dmi_read(target, DMI_DATA0 + index - info->progbufsize); return dmi_read(target, DMI_PROGBUF0 + index); } From 6ba66c95034da6743baa89c11200c711f557f602 Mon Sep 17 00:00:00 2001 From: Palmer Dabbelt Date: Wed, 25 Oct 2017 18:14:32 -0700 Subject: [PATCH 051/127] No Russian --- tcl/target/{1986ве1т.cfg => 1986Be1T.cfg} | 0 tcl/target/{к1879xб1я.cfg => K1879x61R.cfg} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tcl/target/{1986ве1т.cfg => 1986Be1T.cfg} (100%) rename tcl/target/{к1879xб1я.cfg => K1879x61R.cfg} (100%) diff --git a/tcl/target/1986ве1т.cfg b/tcl/target/1986Be1T.cfg similarity index 100% rename from tcl/target/1986ве1т.cfg rename to tcl/target/1986Be1T.cfg diff --git a/tcl/target/к1879xб1я.cfg b/tcl/target/K1879x61R.cfg similarity index 100% rename from tcl/target/к1879xб1я.cfg rename to tcl/target/K1879x61R.cfg From 02df0abb547a71e34f7b5bee8ffbc4ded44572de Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Tue, 3 Oct 2017 12:59:06 -0700 Subject: [PATCH 052/127] Cortex-M: fix stale DHCSR cache values MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In cortex_m_assert_reset, in two locations, DHCSR is written directly using mem_ap_write_u32. This means that the cached version, target_to_cm(target)->dcb_dhcsr, is not updated when these writes are performed, so subsequent writes to DHCSR that use cortex_m_write_debug_halt_mask will change those bits back to their old values which, unless modified in that particular invocation, come from the cache. This causes an actual, observable bug on an STM32F7 in which running “reset run” immediately after “program” can in some cases result in execution proceeding with C_MASKINTS set (it is cleared on line 1021 but is then set immediately afterward in cortex_m_clear_halt), causing failure of the application. Replace these mem_ap_write_u32 calls with cortex_m_write_debug_halt_mask calls to do the same jobs. Change-Id: Id35ca7f6057c2df2ba9cd67c53a73b50816d0b71 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4239 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/cortex_m.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index e80cd2356..11dbf24f2 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -242,7 +242,7 @@ static int cortex_m_endreset_event(struct target *target) if (retval != ERROR_OK) return retval; if (!(cortex_m->dcb_dhcsr & C_DEBUGEN)) { - retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS); if (retval != ERROR_OK) return retval; } @@ -1005,12 +1005,12 @@ static int cortex_m_assert_reset(struct target *target) /* Store important errors instead of failing and proceed to reset assert */ if (retval != ERROR_OK || !(cortex_m->dcb_dhcsr & C_DEBUGEN)) - retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT | C_STEP | C_MASKINTS); /* If the processor is sleeping in a WFI or WFE instruction, the * C_HALT bit must be asserted to regain control */ if (retval == ERROR_OK && (cortex_m->dcb_dhcsr & S_SLEEP)) - retval = mem_ap_write_u32(armv7m->debug_ap, DCB_DHCSR, DBGKEY | C_HALT | C_DEBUGEN); + retval = cortex_m_write_debug_halt_mask(target, C_HALT, 0); mem_ap_write_u32(armv7m->debug_ap, DCB_DCRDR, 0); /* Ignore less important errors */ @@ -1018,8 +1018,7 @@ static int cortex_m_assert_reset(struct target *target) if (!target->reset_halt) { /* Set/Clear C_MASKINTS in a separate operation */ if (cortex_m->dcb_dhcsr & C_MASKINTS) - mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DHCSR, - DBGKEY | C_DEBUGEN | C_HALT); + cortex_m_write_debug_halt_mask(target, 0, C_MASKINTS); /* clear any debug flags before resuming */ cortex_m_clear_halt(target); From bca67d107fb92f583fd906ae974e5ed0d7438c5b Mon Sep 17 00:00:00 2001 From: Christopher Head Date: Tue, 3 Oct 2017 13:23:57 -0700 Subject: [PATCH 053/127] Cortex-M: Delete an unnecessary local variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The dhcsr_save variable was used to save the value of cortex_m->dcb_dhcsr so it could be restored later. However, all writes in between the save and the restore use mem_ap_write_atomic_u32, not cortex_m_write_debug_halt_mask, which means cortex_m->dcb_dhcsr isn’t changed anyway. Delete the unnecessary local. Change-Id: I064a3134e21398e1ecfc9f1fa7efd7b020b52341 Signed-off-by: Christopher Head Reviewed-on: http://openocd.zylin.com/4240 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/cortex_m.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 11dbf24f2..2f8c2a2c8 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -168,12 +168,8 @@ static int cortex_m_single_step_core(struct target *target) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; - uint32_t dhcsr_save; int retval; - /* backup dhcsr reg */ - dhcsr_save = cortex_m->dcb_dhcsr; - /* Mask interrupts before clearing halt, if done already. This avoids * Erratum 377497 (fixed in r1p0) where setting MASKINTS while clearing * HALT can put the core into an unknown state. @@ -191,7 +187,6 @@ static int cortex_m_single_step_core(struct target *target) LOG_DEBUG(" "); /* restore dhcsr reg */ - cortex_m->dcb_dhcsr = dhcsr_save; cortex_m_clear_halt(target); return ERROR_OK; From c0881ba2d5752ce747a4f74daf7531662f9360a9 Mon Sep 17 00:00:00 2001 From: Jonathan McDowell Date: Fri, 13 Oct 2017 07:53:32 +0100 Subject: [PATCH 054/127] tcl/interface/ftdi/openrd: Fix FTDI channel + device description Similar to the Sheevaplug fix inf95f8b70fbd0f7e9c91a2d9006b1abb2dd07ebf2 the OpenRD device has its JTAG interface on the first channel of the ft2232, which is 0 for the new driver but was 1 for the old one. Correct the config file appropriately. Also the device description was missing the trailing " B" and thus not picking up the device correctly. Finally add an adapter_khz setting in the OpenRD board configuration file - set to 2MHz to match the Sheeva variant. Confirmed as working thanks to Phil Hands providing me access to his hardware to test on. See also Debian Bug#793214; https://bugs.debian.org/793214 Change-Id: Ifacf53124eaa330bbbdf36dfa79e3256bf2a5201 Signed-off-by: Jonathan McDowell Reviewed-on: http://openocd.zylin.com/4254 Tested-by: jenkins Reviewed-by: Spencer Oliver --- tcl/board/openrd.cfg | 2 ++ tcl/interface/ftdi/openrd.cfg | 9 ++------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tcl/board/openrd.cfg b/tcl/board/openrd.cfg index 1051c25d9..db3cb0326 100644 --- a/tcl/board/openrd.cfg +++ b/tcl/board/openrd.cfg @@ -3,6 +3,8 @@ source [find interface/ftdi/openrd.cfg] source [find target/feroceon.cfg] +adapter_khz 2000 + $_TARGETNAME configure \ -work-area-phys 0x10000000 \ -work-area-size 65536 \ diff --git a/tcl/interface/ftdi/openrd.cfg b/tcl/interface/ftdi/openrd.cfg index 8c1a80596..9ec5b5f65 100644 --- a/tcl/interface/ftdi/openrd.cfg +++ b/tcl/interface/ftdi/openrd.cfg @@ -4,15 +4,10 @@ # http://www.marvell.com/products/embedded_processors/developer/kirkwood/openrd.jsp # -echo "WARNING!" -echo "This file was not tested with real interface, it is based on code in ft2232.c." -echo "Please report your experience with this file to openocd-devel mailing list," -echo "so it could be marked as working or fixed." - interface ftdi -ftdi_device_desc "OpenRD JTAGKey FT2232D" +ftdi_device_desc "OpenRD JTAGKey FT2232D B" ftdi_vid_pid 0x0403 0x9e90 -ftdi_channel 1 +ftdi_channel 0 ftdi_layout_init 0x0608 0x0f1b ftdi_layout_signal nTRST -data 0x0200 From 41092636d1a10d7fe55a986f0d5556a4c34b58d2 Mon Sep 17 00:00:00 2001 From: Jonas Norling Date: Wed, 25 Oct 2017 11:33:06 +0200 Subject: [PATCH 055/127] ftdi: Enable SWDIO output before sending data on it The SWDIO buffer has to be enabled, by setting SWDIO_OE, for data on SWDIO to reach the target. Explicitly do this before sending the switch sequences for JTAG-to-SWD, etc. This makes the code insensitive to the state of SWDIO_OE specified in ftdi_layout_init. It used to work only on adapters with a non-inverted SWDIO_OE inited to 1, or inverted SWDIO_OE inited to 0. Change-Id: I4b9e520ac1c7ce2a437251a05fc036bc68de718e Signed-off-by: Jonas Norling Reviewed-on: http://openocd.zylin.com/4270 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Andreas Fritiofson --- src/jtag/drivers/ftdi.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c index 75a3ce43e..32876bac5 100644 --- a/src/jtag/drivers/ftdi.c +++ b/src/jtag/drivers/ftdi.c @@ -1218,14 +1218,17 @@ static int ftdi_swd_switch_seq(enum swd_special_seq seq) switch (seq) { case LINE_RESET: LOG_DEBUG("SWD line reset"); + ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_line_reset, 0, swd_seq_line_reset_len, SWD_MODE); break; case JTAG_TO_SWD: LOG_DEBUG("JTAG-to-SWD"); + ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_jtag_to_swd, 0, swd_seq_jtag_to_swd_len, SWD_MODE); break; case SWD_TO_JTAG: LOG_DEBUG("SWD-to-JTAG"); + ftdi_swd_swdio_en(true); mpsse_clock_data_out(mpsse_ctx, swd_seq_swd_to_jtag, 0, swd_seq_swd_to_jtag_len, SWD_MODE); break; default: From db754536e8f4fe2edd92c5c0961c8346e2b8882d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 27 Oct 2017 13:15:22 -0700 Subject: [PATCH 056/127] Support 64-bit FPRs on RV32. Because there is no instruction that moves just half of a 64-bit FPR to/from a GPR, we need to use scratch memory for this operation. This code can theoretically use: 1. DMI_DATA, if it is memory mapped in the target. 2. DMI_PROGBUF, if it is writable in the target. 3. A user-configured address. I have only tested this code very lightly. One reason is that gdb thinks that on RV32 harts every register is 32 bits wide. Another is that this is mostly proof-of-concept to satisfy the small program buffer code review, which I don't want to drag out forever. Existing tests don't realize that floating support was broken with RV32D, and don't realize that it still doesn't work because of the gdb problem mentioned above. This change improves Issue #110 but there's more work to be done. Change-Id: I99b8a36e5fea26f1d9e16e36cf99adc7be26b944 --- src/target/riscv/riscv-013.c | 312 ++++++++++++++++++++++++++++++++--- src/target/riscv/riscv.c | 49 +++++- src/target/riscv/riscv.h | 3 + 3 files changed, 329 insertions(+), 35 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 5ff4a6ffe..efcc89520 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -28,6 +28,7 @@ #include "batch.h" #define DMI_DATA1 (DMI_DATA0 + 1) +#define DMI_PROGBUF1 (DMI_PROGBUF0 + 1) static void riscv013_on_step_or_resume(struct target *target, bool step); static void riscv013_step_or_resume_current_hart(struct target *target, bool step); @@ -55,6 +56,12 @@ static void riscv013_fill_dmi_read_u64(struct target *target, char *buf, int a); static int riscv013_dmi_write_u64_bits(struct target *target); static void riscv013_fill_dmi_nop_u64(struct target *target, char *buf); static int register_read_direct(struct target *target, uint64_t *value, uint32_t number); +static int register_write_direct(struct target *target, unsigned number, + uint64_t value); +static int read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer); +static int write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, const uint8_t *buffer); /** * Since almost everything can be accomplish by scanning the dbus register, all @@ -127,6 +134,12 @@ struct memory_cache_line { bool dirty; }; +typedef enum { + YNM_MAYBE, + YNM_YES, + YNM_NO +} yes_no_maybe_t; + typedef struct { /* Number of address bits in the dbus register. */ unsigned abits; @@ -143,6 +156,10 @@ typedef struct { * reg_cache. */ uint64_t mstatus_actual; + yes_no_maybe_t progbuf_writable; + /* We only need the address so that we know the alignment of the buffer. */ + riscv_addr_t progbuf_address; + /* Single buffer that contains all register names, instead of calling * malloc for each register. Needs to be freed when reg_list is freed. */ char *reg_names; @@ -175,7 +192,12 @@ typedef struct { // When a function returns some error due to a failure indicated by the // target in cmderr, the caller can look here to see what that error was. // (Compare with errno.) - unsigned cmderr; + uint8_t cmderr; + + // Some fields from hartinfo. + uint8_t datasize; + uint8_t dataaccess; + int16_t dataaddr; } riscv013_info_t; static void decode_dmi(char *text, unsigned address, unsigned data) @@ -737,6 +759,200 @@ static int register_write_abstract(struct target *target, uint32_t number, return ERROR_OK; } +static int examine_progbuf(struct target *target) +{ + riscv013_info_t *info = get_info(target); + + if (info->progbuf_writable != YNM_MAYBE) + return ERROR_OK; + + // Figure out if progbuf is writable. + + if (info->progbufsize < 1) { + info->progbuf_writable = YNM_NO; + LOG_INFO("No program buffer present."); + return ERROR_OK; + } + + uint64_t s0; + if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + struct riscv_program program; + riscv_program_init(&program, target); + riscv_program_insert(&program, auipc(S0)); + if (riscv_program_exec(&program, target) != ERROR_OK) + return ERROR_FAIL; + + if (register_read_direct(target, &info->progbuf_address, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; + + riscv_program_init(&program, target); + riscv_program_insert(&program, sw(S0, S0, 0)); + int result = riscv_program_exec(&program, target); + + if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) + return ERROR_FAIL; + + if (result != ERROR_OK) { + // This program might have failed if the program buffer is not + // writable. + info->progbuf_writable = YNM_NO; + return ERROR_OK; + } + + uint32_t written = dmi_read(target, DMI_PROGBUF0); + if (written == (uint32_t) info->progbuf_address) { + LOG_INFO("progbuf is writable at 0x%" TARGET_PRIxADDR, + info->progbuf_address); + info->progbuf_writable = YNM_YES; + + } else { + LOG_INFO("progbuf is not writeable at 0x%" TARGET_PRIxADDR, + info->progbuf_address); + info->progbuf_writable = YNM_NO; + } + + return ERROR_OK; +} + +typedef enum { + SPACE_DMI_DATA, + SPACE_DMI_PROGBUF, + SPACE_DMI_RAM +} memory_space_t; + +typedef struct { + // How can the debugger access this memory? + memory_space_t memory_space; + // Memory address to access the scratch memory from the hart. + riscv_addr_t hart_address; + // Memory address to access the scratch memory from the debugger. + riscv_addr_t debug_address; +} scratch_mem_t; + +/** + * Find some scratch memory to be used with the given program. + */ +static int scratch_find(struct target *target, + scratch_mem_t *scratch, + struct riscv_program *program, + unsigned size_bytes) +{ + riscv013_info_t *info = get_info(target); + + riscv_addr_t alignment = 1; + while (alignment < size_bytes) + alignment *= 2; + + if (info->dataaccess == 1) { + // Sign extend dataaddr. + scratch->hart_address = info->dataaddr; + if (info->dataaddr & (1<<11)) { + scratch->hart_address |= 0xfffffffffffff000ULL; + } + // Align. + scratch->hart_address = (scratch->hart_address + alignment - 1) & ~(alignment - 1); + + if ((size_bytes + scratch->hart_address - info->dataaddr + 3) / 4 >= + info->datasize) { + scratch->memory_space = SPACE_DMI_DATA; + scratch->debug_address = (scratch->hart_address - info->dataaddr) / 4; + return ERROR_OK; + } + } + + if (examine_progbuf(target) != ERROR_OK) + return ERROR_FAIL; + + // Allow for ebreak at the end of the program. + unsigned program_size = (program->instruction_count + 1 ) * 4; + scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) & + ~(alignment - 1); + if ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >= + info->progbufsize) { + scratch->memory_space = SPACE_DMI_PROGBUF; + scratch->debug_address = (scratch->hart_address - info->progbuf_address) / 4; + return ERROR_OK; + } + + if (riscv_use_scratch_ram) { + scratch->hart_address = (riscv_use_scratch_ram + alignment - 1) & + ~(alignment - 1); + scratch->memory_space = SPACE_DMI_RAM; + scratch->debug_address = scratch->hart_address; + } + + LOG_ERROR("Couldn't find %d bytes of scratch RAM to use. Please configure " + "an address with 'riscv set_scratch_ram'.", size_bytes); + return ERROR_FAIL; +} + +static int scratch_read64(struct target *target, scratch_mem_t *scratch, + uint64_t *value) +{ + switch (scratch->memory_space) { + case SPACE_DMI_DATA: + *value = dmi_read(target, DMI_DATA0 + scratch->debug_address); + *value |= ((uint64_t) dmi_read(target, DMI_DATA1 + + scratch->debug_address)) << 32; + break; + case SPACE_DMI_PROGBUF: + *value = dmi_read(target, DMI_PROGBUF0 + scratch->debug_address); + *value |= ((uint64_t) dmi_read(target, DMI_PROGBUF1 + + scratch->debug_address)) << 32; + break; + case SPACE_DMI_RAM: + { + uint8_t buffer[8]; + if (read_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + return ERROR_FAIL; + *value = buffer[0] | + (((uint64_t) buffer[1]) << 8) | + (((uint64_t) buffer[2]) << 16) | + (((uint64_t) buffer[3]) << 24) | + (((uint64_t) buffer[4]) << 32) | + (((uint64_t) buffer[5]) << 40) | + (((uint64_t) buffer[6]) << 48) | + (((uint64_t) buffer[7]) << 56); + } + break; + } + return ERROR_OK; +} + +static int scratch_write64(struct target *target, scratch_mem_t *scratch, + uint64_t value) +{ + switch (scratch->memory_space) { + case SPACE_DMI_DATA: + dmi_write(target, DMI_DATA0 + scratch->debug_address, value); + dmi_write(target, DMI_DATA1 + scratch->debug_address, value >> 32); + break; + case SPACE_DMI_PROGBUF: + dmi_write(target, DMI_PROGBUF0 + scratch->debug_address, value); + dmi_write(target, DMI_PROGBUF1 + scratch->debug_address, value >> 32); + break; + case SPACE_DMI_RAM: + { + uint8_t buffer[8] = { + value, + value >> 8, + value >> 16, + value >> 24, + value >> 32, + value >> 40, + value >> 48, + value >> 56 + }; + if (write_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + return ERROR_FAIL; + } + break; + } + return ERROR_OK; +} + static int register_write_direct(struct target *target, unsigned number, uint64_t value) { @@ -749,33 +965,49 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_OK; struct riscv_program program; - riscv_program_init(&program, target); uint64_t s0; if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) - return ERROR_FAIL; + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + supports_extension(target, 'D') && + riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a register, so + * we need to use some scratch RAM. */ + riscv_program_insert(&program, fld(number - GDB_REGNO_FPR0, S0, 0)); + + scratch_mem_t scratch; + if (scratch_find(target, &scratch, &program, 8) != ERROR_OK) + return ERROR_FAIL; + + if (register_write_direct(target, GDB_REGNO_S0, scratch.hart_address) + != ERROR_OK) + return ERROR_FAIL; + + if (scratch_write64(target, &scratch, value) != ERROR_OK) + return ERROR_FAIL; - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { - riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); - } else { - riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); - } - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - riscv_program_csrw(&program, S0, number); } else { - LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); - abort(); + if (register_write_direct(target, GDB_REGNO_S0, value) != ERROR_OK) + return ERROR_FAIL; + + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + if (supports_extension(target, 'D')) { + riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); + } else { + riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); + } + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + riscv_program_csrw(&program, S0, number); + } else { + LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); + abort(); + } } int exec_out = riscv_program_exec(&program, target); - if (exec_out != ERROR_OK) { - riscv013_clear_abstract_error(target); - } // Restore S0. if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) @@ -791,21 +1023,38 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t riscv_xlen(target)); if (result != ERROR_OK) { + assert(number != GDB_REGNO_S0); + result = ERROR_OK; struct riscv_program program; riscv_program_init(&program, target); - assert(number != GDB_REGNO_S0); + + scratch_mem_t scratch; + bool use_scratch = false; uint64_t s0; if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; // Write program to move data into s0. + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { // TODO: Possibly set F in mstatus. - // TODO: Fully support D extension on RV32. - if (supports_extension(target, 'D') && riscv_xlen(target) >= 64) { + if (supports_extension(target, 'D') && riscv_xlen(target) < 64) { + /* There are no instructions to move all the bits from a + * register, so we need to use some scratch RAM. */ + riscv_program_insert(&program, fsd(number - GDB_REGNO_FPR0, S0, + 0)); + + if (scratch_find(target, &scratch, &program, 8) != ERROR_OK) + return ERROR_FAIL; + use_scratch = true; + + if (register_write_direct(target, GDB_REGNO_S0, + scratch.hart_address) != ERROR_OK) + return ERROR_FAIL; + } else if (supports_extension(target, 'D')) { riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); } else { riscv_program_insert(&program, fmv_x_s(S0, number - GDB_REGNO_FPR0)); @@ -819,13 +1068,16 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t // Execute program. result = riscv_program_exec(&program, target); - if (result != ERROR_OK) { - riscv013_clear_abstract_error(target); + + if (use_scratch) { + if (scratch_read64(target, &scratch, value) != ERROR_OK) + return ERROR_FAIL; + } else { + // Read S0 + if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) + return ERROR_FAIL; } - // Read S0 - if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; // Restore S0. if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; @@ -993,7 +1245,6 @@ static int examine(struct target *target) info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); info->dtmcontrol_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); - uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); if (get_field(dmstatus, DMI_DMSTATUS_VERSION) != 2) { LOG_ERROR("OpenOCD only supports Debug Module version 2, not %d " @@ -1004,10 +1255,17 @@ static int examine(struct target *target) // Reset the Debug Module. dmi_write(target, DMI_DMCONTROL, 0); dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); - dmcontrol = dmi_read(target, DMI_DMCONTROL); + uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); + + uint32_t hartinfo = dmi_read(target, DMI_HARTINFO); LOG_DEBUG("dmcontrol: 0x%08x", dmcontrol); LOG_DEBUG("dmstatus: 0x%08x", dmstatus); + LOG_DEBUG("hartinfo: 0x%08x", hartinfo); + + info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); + info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); + info->dataaddr = get_field(hartinfo, DMI_HARTINFO_DATAADDR); if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 820094da3..b9be133f3 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -200,6 +200,9 @@ int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; /* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; +bool riscv_use_scratch_ram = false; +uint64_t riscv_scratch_ram_address = 0; + static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; @@ -1120,8 +1123,8 @@ int riscv_openocd_step( } /* Command Handlers */ -COMMAND_HANDLER(riscv_set_command_timeout_sec) { - +COMMAND_HANDLER(riscv_set_command_timeout_sec) +{ if (CMD_ARGC != 1) { LOG_ERROR("Command takes exactly 1 parameter"); return ERROR_COMMAND_SYNTAX_ERROR; @@ -1137,11 +1140,11 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec) { return ERROR_OK; } -COMMAND_HANDLER(riscv_set_reset_timeout_sec) { - +COMMAND_HANDLER(riscv_set_reset_timeout_sec) +{ if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; } int timeout = atoi(CMD_ARGV[0]); if (timeout <= 0){ @@ -1153,6 +1156,29 @@ COMMAND_HANDLER(riscv_set_reset_timeout_sec) { return ERROR_OK; } +COMMAND_HANDLER(riscv_set_scratch_ram) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + if (!strcmp(CMD_ARGV[0], "none")) { + riscv_use_scratch_ram = false; + return ERROR_OK; + } + + long long unsigned int address; + int result = sscanf(CMD_ARGV[0], "%Lx", &address); + if (result != (int) strlen(CMD_ARGV[0])) { + LOG_ERROR("%s is not a valid address for command.", CMD_ARGV[0]); + riscv_use_scratch_ram = false; + return ERROR_FAIL; + } + + riscv_scratch_ram_address = address; + riscv_use_scratch_ram = true; + return ERROR_OK; +} static const struct command_registration riscv_exec_command_handlers[] = { { @@ -1161,14 +1187,21 @@ static const struct command_registration riscv_exec_command_handlers[] = { .mode = COMMAND_ANY, .usage = "riscv set_command_timeout_sec [sec]", .help = "Set the wall-clock timeout (in seconds) for individual commands" - }, - { + }, + { .name = "set_reset_timeout_sec", .handler = riscv_set_reset_timeout_sec, .mode = COMMAND_ANY, .usage = "riscv set_reset_timeout_sec [sec]", .help = "Set the wall-clock timeout (in seconds) after reset is deasserted" }, + { + .name = "set_scratch_ram", + .handler = riscv_set_scratch_ram, + .mode = COMMAND_ANY, + .usage = "riscv set_scratch_ram none|[address]", + .help = "Set address of 16 bytes of scratch RAM the debugger can use, or 'none'." + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index f19f06c4c..4ff61270f 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -111,6 +111,9 @@ extern int riscv_command_timeout_sec; /* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ extern int riscv_reset_timeout_sec; +extern bool riscv_use_scratch_ram; +extern uint64_t riscv_scratch_ram_address; + /* Everything needs the RISC-V specific info structure, so here's a nice macro * that provides that. */ static inline riscv_info_t *riscv_info(const struct target *target) __attribute__((unused)); From 52cdf286cae5bf31b1d55730c5020b8920f79db2 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 16 Nov 2017 15:58:08 -0800 Subject: [PATCH 057/127] Add missing return. Change-Id: Ida32482903cdfd8eeb043088e84bb1f4f5ac673c --- src/target/riscv/riscv-013.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 8f7dc6adf..1768b6220 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -877,6 +877,7 @@ static int scratch_find(struct target *target, ~(alignment - 1); scratch->memory_space = SPACE_DMI_RAM; scratch->debug_address = scratch->hart_address; + return ERROR_OK; } LOG_ERROR("Couldn't find %d bytes of scratch RAM to use. Please configure " From 4d5f74fbe6b7b152d82f776241cc88f417659084 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 27 Nov 2017 13:23:33 -0800 Subject: [PATCH 058/127] Update encoding.h. Change-Id: Id653500aa525746e8824ff5fd2850c62c8c21c08 --- src/target/riscv/encoding.h | 262 +++++++++++++++++++++++++++++------- src/target/riscv/opcodes.h | 12 +- 2 files changed, 216 insertions(+), 58 deletions(-) diff --git a/src/target/riscv/encoding.h b/src/target/riscv/encoding.h index 35e0f9fe0..8ec134596 100644 --- a/src/target/riscv/encoding.h +++ b/src/target/riscv/encoding.h @@ -17,10 +17,14 @@ #define MSTATUS_FS 0x00006000 #define MSTATUS_XS 0x00018000 #define MSTATUS_MPRV 0x00020000 -#define MSTATUS_PUM 0x00040000 +#define MSTATUS_SUM 0x00040000 #define MSTATUS_MXR 0x00080000 -#define MSTATUS_VM 0x1F000000 +#define MSTATUS_TVM 0x00100000 +#define MSTATUS_TW 0x00200000 +#define MSTATUS_TSR 0x00400000 #define MSTATUS32_SD 0x80000000 +#define MSTATUS_UXL 0x0000000300000000 +#define MSTATUS_SXL 0x0000000C00000000 #define MSTATUS64_SD 0x8000000000000000 #define SSTATUS_UIE 0x00000001 @@ -30,8 +34,10 @@ #define SSTATUS_SPP 0x00000100 #define SSTATUS_FS 0x00006000 #define SSTATUS_XS 0x00018000 -#define SSTATUS_PUM 0x00040000 +#define SSTATUS_SUM 0x00040000 +#define SSTATUS_MXR 0x00080000 #define SSTATUS32_SD 0x80000000 +#define SSTATUS_UXL 0x0000000300000000 #define SSTATUS64_SD 0x8000000000000000 #define DCSR_XDEBUGVER (3U<<30) @@ -107,12 +113,30 @@ #define PRV_H 2 #define PRV_M 3 -#define VM_MBARE 0 -#define VM_MBB 1 -#define VM_MBBID 2 -#define VM_SV32 8 -#define VM_SV39 9 -#define VM_SV48 10 +#define SPTBR32_MODE 0x80000000 +#define SPTBR32_ASID 0x7FC00000 +#define SPTBR32_PPN 0x003FFFFF +#define SPTBR64_MODE 0xF000000000000000 +#define SPTBR64_ASID 0x0FFFF00000000000 +#define SPTBR64_PPN 0x00000FFFFFFFFFFF + +#define SPTBR_MODE_OFF 0 +#define SPTBR_MODE_SV32 1 +#define SPTBR_MODE_SV39 8 +#define SPTBR_MODE_SV48 9 +#define SPTBR_MODE_SV57 10 +#define SPTBR_MODE_SV64 11 + +#define PMP_R 0x01 +#define PMP_W 0x02 +#define PMP_X 0x04 +#define PMP_A 0x18 +#define PMP_L 0x80 +#define PMP_SHIFT 2 + +#define PMP_TOR 0x08 +#define PMP_NA4 0x10 +#define PMP_NAPOT 0x18 #define IRQ_S_SOFT 1 #define IRQ_H_SOFT 2 @@ -127,9 +151,8 @@ #define IRQ_HOST 13 #define DEFAULT_RSTVEC 0x00001000 -#define DEFAULT_NMIVEC 0x00001004 -#define DEFAULT_MTVEC 0x00001010 -#define CONFIG_STRING_ADDR 0x0000100C +#define CLINT_BASE 0x02000000 +#define CLINT_SIZE 0x000c0000 #define EXT_IO_BASE 0x40000000 #define DRAM_BASE 0x80000000 @@ -150,14 +173,16 @@ #ifdef __riscv -#ifdef __riscv64 +#if __riscv_xlen == 64 # define MSTATUS_SD MSTATUS64_SD # define SSTATUS_SD SSTATUS64_SD # define RISCV_PGLEVEL_BITS 9 +# define SPTBR_MODE SPTBR64_MODE #else # define MSTATUS_SD MSTATUS32_SD # define SSTATUS_SD SSTATUS32_SD # define RISCV_PGLEVEL_BITS 10 +# define SPTBR_MODE SPTBR32_MODE #endif #define RISCV_PGSHIFT 12 #define RISCV_PGSIZE (1 << RISCV_PGSHIFT) @@ -171,30 +196,18 @@ __tmp; }) #define write_csr(reg, val) ({ \ - if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ - asm volatile ("csrw " #reg ", %0" :: "i"(val)); \ - else \ - asm volatile ("csrw " #reg ", %0" :: "r"(val)); }) + asm volatile ("csrw " #reg ", %0" :: "rK"(val)); }) #define swap_csr(reg, val) ({ unsigned long __tmp; \ - if (__builtin_constant_p(val) && (unsigned long)(val) < 32) \ - asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "i"(val)); \ - else \ - asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "r"(val)); \ + asm volatile ("csrrw %0, " #reg ", %1" : "=r"(__tmp) : "rK"(val)); \ __tmp; }) #define set_csr(reg, bit) ({ unsigned long __tmp; \ - if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ - asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ - else \ - asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + asm volatile ("csrrs %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ __tmp; }) #define clear_csr(reg, bit) ({ unsigned long __tmp; \ - if (__builtin_constant_p(bit) && (unsigned long)(bit) < 32) \ - asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "i"(bit)); \ - else \ - asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "r"(bit)); \ + asm volatile ("csrrc %0, " #reg ", %1" : "=r"(__tmp) : "rK"(bit)); \ __tmp; }) #define rdtime() read_csr(time) @@ -208,7 +221,7 @@ #endif #endif -/* Automatically generated by parse-opcodes */ +/* Automatically generated by parse-opcodes. */ #ifndef RISCV_ENCODING_H #define RISCV_ENCODING_H #define MATCH_BEQ 0x63 @@ -391,14 +404,12 @@ #define MASK_URET 0xffffffff #define MATCH_SRET 0x10200073 #define MASK_SRET 0xffffffff -#define MATCH_HRET 0x20200073 -#define MASK_HRET 0xffffffff #define MATCH_MRET 0x30200073 #define MASK_MRET 0xffffffff #define MATCH_DRET 0x7b200073 #define MASK_DRET 0xffffffff -#define MATCH_SFENCE_VM 0x10400073 -#define MASK_SFENCE_VM 0xfff07fff +#define MATCH_SFENCE_VMA 0x12000073 +#define MASK_SFENCE_VMA 0xfe007fff #define MATCH_WFI 0x10500073 #define MASK_WFI 0xffffffff #define MATCH_CSRRW 0x1073 @@ -457,6 +468,34 @@ #define MASK_FCVT_D_S 0xfff0007f #define MATCH_FSQRT_D 0x5a000053 #define MASK_FSQRT_D 0xfff0007f +#define MATCH_FADD_Q 0x6000053 +#define MASK_FADD_Q 0xfe00007f +#define MATCH_FSUB_Q 0xe000053 +#define MASK_FSUB_Q 0xfe00007f +#define MATCH_FMUL_Q 0x16000053 +#define MASK_FMUL_Q 0xfe00007f +#define MATCH_FDIV_Q 0x1e000053 +#define MASK_FDIV_Q 0xfe00007f +#define MATCH_FSGNJ_Q 0x26000053 +#define MASK_FSGNJ_Q 0xfe00707f +#define MATCH_FSGNJN_Q 0x26001053 +#define MASK_FSGNJN_Q 0xfe00707f +#define MATCH_FSGNJX_Q 0x26002053 +#define MASK_FSGNJX_Q 0xfe00707f +#define MATCH_FMIN_Q 0x2e000053 +#define MASK_FMIN_Q 0xfe00707f +#define MATCH_FMAX_Q 0x2e001053 +#define MASK_FMAX_Q 0xfe00707f +#define MATCH_FCVT_S_Q 0x40300053 +#define MASK_FCVT_S_Q 0xfff0007f +#define MATCH_FCVT_Q_S 0x46000053 +#define MASK_FCVT_Q_S 0xfff0007f +#define MATCH_FCVT_D_Q 0x42300053 +#define MASK_FCVT_D_Q 0xfff0007f +#define MATCH_FCVT_Q_D 0x46100053 +#define MASK_FCVT_Q_D 0xfff0007f +#define MATCH_FSQRT_Q 0x5e000053 +#define MASK_FSQRT_Q 0xfff0007f #define MATCH_FLE_S 0xa0000053 #define MASK_FLE_S 0xfe00707f #define MATCH_FLT_S 0xa0001053 @@ -469,6 +508,12 @@ #define MASK_FLT_D 0xfe00707f #define MATCH_FEQ_D 0xa2002053 #define MASK_FEQ_D 0xfe00707f +#define MATCH_FLE_Q 0xa6000053 +#define MASK_FLE_Q 0xfe00707f +#define MATCH_FLT_Q 0xa6001053 +#define MASK_FLT_Q 0xfe00707f +#define MATCH_FEQ_Q 0xa6002053 +#define MASK_FEQ_Q 0xfe00707f #define MATCH_FCVT_W_S 0xc0000053 #define MASK_FCVT_W_S 0xfff0007f #define MATCH_FCVT_WU_S 0xc0100053 @@ -477,8 +522,8 @@ #define MASK_FCVT_L_S 0xfff0007f #define MATCH_FCVT_LU_S 0xc0300053 #define MASK_FCVT_LU_S 0xfff0007f -#define MATCH_FMV_X_S 0xe0000053 -#define MASK_FMV_X_S 0xfff0707f +#define MATCH_FMV_X_W 0xe0000053 +#define MASK_FMV_X_W 0xfff0707f #define MATCH_FCLASS_S 0xe0001053 #define MASK_FCLASS_S 0xfff0707f #define MATCH_FCVT_W_D 0xc2000053 @@ -493,6 +538,18 @@ #define MASK_FMV_X_D 0xfff0707f #define MATCH_FCLASS_D 0xe2001053 #define MASK_FCLASS_D 0xfff0707f +#define MATCH_FCVT_W_Q 0xc6000053 +#define MASK_FCVT_W_Q 0xfff0007f +#define MATCH_FCVT_WU_Q 0xc6100053 +#define MASK_FCVT_WU_Q 0xfff0007f +#define MATCH_FCVT_L_Q 0xc6200053 +#define MASK_FCVT_L_Q 0xfff0007f +#define MATCH_FCVT_LU_Q 0xc6300053 +#define MASK_FCVT_LU_Q 0xfff0007f +#define MATCH_FMV_X_Q 0xe6000053 +#define MASK_FMV_X_Q 0xfff0707f +#define MATCH_FCLASS_Q 0xe6001053 +#define MASK_FCLASS_Q 0xfff0707f #define MATCH_FCVT_S_W 0xd0000053 #define MASK_FCVT_S_W 0xfff0007f #define MATCH_FCVT_S_WU 0xd0100053 @@ -501,8 +558,8 @@ #define MASK_FCVT_S_L 0xfff0007f #define MATCH_FCVT_S_LU 0xd0300053 #define MASK_FCVT_S_LU 0xfff0007f -#define MATCH_FMV_S_X 0xf0000053 -#define MASK_FMV_S_X 0xfff0707f +#define MATCH_FMV_W_X 0xf0000053 +#define MASK_FMV_W_X 0xfff0707f #define MATCH_FCVT_D_W 0xd2000053 #define MASK_FCVT_D_W 0xfff0007f #define MATCH_FCVT_D_WU 0xd2100053 @@ -513,14 +570,28 @@ #define MASK_FCVT_D_LU 0xfff0007f #define MATCH_FMV_D_X 0xf2000053 #define MASK_FMV_D_X 0xfff0707f +#define MATCH_FCVT_Q_W 0xd6000053 +#define MASK_FCVT_Q_W 0xfff0007f +#define MATCH_FCVT_Q_WU 0xd6100053 +#define MASK_FCVT_Q_WU 0xfff0007f +#define MATCH_FCVT_Q_L 0xd6200053 +#define MASK_FCVT_Q_L 0xfff0007f +#define MATCH_FCVT_Q_LU 0xd6300053 +#define MASK_FCVT_Q_LU 0xfff0007f +#define MATCH_FMV_Q_X 0xf6000053 +#define MASK_FMV_Q_X 0xfff0707f #define MATCH_FLW 0x2007 #define MASK_FLW 0x707f #define MATCH_FLD 0x3007 #define MASK_FLD 0x707f +#define MATCH_FLQ 0x4007 +#define MASK_FLQ 0x707f #define MATCH_FSW 0x2027 #define MASK_FSW 0x707f #define MATCH_FSD 0x3027 #define MASK_FSD 0x707f +#define MATCH_FSQ 0x4027 +#define MASK_FSQ 0x707f #define MATCH_FMADD_S 0x43 #define MASK_FMADD_S 0x600007f #define MATCH_FMSUB_S 0x47 @@ -537,6 +608,14 @@ #define MASK_FNMSUB_D 0x600007f #define MATCH_FNMADD_D 0x200004f #define MASK_FNMADD_D 0x600007f +#define MATCH_FMADD_Q 0x6000043 +#define MASK_FMADD_Q 0x600007f +#define MATCH_FMSUB_Q 0x6000047 +#define MASK_FMSUB_Q 0x600007f +#define MATCH_FNMSUB_Q 0x600004b +#define MASK_FNMSUB_Q 0x600007f +#define MATCH_FNMADD_Q 0x600004f +#define MASK_FNMADD_Q 0x600007f #define MATCH_C_NOP 0x1 #define MASK_C_NOP 0xffff #define MATCH_C_ADDI16SP 0x6101 @@ -707,6 +786,7 @@ #define CSR_SSTATUS 0x100 #define CSR_SIE 0x104 #define CSR_STVEC 0x105 +#define CSR_SCOUNTEREN 0x106 #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 #define CSR_SCAUSE 0x142 @@ -719,11 +799,32 @@ #define CSR_MIDELEG 0x303 #define CSR_MIE 0x304 #define CSR_MTVEC 0x305 +#define CSR_MCOUNTEREN 0x306 #define CSR_MSCRATCH 0x340 #define CSR_MEPC 0x341 #define CSR_MCAUSE 0x342 #define CSR_MBADADDR 0x343 #define CSR_MIP 0x344 +#define CSR_PMPCFG0 0x3a0 +#define CSR_PMPCFG1 0x3a1 +#define CSR_PMPCFG2 0x3a2 +#define CSR_PMPCFG3 0x3a3 +#define CSR_PMPADDR0 0x3b0 +#define CSR_PMPADDR1 0x3b1 +#define CSR_PMPADDR2 0x3b2 +#define CSR_PMPADDR3 0x3b3 +#define CSR_PMPADDR4 0x3b4 +#define CSR_PMPADDR5 0x3b5 +#define CSR_PMPADDR6 0x3b6 +#define CSR_PMPADDR7 0x3b7 +#define CSR_PMPADDR8 0x3b8 +#define CSR_PMPADDR9 0x3b9 +#define CSR_PMPADDR10 0x3ba +#define CSR_PMPADDR11 0x3bb +#define CSR_PMPADDR12 0x3bc +#define CSR_PMPADDR13 0x3bd +#define CSR_PMPADDR14 0x3be +#define CSR_PMPADDR15 0x3bf #define CSR_TSELECT 0x7a0 #define CSR_TDATA1 0x7a1 #define CSR_TDATA2 0x7a2 @@ -762,8 +863,6 @@ #define CSR_MHPMCOUNTER29 0xb1d #define CSR_MHPMCOUNTER30 0xb1e #define CSR_MHPMCOUNTER31 0xb1f -#define CSR_MUCOUNTEREN 0x320 -#define CSR_MSCOUNTEREN 0x321 #define CSR_MHPMEVENT3 0x323 #define CSR_MHPMEVENT4 0x324 #define CSR_MHPMEVENT5 0x325 @@ -861,17 +960,20 @@ #define CSR_MHPMCOUNTER30H 0xb9e #define CSR_MHPMCOUNTER31H 0xb9f #define CAUSE_MISALIGNED_FETCH 0x0 -#define CAUSE_FAULT_FETCH 0x1 +#define CAUSE_FETCH_ACCESS 0x1 #define CAUSE_ILLEGAL_INSTRUCTION 0x2 #define CAUSE_BREAKPOINT 0x3 #define CAUSE_MISALIGNED_LOAD 0x4 -#define CAUSE_FAULT_LOAD 0x5 +#define CAUSE_LOAD_ACCESS 0x5 #define CAUSE_MISALIGNED_STORE 0x6 -#define CAUSE_FAULT_STORE 0x7 +#define CAUSE_STORE_ACCESS 0x7 #define CAUSE_USER_ECALL 0x8 #define CAUSE_SUPERVISOR_ECALL 0x9 #define CAUSE_HYPERVISOR_ECALL 0xa #define CAUSE_MACHINE_ECALL 0xb +#define CAUSE_FETCH_PAGE_FAULT 0xc +#define CAUSE_LOAD_PAGE_FAULT 0xd +#define CAUSE_STORE_PAGE_FAULT 0xf #endif #ifdef DECLARE_INSN DECLARE_INSN(beq, MATCH_BEQ, MASK_BEQ) @@ -964,10 +1066,9 @@ DECLARE_INSN(ecall, MATCH_ECALL, MASK_ECALL) DECLARE_INSN(ebreak, MATCH_EBREAK, MASK_EBREAK) DECLARE_INSN(uret, MATCH_URET, MASK_URET) DECLARE_INSN(sret, MATCH_SRET, MASK_SRET) -DECLARE_INSN(hret, MATCH_HRET, MASK_HRET) DECLARE_INSN(mret, MATCH_MRET, MASK_MRET) DECLARE_INSN(dret, MATCH_DRET, MASK_DRET) -DECLARE_INSN(sfence_vm, MATCH_SFENCE_VM, MASK_SFENCE_VM) +DECLARE_INSN(sfence_vma, MATCH_SFENCE_VMA, MASK_SFENCE_VMA) DECLARE_INSN(wfi, MATCH_WFI, MASK_WFI) DECLARE_INSN(csrrw, MATCH_CSRRW, MASK_CSRRW) DECLARE_INSN(csrrs, MATCH_CSRRS, MASK_CSRRS) @@ -997,17 +1098,34 @@ DECLARE_INSN(fmax_d, MATCH_FMAX_D, MASK_FMAX_D) DECLARE_INSN(fcvt_s_d, MATCH_FCVT_S_D, MASK_FCVT_S_D) DECLARE_INSN(fcvt_d_s, MATCH_FCVT_D_S, MASK_FCVT_D_S) DECLARE_INSN(fsqrt_d, MATCH_FSQRT_D, MASK_FSQRT_D) +DECLARE_INSN(fadd_q, MATCH_FADD_Q, MASK_FADD_Q) +DECLARE_INSN(fsub_q, MATCH_FSUB_Q, MASK_FSUB_Q) +DECLARE_INSN(fmul_q, MATCH_FMUL_Q, MASK_FMUL_Q) +DECLARE_INSN(fdiv_q, MATCH_FDIV_Q, MASK_FDIV_Q) +DECLARE_INSN(fsgnj_q, MATCH_FSGNJ_Q, MASK_FSGNJ_Q) +DECLARE_INSN(fsgnjn_q, MATCH_FSGNJN_Q, MASK_FSGNJN_Q) +DECLARE_INSN(fsgnjx_q, MATCH_FSGNJX_Q, MASK_FSGNJX_Q) +DECLARE_INSN(fmin_q, MATCH_FMIN_Q, MASK_FMIN_Q) +DECLARE_INSN(fmax_q, MATCH_FMAX_Q, MASK_FMAX_Q) +DECLARE_INSN(fcvt_s_q, MATCH_FCVT_S_Q, MASK_FCVT_S_Q) +DECLARE_INSN(fcvt_q_s, MATCH_FCVT_Q_S, MASK_FCVT_Q_S) +DECLARE_INSN(fcvt_d_q, MATCH_FCVT_D_Q, MASK_FCVT_D_Q) +DECLARE_INSN(fcvt_q_d, MATCH_FCVT_Q_D, MASK_FCVT_Q_D) +DECLARE_INSN(fsqrt_q, MATCH_FSQRT_Q, MASK_FSQRT_Q) DECLARE_INSN(fle_s, MATCH_FLE_S, MASK_FLE_S) DECLARE_INSN(flt_s, MATCH_FLT_S, MASK_FLT_S) DECLARE_INSN(feq_s, MATCH_FEQ_S, MASK_FEQ_S) DECLARE_INSN(fle_d, MATCH_FLE_D, MASK_FLE_D) DECLARE_INSN(flt_d, MATCH_FLT_D, MASK_FLT_D) DECLARE_INSN(feq_d, MATCH_FEQ_D, MASK_FEQ_D) +DECLARE_INSN(fle_q, MATCH_FLE_Q, MASK_FLE_Q) +DECLARE_INSN(flt_q, MATCH_FLT_Q, MASK_FLT_Q) +DECLARE_INSN(feq_q, MATCH_FEQ_Q, MASK_FEQ_Q) DECLARE_INSN(fcvt_w_s, MATCH_FCVT_W_S, MASK_FCVT_W_S) DECLARE_INSN(fcvt_wu_s, MATCH_FCVT_WU_S, MASK_FCVT_WU_S) DECLARE_INSN(fcvt_l_s, MATCH_FCVT_L_S, MASK_FCVT_L_S) DECLARE_INSN(fcvt_lu_s, MATCH_FCVT_LU_S, MASK_FCVT_LU_S) -DECLARE_INSN(fmv_x_s, MATCH_FMV_X_S, MASK_FMV_X_S) +DECLARE_INSN(fmv_x_w, MATCH_FMV_X_W, MASK_FMV_X_W) DECLARE_INSN(fclass_s, MATCH_FCLASS_S, MASK_FCLASS_S) DECLARE_INSN(fcvt_w_d, MATCH_FCVT_W_D, MASK_FCVT_W_D) DECLARE_INSN(fcvt_wu_d, MATCH_FCVT_WU_D, MASK_FCVT_WU_D) @@ -1015,20 +1133,33 @@ DECLARE_INSN(fcvt_l_d, MATCH_FCVT_L_D, MASK_FCVT_L_D) DECLARE_INSN(fcvt_lu_d, MATCH_FCVT_LU_D, MASK_FCVT_LU_D) DECLARE_INSN(fmv_x_d, MATCH_FMV_X_D, MASK_FMV_X_D) DECLARE_INSN(fclass_d, MATCH_FCLASS_D, MASK_FCLASS_D) +DECLARE_INSN(fcvt_w_q, MATCH_FCVT_W_Q, MASK_FCVT_W_Q) +DECLARE_INSN(fcvt_wu_q, MATCH_FCVT_WU_Q, MASK_FCVT_WU_Q) +DECLARE_INSN(fcvt_l_q, MATCH_FCVT_L_Q, MASK_FCVT_L_Q) +DECLARE_INSN(fcvt_lu_q, MATCH_FCVT_LU_Q, MASK_FCVT_LU_Q) +DECLARE_INSN(fmv_x_q, MATCH_FMV_X_Q, MASK_FMV_X_Q) +DECLARE_INSN(fclass_q, MATCH_FCLASS_Q, MASK_FCLASS_Q) DECLARE_INSN(fcvt_s_w, MATCH_FCVT_S_W, MASK_FCVT_S_W) DECLARE_INSN(fcvt_s_wu, MATCH_FCVT_S_WU, MASK_FCVT_S_WU) DECLARE_INSN(fcvt_s_l, MATCH_FCVT_S_L, MASK_FCVT_S_L) DECLARE_INSN(fcvt_s_lu, MATCH_FCVT_S_LU, MASK_FCVT_S_LU) -DECLARE_INSN(fmv_s_x, MATCH_FMV_S_X, MASK_FMV_S_X) +DECLARE_INSN(fmv_w_x, MATCH_FMV_W_X, MASK_FMV_W_X) DECLARE_INSN(fcvt_d_w, MATCH_FCVT_D_W, MASK_FCVT_D_W) DECLARE_INSN(fcvt_d_wu, MATCH_FCVT_D_WU, MASK_FCVT_D_WU) DECLARE_INSN(fcvt_d_l, MATCH_FCVT_D_L, MASK_FCVT_D_L) DECLARE_INSN(fcvt_d_lu, MATCH_FCVT_D_LU, MASK_FCVT_D_LU) DECLARE_INSN(fmv_d_x, MATCH_FMV_D_X, MASK_FMV_D_X) +DECLARE_INSN(fcvt_q_w, MATCH_FCVT_Q_W, MASK_FCVT_Q_W) +DECLARE_INSN(fcvt_q_wu, MATCH_FCVT_Q_WU, MASK_FCVT_Q_WU) +DECLARE_INSN(fcvt_q_l, MATCH_FCVT_Q_L, MASK_FCVT_Q_L) +DECLARE_INSN(fcvt_q_lu, MATCH_FCVT_Q_LU, MASK_FCVT_Q_LU) +DECLARE_INSN(fmv_q_x, MATCH_FMV_Q_X, MASK_FMV_Q_X) DECLARE_INSN(flw, MATCH_FLW, MASK_FLW) DECLARE_INSN(fld, MATCH_FLD, MASK_FLD) +DECLARE_INSN(flq, MATCH_FLQ, MASK_FLQ) DECLARE_INSN(fsw, MATCH_FSW, MASK_FSW) DECLARE_INSN(fsd, MATCH_FSD, MASK_FSD) +DECLARE_INSN(fsq, MATCH_FSQ, MASK_FSQ) DECLARE_INSN(fmadd_s, MATCH_FMADD_S, MASK_FMADD_S) DECLARE_INSN(fmsub_s, MATCH_FMSUB_S, MASK_FMSUB_S) DECLARE_INSN(fnmsub_s, MATCH_FNMSUB_S, MASK_FNMSUB_S) @@ -1037,6 +1168,10 @@ DECLARE_INSN(fmadd_d, MATCH_FMADD_D, MASK_FMADD_D) DECLARE_INSN(fmsub_d, MATCH_FMSUB_D, MASK_FMSUB_D) DECLARE_INSN(fnmsub_d, MATCH_FNMSUB_D, MASK_FNMSUB_D) DECLARE_INSN(fnmadd_d, MATCH_FNMADD_D, MASK_FNMADD_D) +DECLARE_INSN(fmadd_q, MATCH_FMADD_Q, MASK_FMADD_Q) +DECLARE_INSN(fmsub_q, MATCH_FMSUB_Q, MASK_FMSUB_Q) +DECLARE_INSN(fnmsub_q, MATCH_FNMSUB_Q, MASK_FNMSUB_Q) +DECLARE_INSN(fnmadd_q, MATCH_FNMADD_Q, MASK_FNMADD_Q) DECLARE_INSN(c_nop, MATCH_C_NOP, MASK_C_NOP) DECLARE_INSN(c_addi16sp, MATCH_C_ADDI16SP, MASK_C_ADDI16SP) DECLARE_INSN(c_jr, MATCH_C_JR, MASK_C_JR) @@ -1143,6 +1278,7 @@ DECLARE_CSR(hpmcounter31, CSR_HPMCOUNTER31) DECLARE_CSR(sstatus, CSR_SSTATUS) DECLARE_CSR(sie, CSR_SIE) DECLARE_CSR(stvec, CSR_STVEC) +DECLARE_CSR(scounteren, CSR_SCOUNTEREN) DECLARE_CSR(sscratch, CSR_SSCRATCH) DECLARE_CSR(sepc, CSR_SEPC) DECLARE_CSR(scause, CSR_SCAUSE) @@ -1155,11 +1291,32 @@ DECLARE_CSR(medeleg, CSR_MEDELEG) DECLARE_CSR(mideleg, CSR_MIDELEG) DECLARE_CSR(mie, CSR_MIE) DECLARE_CSR(mtvec, CSR_MTVEC) +DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) DECLARE_CSR(mscratch, CSR_MSCRATCH) DECLARE_CSR(mepc, CSR_MEPC) DECLARE_CSR(mcause, CSR_MCAUSE) DECLARE_CSR(mbadaddr, CSR_MBADADDR) DECLARE_CSR(mip, CSR_MIP) +DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) +DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) +DECLARE_CSR(pmpcfg2, CSR_PMPCFG2) +DECLARE_CSR(pmpcfg3, CSR_PMPCFG3) +DECLARE_CSR(pmpaddr0, CSR_PMPADDR0) +DECLARE_CSR(pmpaddr1, CSR_PMPADDR1) +DECLARE_CSR(pmpaddr2, CSR_PMPADDR2) +DECLARE_CSR(pmpaddr3, CSR_PMPADDR3) +DECLARE_CSR(pmpaddr4, CSR_PMPADDR4) +DECLARE_CSR(pmpaddr5, CSR_PMPADDR5) +DECLARE_CSR(pmpaddr6, CSR_PMPADDR6) +DECLARE_CSR(pmpaddr7, CSR_PMPADDR7) +DECLARE_CSR(pmpaddr8, CSR_PMPADDR8) +DECLARE_CSR(pmpaddr9, CSR_PMPADDR9) +DECLARE_CSR(pmpaddr10, CSR_PMPADDR10) +DECLARE_CSR(pmpaddr11, CSR_PMPADDR11) +DECLARE_CSR(pmpaddr12, CSR_PMPADDR12) +DECLARE_CSR(pmpaddr13, CSR_PMPADDR13) +DECLARE_CSR(pmpaddr14, CSR_PMPADDR14) +DECLARE_CSR(pmpaddr15, CSR_PMPADDR15) DECLARE_CSR(tselect, CSR_TSELECT) DECLARE_CSR(tdata1, CSR_TDATA1) DECLARE_CSR(tdata2, CSR_TDATA2) @@ -1198,8 +1355,6 @@ DECLARE_CSR(mhpmcounter28, CSR_MHPMCOUNTER28) DECLARE_CSR(mhpmcounter29, CSR_MHPMCOUNTER29) DECLARE_CSR(mhpmcounter30, CSR_MHPMCOUNTER30) DECLARE_CSR(mhpmcounter31, CSR_MHPMCOUNTER31) -DECLARE_CSR(mucounteren, CSR_MUCOUNTEREN) -DECLARE_CSR(mscounteren, CSR_MSCOUNTEREN) DECLARE_CSR(mhpmevent3, CSR_MHPMEVENT3) DECLARE_CSR(mhpmevent4, CSR_MHPMEVENT4) DECLARE_CSR(mhpmevent5, CSR_MHPMEVENT5) @@ -1299,15 +1454,18 @@ DECLARE_CSR(mhpmcounter31h, CSR_MHPMCOUNTER31H) #endif #ifdef DECLARE_CAUSE DECLARE_CAUSE("misaligned fetch", CAUSE_MISALIGNED_FETCH) -DECLARE_CAUSE("fault fetch", CAUSE_FAULT_FETCH) +DECLARE_CAUSE("fetch access", CAUSE_FETCH_ACCESS) DECLARE_CAUSE("illegal instruction", CAUSE_ILLEGAL_INSTRUCTION) DECLARE_CAUSE("breakpoint", CAUSE_BREAKPOINT) DECLARE_CAUSE("misaligned load", CAUSE_MISALIGNED_LOAD) -DECLARE_CAUSE("fault load", CAUSE_FAULT_LOAD) +DECLARE_CAUSE("load access", CAUSE_LOAD_ACCESS) DECLARE_CAUSE("misaligned store", CAUSE_MISALIGNED_STORE) -DECLARE_CAUSE("fault store", CAUSE_FAULT_STORE) +DECLARE_CAUSE("store access", CAUSE_STORE_ACCESS) DECLARE_CAUSE("user_ecall", CAUSE_USER_ECALL) DECLARE_CAUSE("supervisor_ecall", CAUSE_SUPERVISOR_ECALL) DECLARE_CAUSE("hypervisor_ecall", CAUSE_HYPERVISOR_ECALL) DECLARE_CAUSE("machine_ecall", CAUSE_MACHINE_ECALL) +DECLARE_CAUSE("fetch page fault", CAUSE_FETCH_PAGE_FAULT) +DECLARE_CAUSE("load page fault", CAUSE_LOAD_PAGE_FAULT) +DECLARE_CAUSE("store page fault", CAUSE_STORE_PAGE_FAULT) #endif diff --git a/src/target/riscv/opcodes.h b/src/target/riscv/opcodes.h index c4d9baf6f..874933b27 100644 --- a/src/target/riscv/opcodes.h +++ b/src/target/riscv/opcodes.h @@ -173,12 +173,12 @@ static uint32_t fld(unsigned int dest, unsigned int base, uint16_t offset) MATCH_FLD; } -static uint32_t fmv_x_s(unsigned dest, unsigned src) __attribute__ ((unused)); -static uint32_t fmv_x_s(unsigned dest, unsigned src) +static uint32_t fmv_x_w(unsigned dest, unsigned src) __attribute__ ((unused)); +static uint32_t fmv_x_w(unsigned dest, unsigned src) { return src << 15 | dest << 7 | - MATCH_FMV_X_S; + MATCH_FMV_X_W; } static uint32_t fmv_x_d(unsigned dest, unsigned src) __attribute__ ((unused)); @@ -189,12 +189,12 @@ static uint32_t fmv_x_d(unsigned dest, unsigned src) MATCH_FMV_X_D; } -static uint32_t fmv_s_x(unsigned dest, unsigned src) __attribute__ ((unused)); -static uint32_t fmv_s_x(unsigned dest, unsigned src) +static uint32_t fmv_w_x(unsigned dest, unsigned src) __attribute__ ((unused)); +static uint32_t fmv_w_x(unsigned dest, unsigned src) { return src << 15 | dest << 7 | - MATCH_FMV_S_X; + MATCH_FMV_W_X; } static uint32_t fmv_d_x(unsigned dest, unsigned src) __attribute__ ((unused)); From 7e6445109763d47707e1d31620b3733b5137faba Mon Sep 17 00:00:00 2001 From: Jonas Norling Date: Wed, 25 Oct 2017 10:38:49 +0200 Subject: [PATCH 059/127] adi_v5_swd: Add error message when SWD fails to connect Error message instead of failing silently. Change-Id: Ie54a5bf68459d3c0e96cc38080ffad8de0a4b5ce Signed-off-by: Jonas Norling Reviewed-on: http://openocd.zylin.com/4269 Tested-by: jenkins Reviewed-by: Tomas Vanek --- src/target/adi_v5_swd.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 41ddbd789..a6aada326 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -427,7 +427,10 @@ static int swd_init(struct command_context *ctx) /* First connect after init is not reconnecting. */ dap->do_reconnect = false; - return swd_connect(dap); + int retval = swd_connect(dap); + if (retval != ERROR_OK) + LOG_ERROR("SWD connect failed"); + return retval; } static struct transport swd_transport = { From dba9293a8907516bfec826464ac2896ffaba6da6 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sun, 29 Oct 2017 11:39:51 +0100 Subject: [PATCH 060/127] rtos: Use 'bool' as return type for detect_rtos() Change-Id: I91ad0431d44ed94f48d20c4690f8642d66f52a9b Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4274 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/rtos/ChibiOS.c | 10 +++++----- src/rtos/FreeRTOS.c | 8 ++++---- src/rtos/ThreadX.c | 8 ++++---- src/rtos/eCos.c | 8 ++++---- src/rtos/embKernel.c | 8 ++++---- src/rtos/linux.c | 4 ++-- src/rtos/mqx.c | 8 ++++---- src/rtos/rtos.h | 2 +- src/rtos/uCOS-III.c | 2 +- 9 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/rtos/ChibiOS.c b/src/rtos/ChibiOS.c index 1bc1af8fc..ef0bb16cf 100644 --- a/src/rtos/ChibiOS.c +++ b/src/rtos/ChibiOS.c @@ -103,7 +103,7 @@ static struct ChibiOS_params ChibiOS_params_list[] = { }; #define CHIBIOS_NUM_PARAMS ((int)(sizeof(ChibiOS_params_list)/sizeof(struct ChibiOS_params))) -static int ChibiOS_detect_rtos(struct target *target); +static bool ChibiOS_detect_rtos(struct target *target); static int ChibiOS_create(struct target *target); static int ChibiOS_update_threads(struct rtos *rtos); static int ChibiOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -510,7 +510,7 @@ static int ChibiOS_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) return 0; } -static int ChibiOS_detect_rtos(struct target *target) +static bool ChibiOS_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && ((target->rtos->symbols[ChibiOS_VAL_rlist].address != 0) || @@ -519,14 +519,14 @@ static int ChibiOS_detect_rtos(struct target *target) if (target->rtos->symbols[ChibiOS_VAL_ch_debug].address == 0) { LOG_INFO("It looks like the target may be running ChibiOS " "without ch_debug."); - return 0; + return false; } /* looks like ChibiOS with memory map enabled.*/ - return 1; + return true; } - return 0; + return false; } static int ChibiOS_create(struct target *target) diff --git a/src/rtos/FreeRTOS.c b/src/rtos/FreeRTOS.c index 83961eb95..6027d6739 100644 --- a/src/rtos/FreeRTOS.c +++ b/src/rtos/FreeRTOS.c @@ -99,7 +99,7 @@ static const struct FreeRTOS_params FreeRTOS_params_list[] = { #define FREERTOS_NUM_PARAMS ((int)(sizeof(FreeRTOS_params_list)/sizeof(struct FreeRTOS_params))) -static int FreeRTOS_detect_rtos(struct target *target); +static bool FreeRTOS_detect_rtos(struct target *target); static int FreeRTOS_create(struct target *target); static int FreeRTOS_update_threads(struct rtos *rtos); static int FreeRTOS_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -528,14 +528,14 @@ static int FreeRTOS_get_thread_ascii_info(struct rtos *rtos, threadid_t thread_i #endif -static int FreeRTOS_detect_rtos(struct target *target) +static bool FreeRTOS_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[FreeRTOS_VAL_pxReadyTasksLists].address != 0)) { /* looks like FreeRTOS */ - return 1; + return true; } - return 0; + return false; } static int FreeRTOS_create(struct target *target) diff --git a/src/rtos/ThreadX.c b/src/rtos/ThreadX.c index ab8a66e93..b7dbe6d11 100644 --- a/src/rtos/ThreadX.c +++ b/src/rtos/ThreadX.c @@ -35,7 +35,7 @@ static const struct rtos_register_stacking *get_stacking_info_arm926ejs(const st static int is_thread_id_valid(const struct rtos *rtos, int64_t thread_id); static int is_thread_id_valid_arm926ejs(const struct rtos *rtos, int64_t thread_id); -static int ThreadX_detect_rtos(struct target *target); +static bool ThreadX_detect_rtos(struct target *target); static int ThreadX_create(struct target *target); static int ThreadX_update_threads(struct rtos *rtos); static int ThreadX_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -492,14 +492,14 @@ static int ThreadX_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) return 0; } -static int ThreadX_detect_rtos(struct target *target) +static bool ThreadX_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[ThreadX_VAL_tx_thread_created_ptr].address != 0)) { /* looks like ThreadX */ - return 1; + return true; } - return 0; + return false; } #if 0 diff --git a/src/rtos/eCos.c b/src/rtos/eCos.c index edc3d8b51..9e41030ee 100644 --- a/src/rtos/eCos.c +++ b/src/rtos/eCos.c @@ -27,7 +27,7 @@ #include "helper/types.h" #include "rtos_ecos_stackings.h" -static int eCos_detect_rtos(struct target *target); +static bool eCos_detect_rtos(struct target *target); static int eCos_create(struct target *target); static int eCos_update_threads(struct rtos *rtos); static int eCos_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -363,14 +363,14 @@ static int eCos_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) return 0; } -static int eCos_detect_rtos(struct target *target) +static bool eCos_detect_rtos(struct target *target) { if ((target->rtos->symbols != NULL) && (target->rtos->symbols[eCos_VAL_thread_list].address != 0)) { /* looks like eCos */ - return 1; + return true; } - return 0; + return false; } static int eCos_create(struct target *target) diff --git a/src/rtos/embKernel.c b/src/rtos/embKernel.c index e515383ac..a40c86c3f 100644 --- a/src/rtos/embKernel.c +++ b/src/rtos/embKernel.c @@ -31,7 +31,7 @@ #define EMBKERNEL_MAX_THREAD_NAME_STR_SIZE (64) -static int embKernel_detect_rtos(struct target *target); +static bool embKernel_detect_rtos(struct target *target); static int embKernel_create(struct target *target); static int embKernel_update_threads(struct rtos *rtos); static int embKernel_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list); @@ -107,13 +107,13 @@ static const struct embKernel_params embKernel_params_list[] = { } }; -static int embKernel_detect_rtos(struct target *target) +static bool embKernel_detect_rtos(struct target *target) { if (target->rtos->symbols != NULL) { if (target->rtos->symbols[SYMBOL_ID_sCurrentTask].address != 0) - return 1; + return true; } - return 0; + return false; } static int embKernel_create(struct target *target) diff --git a/src/rtos/linux.c b/src/rtos/linux.c index 3efaab133..3b2a2b0c3 100644 --- a/src/rtos/linux.c +++ b/src/rtos/linux.c @@ -309,10 +309,10 @@ static int linux_os_thread_reg_list(struct rtos *rtos, return ERROR_OK; } -static int linux_os_detect(struct target *target) +static bool linux_os_detect(struct target *target) { LOG_INFO("should no be called"); - return 0; + return false; } static int linux_os_smp_init(struct target *target); diff --git a/src/rtos/mqx.c b/src/rtos/mqx.c index 63a48c54b..531b03b57 100644 --- a/src/rtos/mqx.c +++ b/src/rtos/mqx.c @@ -244,9 +244,9 @@ static int mqx_is_scheduler_running( } /* - * API function, return 1 if MQX is present + * API function, return true if MQX is present */ -static int mqx_detect_rtos( +static bool mqx_detect_rtos( struct target *target ) { @@ -254,9 +254,9 @@ static int mqx_detect_rtos( (target->rtos->symbols != NULL) && (target->rtos->symbols[mqx_VAL_mqx_kernel_data].address != 0) ) { - return 1; + return true; } - return 0; + return false; } /* diff --git a/src/rtos/rtos.h b/src/rtos/rtos.h index 70c1193e5..87aa5027d 100644 --- a/src/rtos/rtos.h +++ b/src/rtos/rtos.h @@ -59,7 +59,7 @@ struct rtos { struct rtos_type { const char *name; - int (*detect_rtos)(struct target *target); + bool (*detect_rtos)(struct target *target); int (*create)(struct target *target); int (*smp_init)(struct target *target); int (*update_threads)(struct rtos *rtos); diff --git a/src/rtos/uCOS-III.c b/src/rtos/uCOS-III.c index 0a0fb3e9e..8e63ea4e6 100644 --- a/src/rtos/uCOS-III.c +++ b/src/rtos/uCOS-III.c @@ -241,7 +241,7 @@ static int uCOS_III_update_thread_offsets(struct rtos *rtos) return ERROR_OK; } -static int uCOS_III_detect_rtos(struct target *target) +static bool uCOS_III_detect_rtos(struct target *target) { return target->rtos->symbols != NULL && target->rtos->symbols[uCOS_III_VAL_OSRunning].address != 0; From 2fcbe3b8f7309d3263e58bf2e3e0125d0bacc8d9 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sun, 29 Oct 2017 15:58:41 +0100 Subject: [PATCH 061/127] target: Constify parameter of is_armv7m() Change-Id: Ieea1b0dec88818e9e8d5c8c5d54aa8959556d77b Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4275 Tested-by: jenkins Reviewed-by: Christopher Head Reviewed-by: Andreas Fritiofson --- src/target/armv7m.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 284bb9caa..6f5d6f995 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -174,7 +174,7 @@ target_to_armv7m(struct target *target) return container_of(target->arch_info, struct armv7m_common, arm); } -static inline bool is_armv7m(struct armv7m_common *armv7m) +static inline bool is_armv7m(const struct armv7m_common *armv7m) { return armv7m->common_magic == ARMV7M_COMMON_MAGIC; } From 8bb7021ca8ef9ec9db8ce629a5d4dad5b73b6b07 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Thu, 22 Sep 2016 22:36:28 +0200 Subject: [PATCH 062/127] server/gdb: Use get_target_from_connection() Change-Id: I2c66bf6da734a3b71e358553943e9fc3c6578c39 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4277 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/server/gdb_server.c | 67 +++++++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 483e5510b..d7fff66a0 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -917,10 +917,11 @@ static int gdb_target_callback_event_handler(struct target *target, static int gdb_new_connection(struct connection *connection) { struct gdb_connection *gdb_connection = malloc(sizeof(struct gdb_connection)); - struct gdb_service *gdb_service = connection->service->priv; + struct target *target; int retval; int initial_ack; + target = get_target_from_connection(connection); connection->priv = gdb_connection; /* initialize gdb connection information */ @@ -949,12 +950,12 @@ static int gdb_new_connection(struct connection *connection) * GDB session could leave dangling breakpoints if e.g. communication * timed out. */ - breakpoint_clear_target(gdb_service->target); - watchpoint_clear_target(gdb_service->target); + breakpoint_clear_target(target); + watchpoint_clear_target(target); /* clean previous rtos session if supported*/ - if ((gdb_service->target->rtos) && (gdb_service->target->rtos->type->clean)) - gdb_service->target->rtos->type->clean(gdb_service->target); + if ((target->rtos) && (target->rtos->type->clean)) + target->rtos->type->clean(target); /* remove the initial ACK from the incoming buffer */ retval = gdb_get_char(connection, &initial_ack); @@ -966,7 +967,7 @@ static int gdb_new_connection(struct connection *connection) */ if (initial_ack != '+') gdb_putback_char(connection, initial_ack); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_ATTACH); + target_call_event_callbacks(target, TARGET_EVENT_GDB_ATTACH); if (gdb_use_memory_map) { /* Connect must fail if the memory map can't be set up correctly. @@ -978,7 +979,7 @@ static int gdb_new_connection(struct connection *connection) for (i = 0; i < flash_get_bank_count(); i++) { struct flash_bank *p; p = get_flash_bank_by_num_noprobe(i); - if (p->target != gdb_service->target) + if (p->target != target) continue; retval = get_flash_bank_by_num(i, &p); if (retval != ERROR_OK) { @@ -992,8 +993,8 @@ static int gdb_new_connection(struct connection *connection) gdb_actual_connections++; LOG_DEBUG("New GDB Connection: %d, Target %s, state: %s", gdb_actual_connections, - target_name(gdb_service->target), - target_state_name(gdb_service->target)); + target_name(target), + target_state_name(target)); /* DANGER! If we fail subsequently, we must remove this handler, * otherwise we occasionally see crashes as the timer can invoke the @@ -1007,9 +1008,11 @@ static int gdb_new_connection(struct connection *connection) static int gdb_connection_closed(struct connection *connection) { - struct gdb_service *gdb_service = connection->service->priv; + struct target *target; struct gdb_connection *gdb_connection = connection->priv; + target = get_target_from_connection(connection); + /* we're done forwarding messages. Tear down callback before * cleaning up connection. */ @@ -1017,8 +1020,8 @@ static int gdb_connection_closed(struct connection *connection) gdb_actual_connections--; LOG_DEBUG("GDB Close, Target: %s, state: %s, gdb_actual_connections=%d", - target_name(gdb_service->target), - target_state_name(gdb_service->target), + target_name(target), + target_state_name(target), gdb_actual_connections); /* see if an image built with vFlash commands is left */ @@ -1029,7 +1032,7 @@ static int gdb_connection_closed(struct connection *connection) } /* if this connection registered a debug-message receiver delete it */ - delete_debug_msg_receiver(connection->cmd_ctx, gdb_service->target); + delete_debug_msg_receiver(connection->cmd_ctx, target); if (connection->priv) { free(connection->priv); @@ -1039,9 +1042,9 @@ static int gdb_connection_closed(struct connection *connection) target_unregister_event_callback(gdb_target_callback_event_handler, connection); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_END); + target_call_event_callbacks(target, TARGET_EVENT_GDB_END); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH); + target_call_event_callbacks(target, TARGET_EVENT_GDB_DETACH); return ERROR_OK; } @@ -2558,9 +2561,11 @@ static int gdb_v_packet(struct connection *connection, char const *packet, int packet_size) { struct gdb_connection *gdb_connection = connection->priv; - struct gdb_service *gdb_service = connection->service->priv; + struct target *target; int result; + target = get_target_from_connection(connection); + /* if flash programming disabled - send a empty reply */ if (gdb_flash_program == 0) { @@ -2597,18 +2602,18 @@ static int gdb_v_packet(struct connection *connection, flash_set_dirty(); /* perform any target specific operations before the erase */ - target_call_event_callbacks(gdb_service->target, + target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_ERASE_START); /* vFlashErase:addr,length messages require region start and * end to be "block" aligned ... if padding is ever needed, * GDB will have become dangerously confused. */ - result = flash_erase_address_range(gdb_service->target, - false, addr, length); + result = flash_erase_address_range(target, false, addr, + length); /* perform any target specific operations after the erase */ - target_call_event_callbacks(gdb_service->target, + target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_ERASE_END); /* perform erase */ @@ -2663,10 +2668,12 @@ static int gdb_v_packet(struct connection *connection, /* process the flashing buffer. No need to erase as GDB * always issues a vFlashErase first. */ - target_call_event_callbacks(gdb_service->target, + target_call_event_callbacks(target, TARGET_EVENT_GDB_FLASH_WRITE_START); - result = flash_write(gdb_service->target, gdb_connection->vflash_image, &written, 0); - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_FLASH_WRITE_END); + result = flash_write(target, gdb_connection->vflash_image, + &written, 0); + target_call_event_callbacks(target, + TARGET_EVENT_GDB_FLASH_WRITE_END); if (result != ERROR_OK) { if (result == ERROR_FLASH_DST_OUT_OF_BANK) gdb_put_packet(connection, "E.memtype", 9); @@ -2690,9 +2697,8 @@ static int gdb_v_packet(struct connection *connection, static int gdb_detach(struct connection *connection) { - struct gdb_service *gdb_service = connection->service->priv; - - target_call_event_callbacks(gdb_service->target, TARGET_EVENT_GDB_DETACH); + target_call_event_callbacks(get_target_from_connection(connection), + TARGET_EVENT_GDB_DETACH); return gdb_put_packet(connection, "OK", 2); } @@ -2771,14 +2777,15 @@ static int gdb_input_inner(struct connection *connection) /* Do not allocate this on the stack */ static char gdb_packet_buffer[GDB_BUFFER_SIZE]; - struct gdb_service *gdb_service = connection->service->priv; - struct target *target = gdb_service->target; + struct target *target; char const *packet = gdb_packet_buffer; int packet_size; int retval; struct gdb_connection *gdb_con = connection->priv; static int extended_protocol; + target = get_target_from_connection(connection); + /* drain input buffer. If one of the packets fail, then an error * packet is replied, if applicable. * @@ -2948,8 +2955,8 @@ static int gdb_input_inner(struct connection *connection) break; case 'R': /* handle extended restart packet */ - breakpoint_clear_target(gdb_service->target); - watchpoint_clear_target(gdb_service->target); + breakpoint_clear_target(target); + watchpoint_clear_target(target); command_run_linef(connection->cmd_ctx, "ocd_gdb_restart %s", target_name(target)); /* set connection as attached after reset */ From 5679dc657c9f4530d2137c1b94f8077ab7fb7146 Mon Sep 17 00:00:00 2001 From: Marc Schink Date: Sun, 29 Oct 2017 19:54:00 +0100 Subject: [PATCH 063/127] server/gdb: Use 'bool' instead of 'int' for boolean values Change-Id: I71c2f2553a29e9ef167ff3313cc06c7b31c64190 Signed-off-by: Marc Schink Reviewed-on: http://openocd.zylin.com/4278 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- src/server/gdb_server.c | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index d7fff66a0..626179c3c 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -71,8 +71,8 @@ struct gdb_connection { int ctrl_c; enum target_state frontend_state; struct image *vflash_image; - int closed; - int busy; + bool closed; + bool busy; int noack_mode; /* set flag to true if you want the next stepi to return immediately. * allowing GDB to pick up a fresh set of register values from the target @@ -215,7 +215,7 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) if (gdb_con->buf_cnt > 0) break; if (gdb_con->buf_cnt == 0) { - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } @@ -227,10 +227,10 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) usleep(1000); break; case WSAECONNABORTED: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; case WSAECONNRESET: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; default: LOG_ERROR("read: %d", errno); @@ -242,14 +242,14 @@ static int gdb_get_char_inner(struct connection *connection, int *next_char) usleep(1000); break; case ECONNABORTED: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; case ECONNRESET: - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; default: LOG_ERROR("read: %s", strerror(errno)); - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } #endif @@ -341,7 +341,7 @@ static int gdb_write(struct connection *connection, void *data, int len) if (connection_write(connection, data, len) == len) return ERROR_OK; - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } @@ -448,7 +448,7 @@ static int gdb_put_packet_inner(struct connection *connection, return ERROR_OK; } else { LOG_ERROR("unknown character(1) 0x%2.2x in reply, dropping connection", reply); - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } } else if (reply == '$') { @@ -458,7 +458,7 @@ static int gdb_put_packet_inner(struct connection *connection, } else { LOG_ERROR("unknown character(2) 0x%2.2x in reply, dropping connection", reply); - gdb_con->closed = 1; + gdb_con->closed = true; return ERROR_SERVER_REMOTE_CLOSED; } } @@ -471,9 +471,9 @@ static int gdb_put_packet_inner(struct connection *connection, int gdb_put_packet(struct connection *connection, char *buffer, int len) { struct gdb_connection *gdb_con = connection->priv; - gdb_con->busy = 1; + gdb_con->busy = true; int retval = gdb_put_packet_inner(connection, buffer, len); - gdb_con->busy = 0; + gdb_con->busy = false; /* we sent some data, reset timer for keep alive messages */ kept_alive(); @@ -679,9 +679,9 @@ static int gdb_get_packet_inner(struct connection *connection, static int gdb_get_packet(struct connection *connection, char *buffer, int *len) { struct gdb_connection *gdb_con = connection->priv; - gdb_con->busy = 1; + gdb_con->busy = true; int retval = gdb_get_packet_inner(connection, buffer, len); - gdb_con->busy = 0; + gdb_con->busy = false; return retval; } @@ -930,8 +930,8 @@ static int gdb_new_connection(struct connection *connection) gdb_connection->ctrl_c = 0; gdb_connection->frontend_state = TARGET_HALTED; gdb_connection->vflash_image = NULL; - gdb_connection->closed = 0; - gdb_connection->busy = 0; + gdb_connection->closed = false; + gdb_connection->busy = false; gdb_connection->noack_mode = 0; gdb_connection->sync = false; gdb_connection->mem_write_error = false; From 5d6bf8704ce7ed9a7e471e601ab91061c39f88c6 Mon Sep 17 00:00:00 2001 From: Robert Jordens Date: Sat, 20 Aug 2016 05:49:49 +0800 Subject: [PATCH 064/127] spi: add n25q256 flash * 256 MBit SPI flash * https://www.micron.com/~/media/documents/products/data-sheet/nor-flash/serial-nor/mt25q/die-rev-a/mt25q_qljs_l_256_aba_0.pdf spells out the entire zoo of IDs * used e.g. on Xilinx KCU105 Change-Id: I18b19292b4869627adb9071266271962fec68fb4 Signed-off-by: Robert Jordens Reviewed-on: http://openocd.zylin.com/4186 Tested-by: jenkins Reviewed-by: Antonio Borneo --- src/flash/nor/spi.c | 98 +++++++++++++++++++++++---------------------- 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index 6501fbc18..273e8508f 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -31,52 +31,54 @@ * from device datasheets and Linux SPI flash drivers. */ const struct flash_device flash_devices[] = { /* name, erase_cmd, chip_erase_cmd, device_id, pagesize, sectorsize, size_in_bytes */ - FLASH_ID("st m25p05", 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), - FLASH_ID("st m25p10", 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), - FLASH_ID("st m25p20", 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), - FLASH_ID("st m25p40", 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000), - FLASH_ID("st m25p80", 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000), - FLASH_ID("st m25p16", 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000), - FLASH_ID("st m25p32", 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000), - FLASH_ID("st m25p64", 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000), - FLASH_ID("st m25p128", 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000), - FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), - FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), - FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), - FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), - FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000), - FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000), - FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000), - FLASH_ID("sp s25fl116k", 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000), - FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000), - FLASH_ID("sp s25fl132k", 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000), - FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000), - FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000), - FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000), - FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000), - FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), - FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), - FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), - FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), - FLASH_ID("atmel 25fs040", 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), - FLASH_ID("mac 25l512", 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), - FLASH_ID("mac 25l1005", 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), - FLASH_ID("mac 25l2005", 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), - FLASH_ID("mac 25l4005", 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000), - FLASH_ID("mac 25l8005", 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000), - FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), - FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), - FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), - FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), - FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), - FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), - FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), - FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), - FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), - FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), - FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000), - FLASH_ID("gd gd25q16c", 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), - FLASH_ID("gd gd25q32c", 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), - FLASH_ID("gd gd25q128c", 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), - FLASH_ID(NULL, 0, 0, 0, 0, 0, 0) + FLASH_ID("st m25p05", 0xd8, 0xc7, 0x00102020, 0x80, 0x8000, 0x10000), + FLASH_ID("st m25p10", 0xd8, 0xc7, 0x00112020, 0x80, 0x8000, 0x20000), + FLASH_ID("st m25p20", 0xd8, 0xc7, 0x00122020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m25p40", 0xd8, 0xc7, 0x00132020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m25p80", 0xd8, 0xc7, 0x00142020, 0x100, 0x10000, 0x100000), + FLASH_ID("st m25p16", 0xd8, 0xc7, 0x00152020, 0x100, 0x10000, 0x200000), + FLASH_ID("st m25p32", 0xd8, 0xc7, 0x00162020, 0x100, 0x10000, 0x400000), + FLASH_ID("st m25p64", 0xd8, 0xc7, 0x00172020, 0x100, 0x10000, 0x800000), + FLASH_ID("st m25p128", 0xd8, 0xc7, 0x00182020, 0x100, 0x40000, 0x1000000), + FLASH_ID("st m45pe10", 0xd8, 0xd8, 0x00114020, 0x100, 0x10000, 0x20000), + FLASH_ID("st m45pe20", 0xd8, 0xd8, 0x00124020, 0x100, 0x10000, 0x40000), + FLASH_ID("st m45pe40", 0xd8, 0xd8, 0x00134020, 0x100, 0x10000, 0x80000), + FLASH_ID("st m45pe80", 0xd8, 0xd8, 0x00144020, 0x100, 0x10000, 0x100000), + FLASH_ID("sp s25fl004", 0xd8, 0xc7, 0x00120201, 0x100, 0x10000, 0x80000), + FLASH_ID("sp s25fl008", 0xd8, 0xc7, 0x00130201, 0x100, 0x10000, 0x100000), + FLASH_ID("sp s25fl016", 0xd8, 0xc7, 0x00140201, 0x100, 0x10000, 0x200000), + FLASH_ID("sp s25fl116k", 0xd8, 0xc7, 0x00154001, 0x100, 0x10000, 0x200000), + FLASH_ID("sp s25fl032", 0xd8, 0xc7, 0x00150201, 0x100, 0x10000, 0x400000), + FLASH_ID("sp s25fl132k", 0xd8, 0xc7, 0x00164001, 0x100, 0x10000, 0x400000), + FLASH_ID("sp s25fl064", 0xd8, 0xc7, 0x00160201, 0x100, 0x10000, 0x800000), + FLASH_ID("sp s25fl164k", 0xd8, 0xc7, 0x00174001, 0x100, 0x10000, 0x800000), + FLASH_ID("sp s25fl128", 0xd8, 0xc7, 0x00182001, 0x100, 0x10000, 0x1000000), + FLASH_ID("sp s25fl256", 0xd8, 0xc7, 0x00190201, 0x100, 0x10000, 0x2000000), + FLASH_ID("atmel 25f512", 0x52, 0xc7, 0x0065001f, 0x80, 0x8000, 0x10000), + FLASH_ID("atmel 25f1024", 0x52, 0x62, 0x0060001f, 0x100, 0x8000, 0x20000), + FLASH_ID("atmel 25f2048", 0x52, 0x62, 0x0063001f, 0x100, 0x10000, 0x40000), + FLASH_ID("atmel 25f4096", 0x52, 0x62, 0x0064001f, 0x100, 0x10000, 0x80000), + FLASH_ID("atmel 25fs040", 0xd7, 0xc7, 0x0004661f, 0x100, 0x10000, 0x80000), + FLASH_ID("mac 25l512", 0xd8, 0xc7, 0x001020c2, 0x010, 0x10000, 0x10000), + FLASH_ID("mac 25l1005", 0xd8, 0xc7, 0x001120c2, 0x010, 0x10000, 0x20000), + FLASH_ID("mac 25l2005", 0xd8, 0xc7, 0x001220c2, 0x010, 0x10000, 0x40000), + FLASH_ID("mac 25l4005", 0xd8, 0xc7, 0x001320c2, 0x010, 0x10000, 0x80000), + FLASH_ID("mac 25l8005", 0xd8, 0xc7, 0x001420c2, 0x010, 0x10000, 0x100000), + FLASH_ID("mac 25l1605", 0xd8, 0xc7, 0x001520c2, 0x100, 0x10000, 0x200000), + FLASH_ID("mac 25l3205", 0xd8, 0xc7, 0x001620c2, 0x100, 0x10000, 0x400000), + FLASH_ID("mac 25l6405", 0xd8, 0xc7, 0x001720c2, 0x100, 0x10000, 0x800000), + FLASH_ID("micron n25q064", 0xd8, 0xc7, 0x0017ba20, 0x100, 0x10000, 0x800000), + FLASH_ID("micron n25q128", 0xd8, 0xc7, 0x0018ba20, 0x100, 0x10000, 0x1000000), + FLASH_ID("micron n25q256 3v", 0xd8, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000), + FLASH_ID("micron n25q256 1.8v", 0xd8, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000), + FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), + FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), + FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), + FLASH_ID("win w25q64cv", 0xd8, 0xc7, 0x001740ef, 0x100, 0x10000, 0x800000), + FLASH_ID("win w25q128fv", 0xd8, 0xc7, 0x001840ef, 0x100, 0x10000, 0x1000000), + FLASH_ID("gd gd25q20", 0x20, 0xc7, 0x00c84012, 0x100, 0x1000, 0x80000), + FLASH_ID("gd gd25q16c", 0xd8, 0xc7, 0x001540c8, 0x100, 0x10000, 0x200000), + FLASH_ID("gd gd25q32c", 0xd8, 0xc7, 0x001640c8, 0x100, 0x10000, 0x400000), + FLASH_ID("gd gd25q128c", 0xd8, 0xc7, 0x001840c8, 0x100, 0x10000, 0x1000000), + FLASH_ID(NULL, 0, 0, 0, 0, 0, 0) }; From 06aebfacda1f60052f6ea0f3d09936184e1bfab8 Mon Sep 17 00:00:00 2001 From: Bas Vermeulen Date: Tue, 21 Nov 2017 17:12:24 +0100 Subject: [PATCH 065/127] Only call cmsis_dap_cmd_DAP_SWD_Configure when swd_mode is enabled The CMSIS-DAP used by NXP's LS1012ARDB board only supports JTAG, and not SWD. Calling cmsis_dap_cmd_DAP_SWD_Configure returns with an error (and doesn't actually do anything in the debugger). Wrap the call to cmsis_dap_cmd_DAP_SWD_Configure in a check for swd_mode, to make sure initialisation doesn't fail needlessly. Change-Id: Id7e568cb6e36886bd7c5b3699d198a77a51c28c9 Signed-off-by: Bas Vermeulen Reviewed-on: http://openocd.zylin.com/4294 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Matthias Welwarsky --- src/jtag/drivers/cmsis_dap_usb.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/jtag/drivers/cmsis_dap_usb.c b/src/jtag/drivers/cmsis_dap_usb.c index 19c3b19c9..345c1fd7e 100644 --- a/src/jtag/drivers/cmsis_dap_usb.c +++ b/src/jtag/drivers/cmsis_dap_usb.c @@ -958,11 +958,14 @@ static int cmsis_dap_init(void) retval = cmsis_dap_cmd_DAP_TFER_Configure(0, 64, 0); if (retval != ERROR_OK) return ERROR_FAIL; - /* Data Phase (bit 2) must be set to 1 if sticky overrun - * detection is enabled */ - retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */ - if (retval != ERROR_OK) - return ERROR_FAIL; + + if (swd_mode) { + /* Data Phase (bit 2) must be set to 1 if sticky overrun + * detection is enabled */ + retval = cmsis_dap_cmd_DAP_SWD_Configure(0); /* 1 TRN, no Data Phase */ + if (retval != ERROR_OK) + return ERROR_FAIL; + } retval = cmsis_dap_cmd_DAP_LED(0x03); /* Both LEDs on */ if (retval != ERROR_OK) From 6a66cccbad7e51ac1b3ea929ab0c86dd02617797 Mon Sep 17 00:00:00 2001 From: Alexandre Torgue Date: Mon, 13 Nov 2017 14:05:28 +0100 Subject: [PATCH 066/127] flash: Add new stm32h7x driver support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add basic support for: -STM32H7x (Embedded flash 2M) Erase and write tested on stm32h743. Change-Id: Ie8d8786227cdeee39fcf5663167a053ad8dcef4c Signed-off-by: Rémi Prud'homme Signed-off-by: Alexandre TORGUE Reviewed-on: http://openocd.zylin.com/4181 Tested-by: jenkins Reviewed-by: Antonio Borneo --- contrib/loaders/flash/stm32h7x.S | 121 +++ doc/openocd.texi | 27 + src/flash/nor/Makefile.am | 1 + src/flash/nor/drivers.c | 2 + src/flash/nor/stm32h7x.c | 1183 ++++++++++++++++++++++++++++++ 5 files changed, 1334 insertions(+) create mode 100644 contrib/loaders/flash/stm32h7x.S create mode 100644 src/flash/nor/stm32h7x.c diff --git a/contrib/loaders/flash/stm32h7x.S b/contrib/loaders/flash/stm32h7x.S new file mode 100644 index 000000000..0f5ea996f --- /dev/null +++ b/contrib/loaders/flash/stm32h7x.S @@ -0,0 +1,121 @@ +/*************************************************************************** + * Copyright (C) 2017 by STMicroelectronics * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc. * + ***************************************************************************/ + + .text + .syntax unified + .cpu cortex-m7 + .thumb + .thumb_func + +/* + * To assemble: + * arm-none-eabi-gcc -c stm32h7x.S + * + * To disassemble: + * arm-none-eabi-objdump -d stm32h7x.o + * + * To generate binary file: + * arm-none-eabi-objcopy -O binary stm32h7x.o stm32h7_flash_write_code.bin + * + * To generate include file: + * xxd -i stm32h7_flash_write_code.bin + */ + +/* + * Code limitations: + * The workarea must have size multiple of 4 bytes, since R/W + * operations are all at 32 bits. + * The workarea must be big enough to contain 32 bytes of data, + * thus the minimum size is (rp, wp, data) = 4 + 4 + 32 = 40 bytes. + * To benefit from concurrent host write-to-buffer and target + * write-to-flash, the workarea must be way bigger than the minimum. + */ + +/* + * Params : + * r0 = workarea start, status (out) + * r1 = workarea end + * r2 = target address + * r3 = count (256 bit words) + * r4 = flash reg base + * + * Clobbered: + * r5 - rp + * r6 - wp, status, tmp + * r7 - loop index, tmp + */ + +#define STM32_FLASH_CR_OFFSET 0x0C /* offset of CR register in FLASH struct */ +#define STM32_FLASH_SR_OFFSET 0x10 /* offset of SR register in FLASH struct */ +#define STM32_CR_PROG 0x00000032 /* PSIZE64 | PG */ +#define STM32_SR_BUSY_MASK 0x00000001 /* BSY */ +#define STM32_SR_ERROR_MASK 0x03ee0000 /* DBECCERR | SNECCERR | RDSERR | RDPERR | OPERR + | INCERR | STRBERR | PGSERR | WRPERR */ + +code: + ldr r5, [r0, #4] /* read rp */ + +wait_fifo: + ldr r6, [r0, #0] /* read wp */ + cbz r6, exit /* abort if wp == 0, status = 0 */ + subs r6, r6, r5 /* number of bytes available for read in r6 */ + ittt mi /* if wrapped around */ + addmi r6, r1 /* add size of buffer */ + submi r6, r0 + submi r6, #8 + cmp r6, #32 /* wait until 32 bytes are available */ + bcc wait_fifo + + mov r6, #STM32_CR_PROG + str r6, [r4, #STM32_FLASH_CR_OFFSET] + + mov r7, #8 /* program by 8 words = 32 bytes */ +write_flash: + ldr r6, [r5], #0x04 /* read one word from src, increment ptr */ + str r6, [r2], #0x04 /* write one word to dst, increment ptr */ + dsb + cmp r5, r1 /* if rp >= end of buffer ... */ + it cs + addcs r5, r0, #8 /* ... then wrap at buffer start */ + subs r7, r7, #1 /* decrement loop index */ + bne write_flash /* loop if not done */ + +busy: + ldr r6, [r4, #STM32_FLASH_SR_OFFSET] + tst r6, #STM32_SR_BUSY_MASK + bne busy /* operation in progress, wait ... */ + + ldr r7, stm32_sr_error_mask + tst r6, r7 + bne error /* fail... */ + + str r5, [r0, #4] /* store rp */ + subs r3, r3, #1 /* decrement count */ + bne wait_fifo /* loop if not done */ + b exit + +error: + movs r7, #0 + str r7, [r0, #4] /* set rp = 0 on error */ + +exit: + mov r0, r6 /* return status in r0 */ + bkpt #0x00 + +stm32_sr_error_mask: + .word STM32_SR_ERROR_MASK diff --git a/doc/openocd.texi b/doc/openocd.texi index e452fa3b3..2719c2d97 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -6009,6 +6009,33 @@ The @var{num} parameter is a value shown by @command{flash banks}, @var{optcr2} @end deffn @end deffn +@deffn {Flash Driver} stm32h7x +All members of the STM32H7 microcontroller families from ST Microelectronics +include internal flash and use ARM Cortex-M7 core. +The driver automatically recognizes a number of these chips using +the chip identification register, and autoconfigures itself. + +Note that some devices have been found that have a flash size register that contains +an invalid value, to workaround this issue you can override the probed value used by +the flash driver. + +@example +flash bank $_FLASHNAME stm32h7x 0 0x20000 0 0 $_TARGETNAME +@end example + +Some stm32h7x-specific commands are defined: + +@deffn Command {stm32h7x lock} num +Locks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + +@deffn Command {stm32h7x unlock} num +Unlocks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn +@end deffn + @deffn {Flash Driver} stm32lx All members of the STM32L microcontroller families from ST Microelectronics include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores. diff --git a/src/flash/nor/Makefile.am b/src/flash/nor/Makefile.am index 4dac110c4..ebf47756f 100644 --- a/src/flash/nor/Makefile.am +++ b/src/flash/nor/Makefile.am @@ -49,6 +49,7 @@ NOR_DRIVERS = \ %D%/stm32f2x.c \ %D%/stm32lx.c \ %D%/stm32l4x.c \ + %D%/stm32h7x.c \ %D%/str7x.c \ %D%/str9x.c \ %D%/str9xpec.c \ diff --git a/src/flash/nor/drivers.c b/src/flash/nor/drivers.c index 9594ed9a3..eacca0346 100644 --- a/src/flash/nor/drivers.c +++ b/src/flash/nor/drivers.c @@ -60,6 +60,7 @@ extern struct flash_driver stm32f1x_flash; extern struct flash_driver stm32f2x_flash; extern struct flash_driver stm32lx_flash; extern struct flash_driver stm32l4x_flash; +extern struct flash_driver stm32h7x_flash; extern struct flash_driver stmsmi_flash; extern struct flash_driver str7x_flash; extern struct flash_driver str9x_flash; @@ -114,6 +115,7 @@ static struct flash_driver *flash_drivers[] = { &stm32f2x_flash, &stm32lx_flash, &stm32l4x_flash, + &stm32h7x_flash, &stmsmi_flash, &str7x_flash, &str9x_flash, diff --git a/src/flash/nor/stm32h7x.c b/src/flash/nor/stm32h7x.c new file mode 100644 index 000000000..01e6f06dc --- /dev/null +++ b/src/flash/nor/stm32h7x.c @@ -0,0 +1,1183 @@ +/*************************************************************************** + * Copyright (C) 2017 by STMicroelectronics * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + ***************************************************************************/ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "imp.h" +#include +#include +#include + + +/* Erase time can be as high as 1000ms, 10x this and it's toast... */ +#define FLASH_ERASE_TIMEOUT 10000 +#define FLASH_WRITE_TIMEOUT 5 + +/* RM 433 */ +/* Same Flash registers for both banks, */ +/* access depends on Flash Base address */ +#define FLASH_ACR 0x00 +#define FLASH_KEYR 0x04 +#define FLASH_OPTKEYR 0x08 +#define FLASH_CR 0x0C +#define FLASH_SR 0x10 +#define FLASH_CCR 0x14 +#define FLASH_OPTCR 0x18 +#define FLASH_OPTCUR 0x1C +#define FLASH_OPTPRG 0x20 +#define FLASH_OPTCCR 0x24 +#define FLASH_WPSNCUR 0x38 +#define FLASH_WPSNPRG 0x3C + + +/* FLASH_CR register bits */ +#define FLASH_LOCK (1 << 0) +#define FLASH_PG (1 << 1) +#define FLASH_SER (1 << 2) +#define FLASH_BER_CMD (1 << 3) +#define FLASH_PSIZE_8 (0 << 4) +#define FLASH_PSIZE_16 (1 << 4) +#define FLASH_PSIZE_32 (2 << 4) +#define FLASH_PSIZE_64 (3 << 4) +#define FLASH_FW (1 << 6) +#define FLASH_START (1 << 7) + +#define FLASH_SNB(a) ((a) << 8) + +/* FLASH_SR register bits */ +#define FLASH_BSY (1 << 0) /* Operation in progress */ +#define FLASH_WRPERR (1 << 17) /* Write protection error */ +#define FLASH_PGSERR (1 << 18) /* Programming sequence error */ +#define FLASH_STRBERR (1 << 19) /* Strobe error */ +#define FLASH_INCERR (1 << 21) /* Increment error */ +#define FLASH_OPERR (1 << 22) /* Operation error */ +#define FLASH_RDPERR (1 << 23) /* Read Protection error */ +#define FLASH_RDSERR (1 << 24) /* Secure Protection error */ +#define FLASH_SNECCERR (1 << 25) /* Single ECC error */ +#define FLASH_DBECCERR (1 << 26) /* Double ECC error */ + +#define FLASH_ERROR (FLASH_WRPERR | FLASH_PGSERR | FLASH_STRBERR | FLASH_INCERR | FLASH_OPERR | \ + FLASH_RDPERR | FLASH_RDSERR | FLASH_SNECCERR | FLASH_DBECCERR) + +/* FLASH_OPTCR register bits */ +#define OPT_LOCK (1 << 0) +#define OPT_START (1 << 1) + +/* FLASH_OPTCUR bit definitions (reading) */ +#define IWDG1_HW (1 << 4) + +/* register unlock keys */ +#define KEY1 0x45670123 +#define KEY2 0xCDEF89AB + +/* option register unlock key */ +#define OPTKEY1 0x08192A3B +#define OPTKEY2 0x4C5D6E7F + +#define DBGMCU_IDCODE_REGISTER 0x5C001000 +#define FLASH_BANK0_ADDRESS 0x08000000 +#define FLASH_BANK1_ADDRESS 0x08100000 +#define FLASH_REG_BASE_B0 0x52002000 +#define FLASH_REG_BASE_B1 0x52002100 +#define FLASH_SIZE_ADDRESS 0x1FF1E880 +#define FLASH_BLOCK_SIZE 32 + +struct stm32h7x_rev { + uint16_t rev; + const char *str; +}; + +struct stm32x_options { + uint8_t RDP; + uint32_t protection; /* bank1 WRP */ + uint32_t protection2; /* bank2 WRP */ + uint8_t user_options; + uint8_t user2_options; + uint8_t user3_options; + uint8_t independent_watchdog_selection; +}; + +struct stm32h7x_part_info { + uint16_t id; + const char *device_str; + const struct stm32h7x_rev *revs; + size_t num_revs; + unsigned int page_size; + unsigned int pages_per_sector; + uint16_t max_flash_size_kb; + uint8_t has_dual_bank; + uint16_t first_bank_size_kb; /* Used when has_dual_bank is true */ + uint32_t flash_base; /* Flash controller registers location */ + uint32_t fsize_base; /* Location of FSIZE register */ +}; + +struct stm32h7x_flash_bank { + int probed; + uint32_t idcode; + uint32_t user_bank_size; + uint32_t flash_base; /* Address of flash reg controller */ + struct stm32x_options option_bytes; + const struct stm32h7x_part_info *part_info; +}; + +static const struct stm32h7x_rev stm32_450_revs[] = { + { 0x1000, "A" }, { 0x1001, "Z" }, { 0x1003, "Y" }, +}; + +static const struct stm32h7x_part_info stm32h7x_parts[] = { + { + .id = 0x450, + .revs = stm32_450_revs, + .num_revs = ARRAY_SIZE(stm32_450_revs), + .device_str = "STM32H7xx 2M", + .page_size = 128, /* 128 KB */ + .max_flash_size_kb = 2048, + .first_bank_size_kb = 1024, + .has_dual_bank = 1, + .flash_base = FLASH_REG_BASE_B0, + .fsize_base = FLASH_SIZE_ADDRESS, + }, +}; + +static int stm32x_unlock_reg(struct flash_bank *bank); +static int stm32x_lock_reg(struct flash_bank *bank); +static int stm32x_probe(struct flash_bank *bank); + +/* flash bank stm32x 0 0 */ + +FLASH_BANK_COMMAND_HANDLER(stm32x_flash_bank_command) +{ + struct stm32h7x_flash_bank *stm32x_info; + + if (CMD_ARGC < 6) + return ERROR_COMMAND_SYNTAX_ERROR; + + stm32x_info = malloc(sizeof(struct stm32h7x_flash_bank)); + bank->driver_priv = stm32x_info; + + stm32x_info->probed = 0; + stm32x_info->user_bank_size = bank->size; + + return ERROR_OK; +} + +static inline uint32_t stm32x_get_flash_reg(struct flash_bank *bank, uint32_t reg) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + return reg + stm32x_info->flash_base; +} + +static inline int stm32x_get_flash_status(struct flash_bank *bank, uint32_t *status) +{ + struct target *target = bank->target; + return target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_SR), status); +} + +static int stm32x_wait_status_busy(struct flash_bank *bank, int timeout) +{ + struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + uint32_t status; + int retval; + + /* wait for busy to clear */ + for (;;) { + retval = stm32x_get_flash_status(bank, &status); + if (retval != ERROR_OK) { + LOG_INFO("wait_status_busy, target_read_u32 : error : remote address 0x%x", stm32x_info->flash_base); + return retval; + } + + if ((status & FLASH_BSY) == 0) + break; + + if (timeout-- <= 0) { + LOG_INFO("wait_status_busy, time out expired, status: 0x%" PRIx32 "", status); + return ERROR_FAIL; + } + alive_sleep(1); + } + + if (status & FLASH_WRPERR) { + LOG_INFO("wait_status_busy, WRPERR : error : remote address 0x%x", stm32x_info->flash_base); + retval = ERROR_FAIL; + } + + /* Clear error + EOP flags but report errors */ + if (status & FLASH_ERROR) { + /* If this operation fails, we ignore it and report the original retval */ + target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), status); + } + return retval; +} + +static int stm32x_unlock_reg(struct flash_bank *bank) +{ + uint32_t ctrl; + struct target *target = bank->target; + + /* first check if not already unlocked + * otherwise writing on FLASH_KEYR will fail + */ + int retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl); + if (retval != ERROR_OK) + return retval; + + if ((ctrl & FLASH_LOCK) == 0) + return ERROR_OK; + + /* unlock flash registers for bank */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_KEYR), KEY2); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), &ctrl); + if (retval != ERROR_OK) + return retval; + + if (ctrl & FLASH_LOCK) { + LOG_ERROR("flash not unlocked STM32_FLASH_CRx: %" PRIx32, ctrl); + return ERROR_TARGET_FAILURE; + } + return ERROR_OK; +} + +static int stm32x_unlock_option_reg(struct flash_bank *bank) +{ + uint32_t ctrl; + struct target *target = bank->target; + + int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl); + if (retval != ERROR_OK) + return retval; + + if ((ctrl & OPT_LOCK) == 0) + return ERROR_OK; + + /* unlock option registers */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY1); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTKEYR, OPTKEY2); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, &ctrl); + if (retval != ERROR_OK) + return retval; + + if (ctrl & OPT_LOCK) { + LOG_ERROR("options not unlocked STM32_FLASH_OPTCR: %" PRIx32, ctrl); + return ERROR_TARGET_FAILURE; + } + + return ERROR_OK; +} + +static int stm32x_lock_reg(struct flash_bank *bank) +{ + struct target *target = bank->target; + + /* Lock bank reg */ + int retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_LOCK); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32x_read_options(struct flash_bank *bank) +{ + uint32_t optiondata; + struct stm32h7x_flash_bank *stm32x_info = NULL; + struct target *target = bank->target; + + stm32x_info = bank->driver_priv; + + /* read current option bytes */ + int retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCUR, &optiondata); + if (retval != ERROR_OK) + return retval; + + /* decode option data */ + stm32x_info->option_bytes.user_options = optiondata & 0xfc; + stm32x_info->option_bytes.RDP = (optiondata >> 8) & 0xff; + stm32x_info->option_bytes.user2_options = (optiondata >> 16) & 0xff; + stm32x_info->option_bytes.user3_options = (optiondata >> 24) & 0x83; + + if (optiondata & IWDG1_HW) + stm32x_info->option_bytes.independent_watchdog_selection = 1; + else + stm32x_info->option_bytes.independent_watchdog_selection = 0; + + if (stm32x_info->option_bytes.RDP != 0xAA) + LOG_INFO("Device Security Bit Set"); + + /* read current WPSN option bytes */ + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSNCUR, &optiondata); + if (retval != ERROR_OK) + return retval; + stm32x_info->option_bytes.protection = optiondata & 0xff; + + /* read current WPSN2 option bytes */ + retval = target_read_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSNCUR, &optiondata); + if (retval != ERROR_OK) + return retval; + stm32x_info->option_bytes.protection2 = optiondata & 0xff; + + return ERROR_OK; +} + +static int stm32x_write_options(struct flash_bank *bank) +{ + struct stm32h7x_flash_bank *stm32x_info = NULL; + struct target *target = bank->target; + uint32_t optiondata; + + stm32x_info = bank->driver_priv; + + int retval = stm32x_unlock_option_reg(bank); + if (retval != ERROR_OK) + return retval; + + /* rebuild option data */ + optiondata = stm32x_info->option_bytes.user_options; + optiondata |= (stm32x_info->option_bytes.RDP << 8); + optiondata |= (stm32x_info->option_bytes.user2_options & 0xff) << 16; + optiondata |= (stm32x_info->option_bytes.user3_options & 0x83) << 24; + + if (stm32x_info->option_bytes.independent_watchdog_selection) + optiondata |= IWDG1_HW; + else + optiondata &= ~IWDG1_HW; + + /* program options */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTPRG, optiondata); + if (retval != ERROR_OK) + return retval; + + optiondata = stm32x_info->option_bytes.protection & 0xff; + /* Program protection WPSNPRG */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_WPSNPRG, optiondata); + if (retval != ERROR_OK) + return retval; + + optiondata = stm32x_info->option_bytes.protection2 & 0xff; + /* Program protection WPSNPRG2 */ + retval = target_write_u32(target, FLASH_REG_BASE_B1 + FLASH_WPSNPRG, optiondata); + if (retval != ERROR_OK) + return retval; + + optiondata = 0x40000000; + /* Remove OPT error flag before programming */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCCR, optiondata); + if (retval != ERROR_OK) + return retval; + + /* start programming cycle */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_START); + if (retval != ERROR_OK) + return retval; + + /* wait for completion */ + int timeout = FLASH_ERASE_TIMEOUT; + for (;;) { + uint32_t status; + retval = target_read_u32(target, FLASH_REG_BASE_B0 + FLASH_SR, &status); + if (retval != ERROR_OK) { + LOG_INFO("stm32x_write_options: wait_status_busy : error"); + return retval; + } + if ((status & FLASH_BSY) == 0) + break; + + if (timeout-- <= 0) { + LOG_INFO("wait_status_busy, time out expired, status: 0x%" PRIx32 "", status); + return ERROR_FAIL; + } + alive_sleep(1); + } + + /* relock option registers */ + retval = target_write_u32(target, FLASH_REG_BASE_B0 + FLASH_OPTCR, OPT_LOCK); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32x_protect_check(struct flash_bank *bank) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + + /* read 'write protection' settings */ + int retval = stm32x_read_options(bank); + if (retval != ERROR_OK) { + LOG_DEBUG("unable to read option bytes"); + return retval; + } + + for (int i = 0; i < bank->num_sectors; i++) { + if (stm32x_info->flash_base == FLASH_REG_BASE_B0) { + if (stm32x_info->option_bytes.protection & (1 << i)) + bank->sectors[i].is_protected = 0; + else + bank->sectors[i].is_protected = 1; + } else { + if (stm32x_info->option_bytes.protection2 & (1 << i)) + bank->sectors[i].is_protected = 0; + else + bank->sectors[i].is_protected = 1; + } + } + return ERROR_OK; +} + +static int stm32x_erase(struct flash_bank *bank, int first, int last) +{ + struct target *target = bank->target; + int retval; + + assert(first < bank->num_sectors); + assert(last < bank->num_sectors); + + if (bank->target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + retval = stm32x_unlock_reg(bank); + if (retval != ERROR_OK) + return retval; + + /* + Sector Erase + To erase a sector, follow the procedure below: + 1. Check that no Flash memory operation is ongoing by checking the BSY bit in the + FLASH_SR register + 2. Set the SER bit and select the sector + you wish to erase (SNB) in the FLASH_CR register + 3. Set the STRT bit in the FLASH_CR register + 4. Wait for the BSY bit to be cleared + */ + for (int i = first; i <= last; i++) { + LOG_DEBUG("erase sector %d", i); + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), + FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64); + if (retval != ERROR_OK) { + LOG_ERROR("Error erase sector %d", i); + return retval; + } + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), + FLASH_SER | FLASH_SNB(i) | FLASH_PSIZE_64 | FLASH_START); + if (retval != ERROR_OK) { + LOG_ERROR("Error erase sector %d", i); + return retval; + } + retval = stm32x_wait_status_busy(bank, FLASH_ERASE_TIMEOUT); + + if (retval != ERROR_OK) { + LOG_ERROR("erase time-out error sector %d", i); + return retval; + } + bank->sectors[i].is_erased = 1; + } + + retval = stm32x_lock_reg(bank); + if (retval != ERROR_OK) { + LOG_ERROR("error during the lock of flash"); + return retval; + } + + return ERROR_OK; +} + +static int stm32x_protect(struct flash_bank *bank, int set, int first, int last) +{ + struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + /* read protection settings */ + int retval = stm32x_read_options(bank); + if (retval != ERROR_OK) { + LOG_DEBUG("unable to read option bytes"); + return retval; + } + + for (int i = first; i <= last; i++) { + if (stm32x_info->flash_base == FLASH_REG_BASE_B0) { + if (set) + stm32x_info->option_bytes.protection &= ~(1 << i); + else + stm32x_info->option_bytes.protection |= (1 << i); + } else { + if (set) + stm32x_info->option_bytes.protection2 &= ~(1 << i); + else + stm32x_info->option_bytes.protection2 |= (1 << i); + } + } + + LOG_INFO("stm32x_protect, option_bytes written WRP1 0x%x , WRP2 0x%x", + (stm32x_info->option_bytes.protection & 0xff), (stm32x_info->option_bytes.protection2 & 0xff)); + + retval = stm32x_write_options(bank); + if (retval != ERROR_OK) + return retval; + + return ERROR_OK; +} + +static int stm32x_write_block(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + /* + * If the size of the data part of the buffer is not a multiple of FLASH_BLOCK_SIZE, we get + * "corrupted fifo read" pointer in target_run_flash_async_algorithm() + */ + uint32_t data_size = 512 * FLASH_BLOCK_SIZE; /* 16384 */ + uint32_t buffer_size = 8 + data_size; + struct working_area *write_algorithm; + struct working_area *source; + uint32_t address = bank->base + offset; + struct reg_param reg_params[5]; + struct armv7m_algorithm armv7m_info; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + int retval = ERROR_OK; + + /* see contrib/loaders/flash/smt32h7x.S for src */ + static const uint8_t stm32x_flash_write_code[] = { + /* : */ + 0x45, 0x68, /* ldr r5, [r0, #4] */ + /* : */ + 0x06, 0x68, /* ldr r6, [r0, #0] */ + 0x26, 0xb3, /* cbz r6, */ + 0x76, 0x1b, /* subs r6, r6, r5 */ + 0x42, 0xbf, /* ittt mi */ + 0x76, 0x18, /* addmi r6, r6, r1 */ + 0x36, 0x1a, /* submi r6, r6, r0 */ + 0x08, 0x3e, /* submi r6, #8 */ + 0x20, 0x2e, /* cmp r6, #32 */ + 0xf6, 0xd3, /* bcc.n */ + 0x4f, 0xf0, 0x32, 0x06, /* mov.w r6, #STM32_PROG */ + 0xe6, 0x60, /* str r6, [r4, #STM32_FLASH_CR_OFFSET] */ + 0x4f, 0xf0, 0x08, 0x07, /* mov.w r7, #8 */ + /* : */ + 0x55, 0xf8, 0x04, 0x6b, /* ldr.w r6, [r5], #4 */ + 0x42, 0xf8, 0x04, 0x6b, /* str.w r6, [r2], #4 */ + 0xbf, 0xf3, 0x4f, 0x8f, /* dsb sy */ + 0x8d, 0x42, /* cmp r5, r1 */ + 0x28, 0xbf, /* it cs */ + 0x00, 0xf1, 0x08, 0x05, /* addcs.w r5, r0, #8 */ + 0x01, 0x3f, /* subs r7, #1 */ + 0xf3, 0xd1, /* bne.n */ + /* : */ + 0x26, 0x69, /* ldr r6, [r4, #STM32_FLASH_SR_OFFSET] */ + 0x16, 0xf0, 0x01, 0x0f, /* tst.w r6, #STM32_SR_BUSY_MASK */ + 0xfb, 0xd1, /* bne.n */ + 0x05, 0x4f, /* ldr r7, [pc, #20] ; () */ + 0x3e, 0x42, /* tst r6, r7 */ + 0x03, 0xd1, /* bne.n */ + 0x45, 0x60, /* str r5, [r0, #4] */ + 0x01, 0x3b, /* subs r3, #1 */ + 0xdb, 0xd1, /* bne.n */ + 0x01, 0xe0, /* b.n */ + /* : */ + 0x00, 0x27, /* movs r7, #0 */ + 0x47, 0x60, /* str r7, [r0, #4] */ + /* : */ + 0x30, 0x46, /* mov r0, r6 */ + 0x00, 0xbe, /* bkpt 0x0000 */ + /* : */ + 0x00, 0x00, 0xee, 0x03 /* .word 0x03ee0000 ; (STM32_SR_ERROR_MASK) */ + }; + + if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), + &write_algorithm) != ERROR_OK) { + LOG_WARNING("no working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + retval = target_write_buffer(target, write_algorithm->address, + sizeof(stm32x_flash_write_code), + stm32x_flash_write_code); + if (retval != ERROR_OK) + return retval; + + /* memory buffer */ + while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) { + data_size /= 2; + buffer_size = 8 + data_size; + if (data_size <= 256) { + /* we already allocated the writing code, but failed to get a + * buffer, free the algorithm */ + target_free_working_area(target, write_algorithm); + + LOG_WARNING("no large enough working area available, can't do block memory writes"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + LOG_DEBUG("target_alloc_working_area_try : buffer_size -> 0x%x", buffer_size); + + armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; + armv7m_info.core_mode = ARM_MODE_THREAD; + + init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ + init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ + init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ + init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (word-256 bits) */ + init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* flash reg base */ + + buf_set_u32(reg_params[0].value, 0, 32, source->address); + buf_set_u32(reg_params[1].value, 0, 32, source->address + source->size); + buf_set_u32(reg_params[2].value, 0, 32, address); + buf_set_u32(reg_params[3].value, 0, 32, count); + buf_set_u32(reg_params[4].value, 0, 32, stm32x_info->flash_base); + + retval = target_run_flash_async_algorithm(target, + buffer, + count, + FLASH_BLOCK_SIZE, + 0, NULL, + 5, reg_params, + source->address, source->size, + write_algorithm->address, 0, + &armv7m_info); + + if (retval == ERROR_FLASH_OPERATION_FAILED) { + LOG_INFO("error executing stm32h7x flash write algorithm"); + + uint32_t flash_sr = buf_get_u32(reg_params[0].value, 0, 32); + + if (flash_sr & FLASH_WRPERR) + LOG_ERROR("flash memory write protected"); + + if ((flash_sr & FLASH_ERROR) != 0) { + LOG_ERROR("flash write failed, FLASH_SR = %08" PRIx32, flash_sr); + /* Clear error + EOP flags but report errors */ + target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CCR), flash_sr); + retval = ERROR_FAIL; + } + } + + target_free_working_area(target, source); + target_free_working_area(target, write_algorithm); + + destroy_reg_param(®_params[0]); + destroy_reg_param(®_params[1]); + destroy_reg_param(®_params[2]); + destroy_reg_param(®_params[3]); + destroy_reg_param(®_params[4]); + return retval; +} + +static int stm32x_write(struct flash_bank *bank, const uint8_t *buffer, + uint32_t offset, uint32_t count) +{ + struct target *target = bank->target; + uint32_t address = bank->base + offset; + int retval, retval2; + + if (bank->target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (offset % FLASH_BLOCK_SIZE) { + LOG_WARNING("offset 0x%" PRIx32 " breaks required 32-byte alignment", offset); + return ERROR_FLASH_DST_BREAKS_ALIGNMENT; + } + + retval = stm32x_unlock_reg(bank); + if (retval != ERROR_OK) + return retval; + + uint32_t blocks_remaining = count / FLASH_BLOCK_SIZE; + uint32_t bytes_remaining = count % FLASH_BLOCK_SIZE; + + /* multiple words (32-bytes) to be programmed in block */ + if (blocks_remaining) { + retval = stm32x_write_block(bank, buffer, offset, blocks_remaining); + if (retval != ERROR_OK) { + if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { + /* if block write failed (no sufficient working area), + * we use normal (slow) dword accesses */ + LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); + } + } else { + buffer += blocks_remaining * FLASH_BLOCK_SIZE; + address += blocks_remaining * FLASH_BLOCK_SIZE; + blocks_remaining = 0; + } + if ((retval != ERROR_OK) && (retval != ERROR_TARGET_RESOURCE_NOT_AVAILABLE)) + goto flash_lock; + } + + /* + Standard programming + The Flash memory programming sequence is as follows: + 1. Check that no main Flash memory operation is ongoing by checking the BSY bit in the + FLASH_SR register. + 2. Set the PG bit in the FLASH_CR register + 3. 8 x Word access (or Force Write FW) + 4. Wait for the BSY bit to be cleared + */ + while (blocks_remaining > 0) { + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); + if (retval != ERROR_OK) + goto flash_lock; + + retval = target_write_buffer(target, address, FLASH_BLOCK_SIZE, buffer); + if (retval != ERROR_OK) + goto flash_lock; + + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + goto flash_lock; + + buffer += FLASH_BLOCK_SIZE; + address += FLASH_BLOCK_SIZE; + blocks_remaining--; + } + + if (bytes_remaining) { + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64); + if (retval != ERROR_OK) + goto flash_lock; + + retval = target_write_buffer(target, address, bytes_remaining, buffer); + if (retval != ERROR_OK) + goto flash_lock; + + /* Force Write buffer of FLASH_BLOCK_SIZE = 32 bytes */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_PG | FLASH_PSIZE_64 | FLASH_FW); + if (retval != ERROR_OK) + goto flash_lock; + + retval = stm32x_wait_status_busy(bank, FLASH_WRITE_TIMEOUT); + if (retval != ERROR_OK) + goto flash_lock; + } + +flash_lock: + retval2 = stm32x_lock_reg(bank); + if (retval2 != ERROR_OK) + LOG_ERROR("error during the lock of flash"); + + if (retval == ERROR_OK) + retval = retval2; + + return retval; +} + +static void setup_sector(struct flash_bank *bank, int start, int num, int size) +{ + for (int i = start; i < (start + num) ; i++) { + assert(i < bank->num_sectors); + bank->sectors[i].offset = bank->size; + bank->sectors[i].size = size; + bank->size += bank->sectors[i].size; + } +} + +static int stm32x_read_id_code(struct flash_bank *bank, uint32_t *id) +{ + /* read stm32 device id register */ + int retval = target_read_u32(bank->target, DBGMCU_IDCODE_REGISTER, id); + if (retval != ERROR_OK) + return retval; + return ERROR_OK; +} + +static int stm32x_probe(struct flash_bank *bank) +{ + struct target *target = bank->target; + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + int i; + uint16_t flash_size_in_kb; + uint32_t device_id; + uint32_t base_address = FLASH_BANK0_ADDRESS; + uint32_t second_bank_base; + + stm32x_info->probed = 0; + stm32x_info->part_info = NULL; + + int retval = stm32x_read_id_code(bank, &stm32x_info->idcode); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("device id = 0x%08" PRIx32 "", stm32x_info->idcode); + + device_id = stm32x_info->idcode & 0xfff; + + for (unsigned int n = 0; n < ARRAY_SIZE(stm32h7x_parts); n++) { + if (device_id == stm32h7x_parts[n].id) + stm32x_info->part_info = &stm32h7x_parts[n]; + } + if (!stm32x_info->part_info) { + LOG_WARNING("Cannot identify target as a STM32H7xx family."); + return ERROR_FAIL; + } else { + LOG_INFO("Device: %s", stm32x_info->part_info->device_str); + } + + /* update the address of controller from data base */ + stm32x_info->flash_base = stm32x_info->part_info->flash_base; + + /* get flash size from target */ + retval = target_read_u16(target, stm32x_info->part_info->fsize_base, &flash_size_in_kb); + if (retval != ERROR_OK) { + /* read error when device has invalid value, set max flash size */ + flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; + } else + LOG_INFO("flash size probed value %d", flash_size_in_kb); + + /* Lower flash size devices are single bank */ + if (stm32x_info->part_info->has_dual_bank && (flash_size_in_kb > stm32x_info->part_info->first_bank_size_kb)) { + /* Use the configured base address to determine if this is the first or second flash bank. + * Verify that the base address is reasonably correct and determine the flash bank size + */ + second_bank_base = base_address + stm32x_info->part_info->first_bank_size_kb * 1024; + if (bank->base == second_bank_base) { + /* This is the second bank */ + base_address = second_bank_base; + flash_size_in_kb = flash_size_in_kb - stm32x_info->part_info->first_bank_size_kb; + /* bank1 also uses a register offset */ + stm32x_info->flash_base = FLASH_REG_BASE_B1; + } else if (bank->base == base_address) { + /* This is the first bank */ + flash_size_in_kb = stm32x_info->part_info->first_bank_size_kb; + } else { + LOG_WARNING("STM32H flash bank base address config is incorrect." + " 0x%" PRIx32 " but should rather be 0x%" PRIx32 " or 0x%" PRIx32, + bank->base, base_address, second_bank_base); + return ERROR_FAIL; + } + LOG_INFO("STM32H flash has dual banks. Bank (%d) size is %dkb, base address is 0x%" PRIx32, + bank->bank_number, flash_size_in_kb, base_address); + } else { + LOG_INFO("STM32H flash size is %dkb, base address is 0x%" PRIx32, flash_size_in_kb, base_address); + } + + /* if the user sets the size manually then ignore the probed value + * this allows us to work around devices that have an invalid flash size register value */ + if (stm32x_info->user_bank_size) { + LOG_INFO("ignoring flash probed value, using configured bank size"); + flash_size_in_kb = stm32x_info->user_bank_size / 1024; + } else if (flash_size_in_kb == 0xffff) { + /* die flash size */ + flash_size_in_kb = stm32x_info->part_info->max_flash_size_kb; + } + + /* did we assign flash size? */ + assert(flash_size_in_kb != 0xffff); + + /* calculate numbers of pages */ + int num_pages = flash_size_in_kb / stm32x_info->part_info->page_size; + + /* check that calculation result makes sense */ + assert(num_pages > 0); + + if (bank->sectors) { + free(bank->sectors); + bank->sectors = NULL; + } + + bank->base = base_address; + bank->num_sectors = num_pages; + bank->sectors = malloc(sizeof(struct flash_sector) * num_pages); + if (bank->sectors == NULL) { + LOG_ERROR("failed to allocate bank sectors"); + return ERROR_FAIL; + } + bank->size = 0; + + /* fixed memory */ + setup_sector(bank, 0, num_pages, stm32x_info->part_info->page_size * 1024); + + for (i = 0; i < num_pages; i++) { + bank->sectors[i].is_erased = -1; + bank->sectors[i].is_protected = 0; + } + + stm32x_info->probed = 1; + return ERROR_OK; +} + +static int stm32x_auto_probe(struct flash_bank *bank) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + + if (stm32x_info->probed) + return ERROR_OK; + + return stm32x_probe(bank); +} + +/* This method must return a string displaying information about the bank */ +static int stm32x_get_info(struct flash_bank *bank, char *buf, int buf_size) +{ + struct stm32h7x_flash_bank *stm32x_info = bank->driver_priv; + const struct stm32h7x_part_info *info = stm32x_info->part_info; + + if (!stm32x_info->probed) { + int retval = stm32x_probe(bank); + if (retval != ERROR_OK) { + snprintf(buf, buf_size, "Unable to find bank information."); + return retval; + } + } + + if (info) { + const char *rev_str = NULL; + uint16_t rev_id = stm32x_info->idcode >> 16; + + for (unsigned int i = 0; i < info->num_revs; i++) + if (rev_id == info->revs[i].rev) + rev_str = info->revs[i].str; + + if (rev_str != NULL) { + snprintf(buf, buf_size, "%s - Rev: %s", + stm32x_info->part_info->device_str, rev_str); + } else { + snprintf(buf, buf_size, + "%s - Rev: unknown (0x%04x)", + stm32x_info->part_info->device_str, rev_id); + } + } else { + snprintf(buf, buf_size, "Cannot identify target as a STM32H7x"); + return ERROR_FAIL; + } + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_lock_command) +{ + struct target *target = NULL; + struct stm32h7x_flash_bank *stm32x_info = NULL; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + stm32x_info = bank->driver_priv; + target = bank->target; + + /* if we have a dual flash bank device then + * we need to perform option byte lock on bank0 only */ + if (stm32x_info->flash_base != FLASH_REG_BASE_B0) { + LOG_ERROR("Option Byte Lock Operation must use bank0"); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (stm32x_read_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to read options", + bank->driver->name); + return ERROR_OK; + } + /* set readout protection */ + stm32x_info->option_bytes.RDP = 0; + + if (stm32x_write_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to lock device", + bank->driver->name); + return ERROR_OK; + } + command_print(CMD_CTX, "%s locked", bank->driver->name); + + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_unlock_command) +{ + struct target *target = NULL; + struct stm32h7x_flash_bank *stm32x_info = NULL; + + if (CMD_ARGC < 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + stm32x_info = bank->driver_priv; + target = bank->target; + + /* if we have a dual flash bank device then + * we need to perform option byte unlock on bank0 only */ + if (stm32x_info->flash_base != FLASH_REG_BASE_B0) { + LOG_ERROR("Option Byte Unlock Operation must use bank0"); + return ERROR_FLASH_OPERATION_FAILED; + } + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (stm32x_read_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to read options", bank->driver->name); + return ERROR_OK; + } + + /* clear readout protection option byte + * this will also force a device unlock if set */ + stm32x_info->option_bytes.RDP = 0xAA; + + if (stm32x_write_options(bank) != ERROR_OK) { + command_print(CMD_CTX, "%s failed to unlock device", bank->driver->name); + return ERROR_OK; + } + command_print(CMD_CTX, "%s unlocked.\n", bank->driver->name); + + return ERROR_OK; +} + +static int stm32x_mass_erase(struct flash_bank *bank) +{ + int retval; + struct target *target = bank->target; + + if (target->state != TARGET_HALTED) { + LOG_ERROR("Target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + retval = stm32x_unlock_reg(bank); + if (retval != ERROR_OK) + return retval; + + /* mass erase flash memory bank */ + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), FLASH_BER_CMD | FLASH_PSIZE_64); + if (retval != ERROR_OK) + return retval; + + retval = target_write_u32(target, stm32x_get_flash_reg(bank, FLASH_CR), + FLASH_BER_CMD | FLASH_PSIZE_64 | FLASH_START); + if (retval != ERROR_OK) + return retval; + + retval = stm32x_wait_status_busy(bank, 30000); + if (retval != ERROR_OK) + return retval; + + retval = stm32x_lock_reg(bank); + if (retval != ERROR_OK) { + LOG_ERROR("error during the lock of flash"); + return retval; + } + return ERROR_OK; +} + +COMMAND_HANDLER(stm32x_handle_mass_erase_command) +{ + int i; + + if (CMD_ARGC < 1) { + command_print(CMD_CTX, "stm32h7x mass_erase "); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + struct flash_bank *bank; + int retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &bank); + if (ERROR_OK != retval) + return retval; + + retval = stm32x_mass_erase(bank); + if (retval == ERROR_OK) { + /* set all sectors as erased */ + for (i = 0; i < bank->num_sectors; i++) + bank->sectors[i].is_erased = 1; + + command_print(CMD_CTX, "stm32h7x mass erase complete"); + } else { + command_print(CMD_CTX, "stm32h7x mass erase failed"); + } + + return retval; +} + +static const struct command_registration stm32x_exec_command_handlers[] = { + { + .name = "lock", + .handler = stm32x_handle_lock_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Lock entire flash device.", + }, + { + .name = "unlock", + .handler = stm32x_handle_unlock_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Unlock entire protected flash device.", + }, + { + .name = "mass_erase", + .handler = stm32x_handle_mass_erase_command, + .mode = COMMAND_EXEC, + .usage = "bank_id", + .help = "Erase entire flash device.", + }, + COMMAND_REGISTRATION_DONE +}; + +static const struct command_registration stm32x_command_handlers[] = { + { + .name = "stm32h7x", + .mode = COMMAND_ANY, + .help = "stm32h7x flash command group", + .usage = "", + .chain = stm32x_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct flash_driver stm32h7x_flash = { + .name = "stm32h7x", + .commands = stm32x_command_handlers, + .flash_bank_command = stm32x_flash_bank_command, + .erase = stm32x_erase, + .protect = stm32x_protect, + .write = stm32x_write, + .read = default_flash_read, + .probe = stm32x_probe, + .auto_probe = stm32x_auto_probe, + .erase_check = default_flash_blank_check, + .protect_check = stm32x_protect_check, + .info = stm32x_get_info, +}; From 6090a5b158ad212a54510f061226ca58155b51fe Mon Sep 17 00:00:00 2001 From: Alexandre Torgue Date: Mon, 13 Nov 2017 17:00:58 +0100 Subject: [PATCH 067/127] Add STM32H7 config files Add 2 target files: -stm32h7x.cfg -stm32h7x_dual_bank.cfg Add 2 config files for: -STM32H743zi-nucleo bord -STM32H743i and STM32H753i eval boards. Change-Id: I2aae2c5acff4f3ff8e1bf232fda5a11a87f71703 Signed-off-by: Alexandre TORGUE Reviewed-on: http://openocd.zylin.com/4182 Tested-by: jenkins Reviewed-by: Antonio Borneo --- tcl/board/st_nucleo_h743zi.cfg | 10 ++++ tcl/board/stm32h7x3i_eval.cfg | 13 +++++ tcl/target/stm32h7x.cfg | 93 +++++++++++++++++++++++++++++++ tcl/target/stm32h7x_dual_bank.cfg | 7 +++ 4 files changed, 123 insertions(+) create mode 100644 tcl/board/st_nucleo_h743zi.cfg create mode 100644 tcl/board/stm32h7x3i_eval.cfg create mode 100644 tcl/target/stm32h7x.cfg create mode 100644 tcl/target/stm32h7x_dual_bank.cfg diff --git a/tcl/board/st_nucleo_h743zi.cfg b/tcl/board/st_nucleo_h743zi.cfg new file mode 100644 index 000000000..baedeb6d4 --- /dev/null +++ b/tcl/board/st_nucleo_h743zi.cfg @@ -0,0 +1,10 @@ +# This is an ST NUCLEO-H743ZI board with single STM32H743ZI chip. +# http://www.st.com/en/evaluation-tools/nucleo-h743zi.html + +source [find interface/stlink-v2-1.cfg] + +transport select hla_swd + +source [find target/stm32h7x_dual_bank.cfg] + +reset_config srst_only diff --git a/tcl/board/stm32h7x3i_eval.cfg b/tcl/board/stm32h7x3i_eval.cfg new file mode 100644 index 000000000..2949ded32 --- /dev/null +++ b/tcl/board/stm32h7x3i_eval.cfg @@ -0,0 +1,13 @@ +# STM32H7[4|5]3I-EVAL: this is for the H7 eval boards. +# This is an ST EVAL-H743XI board with single STM32H743XI chip. +# http://www.st.com/en/evaluation-tools/stm32h743i-eval.html +# This is an ST EVAL-H753XI board with single STM32H753XI chip. +# http://www.st.com/en/evaluation-tools/stm32h753i-eval.html + +source [find interface/stlink-v2-1.cfg] + +transport select hla_swd + +source [find target/stm32h7x_dual_bank.cfg] + +reset_config srst_only diff --git a/tcl/target/stm32h7x.cfg b/tcl/target/stm32h7x.cfg new file mode 100644 index 000000000..02dbed4a8 --- /dev/null +++ b/tcl/target/stm32h7x.cfg @@ -0,0 +1,93 @@ +# script for stm32h7x family + +# +# stm32h7 devices support both JTAG and SWD transports. +# +source [find target/swj-dp.tcl] +source [find mem_helper.tcl] + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm32h7x +} + +set _ENDIAN little + +# Work-area is a space in RAM used for flash programming +# By default use 64kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x10000 +} + +#jtag scan chain +if { [info exists CPUTAPID] } { + set _CPUTAPID $CPUTAPID +} else { + if { [using_jtag] } { + set _CPUTAPID 0x6ba00477 + } { + set _CPUTAPID 0x6ba02477 + } +} + +swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID + +if {[using_jtag]} { + swj_newdap $_CHIPNAME bs -irlen 5 +} + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME + +$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0 + +set _FLASHNAME $_CHIPNAME.flash +flash bank $_FLASHNAME stm32h7x 0x08000000 0 0 0 $_TARGETNAME + +# Clock after reset is HSI at 64 MHz, no need of PLL +adapter_khz 1800 + +adapter_nsrst_delay 100 +if {[using_jtag]} { + jtag_ntrst_delay 100 +} + +# use hardware reset, connect under reset +reset_config srst_only srst_nogate + +if {![using_hla]} { + # if srst is not fitted use SYSRESETREQ to + # perform a soft reset + cortex_m reset_config sysresetreq +} + +$_TARGETNAME configure -event examine-end { + # Enable D3 and D1 DBG clocks + # DBGMCU_CR |= D3DBGCKEN | D1DBGCKEN + mmw 0x5C001004 0x00600000 0 + + # Enable debug during low power modes (uses more power) + # DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP in D3 & D1 Domains + mmw 0x5C001004 0x00000187 0 + + # Stop watchdog counters during halt + # DBGMCU_APB3FZ1 |= WWDG1 + mmw 0x5C001034 0x00000040 0 + # DBGMCU_APB4FZ1 |= WDGLSD1 + mmw 0x5C001054 0x00040000 0 +} + +$_TARGETNAME configure -event trace-config { + # Set TRACECLKEN; TRACE_MODE is set to async; when using sync + # change this value accordingly to configure trace pins + # assignment + mmw 0x5C001004 0x00100000 0 +} + +$_TARGETNAME configure -event reset-init { + # Clock after reset is HSI at 64 MHz, no need of PLL + adapter_khz 4000 +} diff --git a/tcl/target/stm32h7x_dual_bank.cfg b/tcl/target/stm32h7x_dual_bank.cfg new file mode 100644 index 000000000..7e342f931 --- /dev/null +++ b/tcl/target/stm32h7x_dual_bank.cfg @@ -0,0 +1,7 @@ +# script for stm32h7x family (dual flash bank) +source [find target/stm32h7x.cfg] + +# STM32H7xxxI 2Mo have a dual bank flash. +# Add the second flash bank. +set _FLASHNAME $_CHIPNAME.flash1 +flash bank $_FLASHNAME stm32h7x 0x08100000 0 0 0 $_TARGETNAME From 020cb12077cb15be1700bf7733178acfb2b26428 Mon Sep 17 00:00:00 2001 From: Ake Rehnman Date: Mon, 6 Nov 2017 19:56:28 +0100 Subject: [PATCH 068/127] stm8 : new target New STM8 target based mostly on mips4k. Target communication through STLINK/SWIM. No flash driver yet but it is still possible to program flash through load_image command. The usual target debug methods are implemented. Change-Id: I7216f231d3ac7c70cae20f1cd8463c2ed864a329 Signed-off-by: Ake Rehnman Reviewed-on: http://openocd.zylin.com/3953 Tested-by: jenkins Reviewed-by: Tomas Vanek Reviewed-by: Paul Fertser --- contrib/loaders/Makefile | 5 +- contrib/loaders/erase_check/Makefile | 17 + .../loaders/erase_check/stm8_erase_check.inc | 5 + .../loaders/erase_check/stm8_erase_check.s | 69 + src/target/Makefile.am | 5 + src/target/stm8.c | 2219 +++++++++++++++++ src/target/stm8.h | 75 + src/target/target.c | 2 + tcl/target/stm8l.cfg | 87 + tcl/target/stm8s.cfg | 84 + 10 files changed, 2567 insertions(+), 1 deletion(-) create mode 100644 contrib/loaders/erase_check/stm8_erase_check.inc create mode 100644 contrib/loaders/erase_check/stm8_erase_check.s create mode 100644 src/target/stm8.c create mode 100644 src/target/stm8.h create mode 100644 tcl/target/stm8l.cfg create mode 100644 tcl/target/stm8s.cfg diff --git a/contrib/loaders/Makefile b/contrib/loaders/Makefile index 31cccb5ff..a9a27706d 100644 --- a/contrib/loaders/Makefile +++ b/contrib/loaders/Makefile @@ -1,6 +1,6 @@ .PHONY: arm clean-arm -all: arm +all: arm stm8 common_dirs = \ checksum \ @@ -32,3 +32,6 @@ clean: clean-arm for d in $(common_dirs); do \ $(MAKE) -C $$d clean; \ done + +stm8: + $(MAKE) -C erase_check stm8 diff --git a/contrib/loaders/erase_check/Makefile b/contrib/loaders/erase_check/Makefile index 01e62dead..427fa0c07 100644 --- a/contrib/loaders/erase_check/Makefile +++ b/contrib/loaders/erase_check/Makefile @@ -6,6 +6,12 @@ ARM_OBJCOPY ?= $(ARM_CROSS_COMPILE)objcopy ARM_AFLAGS = -EL +STM8_CROSS_COMPILE ?= stm8- +STM8_AS ?= $(STM8_CROSS_COMPILE)as +STM8_OBJCOPY ?= $(STM8_CROSS_COMPILE)objcopy + +STM8_AFLAGS = + arm: armv4_5_erase_check.inc armv7m_erase_check.inc armv7m_0_erase_check.inc armv4_5_%.elf: armv4_5_%.s @@ -26,5 +32,16 @@ armv7m_%.bin: armv7m_%.elf armv7m_%.inc: armv7m_%.bin $(BIN2C) < $< > $@ +stm8: stm8_erase_check.inc + +stm8_%.elf: stm8_%.s + $(STM8_AS) $(STM8_AFLAGS) $< -o $@ + +stm8_%.bin: stm8_%.elf + $(STM8_OBJCOPY) -Obinary $< $@ + +stm8_%.inc: stm8_%.bin + $(BIN2C) < $< > $@ + clean: -rm -f *.elf *.bin *.inc diff --git a/contrib/loaders/erase_check/stm8_erase_check.inc b/contrib/loaders/erase_check/stm8_erase_check.inc new file mode 100644 index 000000000..66b4ec7f5 --- /dev/null +++ b/contrib/loaders/erase_check/stm8_erase_check.inc @@ -0,0 +1,5 @@ +/* Autogenerated with ../../../src/helper/bin2char.sh */ +0x00,0x80,0x00,0x00,0x80,0x00,0x96,0xcf,0x00,0x22,0x1e,0x01,0x16,0x04,0xa6,0xff, +0x90,0x5d,0x26,0x04,0x0d,0x03,0x27,0x17,0x90,0x5d,0x26,0x02,0x0a,0x03,0x90,0x5a, +0x92,0xbc,0x00,0x00,0xa1,0xff,0x26,0x07,0x5c,0x26,0xe5,0x0c,0x00,0x20,0xe1,0x1f, +0x01,0x17,0x04,0x8b, diff --git a/contrib/loaders/erase_check/stm8_erase_check.s b/contrib/loaders/erase_check/stm8_erase_check.s new file mode 100644 index 000000000..62694006b --- /dev/null +++ b/contrib/loaders/erase_check/stm8_erase_check.s @@ -0,0 +1,69 @@ +/* + Copyright (C) 2017 Ake Rehnman + ake.rehnman(at)gmail.com + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +;; +;; erase check memory code +;; + .org 0x0 +;; start address + start_addr: .byte 0x00 + .word 0x8000 +;; byte count + byte_cnt: .byte 0x00 + .word 0x8000 +; +; SP must point to start_addr on entry +; first relocate start_addr to the location +; we are running at +start: + ldw X,SP + ldw .cont+2,X + ldw X,(start_addr+1,SP) ;start addr + ldw Y,(byte_cnt+1,SP) ;count + ld A,#0xff +; +; if count == 0 return +.L1: + tnzw Y + jrne .decrcnt ;continue if low word != 0 + tnz (byte_cnt,SP) ;high byte + jreq .exit ;goto exit +; +; decrement count (byte_cnt) +.decrcnt: + tnzw Y ;low word count + jrne .decr1 + dec (byte_cnt,SP) ;high byte +.decr1: + decw Y; decr low word +; +; first check if [start_addr] is 0xff +.cont: + ldf A, [start_addr.e] + cp A,#0xff + jrne .exit ;exit if not 0xff +; +; increment start_addr (addr) + incw X + jrne .L1 + inc (start_addr,SP) ;increment high byte + jra .L1 +; +.exit: + ldw (start_addr+1,SP),X ;start addr + ldw (byte_cnt+1,SP),Y ;count + break diff --git a/src/target/Makefile.am b/src/target/Makefile.am index 597070c4b..d2aab0a5e 100644 --- a/src/target/Makefile.am +++ b/src/target/Makefile.am @@ -19,6 +19,7 @@ noinst_LTLIBRARIES += %D%/libtarget.la $(AVR32_SRC) \ $(MIPS32_SRC) \ $(NDS32_SRC) \ + $(STM8_SRC) \ $(INTEL_IA32_SRC) \ %D%/avrt.c \ %D%/dsp563xx.c \ @@ -124,6 +125,9 @@ NDS32_SRC = \ %D%/nds32_v3m.c \ %D%/nds32_aice.c +STM8_SRC = \ + %D%/stm8.c + INTEL_IA32_SRC = \ %D%/quark_x10xx.c \ %D%/quark_d20xx.c \ @@ -205,6 +209,7 @@ INTEL_IA32_SRC = \ %D%/nds32_v3.h \ %D%/nds32_v3m.h \ %D%/nds32_aice.h \ + %D%/stm8.h \ %D%/lakemont.h \ %D%/x86_32_common.h \ %D%/arm_cti.h diff --git a/src/target/stm8.c b/src/target/stm8.c new file mode 100644 index 000000000..262497b0d --- /dev/null +++ b/src/target/stm8.c @@ -0,0 +1,2219 @@ +/* + OpenOCD STM8 target driver + Copyright (C) 2017 Ake Rehnman + ake.rehnman(at)gmail.com + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include "target.h" +#include "target_type.h" +#include "hello.h" +#include "jtag/jtag.h" +#include "jtag/hla/hla_transport.h" +#include "jtag/hla/hla_interface.h" +#include "jtag/hla/hla_layout.h" +#include "register.h" +#include "breakpoints.h" +#include "algorithm.h" +#include "stm8.h" + +static struct reg_cache *stm8_build_reg_cache(struct target *target); +static int stm8_read_core_reg(struct target *target, unsigned int num); +static int stm8_write_core_reg(struct target *target, unsigned int num); +static int stm8_save_context(struct target *target); +static void stm8_enable_breakpoints(struct target *target); +static int stm8_unset_breakpoint(struct target *target, + struct breakpoint *breakpoint); +static int stm8_set_breakpoint(struct target *target, + struct breakpoint *breakpoint); +static void stm8_enable_watchpoints(struct target *target); +static int stm8_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint); + +static const struct { + unsigned id; + const char *name; + const uint8_t bits; + enum reg_type type; + const char *group; + const char *feature; + int flag; +} stm8_regs[] = { + { 0, "pc", 32, REG_TYPE_UINT32, "general", "org.gnu.gdb.stm8.core", 0 }, + { 1, "a", 8, REG_TYPE_UINT8, "general", "org.gnu.gdb.stm8.core", 0 }, + { 2, "x", 16, REG_TYPE_UINT16, "general", "org.gnu.gdb.stm8.core", 0 }, + { 3, "y", 16, REG_TYPE_UINT16, "general", "org.gnu.gdb.stm8.core", 0 }, + { 4, "sp", 16, REG_TYPE_UINT16, "general", "org.gnu.gdb.stm8.core", 0 }, + { 5, "cc", 8, REG_TYPE_UINT8, "general", "org.gnu.gdb.stm8.core", 0 }, +}; + +#define STM8_NUM_REGS ARRAY_SIZE(stm8_regs) +#define STM8_PC 0 +#define STM8_A 1 +#define STM8_X 2 +#define STM8_Y 3 +#define STM8_SP 4 +#define STM8_CC 5 + +#define CC_I0 0x8 +#define CC_I1 0x20 + +#define DM_REGS 0x7f00 +#define DM_REG_A 0x7f00 +#define DM_REG_PC 0x7f01 +#define DM_REG_X 0x7f04 +#define DM_REG_Y 0x7f06 +#define DM_REG_SP 0x7f08 +#define DM_REG_CC 0x7f0a + +#define DM_BKR1E 0x7f90 +#define DM_BKR2E 0x7f93 +#define DM_CR1 0x7f96 +#define DM_CR2 0x7f97 +#define DM_CSR1 0x7f98 +#define DM_CSR2 0x7f99 + +#define STE 0x40 +#define STF 0x20 +#define RST 0x10 +#define BRW 0x08 +#define BK2F 0x04 +#define BK1F 0x02 + +#define SWBRK 0x20 +#define SWBKF 0x10 +#define STALL 0x08 +#define FLUSH 0x01 + +#define FLASH_CR1_STM8S 0x505A +#define FLASH_CR2_STM8S 0x505B +#define FLASH_NCR2_STM8S 0x505C +#define FLASH_IAPSR_STM8S 0x505F +#define FLASH_PUKR_STM8S 0x5062 +#define FLASH_DUKR_STM8S 0x5064 + +#define FLASH_CR1_STM8L 0x5050 +#define FLASH_CR2_STM8L 0x5051 +#define FLASH_NCR2_STM8L 0 +#define FLASH_PUKR_STM8L 0x5052 +#define FLASH_DUKR_STM8L 0x5053 +#define FLASH_IAPSR_STM8L 0x5054 + +/* FLASH_IAPSR */ +#define HVOFF 0x40 +#define DUL 0x08 +#define EOP 0x04 +#define PUL 0x02 +#define WR_PG_DIS 0x01 + +/* FLASH_CR2 */ +#define OPT 0x80 +#define WPRG 0x40 +#define ERASE 0x20 +#define FPRG 0x10 +#define PRG 0x01 + +/* SWIM_CSR */ +#define SAFE_MASK 0x80 +#define NO_ACCESS 0x40 +#define SWIM_DM 0x20 +#define HS 0x10 +#define OSCOFF 0x08 +#define SWIM_RST 0x04 +#define HSIT 0x02 +#define PRI 0x01 + +#define SWIM_CSR 0x7f80 + +#define STM8_BREAK 0x8B + +enum mem_type { + RAM, + FLASH, + EEPROM, + OPTION +}; + +struct stm8_algorithm { + int common_magic; +}; + +struct stm8_core_reg { + uint32_t num; + struct target *target; + struct stm8_common *stm8_common; +}; + +enum hw_break_type { + /* break on execute */ + HWBRK_EXEC, + /* break on read */ + HWBRK_RD, + /* break on write */ + HWBRK_WR, + /* break on read, write and execute */ + HWBRK_ACC +}; + +struct stm8_comparator { + bool used; + uint32_t bp_value; + uint32_t reg_address; + enum hw_break_type type; +}; + +static inline struct hl_interface_s *target_to_adapter(struct target *target) +{ + return target->tap->priv; +} + +static int stm8_adapter_read_memory(struct target *target, + uint32_t addr, int size, int count, void *buf) +{ + int ret; + struct hl_interface_s *adapter = target_to_adapter(target); + + ret = adapter->layout->api->read_mem(adapter->handle, + addr, size, count, buf); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_adapter_write_memory(struct target *target, + uint32_t addr, int size, int count, const void *buf) +{ + int ret; + struct hl_interface_s *adapter = target_to_adapter(target); + + ret = adapter->layout->api->write_mem(adapter->handle, + addr, size, count, buf); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_write_u8(struct target *target, + uint32_t addr, uint8_t val) +{ + int ret; + uint8_t buf[1]; + struct hl_interface_s *adapter = target_to_adapter(target); + + buf[0] = val; + ret = adapter->layout->api->write_mem(adapter->handle, addr, 1, 1, buf); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_read_u8(struct target *target, + uint32_t addr, uint8_t *val) +{ + int ret; + struct hl_interface_s *adapter = target_to_adapter(target); + + ret = adapter->layout->api->read_mem(adapter->handle, addr, 1, 1, val); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_set_speed(struct target *target, int speed) +{ + struct hl_interface_s *adapter = target_to_adapter(target); + adapter->layout->api->speed(adapter->handle, speed, 0); + return ERROR_OK; +} + +/* + Disables interrupts. + If interrupts are enabled they are masked and the cc register + is saved. + + Enables interrupts. + Enable interrupts is actually restoring I1 I0 state from previous + call with enable == 0. Note that if stepping and breaking on a sim + instruction will NOT work since the interrupt flags are restored on + debug_entry. We don't have any way for the debugger to exclusively + disable the interrupts +*/ +static int stm8_enable_interrupts(struct target *target, int enable) +{ + struct stm8_common *stm8 = target_to_stm8(target); + uint8_t cc; + + if (enable) { + if (!stm8->cc_valid) + return ERROR_OK; /* cc was not stashed */ + /* fetch current cc */ + stm8_read_u8(target, DM_REG_CC, &cc); + /* clear I1 I0 */ + cc &= ~(CC_I0 + CC_I1); + /* restore I1 & I0 from stash*/ + cc |= (stm8->cc & (CC_I0+CC_I1)); + /* update current cc */ + stm8_write_u8(target, DM_REG_CC, cc); + stm8->cc_valid = false; + } else { + stm8_read_u8(target, DM_REG_CC, &cc); + if ((cc & CC_I0) && (cc & CC_I1)) + return ERROR_OK; /* interrupts already masked */ + /* stash cc */ + stm8->cc = cc; + stm8->cc_valid = true; + /* mask interrupts (disable) */ + cc |= (CC_I0 + CC_I1); + stm8_write_u8(target, DM_REG_CC, cc); + } + + return ERROR_OK; +} + +static int stm8_set_hwbreak(struct target *target, + struct stm8_comparator comparator_list[]) +{ + uint8_t buf[3]; + int i, ret; + + /* Refer to Table 4 in UM0470 */ + uint8_t bc = 0x5; + uint8_t bir = 0; + uint8_t biw = 0; + + uint32_t data; + uint32_t addr; + + if (!comparator_list[0].used) { + comparator_list[0].type = HWBRK_EXEC; + comparator_list[0].bp_value = -1; + } + + if (!comparator_list[1].used) { + comparator_list[1].type = HWBRK_EXEC; + comparator_list[1].bp_value = -1; + } + + if ((comparator_list[0].type == HWBRK_EXEC) + && (comparator_list[1].type == HWBRK_EXEC)) { + comparator_list[0].reg_address = 0; + comparator_list[1].reg_address = 1; + } + + if ((comparator_list[0].type == HWBRK_EXEC) + && (comparator_list[1].type != HWBRK_EXEC)) { + comparator_list[0].reg_address = 0; + comparator_list[1].reg_address = 1; + switch (comparator_list[1].type) { + case HWBRK_RD: + bir = 1; + break; + case HWBRK_WR: + biw = 1; + break; + default: + bir = 1; + biw = 1; + break; + } + } + + if ((comparator_list[1].type == HWBRK_EXEC) + && (comparator_list[0].type != HWBRK_EXEC)) { + comparator_list[0].reg_address = 1; + comparator_list[1].reg_address = 0; + switch (comparator_list[0].type) { + case HWBRK_RD: + bir = 1; + break; + case HWBRK_WR: + biw = 1; + break; + default: + bir = 1; + biw = 1; + break; + } + } + + if ((comparator_list[0].type != HWBRK_EXEC) + && (comparator_list[1].type != HWBRK_EXEC)) { + if ((comparator_list[0].type != comparator_list[1].type)) { + LOG_ERROR("data hw breakpoints must be of same type"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } + + for (i = 0; i < 2; i++) { + data = comparator_list[i].bp_value; + addr = comparator_list[i].reg_address; + + buf[0] = data >> 16; + buf[1] = data >> 8; + buf[2] = data; + + if (addr == 0) { + ret = stm8_adapter_write_memory(target, DM_BKR1E, 1, 3, buf); + LOG_DEBUG("DM_BKR1E=%" PRIx32, data); + } else if (addr == 1) { + ret = stm8_adapter_write_memory(target, DM_BKR2E, 1, 3, buf); + LOG_DEBUG("DM_BKR2E=%" PRIx32, data); + } else { + LOG_DEBUG("addr=%" PRIu32, addr); + return ERROR_FAIL; + } + + if (ret != ERROR_OK) + return ret; + + ret = stm8_write_u8(target, DM_CR1, + (bc << 3) + (bir << 2) + (biw << 1)); + LOG_DEBUG("DM_CR1=%" PRIx8, buf[0]); + if (ret != ERROR_OK) + return ret; + + } + return ERROR_OK; +} + +/* read DM control and status regs */ +static int stm8_read_dm_csrx(struct target *target, uint8_t *csr1, + uint8_t *csr2) +{ + int ret; + uint8_t buf[2]; + + ret = stm8_adapter_read_memory(target, DM_CSR1, 1, sizeof(buf), buf); + if (ret != ERROR_OK) + return ret; + if (csr1) + *csr1 = buf[0]; + if (csr2) + *csr2 = buf[1]; + return ERROR_OK; +} + +/* set or clear the single step flag in DM */ +static int stm8_config_step(struct target *target, int enable) +{ + int ret; + uint8_t csr1, csr2; + + ret = stm8_read_dm_csrx(target, &csr1, &csr2); + if (ret != ERROR_OK) + return ret; + if (enable) + csr1 |= STE; + else + csr1 &= ~STE; + + ret = stm8_write_u8(target, DM_CSR1, csr1); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +/* set the stall flag in DM */ +static int stm8_debug_stall(struct target *target) +{ + int ret; + uint8_t csr1, csr2; + + ret = stm8_read_dm_csrx(target, &csr1, &csr2); + if (ret != ERROR_OK) + return ret; + csr2 |= STALL; + ret = stm8_write_u8(target, DM_CSR2, csr2); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_configure_break_unit(struct target *target) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (stm8->bp_scanned) + return ERROR_OK; + + stm8->num_hw_bpoints = 2; + stm8->num_hw_bpoints_avail = stm8->num_hw_bpoints; + + stm8->hw_break_list = calloc(stm8->num_hw_bpoints, + sizeof(struct stm8_comparator)); + + stm8->hw_break_list[0].reg_address = 0; + stm8->hw_break_list[1].reg_address = 1; + + LOG_DEBUG("hw breakpoints: numinst %i numdata %i", stm8->num_hw_bpoints, + stm8->num_hw_bpoints); + + stm8->bp_scanned = true; + + return ERROR_OK; +} + +static int stm8_examine_debug_reason(struct target *target) +{ + int retval; + uint8_t csr1, csr2; + + retval = stm8_read_dm_csrx(target, &csr1, &csr2); + LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); + + if ((target->debug_reason != DBG_REASON_DBGRQ) + && (target->debug_reason != DBG_REASON_SINGLESTEP)) { + + if (retval != ERROR_OK) + return retval; + + if (csr1 & RST) + /* halted on reset */ + target->debug_reason = DBG_REASON_UNDEFINED; + + if (csr1 & (BK1F+BK2F)) + /* we have halted on a breakpoint (or wp)*/ + target->debug_reason = DBG_REASON_BREAKPOINT; + + if (csr2 & SWBKF) + /* we have halted on a breakpoint */ + target->debug_reason = DBG_REASON_BREAKPOINT; + + } + + return ERROR_OK; +} + +static int stm8_debug_entry(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + /* restore interrupts */ + stm8_enable_interrupts(target, 1); + + stm8_save_context(target); + + /* make sure stepping disabled STE bit in CSR1 cleared */ + stm8_config_step(target, 0); + + /* attempt to find halt reason */ + stm8_examine_debug_reason(target); + + LOG_DEBUG("entered debug state at PC 0x%" PRIx32 ", target->state: %s", + buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32), + target_state_name(target)); + + return ERROR_OK; +} + +/* clear stall flag in DM and flush instruction pipe */ +static int stm8_exit_debug(struct target *target) +{ + int ret; + uint8_t csr1, csr2; + + ret = stm8_read_dm_csrx(target, &csr1, &csr2); + if (ret != ERROR_OK) + return ret; + csr2 |= FLUSH; + ret = stm8_write_u8(target, DM_CSR2, csr2); + if (ret != ERROR_OK) + return ret; + + csr2 &= ~STALL; + csr2 |= SWBRK; + ret = stm8_write_u8(target, DM_CSR2, csr2); + if (ret != ERROR_OK) + return ret; + return ERROR_OK; +} + +static int stm8_read_regs(struct target *target, uint32_t regs[]) +{ + int ret; + uint8_t buf[11]; + + ret = stm8_adapter_read_memory(target, DM_REGS, 1, sizeof(buf), buf); + if (ret != ERROR_OK) + return ret; + + regs[0] = be_to_h_u24(buf+DM_REG_PC-DM_REGS); + regs[1] = buf[DM_REG_A-DM_REGS]; + regs[2] = be_to_h_u16(buf+DM_REG_X-DM_REGS); + regs[3] = be_to_h_u16(buf+DM_REG_Y-DM_REGS); + regs[4] = be_to_h_u16(buf+DM_REG_SP-DM_REGS); + regs[5] = buf[DM_REG_CC-DM_REGS]; + + return ERROR_OK; +} + +static int stm8_write_regs(struct target *target, uint32_t regs[]) +{ + int ret; + uint8_t buf[11]; + + h_u24_to_be(buf+DM_REG_PC-DM_REGS, regs[0]); + buf[DM_REG_A-DM_REGS] = regs[1]; + h_u16_to_be(buf+DM_REG_X-DM_REGS, regs[2]); + h_u16_to_be(buf+DM_REG_Y-DM_REGS, regs[3]); + h_u16_to_be(buf+DM_REG_SP-DM_REGS, regs[4]); + buf[DM_REG_CC-DM_REGS] = regs[5]; + + ret = stm8_adapter_write_memory(target, DM_REGS, 1, sizeof(buf), buf); + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +static int stm8_get_core_reg(struct reg *reg) +{ + int retval; + struct stm8_core_reg *stm8_reg = reg->arch_info; + struct target *target = stm8_reg->target; + struct stm8_common *stm8_target = target_to_stm8(target); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + retval = stm8_target->read_core_reg(target, stm8_reg->num); + + return retval; +} + +static int stm8_set_core_reg(struct reg *reg, uint8_t *buf) +{ + struct stm8_core_reg *stm8_reg = reg->arch_info; + struct target *target = stm8_reg->target; + uint32_t value = buf_get_u32(buf, 0, reg->size); + + if (target->state != TARGET_HALTED) + return ERROR_TARGET_NOT_HALTED; + + buf_set_u32(reg->value, 0, 32, value); + reg->dirty = true; + reg->valid = true; + + return ERROR_OK; +} + +static int stm8_save_context(struct target *target) +{ + unsigned int i; + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + /* read core registers */ + stm8_read_regs(target, stm8->core_regs); + + for (i = 0; i < STM8_NUM_REGS; i++) { + if (!stm8->core_cache->reg_list[i].valid) + stm8->read_core_reg(target, i); + } + + return ERROR_OK; +} + +static int stm8_restore_context(struct target *target) +{ + unsigned int i; + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + for (i = 0; i < STM8_NUM_REGS; i++) { + if (stm8->core_cache->reg_list[i].dirty) + stm8->write_core_reg(target, i); + } + + /* write core regs */ + stm8_write_regs(target, stm8->core_regs); + + return ERROR_OK; +} + +static int stm8_unlock_flash(struct target *target) +{ + uint8_t data[1]; + + struct stm8_common *stm8 = target_to_stm8(target); + + /* check if flash is unlocked */ + stm8_read_u8(target, stm8->flash_iapsr, data); + if (~data[0] & PUL) { + /* unlock flash */ + stm8_write_u8(target, stm8->flash_pukr, 0x56); + stm8_write_u8(target, stm8->flash_pukr, 0xae); + } + + stm8_read_u8(target, stm8->flash_iapsr, data); + if (~data[0] & PUL) + return ERROR_FAIL; + return ERROR_OK; +} + +static int stm8_unlock_eeprom(struct target *target) +{ + uint8_t data[1]; + + struct stm8_common *stm8 = target_to_stm8(target); + + /* check if eeprom is unlocked */ + stm8_read_u8(target, stm8->flash_iapsr, data); + if (~data[0] & DUL) { + /* unlock eeprom */ + stm8_write_u8(target, stm8->flash_dukr, 0xae); + stm8_write_u8(target, stm8->flash_dukr, 0x56); + } + + stm8_read_u8(target, stm8->flash_iapsr, data); + if (~data[0] & DUL) + return ERROR_FAIL; + return ERROR_OK; +} + +static int stm8_write_flash(struct target *target, enum mem_type type, + uint32_t address, + uint32_t size, uint32_t count, uint32_t blocksize_param, + const uint8_t *buffer) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + uint8_t iapsr; + uint8_t opt = 0; + unsigned int i; + uint32_t blocksize = 0; + uint32_t bytecnt; + int res; + + switch (type) { + case (FLASH): + stm8_unlock_flash(target); + break; + case (EEPROM): + stm8_unlock_eeprom(target); + break; + case (OPTION): + stm8_unlock_eeprom(target); + opt = OPT; + break; + default: + LOG_ERROR("BUG: wrong mem_type %d", type); + assert(0); + } + + if (size == 2) { + /* we don't support short writes */ + count = count * 2; + size = 1; + } + + bytecnt = count * size; + + while (bytecnt) { + if ((bytecnt >= blocksize_param) && ((address & (blocksize_param-1)) == 0)) { + if (stm8->flash_cr2) + stm8_write_u8(target, stm8->flash_cr2, PRG + opt); + if (stm8->flash_ncr2) + stm8_write_u8(target, stm8->flash_ncr2, ~(PRG + opt)); + blocksize = blocksize_param; + } else + if ((bytecnt >= 4) && ((address & 0x3) == 0)) { + if (stm8->flash_cr2) + stm8_write_u8(target, stm8->flash_cr2, WPRG + opt); + if (stm8->flash_ncr2) + stm8_write_u8(target, stm8->flash_ncr2, ~(WPRG + opt)); + blocksize = 4; + } else + if (blocksize != 1) { + if (stm8->flash_cr2) + stm8_write_u8(target, stm8->flash_cr2, opt); + if (stm8->flash_ncr2) + stm8_write_u8(target, stm8->flash_ncr2, ~opt); + blocksize = 1; + } + + res = stm8_adapter_write_memory(target, address, 1, blocksize, buffer); + if (res != ERROR_OK) + return res; + address += blocksize; + buffer += blocksize; + bytecnt -= blocksize; + + /* lets hang here until end of program (EOP) */ + for (i = 0; i < 16; i++) { + stm8_read_u8(target, stm8->flash_iapsr, &iapsr); + if (iapsr & EOP) + break; + else + usleep(1000); + } + if (i == 16) + return ERROR_FAIL; + } + + /* disable write access */ + res = stm8_write_u8(target, stm8->flash_iapsr, 0x0); + + if (res != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int stm8_write_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, + const uint8_t *buffer) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR + ", size: 0x%8.8" PRIx32 + ", count: 0x%8.8" PRIx32, + address, size, count); + + if (target->state != TARGET_HALTED) + LOG_WARNING("target not halted"); + + int retval; + + if ((address >= stm8->flashstart) && (address <= stm8->flashend)) + retval = stm8_write_flash(target, FLASH, address, size, count, + stm8->blocksize, buffer); + else if ((address >= stm8->eepromstart) && (address <= stm8->eepromend)) + retval = stm8_write_flash(target, EEPROM, address, size, count, + stm8->blocksize, buffer); + else if ((address >= stm8->optionstart) && (address <= stm8->optionend)) + retval = stm8_write_flash(target, OPTION, address, size, count, 0, buffer); + else + retval = stm8_adapter_write_memory(target, address, size, count, + buffer); + + if (retval != ERROR_OK) + return ERROR_TARGET_FAILURE; + + return retval; +} + +static int stm8_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) +{ + LOG_DEBUG("address: 0x%8.8" TARGET_PRIxADDR + ", size: 0x%8.8" PRIx32 + ", count: 0x%8.8" PRIx32, + address, size, count); + + if (target->state != TARGET_HALTED) + LOG_WARNING("target not halted"); + + int retval; + retval = stm8_adapter_read_memory(target, address, size, count, buffer); + + if (retval != ERROR_OK) + return ERROR_TARGET_FAILURE; + + return retval; +} + +static int stm8_init(struct command_context *cmd_ctx, struct target *target) +{ + stm8_build_reg_cache(target); + + return ERROR_OK; +} + +static int stm8_poll(struct target *target) +{ + int retval = ERROR_OK; + uint8_t csr1, csr2; + +#ifdef LOG_STM8 + LOG_DEBUG("target->state=%d", target->state); +#endif + + /* read dm_csrx control regs */ + retval = stm8_read_dm_csrx(target, &csr1, &csr2); + if (retval != ERROR_OK) { + LOG_DEBUG("stm8_read_dm_csrx failed retval=%d", retval); + /* + We return ERROR_OK here even if we didn't get an answer. + openocd will call target_wait_state until we get target state TARGET_HALTED + */ + return ERROR_OK; + } + + /* check for processor halted */ + if (csr2 & STALL) { + if (target->state != TARGET_HALTED) { + if (target->state == TARGET_UNKNOWN) + LOG_DEBUG("DM_CSR2_STALL already set during server startup."); + + retval = stm8_debug_entry(target); + if (retval != ERROR_OK) { + LOG_DEBUG("stm8_debug_entry failed retval=%d", retval); + return ERROR_TARGET_FAILURE; + } + + if (target->state == TARGET_DEBUG_RUNNING) { + target->state = TARGET_HALTED; + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } else { + target->state = TARGET_HALTED; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + } + } + } else + target->state = TARGET_RUNNING; +#ifdef LOG_STM8 + LOG_DEBUG("csr1 = 0x%02X csr2 = 0x%02X", csr1, csr2); +#endif + return ERROR_OK; +} + +static int stm8_halt(struct target *target) +{ + LOG_DEBUG("target->state: %s", target_state_name(target)); + + if (target->state == TARGET_HALTED) { + LOG_DEBUG("target was already halted"); + return ERROR_OK; + } + + if (target->state == TARGET_UNKNOWN) + LOG_WARNING("target was in unknown state when halt was requested"); + + if (target->state == TARGET_RESET) { + /* we came here in a reset_halt or reset_init sequence + * debug entry was already prepared in stm8_assert_reset() + */ + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; + } + + + /* break processor */ + stm8_debug_stall(target); + + target->debug_reason = DBG_REASON_DBGRQ; + + return ERROR_OK; +} + +static int stm8_reset_assert(struct target *target) +{ + int res = ERROR_OK; + struct hl_interface_s *adapter = target_to_adapter(target); + struct stm8_common *stm8 = target_to_stm8(target); + bool use_srst_fallback = true; + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (jtag_reset_config & RESET_HAS_SRST) { + jtag_add_reset(0, 1); + res = adapter->layout->api->assert_srst(adapter->handle, 0); + + if (res == ERROR_OK) + /* hardware srst supported */ + use_srst_fallback = false; + else if (res != ERROR_COMMAND_NOTFOUND) + /* some other failure */ + return res; + } + + if (use_srst_fallback) { + LOG_DEBUG("Hardware srst not supported, falling back to swim reset"); + res = adapter->layout->api->reset(adapter->handle); + if (res != ERROR_OK) + return res; + } + + /* registers are now invalid */ + register_cache_invalidate(stm8->core_cache); + + target->state = TARGET_RESET; + target->debug_reason = DBG_REASON_NOTHALTED; + + if (target->reset_halt) { + res = target_halt(target); + if (res != ERROR_OK) + return res; + } + + return ERROR_OK; +} + +static int stm8_reset_deassert(struct target *target) +{ + int res; + struct hl_interface_s *adapter = target_to_adapter(target); + + enum reset_types jtag_reset_config = jtag_get_reset_config(); + + if (jtag_reset_config & RESET_HAS_SRST) { + res = adapter->layout->api->assert_srst(adapter->handle, 1); + if ((res != ERROR_OK) && (res != ERROR_COMMAND_NOTFOUND)) + return res; + } + + /* virtual deassert reset, we need it for the internal + * jtag state machine + */ + jtag_add_reset(0, 0); + + /* The cpu should now be stalled. If halt was requested + let poll detect the stall */ + if (target->reset_halt) + return ERROR_OK; + + /* Instead of going thrugh saving context, polling and + then resuming target again just clear stall and proceed. */ + target->state = TARGET_RUNNING; + return stm8_exit_debug(target); +} + +/* stm8_single_step_core() is only used for stepping over breakpoints + from stm8_resume() */ +static int stm8_single_step_core(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + /* configure single step mode */ + stm8_config_step(target, 1); + + /* disable interrupts while stepping */ + if (!stm8->enable_step_irq) + stm8_enable_interrupts(target, 0); + + /* exit debug mode */ + stm8_exit_debug(target); + + stm8_debug_entry(target); + + return ERROR_OK; +} + +static int stm8_resume(struct target *target, int current, + target_addr_t address, int handle_breakpoints, + int debug_execution) +{ + struct stm8_common *stm8 = target_to_stm8(target); + struct breakpoint *breakpoint = NULL; + uint32_t resume_pc; + + LOG_DEBUG("%d " TARGET_ADDR_FMT " %d %d", current, address, + handle_breakpoints, debug_execution); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (!debug_execution) { + target_free_all_working_areas(target); + stm8_enable_breakpoints(target); + stm8_enable_watchpoints(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + stm8_set_hwbreak(target, comparator_list); + } + + /* current = 1: continue on current pc, + otherwise continue at
*/ + if (!current) { + buf_set_u32(stm8->core_cache->reg_list[STM8_PC].value, + 0, 32, address); + stm8->core_cache->reg_list[STM8_PC].dirty = true; + stm8->core_cache->reg_list[STM8_PC].valid = true; + } + + if (!current) + resume_pc = address; + else + resume_pc = buf_get_u32( + stm8->core_cache->reg_list[STM8_PC].value, + 0, 32); + + stm8_restore_context(target); + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + /* Single step past breakpoint at current address */ + breakpoint = breakpoint_find(target, resume_pc); + if (breakpoint) { + LOG_DEBUG("unset breakpoint at " TARGET_ADDR_FMT, + breakpoint->address); + stm8_unset_breakpoint(target, breakpoint); + stm8_single_step_core(target); + stm8_set_breakpoint(target, breakpoint); + } + } + + /* disable interrupts if we are debugging */ + if (debug_execution) + stm8_enable_interrupts(target, 0); + + /* exit debug mode */ + stm8_exit_debug(target); + target->debug_reason = DBG_REASON_NOTHALTED; + + /* registers are now invalid */ + register_cache_invalidate(stm8->core_cache); + + if (!debug_execution) { + target->state = TARGET_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + LOG_DEBUG("target resumed at 0x%" PRIx32 "", resume_pc); + } else { + target->state = TARGET_DEBUG_RUNNING; + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); + LOG_DEBUG("target debug resumed at 0x%" PRIx32 "", resume_pc); + } + + return ERROR_OK; +} + +static int stm8_init_flash_regs(bool enable_stm8l, struct stm8_common *stm8) +{ + stm8->enable_stm8l = enable_stm8l; + + if (stm8->enable_stm8l) { + stm8->flash_cr2 = FLASH_CR2_STM8L; + stm8->flash_ncr2 = FLASH_NCR2_STM8L; + stm8->flash_iapsr = FLASH_IAPSR_STM8L; + stm8->flash_dukr = FLASH_DUKR_STM8L; + stm8->flash_pukr = FLASH_PUKR_STM8L; + } else { + stm8->flash_cr2 = FLASH_CR2_STM8S; + stm8->flash_ncr2 = FLASH_NCR2_STM8S; + stm8->flash_iapsr = FLASH_IAPSR_STM8S; + stm8->flash_dukr = FLASH_DUKR_STM8S; + stm8->flash_pukr = FLASH_PUKR_STM8S; + } + return ERROR_OK; +} + +static int stm8_init_arch_info(struct target *target, + struct stm8_common *stm8, struct jtag_tap *tap) +{ + target->endianness = TARGET_BIG_ENDIAN; + target->arch_info = stm8; + stm8->common_magic = STM8_COMMON_MAGIC; + stm8->fast_data_area = NULL; + stm8->blocksize = 0x80; + stm8->flashstart = 0x8000; + stm8->flashend = 0xffff; + stm8->eepromstart = 0x4000; + stm8->eepromend = 0x43ff; + stm8->optionstart = 0x4800; + stm8->optionend = 0x487F; + + /* has breakpoint/watchpoint unit been scanned */ + stm8->bp_scanned = false; + stm8->hw_break_list = NULL; + + stm8->read_core_reg = stm8_read_core_reg; + stm8->write_core_reg = stm8_write_core_reg; + + stm8_init_flash_regs(0, stm8); + + return ERROR_OK; +} + +static int stm8_target_create(struct target *target, + Jim_Interp *interp) +{ + + struct stm8_common *stm8 = calloc(1, sizeof(struct stm8_common)); + + stm8_init_arch_info(target, stm8, target->tap); + stm8_configure_break_unit(target); + + return ERROR_OK; +} + +static int stm8_read_core_reg(struct target *target, unsigned int num) +{ + uint32_t reg_value; + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (num >= STM8_NUM_REGS) + return ERROR_COMMAND_SYNTAX_ERROR; + + reg_value = stm8->core_regs[num]; + LOG_DEBUG("read core reg %i value 0x%" PRIx32 "", num , reg_value); + buf_set_u32(stm8->core_cache->reg_list[num].value, 0, 32, reg_value); + stm8->core_cache->reg_list[num].valid = true; + stm8->core_cache->reg_list[num].dirty = false; + + return ERROR_OK; +} + +static int stm8_write_core_reg(struct target *target, unsigned int num) +{ + uint32_t reg_value; + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (num >= STM8_NUM_REGS) + return ERROR_COMMAND_SYNTAX_ERROR; + + reg_value = buf_get_u32(stm8->core_cache->reg_list[num].value, 0, 32); + stm8->core_regs[num] = reg_value; + LOG_DEBUG("write core reg %i value 0x%" PRIx32 "", num , reg_value); + stm8->core_cache->reg_list[num].valid = true; + stm8->core_cache->reg_list[num].dirty = false; + + return ERROR_OK; +} + +static int stm8_get_gdb_reg_list(struct target *target, struct reg **reg_list[], + int *reg_list_size, enum target_register_class reg_class) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + unsigned int i; + + *reg_list_size = STM8_NUM_REGS; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < STM8_NUM_REGS; i++) + (*reg_list)[i] = &stm8->core_cache->reg_list[i]; + + return ERROR_OK; +} + +static const struct reg_arch_type stm8_reg_type = { + .get = stm8_get_core_reg, + .set = stm8_set_core_reg, +}; + +static struct reg_cache *stm8_build_reg_cache(struct target *target) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + int num_regs = STM8_NUM_REGS; + struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); + struct reg_cache *cache = malloc(sizeof(struct reg_cache)); + struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); + struct stm8_core_reg *arch_info = malloc( + sizeof(struct stm8_core_reg) * num_regs); + struct reg_feature *feature; + int i; + + /* Build the process context cache */ + cache->name = "stm8 registers"; + cache->next = NULL; + cache->reg_list = reg_list; + cache->num_regs = num_regs; + (*cache_p) = cache; + stm8->core_cache = cache; + + for (i = 0; i < num_regs; i++) { + arch_info[i].num = stm8_regs[i].id; + arch_info[i].target = target; + arch_info[i].stm8_common = stm8; + + reg_list[i].name = stm8_regs[i].name; + reg_list[i].size = stm8_regs[i].bits; + + reg_list[i].value = calloc(1, 4); + reg_list[i].valid = false; + reg_list[i].type = &stm8_reg_type; + reg_list[i].arch_info = &arch_info[i]; + + reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); + if (reg_list[i].reg_data_type) + reg_list[i].reg_data_type->type = stm8_regs[i].type; + else { + LOG_ERROR("unable to allocate reg type list"); + return NULL; + } + + reg_list[i].dirty = false; + reg_list[i].group = stm8_regs[i].group; + reg_list[i].number = stm8_regs[i].id; + reg_list[i].exist = true; + reg_list[i].caller_save = true; /* gdb defaults to true */ + + feature = calloc(1, sizeof(struct reg_feature)); + if (feature) { + feature->name = stm8_regs[i].feature; + reg_list[i].feature = feature; + } else + LOG_ERROR("unable to allocate feature list"); + } + + return cache; +} + +static void stm8_free_reg_cache(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + struct reg_cache *cache; + struct reg *reg; + unsigned int i; + + cache = stm8->core_cache; + + if (!cache) + return; + + for (i = 0; i < cache->num_regs; i++) { + reg = &cache->reg_list[i]; + + free(reg->feature); + free(reg->reg_data_type); + free(reg->value); + } + + free(cache->reg_list[0].arch_info); + free(cache->reg_list); + free(cache); + + stm8->core_cache = NULL; +} + +static void stm8_deinit(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + free(stm8->hw_break_list); + + stm8_free_reg_cache(target); + + free(stm8); +} + +static int stm8_arch_state(struct target *target) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + LOG_USER("target halted due to %s, pc: 0x%8.8" PRIx32 "", + debug_reason_name(target), + buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32)); + + return ERROR_OK; +} + +static int stm8_step(struct target *target, int current, + target_addr_t address, int handle_breakpoints) +{ + LOG_DEBUG("%" PRIx32 " " TARGET_ADDR_FMT " %" PRIx32, + current, address, handle_breakpoints); + + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + struct breakpoint *breakpoint = NULL; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* current = 1: continue on current pc, otherwise continue at
*/ + if (!current) { + buf_set_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32, address); + stm8->core_cache->reg_list[STM8_PC].dirty = true; + stm8->core_cache->reg_list[STM8_PC].valid = true; + } + + /* the front-end may request us not to handle breakpoints */ + if (handle_breakpoints) { + breakpoint = breakpoint_find(target, + buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32)); + if (breakpoint) + stm8_unset_breakpoint(target, breakpoint); + } + + /* restore context */ + stm8_restore_context(target); + + /* configure single step mode */ + stm8_config_step(target, 1); + + target->debug_reason = DBG_REASON_SINGLESTEP; + + target_call_event_callbacks(target, TARGET_EVENT_RESUMED); + + /* disable interrupts while stepping */ + if (!stm8->enable_step_irq) + stm8_enable_interrupts(target, 0); + + /* exit debug mode */ + stm8_exit_debug(target); + + /* registers are now invalid */ + register_cache_invalidate(stm8->core_cache); + + LOG_DEBUG("target stepped "); + stm8_debug_entry(target); + + if (breakpoint) + stm8_set_breakpoint(target, breakpoint); + + target_call_event_callbacks(target, TARGET_EVENT_HALTED); + + return ERROR_OK; +} + +static void stm8_enable_breakpoints(struct target *target) +{ + struct breakpoint *breakpoint = target->breakpoints; + + /* set any pending breakpoints */ + while (breakpoint) { + if (breakpoint->set == 0) + stm8_set_breakpoint(target, breakpoint); + breakpoint = breakpoint->next; + } +} + +static int stm8_set_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + struct stm8_common *stm8 = target_to_stm8(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + int retval; + + if (breakpoint->set) { + LOG_WARNING("breakpoint already set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) { + int bp_num = 0; + + while (comparator_list[bp_num].used && (bp_num < stm8->num_hw_bpoints)) + bp_num++; + if (bp_num >= stm8->num_hw_bpoints) { + LOG_ERROR("Can not find free breakpoint register (bpid: %" PRIu32 ")", + breakpoint->unique_id); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + breakpoint->set = bp_num + 1; + comparator_list[bp_num].used = true; + comparator_list[bp_num].bp_value = breakpoint->address; + comparator_list[bp_num].type = HWBRK_EXEC; + + retval = stm8_set_hwbreak(target, comparator_list); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("bpid: %" PRIu32 ", bp_num %i bp_value 0x%" PRIx32 "", + breakpoint->unique_id, + bp_num, comparator_list[bp_num].bp_value); + } else if (breakpoint->type == BKPT_SOFT) { + LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); + if (breakpoint->length == 1) { + uint8_t verify = 0x55; + + retval = target_read_u8(target, breakpoint->address, + breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + retval = target_write_u8(target, breakpoint->address, STM8_BREAK); + if (retval != ERROR_OK) + return retval; + + retval = target_read_u8(target, breakpoint->address, &verify); + if (retval != ERROR_OK) + return retval; + if (verify != STM8_BREAK) { + LOG_ERROR("Unable to set breakpoint at address " TARGET_ADDR_FMT + " - check that memory is read/writable", + breakpoint->address); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + } else { + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + breakpoint->set = 1; /* Any nice value but 0 */ + } + + return ERROR_OK; +} + +static int stm8_add_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + struct stm8_common *stm8 = target_to_stm8(target); + int ret; + + if (breakpoint->type == BKPT_HARD) { + if (stm8->num_hw_bpoints_avail < 1) { + LOG_INFO("no hardware breakpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + ret = stm8_set_breakpoint(target, breakpoint); + if (ret != ERROR_OK) + return ret; + + stm8->num_hw_bpoints_avail--; + return ERROR_OK; + } + + ret = stm8_set_breakpoint(target, breakpoint); + if (ret != ERROR_OK) + return ret; + + return ERROR_OK; +} + +static int stm8_unset_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + int retval; + + if (!breakpoint->set) { + LOG_WARNING("breakpoint not set"); + return ERROR_OK; + } + + if (breakpoint->type == BKPT_HARD) { + int bp_num = breakpoint->set - 1; + if ((bp_num < 0) || (bp_num >= stm8->num_hw_bpoints)) { + LOG_DEBUG("Invalid comparator number in breakpoint (bpid: %" PRIu32 ")", + breakpoint->unique_id); + return ERROR_OK; + } + LOG_DEBUG("bpid: %" PRIu32 " - releasing hw: %d", + breakpoint->unique_id, + bp_num); + comparator_list[bp_num].used = false; + retval = stm8_set_hwbreak(target, comparator_list); + if (retval != ERROR_OK) + return retval; + } else { + /* restore original instruction (kept in target endianness) */ + LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); + if (breakpoint->length == 1) { + uint8_t current_instr; + + /* check that user program has not + modified breakpoint instruction */ + retval = target_read_memory(target, breakpoint->address, 1, 1, + (uint8_t *)¤t_instr); + if (retval != ERROR_OK) + return retval; + + if (current_instr == STM8_BREAK) { + retval = target_write_memory(target, breakpoint->address, 1, 1, + breakpoint->orig_instr); + if (retval != ERROR_OK) + return retval; + } + } else + return ERROR_FAIL; + } + breakpoint->set = 0; + + return ERROR_OK; +} + +static int stm8_remove_breakpoint(struct target *target, + struct breakpoint *breakpoint) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (breakpoint->set) + stm8_unset_breakpoint(target, breakpoint); + + if (breakpoint->type == BKPT_HARD) + stm8->num_hw_bpoints_avail++; + + return ERROR_OK; +} + +static int stm8_set_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct stm8_common *stm8 = target_to_stm8(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + int wp_num = 0; + int ret; + + if (watchpoint->set) { + LOG_WARNING("watchpoint already set"); + return ERROR_OK; + } + + while (comparator_list[wp_num].used && (wp_num < stm8->num_hw_bpoints)) + wp_num++; + if (wp_num >= stm8->num_hw_bpoints) { + LOG_ERROR("Can not find free hw breakpoint"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + if (watchpoint->length != 1) { + LOG_ERROR("Only watchpoints of length 1 are supported"); + return ERROR_TARGET_UNALIGNED_ACCESS; + } + + enum hw_break_type enable = 0; + + switch (watchpoint->rw) { + case WPT_READ: + enable = HWBRK_RD; + break; + case WPT_WRITE: + enable = HWBRK_WR; + break; + case WPT_ACCESS: + enable = HWBRK_ACC; + break; + default: + LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + } + + comparator_list[wp_num].used = true; + comparator_list[wp_num].bp_value = watchpoint->address; + comparator_list[wp_num].type = enable; + + ret = stm8_set_hwbreak(target, comparator_list); + if (ret != ERROR_OK) { + comparator_list[wp_num].used = false; + return ret; + } + + watchpoint->set = wp_num + 1; + + LOG_DEBUG("wp_num %i bp_value 0x%" PRIx32 "", + wp_num, + comparator_list[wp_num].bp_value); + + return ERROR_OK; +} + +static int stm8_add_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int ret; + struct stm8_common *stm8 = target_to_stm8(target); + + if (stm8->num_hw_bpoints_avail < 1) { + LOG_INFO("no hardware watchpoints available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + ret = stm8_set_watchpoint(target, watchpoint); + if (ret != ERROR_OK) + return ret; + + stm8->num_hw_bpoints_avail--; + return ERROR_OK; +} + +static void stm8_enable_watchpoints(struct target *target) +{ + struct watchpoint *watchpoint = target->watchpoints; + + /* set any pending watchpoints */ + while (watchpoint) { + if (watchpoint->set == 0) + stm8_set_watchpoint(target, watchpoint); + watchpoint = watchpoint->next; + } +} + +static int stm8_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + struct stm8_comparator *comparator_list = stm8->hw_break_list; + + if (!watchpoint->set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + int wp_num = watchpoint->set - 1; + if ((wp_num < 0) || (wp_num >= stm8->num_hw_bpoints)) { + LOG_DEBUG("Invalid hw comparator number in watchpoint"); + return ERROR_OK; + } + comparator_list[wp_num].used = false; + watchpoint->set = 0; + + stm8_set_hwbreak(target, comparator_list); + + return ERROR_OK; +} + +static int stm8_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (watchpoint->set) + stm8_unset_watchpoint(target, watchpoint); + + stm8->num_hw_bpoints_avail++; + + return ERROR_OK; +} + +static int stm8_examine(struct target *target) +{ + int retval; + uint8_t csr1, csr2; + /* get pointers to arch-specific information */ + struct stm8_common *stm8 = target_to_stm8(target); + struct hl_interface_s *adapter = target_to_adapter(target); + + if (!target_was_examined(target)) { + if (!stm8->swim_configured) { + /* set SWIM_CSR = 0xa0 (enable mem access & mask reset) */ + LOG_DEBUG("writing A0 to SWIM_CSR (SAFE_MASK + SWIM_DM)"); + retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM); + if (retval != ERROR_OK) + return retval; + /* set high speed */ + LOG_DEBUG("writing B0 to SWIM_CSR (SAFE_MASK + SWIM_DM + HS)"); + retval = stm8_write_u8(target, SWIM_CSR, SAFE_MASK + SWIM_DM + HS); + if (retval != ERROR_OK) + return retval; + retval = stm8_set_speed(target, 1); + if (retval == ERROR_OK) + stm8->swim_configured = true; + /* + Now is the time to deassert reset if connect_under_reset. + Releasing reset line will cause the option bytes to load. + The core will still be stalled. + */ + if (adapter->param.connect_under_reset) + stm8_reset_deassert(target); + } else { + LOG_INFO("trying to reconnect"); + + retval = adapter->layout->api->state(adapter->handle); + if (retval != ERROR_OK) { + LOG_ERROR("reconnect failed"); + return ERROR_FAIL; + } + + /* read dm_csrx control regs */ + retval = stm8_read_dm_csrx(target, &csr1, &csr2); + if (retval != ERROR_OK) { + LOG_ERROR("state query failed"); + return ERROR_FAIL; + } + } + + target_set_examined(target); + + return ERROR_OK; + } + + return ERROR_OK; +} + +/** Checks whether a memory region is erased. */ +static int stm8_blank_check_memory(struct target *target, + target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value) +{ + struct working_area *erase_check_algorithm; + struct reg_param reg_params[2]; + struct mem_param mem_params[2]; + struct stm8_algorithm stm8_info; + + static const uint8_t stm8_erase_check_code[] = { +#include "../../contrib/loaders/erase_check/stm8_erase_check.inc" + }; + + if (erased_value != 0xff) { + LOG_ERROR("Erase value 0x%02" PRIx8 " not yet supported for STM8", + erased_value); + return ERROR_FAIL; + } + + /* make sure we have a working area */ + if (target_alloc_working_area(target, sizeof(stm8_erase_check_code), + &erase_check_algorithm) != ERROR_OK) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + + target_write_buffer(target, erase_check_algorithm->address, + sizeof(stm8_erase_check_code), stm8_erase_check_code); + + stm8_info.common_magic = STM8_COMMON_MAGIC; + + init_mem_param(&mem_params[0], 0x0, 3, PARAM_OUT); + buf_set_u32(mem_params[0].value, 0, 24, address); + + init_mem_param(&mem_params[1], 0x3, 3, PARAM_OUT); + buf_set_u32(mem_params[1].value, 0, 24, count); + + init_reg_param(®_params[0], "a", 32, PARAM_IN_OUT); + buf_set_u32(reg_params[0].value, 0, 32, erased_value); + + init_reg_param(®_params[1], "sp", 32, PARAM_OUT); + buf_set_u32(reg_params[1].value, 0, 32, erase_check_algorithm->address); + + int retval = target_run_algorithm(target, 2, mem_params, 2, reg_params, + erase_check_algorithm->address + 6, + erase_check_algorithm->address + (sizeof(stm8_erase_check_code) - 1), + 10000, &stm8_info); + + if (retval == ERROR_OK) + *blank = (*(reg_params[0].value) == 0xff); + + destroy_mem_param(&mem_params[0]); + destroy_mem_param(&mem_params[1]); + destroy_reg_param(®_params[0]); + + target_free_working_area(target, erase_check_algorithm); + + return retval; +} + +static int stm8_checksum_memory(struct target *target, target_addr_t address, + uint32_t count, uint32_t *checksum) +{ + /* let image_calculate_checksum() take care of business */ + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; +} + +/* run to exit point. return error if exit point was not reached. */ +static int stm8_run_and_wait(struct target *target, uint32_t entry_point, + int timeout_ms, uint32_t exit_point, struct stm8_common *stm8) +{ + uint32_t pc; + int retval; + /* This code relies on the target specific resume() and + poll()->debug_entry() sequence to write register values to the + processor and the read them back */ + retval = target_resume(target, 0, entry_point, 0, 1); + if (retval != ERROR_OK) + return retval; + + retval = target_wait_state(target, TARGET_HALTED, timeout_ms); + /* If the target fails to halt due to the breakpoint, force a halt */ + if (retval != ERROR_OK || target->state != TARGET_HALTED) { + retval = target_halt(target); + if (retval != ERROR_OK) + return retval; + retval = target_wait_state(target, TARGET_HALTED, 500); + if (retval != ERROR_OK) + return retval; + return ERROR_TARGET_TIMEOUT; + } + + pc = buf_get_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32); + if (exit_point && (pc != exit_point)) { + LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 " ", pc); + return ERROR_TARGET_TIMEOUT; + } + + return ERROR_OK; +} + +static int stm8_run_algorithm(struct target *target, int num_mem_params, + struct mem_param *mem_params, int num_reg_params, + struct reg_param *reg_params, target_addr_t entry_point, + target_addr_t exit_point, int timeout_ms, void *arch_info) +{ + struct stm8_common *stm8 = target_to_stm8(target); + + uint32_t context[STM8_NUM_REGS]; + int retval = ERROR_OK; + + LOG_DEBUG("Running algorithm"); + + /* NOTE: stm8_run_algorithm requires that each + algorithm uses a software breakpoint + at the exit point */ + + if (stm8->common_magic != STM8_COMMON_MAGIC) { + LOG_ERROR("current target isn't a STM8 target"); + return ERROR_TARGET_INVALID; + } + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + /* refresh core register cache */ + for (unsigned int i = 0; i < STM8_NUM_REGS; i++) { + if (!stm8->core_cache->reg_list[i].valid) + stm8->read_core_reg(target, i); + context[i] = buf_get_u32(stm8->core_cache->reg_list[i].value, 0, 32); + } + + for (int i = 0; i < num_mem_params; i++) { + retval = target_write_buffer(target, mem_params[i].address, + mem_params[i].size, mem_params[i].value); + if (retval != ERROR_OK) + return retval; + } + + for (int i = 0; i < num_reg_params; i++) { + struct reg *reg = register_get_by_name(stm8->core_cache, + reg_params[i].reg_name, 0); + + if (!reg) { + LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (reg_params[i].size != 32) { + LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", + reg_params[i].reg_name); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + stm8_set_core_reg(reg, reg_params[i].value); + } + + retval = stm8_run_and_wait(target, entry_point, + timeout_ms, exit_point, stm8); + + if (retval != ERROR_OK) + return retval; + + for (int i = 0; i < num_mem_params; i++) { + if (mem_params[i].direction != PARAM_OUT) { + retval = target_read_buffer(target, mem_params[i].address, + mem_params[i].size, mem_params[i].value); + if (retval != ERROR_OK) + return retval; + } + } + + for (int i = 0; i < num_reg_params; i++) { + if (reg_params[i].direction != PARAM_OUT) { + struct reg *reg = register_get_by_name(stm8->core_cache, + reg_params[i].reg_name, 0); + if (!reg) { + LOG_ERROR("BUG: register '%s' not found", + reg_params[i].reg_name); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (reg_params[i].size != 32) { + LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", + reg_params[i].reg_name); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + buf_set_u32(reg_params[i].value, + 0, 32, buf_get_u32(reg->value, 0, 32)); + } + } + + /* restore everything we saved before */ + for (unsigned int i = 0; i < STM8_NUM_REGS; i++) { + uint32_t regvalue; + regvalue = buf_get_u32(stm8->core_cache->reg_list[i].value, 0, 32); + if (regvalue != context[i]) { + LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, + stm8->core_cache->reg_list[i].name, context[i]); + buf_set_u32(stm8->core_cache->reg_list[i].value, + 0, 32, context[i]); + stm8->core_cache->reg_list[i].valid = true; + stm8->core_cache->reg_list[i].dirty = true; + } + } + + return ERROR_OK; +} + +int stm8_jim_configure(struct target *target, Jim_GetOptInfo *goi) +{ + struct stm8_common *stm8 = target_to_stm8(target); + jim_wide w; + int e; + const char *arg; + + arg = Jim_GetString(goi->argv[0], NULL); + if (!strcmp(arg, "-blocksize")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-blocksize ?bytes? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->blocksize = w; + LOG_DEBUG("blocksize=%8.8x", stm8->blocksize); + return JIM_OK; + } + if (!strcmp(arg, "-flashstart")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-flashstart ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->flashstart = w; + LOG_DEBUG("flashstart=%8.8x", stm8->flashstart); + return JIM_OK; + } + if (!strcmp(arg, "-flashend")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-flashend ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->flashend = w; + LOG_DEBUG("flashend=%8.8x", stm8->flashend); + return JIM_OK; + } + if (!strcmp(arg, "-eepromstart")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-eepromstart ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->eepromstart = w; + LOG_DEBUG("eepromstart=%8.8x", stm8->eepromstart); + return JIM_OK; + } + if (!strcmp(arg, "-eepromend")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-eepromend ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->eepromend = w; + LOG_DEBUG("eepromend=%8.8x", stm8->eepromend); + return JIM_OK; + } + if (!strcmp(arg, "-optionstart")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-optionstart ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->optionstart = w; + LOG_DEBUG("optionstart=%8.8x", stm8->optionstart); + return JIM_OK; + } + if (!strcmp(arg, "-optionend")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, + "-optionend ?address? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide(goi, &w); + if (e != JIM_OK) + return e; + + stm8->optionend = w; + LOG_DEBUG("optionend=%8.8x", stm8->optionend); + return JIM_OK; + } + if (!strcmp(arg, "-enable_step_irq")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + stm8->enable_step_irq = true; + LOG_DEBUG("enable_step_irq=%8.8x", stm8->enable_step_irq); + return JIM_OK; + } + if (!strcmp(arg, "-enable_stm8l")) { + e = Jim_GetOpt_String(goi, &arg, NULL); + if (e != JIM_OK) + return e; + + stm8->enable_stm8l = true; + LOG_DEBUG("enable_stm8l=%8.8x", stm8->enable_stm8l); + stm8_init_flash_regs(stm8->enable_stm8l, stm8); + return JIM_OK; + } + return JIM_CONTINUE; +} + +COMMAND_HANDLER(stm8_handle_enable_step_irq_command) +{ + const char *msg; + struct target *target = get_current_target(CMD_CTX); + struct stm8_common *stm8 = target_to_stm8(target); + bool enable = stm8->enable_step_irq; + + if (CMD_ARGC > 0) { + COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); + stm8->enable_step_irq = enable; + } + msg = stm8->enable_step_irq ? "enabled" : "disabled"; + command_print(CMD_CTX, "enable_step_irq = %s", msg); + return ERROR_OK; +} + +COMMAND_HANDLER(stm8_handle_enable_stm8l_command) +{ + const char *msg; + struct target *target = get_current_target(CMD_CTX); + struct stm8_common *stm8 = target_to_stm8(target); + bool enable = stm8->enable_stm8l; + + if (CMD_ARGC > 0) { + COMMAND_PARSE_ENABLE(CMD_ARGV[0], enable); + stm8->enable_stm8l = enable; + } + msg = stm8->enable_stm8l ? "enabled" : "disabled"; + command_print(CMD_CTX, "enable_stm8l = %s", msg); + stm8_init_flash_regs(stm8->enable_stm8l, stm8); + return ERROR_OK; +} + +static const struct command_registration stm8_exec_command_handlers[] = { + { + .name = "enable_step_irq", + .handler = stm8_handle_enable_step_irq_command, + .mode = COMMAND_ANY, + .help = "Enable/disable irq handling during step", + .usage = "[1/0]", + }, + { + .name = "enable_stm8l", + .handler = stm8_handle_enable_stm8l_command, + .mode = COMMAND_ANY, + .help = "Enable/disable STM8L flash programming", + .usage = "[1/0]", + }, + COMMAND_REGISTRATION_DONE +}; + +const struct command_registration stm8_command_handlers[] = { + { + .name = "stm8", + .mode = COMMAND_ANY, + .help = "stm8 command group", + .usage = "", + .chain = stm8_exec_command_handlers, + }, + COMMAND_REGISTRATION_DONE +}; + +struct target_type stm8_target = { + .name = "stm8", + + .poll = stm8_poll, + .arch_state = stm8_arch_state, + + .halt = stm8_halt, + .resume = stm8_resume, + .step = stm8_step, + + .assert_reset = stm8_reset_assert, + .deassert_reset = stm8_reset_deassert, + + .get_gdb_reg_list = stm8_get_gdb_reg_list, + + .read_memory = stm8_read_memory, + .write_memory = stm8_write_memory, + .checksum_memory = stm8_checksum_memory, + .blank_check_memory = stm8_blank_check_memory, + + .run_algorithm = stm8_run_algorithm, + + .add_breakpoint = stm8_add_breakpoint, + .remove_breakpoint = stm8_remove_breakpoint, + .add_watchpoint = stm8_add_watchpoint, + .remove_watchpoint = stm8_remove_watchpoint, + + .commands = stm8_command_handlers, + .target_create = stm8_target_create, + .init_target = stm8_init, + .examine = stm8_examine, + + .deinit_target = stm8_deinit, + .target_jim_configure = stm8_jim_configure, +}; diff --git a/src/target/stm8.h b/src/target/stm8.h new file mode 100644 index 000000000..39fac3e32 --- /dev/null +++ b/src/target/stm8.h @@ -0,0 +1,75 @@ +/* + OpenOCD STM8 target driver + Copyright (C) 2017 Ake Rehnman + ake.rehnman(at)gmail.com + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef OPENOCD_TARGET_STM8_H +#define OPENOCD_TARGET_STM8_H + +struct target; + +#define STM8_COMMON_MAGIC 0x53544D38 +#define STM8_NUM_CORE_REGS 6 + +struct stm8_common { + uint32_t common_magic; + void *arch_info; + struct reg_cache *core_cache; + uint32_t core_regs[STM8_NUM_CORE_REGS]; + + /* working area for fastdata access */ + struct working_area *fast_data_area; + + bool swim_configured; + bool bp_scanned; + uint8_t num_hw_bpoints; + uint8_t num_hw_bpoints_avail; + struct stm8_comparator *hw_break_list; + uint32_t blocksize; + uint32_t flashstart; + uint32_t flashend; + uint32_t eepromstart; + uint32_t eepromend; + uint32_t optionstart; + uint32_t optionend; + bool enable_step_irq; + + bool enable_stm8l; + uint32_t flash_cr2; + uint32_t flash_ncr2; + uint32_t flash_iapsr; + uint32_t flash_dukr; + uint32_t flash_pukr; + + /* cc value used for interrupt flags restore */ + uint32_t cc; + bool cc_valid; + + /* register cache to processor synchronization */ + int (*read_core_reg)(struct target *target, unsigned int num); + int (*write_core_reg)(struct target *target, unsigned int num); +}; + +static inline struct stm8_common * +target_to_stm8(struct target *target) +{ + return target->arch_info; +} + +const struct command_registration stm8_command_handlers[]; + +#endif /* OPENOCD_TARGET_STM8_H */ diff --git a/src/target/target.c b/src/target/target.c index 36318d88e..dcb672506 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -105,6 +105,7 @@ extern struct target_type nds32_v3m_target; extern struct target_type or1k_target; extern struct target_type quark_x10xx_target; extern struct target_type quark_d20xx_target; +extern struct target_type stm8_target; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -136,6 +137,7 @@ static struct target_type *target_types[] = { &or1k_target, &quark_x10xx_target, &quark_d20xx_target, + &stm8_target, #if BUILD_TARGET64 &aarch64_target, #endif diff --git a/tcl/target/stm8l.cfg b/tcl/target/stm8l.cfg new file mode 100644 index 000000000..5cc99e191 --- /dev/null +++ b/tcl/target/stm8l.cfg @@ -0,0 +1,87 @@ +# script for stm8l family + +# +# stm8 devices support SWIM transports only. +# + +transport select stlink_swim + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm8l +} + +# Work-area is a space in RAM used for flash programming +# By default use 1kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x400 +} + +if { [info exists FLASHSTART] } { + set _FLASHSTART $FLASHSTART +} else { + set _FLASHSTART 0x8000 +} + +if { [info exists FLASHEND] } { + set _FLASHEND $FLASHEND +} else { + set _FLASHEND 0xffff +} + +if { [info exists EEPROMSTART] } { + set _EEPROMSTART $EEPROMSTART +} else { + set _EEPROMSTART 0x4000 +} + +if { [info exists EEPROMEND] } { + set _EEPROMEND $EEPROMEND +} else { + set _EEPROMEND 0x43ff +} + +if { [info exists OPTIONSTART] } { + set _OPTIONSTART $OPTIONSTART +} else { + set _OPTIONSTART 0x4800 +} + +if { [info exists OPTIONEND] } { + set _OPTIONEND $OPTIONEND +} else { + set _OPTIONEND 0x487f +} + +if { [info exists BLOCKSIZE] } { + set _BLOCKSIZE $BLOCKSIZE +} else { + set _BLOCKSIZE 0x80 +} + +hla newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME stm8 -chain-position $_CHIPNAME.cpu + +$_TARGETNAME configure -work-area-phys 0x0 -work-area-size $_WORKAREASIZE -work-area-backup 1 +$_TARGETNAME configure -flashstart $_FLASHSTART -flashend $_FLASHEND -eepromstart $_EEPROMSTART -eepromend $_EEPROMEND +$_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocksize $_BLOCKSIZE + +# Uncomment this line to enable interrupts while instruction step +#$_TARGETNAME configure -enable_step_irq + +# Set stm8l type +$_TARGETNAME configure -enable_stm8l + +# The khz rate does not apply here, only slow <0> and fast <1> +adapter_khz 1 + +reset_config srst_only + +#uncomment this line to connect under reset +#reset_config srst_nogate connect_assert_srst diff --git a/tcl/target/stm8s.cfg b/tcl/target/stm8s.cfg new file mode 100644 index 000000000..d55e61b08 --- /dev/null +++ b/tcl/target/stm8s.cfg @@ -0,0 +1,84 @@ +# script for stm8s family + +# +# stm8 devices support SWIM transports only. +# + +transport select stlink_swim + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME stm8s +} + +# Work-area is a space in RAM used for flash programming +# By default use 1kB +if { [info exists WORKAREASIZE] } { + set _WORKAREASIZE $WORKAREASIZE +} else { + set _WORKAREASIZE 0x400 +} + +if { [info exists FLASHSTART] } { + set _FLASHSTART $FLASHSTART +} else { + set _FLASHSTART 0x8000 +} + +if { [info exists FLASHEND] } { + set _FLASHEND $FLASHEND +} else { + set _FLASHEND 0xffff +} + +if { [info exists EEPROMSTART] } { + set _EEPROMSTART $EEPROMSTART +} else { + set _EEPROMSTART 0x4000 +} + +if { [info exists EEPROMEND] } { + set _EEPROMEND $EEPROMEND +} else { + set _EEPROMEND 0x43ff +} + +if { [info exists OPTIONSTART] } { + set _OPTIONSTART $OPTIONSTART +} else { + set _OPTIONSTART 0x4800 +} + +if { [info exists OPTIONEND] } { + set _OPTIONEND $OPTIONEND +} else { + set _OPTIONEND 0x487f +} + +if { [info exists BLOCKSIZE] } { + set _BLOCKSIZE $BLOCKSIZE +} else { + set _BLOCKSIZE 0x80 +} + +hla newtap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id 0 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME stm8 -chain-position $_CHIPNAME.cpu + +$_TARGETNAME configure -work-area-phys 0x0 -work-area-size $_WORKAREASIZE -work-area-backup 1 +$_TARGETNAME configure -flashstart $_FLASHSTART -flashend $_FLASHEND -eepromstart $_EEPROMSTART -eepromend $_EEPROMEND +$_TARGETNAME configure -optionstart $_OPTIONSTART -optionend $_OPTIONEND -blocksize $_BLOCKSIZE + +# Uncomment this line to enable interrupts while instruction step +#$_TARGETNAME configure -enable_step_irq + +# The khz rate does not apply here, only slow <0> and fast <1> +adapter_khz 1 + +reset_config srst_only + +# uncomment this line to connect under reset +#reset_config srst_nogate connect_assert_srst From 9021210428c87bd8db943c0d88a682077aedb533 Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Wed, 6 Dec 2017 22:04:49 +0000 Subject: [PATCH 069/127] docs: add missing stm32 flash driver documentation Change-Id: I433780646e6fdfd0c2527b4a68025946ccb79d8b Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/4307 Tested-by: jenkins Reviewed-by: Reviewed-by: Antonio Borneo --- doc/openocd.texi | 67 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/doc/openocd.texi b/doc/openocd.texi index 2719c2d97..ac491b144 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5952,6 +5952,12 @@ Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn +@deffn Command {stm32f1x mass_erase} num +Mass erases the entire stm32f1x device. This is the only way to +unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + @deffn Command {stm32f1x options_read} num Read and display the stm32 option bytes written by the @command{stm32f1x options_write} command. @@ -5970,6 +5976,10 @@ include internal flash and use ARM Cortex-M3/M4/M7 cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. +@example +flash bank $_FLASHNAME stm32f2x 0 0 0 0 $_TARGETNAME +@end example + Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @@ -5990,6 +6000,12 @@ Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn +@deffn Command {stm32f2x mass_erase} num +Mass erases the entire stm32f2x device. This is the only way to +unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + @deffn Command {stm32f2x options_read} num Reads and displays user options and (where implemented) boot_addr0, boot_addr1, optcr2. The @var{num} parameter is a value shown by @command{flash banks}. @@ -6015,6 +6031,10 @@ include internal flash and use ARM Cortex-M7 core. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. +@example +flash bank $_FLASHNAME stm32h7x 0 0 0 0 $_TARGETNAME +@end example + Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. @@ -6034,6 +6054,12 @@ The @var{num} parameter is a value shown by @command{flash banks}. Unlocks the entire stm32 device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn + +@deffn Command {stm32h7x mass_erase} num +Mass erases the entire stm32h7x device. This is the only way to +unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn @end deffn @deffn {Flash Driver} stm32lx @@ -6042,6 +6068,10 @@ include internal flash and use ARM Cortex-M3 and Cortex-M0+ cores. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. +@example +flash bank $_FLASHNAME stm32lx 0 0 0 0 $_TARGETNAME +@end example + Note that some devices have been found that have a flash size register that contains an invalid value, to workaround this issue you can override the probed value used by the flash driver. If you use 0 as the bank base address, it tells the @@ -6062,6 +6092,43 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn +@deffn {Flash Driver} stm32l4x +All members of the STM32L4 microcontroller families from ST Microelectronics +include internal flash and use ARM Cortex-M4 cores. +The driver automatically recognizes a number of these chips using +the chip identification register, and autoconfigures itself. + +@example +flash bank $_FLASHNAME stm32l4x 0 0 0 0 $_TARGETNAME +@end example + +Note that some devices have been found that have a flash size register that contains +an invalid value, to workaround this issue you can override the probed value used by +the flash driver. + +@example +flash bank $_FLASHNAME stm32l4x 0x08000000 0x40000 0 0 $_TARGETNAME +@end example + +Some stm32l4x-specific commands are defined: + +@deffn Command {stm32l4x lock} num +Locks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + +@deffn Command {stm32l4x unlock} num +Unlocks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + +@deffn Command {stm32l4x mass_erase} num +Mass erases the entire stm32l4x device. This is the only way to +unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn +@end deffn + @deffn {Flash Driver} str7x All members of the STR7 microcontroller family from ST Microelectronics include internal flash and use ARM7TDMI cores. From eb26a884e0ff0fb6568aeda65fe21eec1e5b6557 Mon Sep 17 00:00:00 2001 From: elmot Date: Thu, 7 Dec 2017 10:08:28 +0200 Subject: [PATCH 070/127] config: stm32l01x and stm32l02x chips support New low-end chips have only 2k of RAM, workarea size adjusted Change-Id: Ibfccd73fef9e6dabffc87d901736c5626ce411fe Signed-off-by: Ilia Motornyi Reviewed-on: http://openocd.zylin.com/4308 Tested-by: jenkins Reviewed-by: Karl Palsson Reviewed-by: Andreas Fritiofson --- tcl/target/stm32l0.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tcl/target/stm32l0.cfg b/tcl/target/stm32l0.cfg index 245213b42..417b282d3 100644 --- a/tcl/target/stm32l0.cfg +++ b/tcl/target/stm32l0.cfg @@ -15,11 +15,11 @@ if { [info exists CHIPNAME] } { set _ENDIAN little # Work-area is a space in RAM used for flash programming -# By default use 8kB (max ram on smallest part) +# By default use 2kB (max ram on smallest part) if { [info exists WORKAREASIZE] } { set _WORKAREASIZE $WORKAREASIZE } else { - set _WORKAREASIZE 0x2000 + set _WORKAREASIZE 0x800 } # JTAG speed should be <= F_CPU/6. From 0a65a6527d2f0cf1dbd4cbee41924a27cc56bd53 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 11 Dec 2017 12:58:20 -0800 Subject: [PATCH 071/127] Fix build. Change-Id: I4e3a36fac77fefa271ae9facbaa990fa330501ae --- src/target/riscv/riscv-013.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 1768b6220..1f3bb74f2 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -994,7 +994,7 @@ static int register_write_direct(struct target *target, unsigned number, if (supports_extension(target, 'D')) { riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); } else { - riscv_program_insert(&program, fmv_s_x(number - GDB_REGNO_FPR0, S0)); + riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0)); } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrw(&program, S0, number); @@ -1054,7 +1054,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t } else if (supports_extension(target, 'D')) { riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); } else { - riscv_program_insert(&program, fmv_x_s(S0, number - GDB_REGNO_FPR0)); + riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)); } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrr(&program, S0, number); From 31c58c139d85c35cc8ebce4196edb2c5eb157c7a Mon Sep 17 00:00:00 2001 From: Paul Fertser Date: Thu, 26 Jan 2017 23:41:40 +0300 Subject: [PATCH 072/127] jtag: drivers: stlink: handle all versions with single config Extend HLA interface to allow multiple VID/PID pairs and use it to autodetect the connected stlink version. Change-Id: I35cd895b2260e23cf0e8fcb1fc11a78c2b99c69b Signed-off-by: Paul Fertser Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/3961 Tested-by: jenkins Reviewed-by: Karl Palsson Reviewed-by: Andreas Bolsch Reviewed-by: Spencer Oliver --- doc/openocd.texi | 4 ++-- src/jtag/drivers/stlink_usb.c | 28 +++++++++++++--------------- src/jtag/drivers/ti_icdi_usb.c | 8 ++++++-- src/jtag/hla/hla_interface.c | 26 +++++++++++++++++++------- src/jtag/hla/hla_interface.h | 10 ++++++---- tcl/board/st_nucleo_f0.cfg | 2 +- tcl/board/st_nucleo_f103rb.cfg | 2 +- tcl/board/st_nucleo_f3.cfg | 2 +- tcl/board/st_nucleo_f4.cfg | 2 +- tcl/board/st_nucleo_l1.cfg | 2 +- tcl/board/st_nucleo_l476rg.cfg | 2 +- tcl/board/stm320518_eval_stlink.cfg | 2 +- tcl/board/stm3220g_eval_stlink.cfg | 2 +- tcl/board/stm3241g_eval_stlink.cfg | 2 +- tcl/board/stm32429i_eval_stlink.cfg | 2 +- tcl/board/stm32439i_eval_stlink.cfg | 2 +- tcl/board/stm32f0discovery.cfg | 2 +- tcl/board/stm32f3discovery.cfg | 2 +- tcl/board/stm32f429disc1.cfg | 2 +- tcl/board/stm32f429discovery.cfg | 2 +- tcl/board/stm32f469discovery.cfg | 2 +- tcl/board/stm32f4discovery.cfg | 2 +- tcl/board/stm32f7discovery.cfg | 2 +- tcl/board/stm32l0discovery.cfg | 2 +- tcl/board/stm32l4discovery.cfg | 2 +- tcl/board/stm32ldiscovery.cfg | 2 +- tcl/board/stm32vldiscovery.cfg | 2 +- tcl/interface/stlink-v1.cfg | 11 ++--------- tcl/interface/stlink-v2-1.cfg | 18 ++---------------- tcl/interface/stlink-v2.cfg | 18 ++---------------- tcl/interface/stlink.cfg | 17 +++++++++++++++++ 31 files changed, 91 insertions(+), 93 deletions(-) create mode 100644 tcl/interface/stlink.cfg diff --git a/doc/openocd.texi b/doc/openocd.texi index ac491b144..7de0db8b7 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -2948,8 +2948,8 @@ Specifies the serial number of the adapter. Specifies the adapter layout to use. @end deffn -@deffn {Config Command} {hla_vid_pid} vid pid -The vendor ID and product ID of the device. +@deffn {Config Command} {hla_vid_pid} [vid pid]+ +Pairs of vendor IDs and product IDs of the device. @end deffn @deffn {Command} {hla_command} command diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c index 0bdcd316b..64868ea9e 100644 --- a/src/jtag/drivers/stlink_usb.c +++ b/src/jtag/drivers/stlink_usb.c @@ -1650,13 +1650,11 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) h->transport = param->transport; - const uint16_t vids[] = { param->vid, 0 }; - const uint16_t pids[] = { param->pid, 0 }; - const char *serial = param->serial; - - LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", - param->transport, param->vid, param->pid, - param->serial ? param->serial : ""); + for (unsigned i = 0; param->vid[i]; i++) { + LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x serial: %s", + param->transport, param->vid[i], param->pid[i], + param->serial ? param->serial : ""); + } /* On certain host USB configurations(e.g. MacBook Air) @@ -1668,7 +1666,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) in order to become operational. */ do { - if (jtag_libusb_open(vids, pids, serial, &h->fd) != ERROR_OK) { + if (jtag_libusb_open(param->vid, param->pid, param->serial, &h->fd) != ERROR_OK) { LOG_ERROR("open failed"); goto error_open; } @@ -1683,8 +1681,14 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) /* RX EP is common for all versions */ h->rx_ep = STLINK_RX_EP; + uint16_t pid; + if (jtag_libusb_get_pid(jtag_libusb_get_device(h->fd), &pid) != ERROR_OK) { + LOG_DEBUG("libusb_get_pid failed"); + goto error_open; + } + /* wrap version for first read */ - switch (param->pid) { + switch (pid) { case STLINK_V1_PID: h->version.stlink = 1; h->tx_ep = STLINK_TX_EP; @@ -1736,12 +1740,6 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd) } } while (1); - /* compare usb vid/pid */ - if ((param->vid != h->vid) || (param->pid != h->pid)) - LOG_INFO("vid/pid are not identical: 0x%04X/0x%04X 0x%04X/0x%04X", - param->vid, param->pid, - h->vid, h->pid); - /* check if mode is supported */ err = ERROR_OK; diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c index 171ac66c4..f316c8256 100644 --- a/src/jtag/drivers/ti_icdi_usb.c +++ b/src/jtag/drivers/ti_icdi_usb.c @@ -688,14 +688,18 @@ static int icdi_usb_open(struct hl_interface_param_s *param, void **fd) } LOG_DEBUG("transport: %d vid: 0x%04x pid: 0x%04x", param->transport, - param->vid, param->pid); + param->vid[0], param->pid[0]); + + /* TODO: convert libusb_ calls to jtag_libusb_ */ + if (param->vid[1]) + LOG_WARNING("Bad configuration: 'hla_vid_pid' command does not accept more than one VID PID pair on ti-icdi!"); if (libusb_init(&h->usb_ctx) != 0) { LOG_ERROR("libusb init failed"); goto error_open; } - h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid, param->pid); + h->usb_dev = libusb_open_device_with_vid_pid(h->usb_ctx, param->vid[0], param->pid[0]); if (!h->usb_dev) { LOG_ERROR("open failed"); goto error_open; diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c index 9217631b0..62a8f5947 100644 --- a/src/jtag/hla/hla_interface.c +++ b/src/jtag/hla/hla_interface.c @@ -35,7 +35,7 @@ #include -static struct hl_interface_s hl_if = { {0, 0, 0, 0, 0, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; +static struct hl_interface_s hl_if = { {0, 0, { 0 }, { 0 }, 0, HL_TRANSPORT_UNKNOWN, false, -1}, 0, 0 }; int hl_interface_open(enum hl_transports tr) { @@ -264,15 +264,27 @@ COMMAND_HANDLER(hl_interface_handle_layout_command) COMMAND_HANDLER(hl_interface_handle_vid_pid_command) { - LOG_DEBUG("hl_interface_handle_vid_pid_command"); - - if (CMD_ARGC != 2) { - LOG_WARNING("ignoring extra IDs in hl_vid_pid (maximum is 1 pair)"); + if (CMD_ARGC > HLA_MAX_USB_IDS * 2) { + LOG_WARNING("ignoring extra IDs in hla_vid_pid " + "(maximum is %d pairs)", HLA_MAX_USB_IDS); + CMD_ARGC = HLA_MAX_USB_IDS * 2; + } + if (CMD_ARGC < 2 || (CMD_ARGC & 1)) { + LOG_WARNING("incomplete hla_vid_pid configuration directive"); return ERROR_COMMAND_SYNTAX_ERROR; } - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[0], hl_if.param.vid); - COMMAND_PARSE_NUMBER(u16, CMD_ARGV[1], hl_if.param.pid); + unsigned i; + for (i = 0; i < CMD_ARGC; i += 2) { + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i], hl_if.param.vid[i / 2]); + COMMAND_PARSE_NUMBER(u16, CMD_ARGV[i + 1], hl_if.param.pid[i / 2]); + } + + /* + * Explicitly terminate, in case there are multiple instances of + * hla_vid_pid. + */ + hl_if.param.vid[i / 2] = hl_if.param.pid[i / 2] = 0; return ERROR_OK; } diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h index 0992d1cad..262025e98 100644 --- a/src/jtag/hla/hla_interface.h +++ b/src/jtag/hla/hla_interface.h @@ -29,15 +29,17 @@ enum e_hl_transports; /** */ extern const char *hl_transports[]; +#define HLA_MAX_USB_IDS 8 + struct hl_interface_param_s { /** */ const char *device_desc; /** */ const char *serial; - /** */ - uint16_t vid; - /** */ - uint16_t pid; + /** List of recognised VIDs */ + uint16_t vid[HLA_MAX_USB_IDS + 1]; + /** List of recognised PIDs */ + uint16_t pid[HLA_MAX_USB_IDS + 1]; /** */ unsigned api; /** */ diff --git a/tcl/board/st_nucleo_f0.cfg b/tcl/board/st_nucleo_f0.cfg index e9fda19a6..e6a03bba8 100644 --- a/tcl/board/st_nucleo_f0.cfg +++ b/tcl/board/st_nucleo_f0.cfg @@ -6,7 +6,7 @@ # STM32F091RC # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260944 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_f103rb.cfg b/tcl/board/st_nucleo_f103rb.cfg index 71a92f704..e1990dcf4 100644 --- a/tcl/board/st_nucleo_f103rb.cfg +++ b/tcl/board/st_nucleo_f103rb.cfg @@ -1,7 +1,7 @@ # This is an ST NUCLEO F103RB board with a single STM32F103RBT6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF259875 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_f3.cfg b/tcl/board/st_nucleo_f3.cfg index 9dffdcbbd..fec612b39 100644 --- a/tcl/board/st_nucleo_f3.cfg +++ b/tcl/board/st_nucleo_f3.cfg @@ -1,7 +1,7 @@ # This is an ST NUCLEO F334R8 board with a single STM32F334R8T6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260004 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_f4.cfg b/tcl/board/st_nucleo_f4.cfg index b5a78c1c0..11f6f8778 100644 --- a/tcl/board/st_nucleo_f4.cfg +++ b/tcl/board/st_nucleo_f4.cfg @@ -4,7 +4,7 @@ # STM32F411RET6 # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260320 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_l1.cfg b/tcl/board/st_nucleo_l1.cfg index 56e275627..d97eb7c17 100644 --- a/tcl/board/st_nucleo_l1.cfg +++ b/tcl/board/st_nucleo_l1.cfg @@ -1,7 +1,7 @@ # This is an ST NUCLEO L152RE board with a single STM32L152RET6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF260002 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/st_nucleo_l476rg.cfg b/tcl/board/st_nucleo_l476rg.cfg index 2baa34e76..4426c3bc9 100644 --- a/tcl/board/st_nucleo_l476rg.cfg +++ b/tcl/board/st_nucleo_l476rg.cfg @@ -1,7 +1,7 @@ # This is a ST NUCLEO L476RG board with a single STM32L476RGT6 chip. # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1847/PF261636 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm320518_eval_stlink.cfg b/tcl/board/stm320518_eval_stlink.cfg index ce074cbf2..a7fef0765 100644 --- a/tcl/board/stm320518_eval_stlink.cfg +++ b/tcl/board/stm320518_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm3220g_eval_stlink.cfg b/tcl/board/stm3220g_eval_stlink.cfg index 43a4df986..b58e42fe5 100644 --- a/tcl/board/stm3220g_eval_stlink.cfg +++ b/tcl/board/stm3220g_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm3241g_eval_stlink.cfg b/tcl/board/stm3241g_eval_stlink.cfg index 9c7ad5d95..b1c54a2c6 100644 --- a/tcl/board/stm3241g_eval_stlink.cfg +++ b/tcl/board/stm3241g_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32429i_eval_stlink.cfg b/tcl/board/stm32429i_eval_stlink.cfg index 2b51cea67..010d37198 100644 --- a/tcl/board/stm32429i_eval_stlink.cfg +++ b/tcl/board/stm32429i_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32439i_eval_stlink.cfg b/tcl/board/stm32439i_eval_stlink.cfg index 5995fb1d2..b722ce67c 100644 --- a/tcl/board/stm32439i_eval_stlink.cfg +++ b/tcl/board/stm32439i_eval_stlink.cfg @@ -4,7 +4,7 @@ # # This is for using the onboard STLINK/V2 -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f0discovery.cfg b/tcl/board/stm32f0discovery.cfg index bae9a69ba..e2b5e3844 100644 --- a/tcl/board/stm32f0discovery.cfg +++ b/tcl/board/stm32f0discovery.cfg @@ -1,7 +1,7 @@ # This is an STM32F0 discovery board with a single STM32F051R8T6 chip. # http://www.st.com/internet/evalboard/product/253215.jsp -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f3discovery.cfg b/tcl/board/stm32f3discovery.cfg index 5a17b4c99..9bb62f5f2 100644 --- a/tcl/board/stm32f3discovery.cfg +++ b/tcl/board/stm32f3discovery.cfg @@ -1,7 +1,7 @@ # This is an STM32F3 discovery board with a single STM32F303VCT6 chip. # http://www.st.com/internet/evalboard/product/254044.jsp -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f429disc1.cfg b/tcl/board/stm32f429disc1.cfg index 9d3cdd757..c0bcebae4 100644 --- a/tcl/board/stm32f429disc1.cfg +++ b/tcl/board/stm32f429disc1.cfg @@ -3,7 +3,7 @@ # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 # -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f429discovery.cfg b/tcl/board/stm32f429discovery.cfg index e06d2a51c..7aef09d4f 100644 --- a/tcl/board/stm32f429discovery.cfg +++ b/tcl/board/stm32f429discovery.cfg @@ -3,7 +3,7 @@ # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 # -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f469discovery.cfg b/tcl/board/stm32f469discovery.cfg index 63b13638a..a9559a756 100644 --- a/tcl/board/stm32f469discovery.cfg +++ b/tcl/board/stm32f469discovery.cfg @@ -3,7 +3,7 @@ # http://www.st.com/web/catalog/tools/FM116/CL1620/SC959/SS1532/LN1848/PF262395 # -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f4discovery.cfg b/tcl/board/stm32f4discovery.cfg index 963e0f959..60b7f42b5 100644 --- a/tcl/board/stm32f4discovery.cfg +++ b/tcl/board/stm32f4discovery.cfg @@ -1,7 +1,7 @@ # This is an STM32F4 discovery board with a single STM32F407VGT6 chip. # http://www.st.com/internet/evalboard/product/252419.jsp -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32f7discovery.cfg b/tcl/board/stm32f7discovery.cfg index 085340f30..7d1bc9665 100755 --- a/tcl/board/stm32f7discovery.cfg +++ b/tcl/board/stm32f7discovery.cfg @@ -2,7 +2,7 @@ # http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/LN1848/PF261641 # This is for using the onboard STLINK/V2-1 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32l0discovery.cfg b/tcl/board/stm32l0discovery.cfg index a03506224..aabbf8170 100644 --- a/tcl/board/stm32l0discovery.cfg +++ b/tcl/board/stm32l0discovery.cfg @@ -1,7 +1,7 @@ # This is an STM32L053 discovery board with a single STM32L053 chip. # http://www.st.com/web/en/catalog/tools/PF260319 -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32l4discovery.cfg b/tcl/board/stm32l4discovery.cfg index eb1933116..8b79841ed 100644 --- a/tcl/board/stm32l4discovery.cfg +++ b/tcl/board/stm32l4discovery.cfg @@ -4,7 +4,7 @@ # an stlink-v2-1 interface. # This is for STM32L4 boards that are connected via stlink-v2-1. -source [find interface/stlink-v2-1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32ldiscovery.cfg b/tcl/board/stm32ldiscovery.cfg index 8678d290b..3e397cba4 100644 --- a/tcl/board/stm32ldiscovery.cfg +++ b/tcl/board/stm32ldiscovery.cfg @@ -1,7 +1,7 @@ # This is an STM32L discovery board with a single STM32L152RBT6 chip. # http://www.st.com/internet/evalboard/product/250990.jsp -source [find interface/stlink-v2.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/board/stm32vldiscovery.cfg b/tcl/board/stm32vldiscovery.cfg index 970b5101e..60805b32c 100644 --- a/tcl/board/stm32vldiscovery.cfg +++ b/tcl/board/stm32vldiscovery.cfg @@ -1,7 +1,7 @@ # This is an STM32VL discovery board with a single STM32F100RB chip. # http://www.st.com/internet/evalboard/product/250863.jsp -source [find interface/stlink-v1.cfg] +source [find interface/stlink.cfg] transport select hla_swd diff --git a/tcl/interface/stlink-v1.cfg b/tcl/interface/stlink-v1.cfg index 13f207dc6..000422725 100644 --- a/tcl/interface/stlink-v1.cfg +++ b/tcl/interface/stlink-v1.cfg @@ -1,9 +1,2 @@ -# -# STMicroelectronics ST-LINK/V1 in-circuit debugger/programmer -# - -interface hla -hla_layout stlink -hla_device_desc "ST-LINK/V1" -hla_vid_pid 0x0483 0x3744 - +echo "WARNING: interface/stlink-v1.cfg is deprecated, please switch to interface/stlink.cfg" +source [find interface/stlink.cfg] diff --git a/tcl/interface/stlink-v2-1.cfg b/tcl/interface/stlink-v2-1.cfg index 093e80177..62f37dc33 100644 --- a/tcl/interface/stlink-v2-1.cfg +++ b/tcl/interface/stlink-v2-1.cfg @@ -1,16 +1,2 @@ -# -# STMicroelectronics ST-LINK/V2-1 in-circuit debugger/programmer -# - -interface hla -hla_layout stlink -hla_device_desc "ST-LINK/V2-1" -hla_vid_pid 0x0483 0x374b - -# Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 -# devices seem to have serial numbers with unreadable characters. ST-LINK/V2 -# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial -# number reset issues. -# eg. -#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" - +echo "WARNING: interface/stlink-v2-1.cfg is deprecated, please switch to interface/stlink.cfg" +source [find interface/stlink.cfg] diff --git a/tcl/interface/stlink-v2.cfg b/tcl/interface/stlink-v2.cfg index ae545a118..070e46958 100644 --- a/tcl/interface/stlink-v2.cfg +++ b/tcl/interface/stlink-v2.cfg @@ -1,16 +1,2 @@ -# -# STMicroelectronics ST-LINK/V2 in-circuit debugger/programmer -# - -interface hla -hla_layout stlink -hla_device_desc "ST-LINK/V2" -hla_vid_pid 0x0483 0x3748 - -# Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 -# devices seem to have serial numbers with unreadable characters. ST-LINK/V2 -# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial -# number reset issues. -# eg. -#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" - +echo "WARNING: interface/stlink-v2.cfg is deprecated, please switch to interface/stlink.cfg" +source [find interface/stlink.cfg] diff --git a/tcl/interface/stlink.cfg b/tcl/interface/stlink.cfg new file mode 100644 index 000000000..d747d8533 --- /dev/null +++ b/tcl/interface/stlink.cfg @@ -0,0 +1,17 @@ +# +# STMicroelectronics ST-LINK/V1, ST-LINK/V2, ST-LINK/V2-1 in-circuit +# debugger/programmer +# + +interface hla +hla_layout stlink +hla_device_desc "ST-LINK" +hla_vid_pid 0x0483 0x3744 0x0483 0x3748 0x0483 0x374b + +# Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2 +# devices seem to have serial numbers with unreadable characters. ST-LINK/V2 +# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial +# number reset issues. +# eg. +#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f" + From 04227634896ebe6a600d647508b6c934791662b7 Mon Sep 17 00:00:00 2001 From: Spencer Oliver Date: Thu, 7 Dec 2017 12:30:35 +0000 Subject: [PATCH 073/127] doc: improve stm32 flash driver documentation also remove legacy footnote as it adds no value. Change-Id: I3892acf244bd8fba6f844a5d82a66004e193a395 Signed-off-by: Spencer Oliver Reviewed-on: http://openocd.zylin.com/4309 Tested-by: jenkins Reviewed-by: Karl Palsson --- doc/openocd.texi | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 7de0db8b7..574834404 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -5888,9 +5888,6 @@ All members of the Stellaris LM3Sxxx, LM4x and Tiva C microcontroller families from Texas Instruments include internal flash. The driver automatically recognizes a number of these chips using the chip identification register, and autoconfigures itself. -@footnote{Currently there is a @command{stellaris mass_erase} command. -That seems pointless since the same effect can be had using the -standard @command{flash erase_address} command.} @example flash bank $_FLASHNAME stellaris 0 0 0 0 $_TARGETNAME @@ -5936,11 +5933,7 @@ as per the following example. flash bank $_FLASHNAME stm32f1x 0x08080000 0 0 0 $_TARGETNAME @end example -Some stm32f1x-specific commands -@footnote{Currently there is a @command{stm32f1x mass_erase} command. -That seems pointless since the same effect can be had using the -standard @command{flash erase_address} command.} -are defined: +Some stm32f1x-specific commands are defined: @deffn Command {stm32f1x lock} num Locks the entire stm32 device. @@ -5953,8 +5946,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f1x mass_erase} num -Mass erases the entire stm32f1x device. This is the only way to -unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +Mass erases the entire stm32f1x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @@ -6001,8 +5993,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32f2x mass_erase} num -Mass erases the entire stm32f2x device. This is the only way to -unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +Mass erases the entire stm32f2x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @@ -6056,8 +6047,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32h7x mass_erase} num -Mass erases the entire stm32h7x device. This is the only way to -unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +Mass erases the entire stm32h7x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn @@ -6084,6 +6074,16 @@ flash bank $_FLASHNAME stm32lx 0x08000000 0x20000 0 0 $_TARGETNAME Some stm32lx-specific commands are defined: +@deffn Command {stm32lx lock} num +Locks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + +@deffn Command {stm32lx unlock} num +Unlocks the entire stm32 device. +The @var{num} parameter is a value shown by @command{flash banks}. +@end deffn + @deffn Command {stm32lx mass_erase} num Mass erases the entire stm32lx device (all flash banks and EEPROM data). This is the only way to unlock a protected flash (unless RDP @@ -6123,8 +6123,7 @@ The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @deffn Command {stm32l4x mass_erase} num -Mass erases the entire stm32l4x device. This is the only way to -unlock a protected flash (unless RDP Level is 2 which can't be unlocked at all). +Mass erases the entire stm32l4x device. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn @end deffn From 90a6245eecd82c95112c09700cfebcf2403d0478 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 26 Oct 2017 18:00:33 +0200 Subject: [PATCH 074/127] flash/nor/stm32f2x: fix protection block size for F767 in dual bank mode A protection block comprises two adjacent sectors in dual bank mode. As there are 64 and 128kB sectors joined in blocks 2 and 8, block size should be computed as a sum of sector sizes. Change-Id: Ie915df8cf7ca232c4565d7e0c514c8933e71fdfe Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4271 Tested-by: jenkins Reviewed-by: Andreas Bolsch Reviewed-by: Spencer Oliver --- src/flash/nor/stm32f2x.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 65cb212b6..8127f1334 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -1047,7 +1047,8 @@ static int stm32x_probe(struct flash_bank *bank) if (device_id == 0x451) { for (i = 0; i < num_prot_blocks; i++) { bank->prot_blocks[i].offset = bank->sectors[i << 1].offset; - bank->prot_blocks[i].size = bank->sectors[i << 1].size << 1; + bank->prot_blocks[i].size = bank->sectors[i << 1].size + + bank->sectors[(i << 1) + 1].size; } } } else { From 3f6ab8e6a6f80f4a6486c688793daad866d21863 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Thu, 23 Nov 2017 14:47:37 +0100 Subject: [PATCH 075/127] flash/nor/stm32f2x: fix erase on STM32F413/423 Theese devices do not have a gap in sector numbering. The driver translates sectors numbers 12 13... to 16 17... as used on dual bank flash devices. Therefore erase of sector 12 and above fails with error 'stm32x device protected' on F413/423. Drop sector number translation for devices without has_large_mem flag. Change-Id: I65531c0dfe02e2fd0f3d68f0615e0926e9901391 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4299 Tested-by: jenkins Reviewed-by: Andreas Bolsch Reviewed-by: Spencer Oliver --- src/flash/nor/stm32f2x.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c index 8127f1334..b0992b404 100644 --- a/src/flash/nor/stm32f2x.c +++ b/src/flash/nor/stm32f2x.c @@ -143,9 +143,8 @@ #define FLASH_PSIZE_16 (1 << 8) #define FLASH_PSIZE_32 (2 << 8) #define FLASH_PSIZE_64 (3 << 8) -/* The sector number encoding is not straight binary for dual bank flash. - * Warning: evaluates the argument multiple times */ -#define FLASH_SNB(a) ((((a) >= 12) ? 0x10 | ((a) - 12) : (a)) << 3) +/* The sector number encoding is not straight binary for dual bank flash. */ +#define FLASH_SNB(a) ((a) << 3) #define FLASH_LOCK (1 << 31) /* FLASH_SR register bits */ @@ -489,6 +488,7 @@ static int stm32x_protect_check(struct flash_bank *bank) static int stm32x_erase(struct flash_bank *bank, int first, int last) { + struct stm32x_flash_bank *stm32x_info = bank->driver_priv; struct target *target = bank->target; int i; @@ -516,8 +516,14 @@ static int stm32x_erase(struct flash_bank *bank, int first, int last) */ for (i = first; i <= last; i++) { + int snb; + if (stm32x_info->has_large_mem && i >= 12) + snb = (i - 12) | 0x10; + else + snb = i; + retval = target_write_u32(target, - stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(i) | FLASH_STRT); + stm32x_get_flash_reg(bank, STM32_FLASH_CR), FLASH_SER | FLASH_SNB(snb) | FLASH_STRT); if (retval != ERROR_OK) return retval; From 19f8f58c0d4d9ee618969254a368e4396657b946 Mon Sep 17 00:00:00 2001 From: Tomas Vanek Date: Tue, 31 Oct 2017 12:32:22 +0100 Subject: [PATCH 076/127] target: remove unused event definitions Events reset-halt-pre, reset-halt-post, reset-wait-pre and reset-wait-post are not used anywhere. Change-Id: I9a0f94875b102d9b08f6c2fd9d73a9f05f8e8e79 Signed-off-by: Tomas Vanek Reviewed-on: http://openocd.zylin.com/4285 Tested-by: jenkins Reviewed-by: Andreas Fritiofson --- doc/openocd.texi | 12 ------------ src/target/target.c | 4 ---- src/target/target.h | 4 ---- 3 files changed, 20 deletions(-) diff --git a/doc/openocd.texi b/doc/openocd.texi index 574834404..ebd03c4cb 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4503,12 +4503,6 @@ and (if the target is using it) after SRST has been released on the scan chain. @item @b{reset-end} @* Issued as the final step in @command{reset} processing. -@ignore -@item @b{reset-halt-post} -@* Currently not used -@item @b{reset-halt-pre} -@* Currently not used -@end ignore @item @b{reset-init} @* Used by @b{reset init} command for board-specific initialization. This event fires after @emph{reset-deassert-post}. @@ -4525,12 +4519,6 @@ before @command{reset_init} is called. This is the most robust place to use @command{jtag_rclk} or @command{adapter_khz} to switch to a low JTAG clock rate, when reset disables PLLs needed to use a fast clock. -@ignore -@item @b{reset-wait-pos} -@* Currently not used -@item @b{reset-wait-pre} -@* Currently not used -@end ignore @item @b{resume-start} @* Before any target is resumed @item @b{resume-end} diff --git a/src/target/target.c b/src/target/target.c index dcb672506..a9907b0c3 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -204,10 +204,6 @@ static const Jim_Nvp nvp_target_event[] = { { .value = TARGET_EVENT_RESET_ASSERT_POST, .name = "reset-assert-post" }, { .value = TARGET_EVENT_RESET_DEASSERT_PRE, .name = "reset-deassert-pre" }, { .value = TARGET_EVENT_RESET_DEASSERT_POST, .name = "reset-deassert-post" }, - { .value = TARGET_EVENT_RESET_HALT_PRE, .name = "reset-halt-pre" }, - { .value = TARGET_EVENT_RESET_HALT_POST, .name = "reset-halt-post" }, - { .value = TARGET_EVENT_RESET_WAIT_PRE, .name = "reset-wait-pre" }, - { .value = TARGET_EVENT_RESET_WAIT_POST, .name = "reset-wait-post" }, { .value = TARGET_EVENT_RESET_INIT, .name = "reset-init" }, { .value = TARGET_EVENT_RESET_END, .name = "reset-end" }, diff --git a/src/target/target.h b/src/target/target.h index 53f9e2614..0096cae10 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -253,10 +253,6 @@ enum target_event { TARGET_EVENT_RESET_ASSERT_POST, TARGET_EVENT_RESET_DEASSERT_PRE, TARGET_EVENT_RESET_DEASSERT_POST, - TARGET_EVENT_RESET_HALT_PRE, - TARGET_EVENT_RESET_HALT_POST, - TARGET_EVENT_RESET_WAIT_PRE, - TARGET_EVENT_RESET_WAIT_POST, TARGET_EVENT_RESET_INIT, TARGET_EVENT_RESET_END, From 3624d5e5eb3810e1277b56f99d94242210cfc4d8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 13 Dec 2017 14:23:05 -0800 Subject: [PATCH 077/127] Add win32 build to travis. Change-Id: I8ce62ff321c6f3627d42fff13236f7fc9440d429 --- .travis.yml | 33 +++++++++++++++++++++++++++------ 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index a99f743e0..2ec1ede93 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,11 +4,16 @@ dist: trusty matrix: include: - os: linux - env: BUILD=x86_64-linux-gnu + env: + - BUILD=x86_64-linux-gnu + - EXECUTABLE=openocd compiler: gcc - os: linux - env: BUILD=i686-linux-gnu CFLAGS=-m32 + env: + - BUILD=i686-linux-gnu + - CFLAGS=-m32 + - EXECUTABLE=openocd addons: apt: packages: @@ -16,17 +21,33 @@ matrix: compiler: gcc - os: linux - env: BUILD=x86_64-linux-gnu + env: + - BUILD=x86_64-linux-gnu + - EXECUTABLE=openocd compiler: clang - os: linux - env: BUILD=i686-linux-gnu CFLAGS=-m32 + env: + - BUILD=i686-linux-gnu + - CFLAGS=-m32 + - EXECUTABLE=openocd compiler: clang addons: apt: packages: - gcc-multilib + - os: linux + env: + - BUILD=i686-w64-mingw + - CONFIGURE_ARGS="--build=i686-unknown-linux-gnu --host=i686-w64-mingw32" + - EXECUTABLE=openocd.exe + compiler: i686-w64-mingw32-gcc + addons: + apt: + packages: + - binutils-mingw-w64-i686 gcc-mingw-w64-i686 g++-mingw-w64-i686 + script: - - ./bootstrap && ./configure --enable-remote-bitbang --enable-jtag_vpi && make - - file src/openocd + - ./bootstrap && ./configure --enable-remote-bitbang --enable-jtag_vpi $CONFIGURE_ARGS && make + - file src/$EXECUTABLE From 7eceac758ca08c3feeb77167ee2eb9829b1d93bc Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 13 Dec 2017 14:32:11 -0800 Subject: [PATCH 078/127] Use abstraction because Windows is not POSIX Fixes #138 Change-Id: I4d9b49762e318fe91f1561ed315829b43daefef4 --- src/helper/replacements.h | 11 +++++++++++ src/jtag/drivers/remote_bitbang.c | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/helper/replacements.h b/src/helper/replacements.h index 1e2fbf20f..f43b7e0f3 100644 --- a/src/helper/replacements.h +++ b/src/helper/replacements.h @@ -199,6 +199,17 @@ static inline int close_socket(int sock) #endif } +static inline void socket_block(int fd) +{ +#ifdef _WIN32 + unsigned long nonblock = 0; + ioctlsocket(fd, FIONBIO, &nonblock); +#else + int oldopts = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, oldopts & ~O_NONBLOCK); +#endif +} + static inline void socket_nonblock(int fd) { #ifdef _WIN32 diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index 5e78ccb45..4e1995c0c 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -59,7 +59,7 @@ static int remote_bitbang_buf_full(void) /* Read any incoming data, placing it into the buffer. */ static void remote_bitbang_fill_buf(void) { - fcntl(remote_bitbang_fd, F_SETFL, O_NONBLOCK); + socket_nonblock(remote_bitbang_fd); while (!remote_bitbang_buf_full()) { unsigned contiguous_available_space; if (remote_bitbang_end >= remote_bitbang_start) { @@ -148,7 +148,7 @@ static int remote_bitbang_rread(void) } /* Enable blocking access. */ - fcntl(remote_bitbang_fd, F_SETFL, 0); + socket_block(remote_bitbang_fd); char c; ssize_t count = read(remote_bitbang_fd, &c, 1); if (count == 1) { From 6aff46adcc46e2f12e1a8b31a5e300e602764547 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 14 Dec 2017 13:51:13 -0800 Subject: [PATCH 079/127] Fix cut and paste bug. Now reading 64-bit FPRs on 32-bit harts using scratch memory might work. Change-Id: Ie8c0fc689386c6e724ecab5e8c855e725fa8dd97 --- src/target/riscv/riscv-013.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 1f3bb74f2..14a7d2671 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -873,7 +873,7 @@ static int scratch_find(struct target *target, } if (riscv_use_scratch_ram) { - scratch->hart_address = (riscv_use_scratch_ram + alignment - 1) & + scratch->hart_address = (riscv_scratch_ram_address + alignment - 1) & ~(alignment - 1); scratch->memory_space = SPACE_DMI_RAM; scratch->debug_address = scratch->hart_address; From 1e43d32e014be32a26388c6a1f0286f2d7c51ee8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 15 Dec 2017 15:31:03 -0800 Subject: [PATCH 080/127] Use %ll instead of %L instead of scanf. Mac build barfs on L, and the manpage says they're equivalent. Hopefully fixes #147 Change-Id: I3aa57775731f3f5ceb03097cae2a9dc6fd426dcd --- src/target/riscv/riscv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index b9be133f3..ac7b997d8 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1168,7 +1168,7 @@ COMMAND_HANDLER(riscv_set_scratch_ram) } long long unsigned int address; - int result = sscanf(CMD_ARGV[0], "%Lx", &address); + int result = sscanf(CMD_ARGV[0], "%llx", &address); if (result != (int) strlen(CMD_ARGV[0])) { LOG_ERROR("%s is not a valid address for command.", CMD_ARGV[0]); riscv_use_scratch_ram = false; From c421fefdcb4c16648e22574afdbc0677675844f8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 10 Nov 2017 15:30:52 -0800 Subject: [PATCH 081/127] Checkpoint that seems to work. Change-Id: I9599aacc256f6340795097732b6f8e8869c2099f --- src/target/riscv/riscv-013.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 14a7d2671..338c2432c 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1179,6 +1179,24 @@ static int init_target(struct command_context *cmd_ctx, char *reg_name = info->reg_names; info->reg_values = NULL; + static struct reg_feature feature_cpu = { + .name = "org.gnu.gdb.riscv.cpu" + }; + static struct reg_feature feature_fpu = { + .name = "org.gnu.gdb.riscv.fpu" + }; + static struct reg_feature feature_csr = { + .name = "org.gnu.gdb.riscv.csr" + }; + static struct reg_feature feature_virtual = { + .name = "org.gnu.gdb.riscv.virtual" + }; + + static struct reg_data_type type_ieee_single = { + .type = REG_TYPE_IEEE_SINGLE, + .id = "ieee_single" + }; + for (unsigned int i = 0; i < GDB_REGNO_COUNT; i++) { struct reg *r = &target->reg_cache->reg_list[i]; r->number = i; @@ -1190,14 +1208,26 @@ static int init_target(struct command_context *cmd_ctx, r->arch_info = target; if (i <= GDB_REGNO_XPR31) { sprintf(reg_name, "x%d", i); + r->group = "general"; + r->feature = &feature_cpu; } else if (i == GDB_REGNO_PC) { sprintf(reg_name, "pc"); + r->group = "general"; + r->feature = &feature_cpu; } else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) { sprintf(reg_name, "f%d", i - GDB_REGNO_FPR0); + r->group = "float"; + r->feature = &feature_fpu; + // TODO: check D or F extension + r->reg_data_type = &type_ieee_single; } else if (i >= GDB_REGNO_CSR0 && i <= GDB_REGNO_CSR4095) { sprintf(reg_name, "csr%d", i - GDB_REGNO_CSR0); + r->group = "csr"; + r->feature = &feature_csr; } else if (i == GDB_REGNO_PRIV) { sprintf(reg_name, "priv"); + r->group = "general"; + r->feature = &feature_virtual; } if (reg_name[0]) { r->name = reg_name; From e648856a412b8d0aca6efe100e83c44cd8a60bef Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 13 Nov 2017 13:14:07 -0800 Subject: [PATCH 082/127] `make all` debug tests now pass. Also properly support (I think) D extension on RV32. Change-Id: I2f0162d36e4c18c251f99b6943403cef30d17d29 --- src/target/riscv/riscv-013.c | 202 +++++++++++++++++++---------------- src/target/riscv/riscv.c | 27 ++++- src/target/riscv/riscv.h | 2 + 3 files changed, 132 insertions(+), 99 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 338c2432c..ba55379a3 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -128,12 +128,6 @@ struct trigger { int unique_id; }; -struct memory_cache_line { - uint32_t data; - bool valid; - bool dirty; -}; - typedef enum { YNM_MAYBE, YNM_YES, @@ -302,20 +296,6 @@ static int register_get(struct reg *reg); /*** Utility functions. ***/ -bool supports_extension(struct target *target, char letter) -{ - RISCV_INFO(r); - unsigned num; - if (letter >= 'a' && letter <= 'z') { - num = letter - 'a'; - } else if (letter >= 'A' && letter <= 'Z') { - num = letter - 'A'; - } else { - return false; - } - return r->misa & (1 << num); -} - static void select_dmi(struct target *target) { static uint8_t ir_dmi[1] = {DTM_DMI}; @@ -969,7 +949,7 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_FAIL; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && - supports_extension(target, 'D') && + riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a register, so * we need to use some scratch RAM. */ @@ -991,7 +971,7 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_FAIL; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (supports_extension(target, 'D')) { + if (riscv_supports_extension(target, 'D')) { riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); } else { riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0)); @@ -1038,7 +1018,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { // TODO: Possibly set F in mstatus. - if (supports_extension(target, 'D') && riscv_xlen(target) < 64) { + if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a * register, so we need to use some scratch RAM. */ riscv_program_insert(&program, fsd(number - GDB_REGNO_FPR0, S0, @@ -1051,7 +1031,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t if (register_write_direct(target, GDB_REGNO_S0, scratch.hart_address) != ERROR_OK) return ERROR_FAIL; - } else if (supports_extension(target, 'D')) { + } else if (riscv_supports_extension(target, 'D')) { riscv_program_insert(&program, fmv_x_d(S0, number - GDB_REGNO_FPR0)); } else { riscv_program_insert(&program, fmv_x_w(S0, number - GDB_REGNO_FPR0)); @@ -1094,7 +1074,7 @@ static int register_get(struct reg *reg) { struct target *target = (struct target *) reg->arch_info; uint64_t value = riscv_get_register(target, reg->number); - buf_set_u64(reg->value, 0, 64, value); + buf_set_u64(reg->value, 0, reg->size, value); return ERROR_OK; } @@ -1109,7 +1089,7 @@ static int register_set(struct reg *reg, uint8_t *buf) { struct target *target = (struct target *) reg->arch_info; - uint64_t value = buf_get_u64(buf, 0, riscv_xlen(target)); + uint64_t value = buf_get_u64(buf, 0, reg->size); LOG_DEBUG("write 0x%" PRIx64 " to %s", value, reg->name); struct reg *r = &target->reg_cache->reg_list[reg->number]; @@ -1124,6 +1104,99 @@ static struct reg_arch_type riscv_reg_arch_type = { .set = register_set }; +static int init_registers(struct target *target) +{ + riscv013_info_t *info = get_info(target); + + if (target->reg_cache) { + if (target->reg_cache->reg_list) + free(target->reg_cache->reg_list); + free(target->reg_cache); + } + + target->reg_cache = calloc(1, sizeof(*target->reg_cache)); + target->reg_cache->name = "RISC-V Registers"; + target->reg_cache->num_regs = GDB_REGNO_COUNT; + + target->reg_cache->reg_list = calloc(GDB_REGNO_COUNT, sizeof(struct reg)); + + const unsigned int max_reg_name_len = 12; + if (info->reg_names) + free(info->reg_names); + info->reg_names = calloc(1, GDB_REGNO_COUNT * max_reg_name_len); + char *reg_name = info->reg_names; + info->reg_values = NULL; + + static struct reg_feature feature_cpu = { + .name = "org.gnu.gdb.riscv.cpu" + }; + static struct reg_feature feature_fpu = { + .name = "org.gnu.gdb.riscv.fpu" + }; + static struct reg_feature feature_csr = { + .name = "org.gnu.gdb.riscv.csr" + }; + static struct reg_feature feature_virtual = { + .name = "org.gnu.gdb.riscv.virtual" + }; + + static struct reg_data_type type_ieee_single = { + .type = REG_TYPE_IEEE_SINGLE, + .id = "ieee_single" + }; + static struct reg_data_type type_ieee_double = { + .type = REG_TYPE_IEEE_DOUBLE, + .id = "ieee_double" + }; + + for (unsigned int i = 0; i < GDB_REGNO_COUNT; i++) { + struct reg *r = &target->reg_cache->reg_list[i]; + r->number = i; + r->caller_save = true; + r->dirty = false; + r->valid = false; + r->exist = true; + r->type = &riscv_reg_arch_type; + r->arch_info = target; + // r->size is set in riscv_invalidate_register_cache, maybe because the + // target is in theory allowed to change XLEN on us. But I expect a lot + // of other things to break in that case as well. + if (i <= GDB_REGNO_XPR31) { + sprintf(reg_name, "x%d", i); + r->group = "general"; + r->feature = &feature_cpu; + } else if (i == GDB_REGNO_PC) { + sprintf(reg_name, "pc"); + r->group = "general"; + r->feature = &feature_cpu; + } else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) { + sprintf(reg_name, "f%d", i - GDB_REGNO_FPR0); + r->group = "float"; + r->feature = &feature_fpu; + if (riscv_supports_extension(target, 'D')) { + r->reg_data_type = &type_ieee_double; + } else if (riscv_supports_extension(target, 'F')) { + r->reg_data_type = &type_ieee_single; + } + } else if (i >= GDB_REGNO_CSR0 && i <= GDB_REGNO_CSR4095) { + sprintf(reg_name, "csr%d", i - GDB_REGNO_CSR0); + r->group = "csr"; + r->feature = &feature_csr; + } else if (i == GDB_REGNO_PRIV) { + sprintf(reg_name, "priv"); + r->group = "general"; + r->feature = &feature_virtual; + } + if (reg_name[0]) { + r->name = reg_name; + } + reg_name += strlen(reg_name) + 1; + assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len); + } + + return ERROR_OK; +} + static int init_target(struct command_context *cmd_ctx, struct target *target) { @@ -1168,74 +1241,6 @@ static int init_target(struct command_context *cmd_ctx, info->abstract_read_fpr_supported = true; info->abstract_write_fpr_supported = true; - target->reg_cache = calloc(1, sizeof(*target->reg_cache)); - target->reg_cache->name = "RISC-V Registers"; - target->reg_cache->num_regs = GDB_REGNO_COUNT; - - target->reg_cache->reg_list = calloc(GDB_REGNO_COUNT, sizeof(struct reg)); - - const unsigned int max_reg_name_len = 12; - info->reg_names = calloc(1, GDB_REGNO_COUNT * max_reg_name_len); - char *reg_name = info->reg_names; - info->reg_values = NULL; - - static struct reg_feature feature_cpu = { - .name = "org.gnu.gdb.riscv.cpu" - }; - static struct reg_feature feature_fpu = { - .name = "org.gnu.gdb.riscv.fpu" - }; - static struct reg_feature feature_csr = { - .name = "org.gnu.gdb.riscv.csr" - }; - static struct reg_feature feature_virtual = { - .name = "org.gnu.gdb.riscv.virtual" - }; - - static struct reg_data_type type_ieee_single = { - .type = REG_TYPE_IEEE_SINGLE, - .id = "ieee_single" - }; - - for (unsigned int i = 0; i < GDB_REGNO_COUNT; i++) { - struct reg *r = &target->reg_cache->reg_list[i]; - r->number = i; - r->caller_save = true; - r->dirty = false; - r->valid = false; - r->exist = true; - r->type = &riscv_reg_arch_type; - r->arch_info = target; - if (i <= GDB_REGNO_XPR31) { - sprintf(reg_name, "x%d", i); - r->group = "general"; - r->feature = &feature_cpu; - } else if (i == GDB_REGNO_PC) { - sprintf(reg_name, "pc"); - r->group = "general"; - r->feature = &feature_cpu; - } else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) { - sprintf(reg_name, "f%d", i - GDB_REGNO_FPR0); - r->group = "float"; - r->feature = &feature_fpu; - // TODO: check D or F extension - r->reg_data_type = &type_ieee_single; - } else if (i >= GDB_REGNO_CSR0 && i <= GDB_REGNO_CSR4095) { - sprintf(reg_name, "csr%d", i - GDB_REGNO_CSR0); - r->group = "csr"; - r->feature = &feature_csr; - } else if (i == GDB_REGNO_PRIV) { - sprintf(reg_name, "priv"); - r->group = "general"; - r->feature = &feature_virtual; - } - if (reg_name[0]) { - r->name = reg_name; - } - reg_name += strlen(reg_name) + 1; - assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len); - } - return ERROR_OK; } @@ -1345,6 +1350,10 @@ static int examine(struct target *target) LOG_DEBUG("Enumerated %d harts", r->hart_count); + // Get a functional register cache going. + if (init_registers(target) != ERROR_OK) + return ERROR_FAIL; + /* Halt every hart so we can probe them. */ riscv_halt_all_harts(target); @@ -1381,6 +1390,11 @@ static int examine(struct target *target) /* Resumes all the harts, so the debugger can later pause them. */ riscv_resume_all_harts(target); target->state = TARGET_RUNNING; + + // Now reinit registers based on what we discovered. + if (init_registers(target) != ERROR_OK) + return ERROR_FAIL; + target_set_examined(target); if (target->rtos) { diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index b9be133f3..9f00a52c9 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1352,6 +1352,20 @@ int riscv_step_rtos_hart(struct target *target) return ERROR_OK; } +bool riscv_supports_extension(struct target *target, char letter) +{ + RISCV_INFO(r); + unsigned num; + if (letter >= 'a' && letter <= 'z') { + num = letter - 'a'; + } else if (letter >= 'A' && letter <= 'Z') { + num = letter - 'A'; + } else { + return false; + } + return r->misa & (1 << num); +} + int riscv_xlen(const struct target *target) { return riscv_xlen_of_hart(target, riscv_current_hartid(target)); @@ -1410,13 +1424,16 @@ void riscv_invalidate_register_cache(struct target *target) reg->value = &r->reg_cache_values[i]; reg->valid = false; - switch (i) { - case GDB_REGNO_PRIV: + if (i == GDB_REGNO_PRIV) { reg->size = 8; - break; - default: + } else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) { + if (riscv_supports_extension(target, 'D')) { + reg->size = 64; + } else if (riscv_supports_extension(target, 'F')) { + reg->size = 32; + } + } else { reg->size = riscv_xlen(target); - break; } } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 4ff61270f..8cab47fad 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -168,6 +168,8 @@ int riscv_resume_one_hart(struct target *target, int hartid); * then the only hart. */ int riscv_step_rtos_hart(struct target *target); +bool riscv_supports_extension(struct target *target, char letter); + /* Returns XLEN for the given (or current) hart. */ int riscv_xlen(const struct target *target); int riscv_xlen_of_hart(const struct target *target, int hartid); From a5cb0b22704c25fa2cbadd2b3b2024a662362c87 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 17 Nov 2017 15:34:18 -0800 Subject: [PATCH 083/127] WIP. Hide FPRs if the hart doesn't support F/D. Change-Id: I988c0c36f2de8157d76874a697b3c054773b787d --- src/target/riscv/riscv-013.c | 33 ++++++++++++++++++++------------- src/target/riscv/riscv.c | 21 +++++++++++---------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index ba55379a3..9e57a2245 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1149,40 +1149,47 @@ static int init_registers(struct target *target) .id = "ieee_double" }; - for (unsigned int i = 0; i < GDB_REGNO_COUNT; i++) { - struct reg *r = &target->reg_cache->reg_list[i]; - r->number = i; + // When gdb request register N, gdb_get_register_packet() assumes that this + // is register at index N in reg_list. So if there are certain registers + // that don't exist, we need to leave holes in the list (or renumber, but + // it would be nice not to have yet another set of numbers to translate + // between). + for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) { + struct reg *r = &target->reg_cache->reg_list[number]; r->caller_save = true; r->dirty = false; r->valid = false; r->exist = true; r->type = &riscv_reg_arch_type; r->arch_info = target; + r->number = number; // r->size is set in riscv_invalidate_register_cache, maybe because the // target is in theory allowed to change XLEN on us. But I expect a lot // of other things to break in that case as well. - if (i <= GDB_REGNO_XPR31) { - sprintf(reg_name, "x%d", i); + if (number <= GDB_REGNO_XPR31) { + sprintf(reg_name, "x%d", number); r->group = "general"; r->feature = &feature_cpu; - } else if (i == GDB_REGNO_PC) { + } else if (number == GDB_REGNO_PC) { sprintf(reg_name, "pc"); r->group = "general"; r->feature = &feature_cpu; - } else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) { - sprintf(reg_name, "f%d", i - GDB_REGNO_FPR0); - r->group = "float"; - r->feature = &feature_fpu; + } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { if (riscv_supports_extension(target, 'D')) { r->reg_data_type = &type_ieee_double; } else if (riscv_supports_extension(target, 'F')) { r->reg_data_type = &type_ieee_single; + } else { + r->exist = false; } - } else if (i >= GDB_REGNO_CSR0 && i <= GDB_REGNO_CSR4095) { - sprintf(reg_name, "csr%d", i - GDB_REGNO_CSR0); + sprintf(reg_name, "f%d", number - GDB_REGNO_FPR0); + r->group = "float"; + r->feature = &feature_fpu; + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + sprintf(reg_name, "csr%d", number - GDB_REGNO_CSR0); r->group = "csr"; r->feature = &feature_csr; - } else if (i == GDB_REGNO_PRIV) { + } else if (number == GDB_REGNO_PRIV) { sprintf(reg_name, "priv"); r->group = "general"; r->feature = &feature_virtual; diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 9f00a52c9..431e06f79 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -760,6 +760,11 @@ static int riscv_get_gdb_reg_list(struct target *target, LOG_DEBUG("reg_class=%d", reg_class); LOG_DEBUG("rtos_hartid=%d current_hartid=%d", r->rtos_hartid, r->current_hartid); + if (!target->reg_cache) { + LOG_ERROR("Target not initialized. Return ERROR_FAIL."); + return ERROR_FAIL; + } + if (r->rtos_hartid != -1 && riscv_rtos_enabled(target)) riscv_set_current_hartid(target, r->rtos_hartid); else @@ -770,7 +775,7 @@ static int riscv_get_gdb_reg_list(struct target *target, *reg_list_size = 32; break; case REG_CLASS_ALL: - *reg_list_size = REG_COUNT; + *reg_list_size = GDB_REGNO_COUNT; break; default: LOG_ERROR("Unsupported reg_class: %d", reg_class); @@ -781,14 +786,10 @@ static int riscv_get_gdb_reg_list(struct target *target, if (!*reg_list) { return ERROR_FAIL; } - - if (!target->reg_cache) { - LOG_ERROR("Target not initialized. Return ERROR_FAIL."); - return ERROR_FAIL; - } - + for (int i = 0; i < *reg_list_size; i++) { - assert(target->reg_cache->reg_list[i].size > 0); + assert(!target->reg_cache->reg_list[i].valid || + target->reg_cache->reg_list[i].size > 0); (*reg_list)[i] = &target->reg_cache->reg_list[i]; } @@ -1424,9 +1425,9 @@ void riscv_invalidate_register_cache(struct target *target) reg->value = &r->reg_cache_values[i]; reg->valid = false; - if (i == GDB_REGNO_PRIV) { + if (reg->number == GDB_REGNO_PRIV) { reg->size = 8; - } else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) { + } else if (reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) { if (riscv_supports_extension(target, 'D')) { reg->size = 64; } else if (riscv_supports_extension(target, 'F')) { From 7c989698a14b2626702ffb8812e78c7fd274af75 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 27 Nov 2017 13:09:42 -0800 Subject: [PATCH 084/127] WIP better CSR names, and include only existing Change-Id: I1a234ee07c417ba56da10a61fc2bdbdcc60490a8 --- src/target/riscv/riscv-013.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 9e57a2245..a63d168c9 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1186,9 +1186,40 @@ static int init_registers(struct target *target) r->group = "float"; r->feature = &feature_fpu; } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - sprintf(reg_name, "csr%d", number - GDB_REGNO_CSR0); r->group = "csr"; r->feature = &feature_csr; + r->exist = true; + switch (number) { + case CSR_FFLAGS: + strcpy(reg_name, "fflags"); + r->exist = riscv_supports_extension(target, 'F'); + r->group = "float"; + r->feature = &feature_fpu; + break; + case CSR_FRM: + strcpy(reg_name, "frm"); + r->exist = riscv_supports_extension(target, 'F'); + r->group = "float"; + r->feature = &feature_fpu; + break; + case CSR_FCSR: + strcpy(reg_name, "fcsr"); + r->exist = riscv_supports_extension(target, 'F'); + r->group = "float"; + r->feature = &feature_fpu; + break; + case CSR_CYCLE: + strcpy(reg_name, "cycle"); + break; + case CSR_TIME: + strcpy(reg_name, "time"); + break; + case CSR_INSTRET: + strcpy(reg_name, "instret"); + break; + default: + sprintf(reg_name, "csr%d", number - GDB_REGNO_CSR0); + } } else if (number == GDB_REGNO_PRIV) { sprintf(reg_name, "priv"); r->group = "general"; From 26a54452d2acb33e5343ee44b5982ad16e3af169 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 27 Nov 2017 14:47:33 -0800 Subject: [PATCH 085/127] Fix register names. Use the ABI ones for every register that we have one for. Change-Id: I2a993abff416d2652dbe026b3fb498e144a5006f --- src/target/riscv/gdb_regs.h | 41 +++++++++++++++--- src/target/riscv/program.c | 8 ++-- src/target/riscv/riscv-011.c | 2 +- src/target/riscv/riscv-013.c | 82 ++++++++++++++++++++++++++++-------- src/target/riscv/riscv.c | 21 ++------- 5 files changed, 108 insertions(+), 46 deletions(-) diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h index 2952e10ab..3f60d018d 100644 --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -4,12 +4,41 @@ // gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in // its source tree. We must interpret the numbers the same here. enum gdb_regno { - GDB_REGNO_XPR0 = 0, - GDB_REGNO_X0 = GDB_REGNO_XPR0 + 0, - GDB_REGNO_ZERO = GDB_REGNO_XPR0 + 0, - GDB_REGNO_S0 = GDB_REGNO_XPR0 + 8, - GDB_REGNO_S1 = GDB_REGNO_XPR0 + 9, - GDB_REGNO_XPR31 = GDB_REGNO_XPR0 + 31, + GDB_REGNO_ZERO = 0, /* Read-only register, always 0. */ + GDB_REGNO_RA = 1, /* Return Address. */ + GDB_REGNO_SP = 2, /* Stack Pointer. */ + GDB_REGNO_GP = 3, /* Global Pointer. */ + GDB_REGNO_TP = 4, /* Thread Pointer. */ + GDB_REGNO_T0, + GDB_REGNO_T1, + GDB_REGNO_T2, + GDB_REGNO_S0 = 8, + GDB_REGNO_FP = 8, /* Frame Pointer. */ + GDB_REGNO_S1, + GDB_REGNO_A0 = 10, /* First argument. */ + GDB_REGNO_A1 = 11, /* Second argument. */ + GDB_REGNO_A2, + GDB_REGNO_A3, + GDB_REGNO_A4, + GDB_REGNO_A5, + GDB_REGNO_A6, + GDB_REGNO_A7, + GDB_REGNO_S2, + GDB_REGNO_S3, + GDB_REGNO_S4, + GDB_REGNO_S5, + GDB_REGNO_S6, + GDB_REGNO_S7, + GDB_REGNO_S8, + GDB_REGNO_S9, + GDB_REGNO_S10, + GDB_REGNO_S11, + GDB_REGNO_T3, + GDB_REGNO_T4, + GDB_REGNO_T5, + GDB_REGNO_T6, + GDB_REGNO_XPR31 = GDB_REGNO_T6, + GDB_REGNO_PC = 32, GDB_REGNO_FPR0 = 33, GDB_REGNO_FPR31 = GDB_REGNO_FPR0 + 31, diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index e7238ddce..0c0dbd8bf 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -45,7 +45,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) keep_alive(); riscv_reg_t saved_registers[GDB_REGNO_XPR31 + 1]; - for (size_t i = GDB_REGNO_XPR0 + 1; i <= GDB_REGNO_XPR31; ++i) { + for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) { if (p->writes_xreg[i]) { LOG_DEBUG("Saving register %d as used by program", (int)i); saved_registers[i] = riscv_get_register(t, i); @@ -72,7 +72,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) if (i >= riscv_debug_buffer_size(p->target)) p->debug_buffer[i] = riscv_read_debug_buffer(t, i); - for (size_t i = GDB_REGNO_XPR0; i <= GDB_REGNO_XPR31; ++i) + for (size_t i = GDB_REGNO_ZERO; i <= GDB_REGNO_XPR31; ++i) if (p->writes_xreg[i]) riscv_set_register(t, i, saved_registers[i]); @@ -112,13 +112,13 @@ int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); - return riscv_program_insert(p, csrrs(d, GDB_REGNO_X0, csr - GDB_REGNO_CSR0)); + return riscv_program_insert(p, csrrs(d, GDB_REGNO_ZERO, csr - GDB_REGNO_CSR0)); } int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0); - return riscv_program_insert(p, csrrw(GDB_REGNO_X0, s, csr - GDB_REGNO_CSR0)); + return riscv_program_insert(p, csrrw(GDB_REGNO_ZERO, s, csr - GDB_REGNO_CSR0)); } int riscv_program_fence_i(struct riscv_program *p) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 6e576fef9..1382387d3 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1344,7 +1344,7 @@ static int register_write(struct target *target, unsigned int number, cache_set_store(target, 1, S0, SLOT_LAST); cache_set_jump(target, 2); } else if (number <= GDB_REGNO_XPR31) { - cache_set_load(target, 0, number - GDB_REGNO_XPR0, SLOT0); + cache_set_load(target, 0, number - GDB_REGNO_ZERO, SLOT0); cache_set_jump(target, 1); } else if (number == GDB_REGNO_PC) { info->dpc = value; diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index a63d168c9..4238273a6 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -647,7 +647,7 @@ static uint32_t access_register_command(uint32_t number, unsigned size, if (number <= GDB_REGNO_XPR31) { command = set_field(command, AC_ACCESS_REGISTER_REGNO, - 0x1000 + number - GDB_REGNO_XPR0); + 0x1000 + number - GDB_REGNO_ZERO); } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { command = set_field(command, AC_ACCESS_REGISTER_REGNO, 0x1020 + number - GDB_REGNO_FPR0); @@ -1104,6 +1104,16 @@ static struct reg_arch_type riscv_reg_arch_type = { .set = register_set }; +struct csr_info { + unsigned number; + const char *name; +}; + +static int cmp_csr_info(const void *p1, const void *p2) +{ + return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number); +} + static int init_registers(struct target *target) { riscv013_info_t *info = get_info(target); @@ -1148,6 +1158,14 @@ static int init_registers(struct target *target) .type = REG_TYPE_IEEE_DOUBLE, .id = "ieee_double" }; + struct csr_info csr_info[] = { +#define DECLARE_CSR(name, number) { number, #name }, +#include "encoding.h" +#undef DECLARE_CSR + }; + // encoding.h does not contain the registers in sorted order. + qsort(csr_info, DIM(csr_info), sizeof(*csr_info), cmp_csr_info); + unsigned csr_info_index = 0; // When gdb request register N, gdb_get_register_packet() assumes that this // is register at index N in reg_list. So if there are certain registers @@ -1167,7 +1185,40 @@ static int init_registers(struct target *target) // target is in theory allowed to change XLEN on us. But I expect a lot // of other things to break in that case as well. if (number <= GDB_REGNO_XPR31) { - sprintf(reg_name, "x%d", number); + switch (number) { + case GDB_REGNO_ZERO: r->name = "zero"; break; + case GDB_REGNO_RA: r->name = "ra"; break; + case GDB_REGNO_SP: r->name = "sp"; break; + case GDB_REGNO_GP: r->name = "gp"; break; + case GDB_REGNO_TP: r->name = "tp"; break; + case GDB_REGNO_T0: r->name = "t0"; break; + case GDB_REGNO_T1: r->name = "t1"; break; + case GDB_REGNO_T2: r->name = "t2"; break; + case GDB_REGNO_FP: r->name = "fp"; break; + case GDB_REGNO_S1: r->name = "s1"; break; + case GDB_REGNO_A0: r->name = "a0"; break; + case GDB_REGNO_A1: r->name = "a1"; break; + case GDB_REGNO_A2: r->name = "a2"; break; + case GDB_REGNO_A3: r->name = "a3"; break; + case GDB_REGNO_A4: r->name = "a4"; break; + case GDB_REGNO_A5: r->name = "a5"; break; + case GDB_REGNO_A6: r->name = "a6"; break; + case GDB_REGNO_A7: r->name = "a7"; break; + case GDB_REGNO_S2: r->name = "s2"; break; + case GDB_REGNO_S3: r->name = "s3"; break; + case GDB_REGNO_S4: r->name = "s4"; break; + case GDB_REGNO_S5: r->name = "s5"; break; + case GDB_REGNO_S6: r->name = "s6"; break; + case GDB_REGNO_S7: r->name = "s7"; break; + case GDB_REGNO_S8: r->name = "s8"; break; + case GDB_REGNO_S9: r->name = "s9"; break; + case GDB_REGNO_S10: r->name = "s10"; break; + case GDB_REGNO_S11: r->name = "s11"; break; + case GDB_REGNO_T3: r->name = "t3"; break; + case GDB_REGNO_T4: r->name = "t4"; break; + case GDB_REGNO_T5: r->name = "t5"; break; + case GDB_REGNO_T6: r->name = "t6"; break; + } r->group = "general"; r->feature = &feature_cpu; } else if (number == GDB_REGNO_PC) { @@ -1189,36 +1240,33 @@ static int init_registers(struct target *target) r->group = "csr"; r->feature = &feature_csr; r->exist = true; - switch (number) { + unsigned csr_number = number - GDB_REGNO_CSR0; + + while (csr_info[csr_info_index].number < csr_number) { + csr_info_index++; + } + if (csr_info[csr_info_index].number == csr_number) { + r->name = csr_info[csr_info_index].name; + } else { + sprintf(reg_name, "csr%d", csr_number); + } + + switch (csr_number) { case CSR_FFLAGS: - strcpy(reg_name, "fflags"); r->exist = riscv_supports_extension(target, 'F'); r->group = "float"; r->feature = &feature_fpu; break; case CSR_FRM: - strcpy(reg_name, "frm"); r->exist = riscv_supports_extension(target, 'F'); r->group = "float"; r->feature = &feature_fpu; break; case CSR_FCSR: - strcpy(reg_name, "fcsr"); r->exist = riscv_supports_extension(target, 'F'); r->group = "float"; r->feature = &feature_fpu; break; - case CSR_CYCLE: - strcpy(reg_name, "cycle"); - break; - case CSR_TIME: - strcpy(reg_name, "time"); - break; - case CSR_INSTRET: - strcpy(reg_name, "instret"); - break; - default: - sprintf(reg_name, "csr%d", number - GDB_REGNO_CSR0); } } else if (number == GDB_REGNO_PRIV) { sprintf(reg_name, "priv"); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 431e06f79..a196fdce8 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -151,21 +151,6 @@ typedef enum slot { #define DBUS_ADDRESS_UNKNOWN 0xffff -// gdb's register list is defined in riscv_gdb_reg_names gdb/riscv-tdep.c in -// its source tree. We must interpret the numbers the same here. -enum { - REG_XPR0 = 0, - REG_XPR31 = 31, - REG_PC = 32, - REG_FPR0 = 33, - REG_FPR31 = 64, - REG_CSR0 = 65, - REG_MSTATUS = CSR_MSTATUS + REG_CSR0, - REG_CSR4095 = 4160, - REG_PRIV = 4161, - REG_COUNT -}; - #define MAX_HWBPS 16 #define DRAM_CACHE_SIZE 16 @@ -842,7 +827,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, return ERROR_FAIL; } - if (r->number > REG_XPR31) { + if (r->number > GDB_REGNO_XPR31) { LOG_ERROR("Only GPRs can be use as argument registers."); return ERROR_FAIL; } @@ -1404,7 +1389,7 @@ void riscv_set_current_hartid(struct target *target, int hartid) /* Avoid invalidating the register cache all the time. */ if (r->registers_initialized && (!riscv_rtos_enabled(target) || (previous_hartid == hartid)) - && target->reg_cache->reg_list[GDB_REGNO_XPR0].size == (unsigned)riscv_xlen(target) + && target->reg_cache->reg_list[GDB_REGNO_ZERO].size == (unsigned)riscv_xlen(target) && (!riscv_rtos_enabled(target) || (r->rtos_hartid != -1))) { return; } else @@ -1694,7 +1679,7 @@ const char *gdb_regno_name(enum gdb_regno regno) return "priv"; default: if (regno <= GDB_REGNO_XPR31) { - sprintf(buf, "x%d", regno - GDB_REGNO_XPR0); + sprintf(buf, "x%d", regno - GDB_REGNO_ZERO); } else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0); } else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) { From 8926e66d3a36304af8244dfa177bd8e45a09010d Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 29 Nov 2017 13:38:04 -0800 Subject: [PATCH 086/127] Hide unknown registers, which probably don't exist Change-Id: Iffa8fa5ff4b0a01abd30fa302b7087e2011337bf --- src/target/riscv/riscv-013.c | 6 ++++++ src/target/target.c | 28 +++++++++++++++------------- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 4238273a6..1c48e5566 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1249,6 +1249,12 @@ static int init_registers(struct target *target) r->name = csr_info[csr_info_index].name; } else { sprintf(reg_name, "csr%d", csr_number); + // Assume unnamed registers don't exist, unless we have some + // configuration that tells us otherwise. That's important + // because eg. Eclipse crashes if a target has too many + // registers, and apparently has no way of only showing a + // subset of registers in any case. + r->exist = false; } switch (csr_number) { diff --git a/src/target/target.c b/src/target/target.c index adedd4709..327844479 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -2742,21 +2742,23 @@ COMMAND_HANDLER(handle_reg_command) i < cache->num_regs; i++, reg++, count++) { /* only print cached values if they are valid */ - if (reg->valid) { - value = buf_to_str(reg->value, - reg->size, 16); - command_print(CMD_CTX, - "(%i) %s (/%" PRIu32 "): 0x%s%s", - count, reg->name, - reg->size, value, - reg->dirty + if (reg->exist) { + if (reg->valid) { + value = buf_to_str(reg->value, + reg->size, 16); + command_print(CMD_CTX, + "(%i) %s (/%" PRIu32 "): 0x%s%s", + count, reg->name, + reg->size, value, + reg->dirty ? " (dirty)" : ""); - free(value); - } else { - command_print(CMD_CTX, "(%i) %s (/%" PRIu32 ")", - count, reg->name, - reg->size) ; + free(value); + } else { + command_print(CMD_CTX, "(%i) %s (/%" PRIu32 ")", + count, reg->name, + reg->size) ; + } } } cache = cache->next; From f341db9f72f8e35df0b92190558fd3c2f4c85446 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 1 Dec 2017 12:42:16 -0800 Subject: [PATCH 087/127] WIP xml register for 0.11. On HiFive1, FPRs show up with no name, and misa is 0x1105 instead of 0x40001105. Change-Id: I4ee223c905ad7d860147014e7b6394668658c6ea --- src/target/riscv/riscv-011.c | 200 ++++++++-------------------- src/target/riscv/riscv-013.c | 245 ++--------------------------------- src/target/riscv/riscv.c | 235 ++++++++++++++++++++++++++++++--- src/target/riscv/riscv.h | 8 +- 4 files changed, 293 insertions(+), 395 deletions(-) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 1382387d3..6692a9de1 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -189,12 +189,6 @@ typedef struct { struct memory_cache_line dram_cache[DRAM_CACHE_SIZE]; - /* Single buffer that contains all register names, instead of calling - * malloc for each register. Needs to be freed when reg_list is freed. */ - char *reg_names; - /* Single buffer that contains all register values. */ - void *reg_values; - // Number of run-test/idle cycles the target requests we do after each dbus // access. unsigned int dtmcontrol_idle; @@ -223,7 +217,7 @@ typedef struct { static int poll_target(struct target *target, bool announce); static int riscv011_poll(struct target *target); -static int register_get(struct reg *reg); +static riscv_reg_t get_register(struct target *target, int hartid, int regid); /*** Utility functions. ***/ @@ -1181,30 +1175,6 @@ static int resume(struct target *target, int debug_execution, bool step) return execute_resume(target, step); } -/** Update register sizes based on xlen. */ -static void update_reg_list(struct target *target) -{ - riscv011_info_t *info = get_info(target); - if (info->reg_values) { - free(info->reg_values); - } - info->reg_values = malloc(GDB_REGNO_COUNT * riscv_xlen(target) / 4); - - for (unsigned int i = 0; i < GDB_REGNO_COUNT; i++) { - struct reg *r = &target->reg_cache->reg_list[i]; - r->value = info->reg_values + i * riscv_xlen(target) / 4; - if (r->dirty) { - LOG_ERROR("Register %d was dirty. Its value is lost.", i); - } - if (i == GDB_REGNO_PRIV) { - r->size = 8; - } else { - r->size = riscv_xlen(target); - } - r->valid = false; - } -} - static uint64_t reg_cache_get(struct target *target, unsigned int number) { struct reg *r = &target->reg_cache->reg_list[number]; @@ -1236,7 +1206,8 @@ static int update_mstatus_actual(struct target *target) // Force reading the register. In that process mstatus_actual will be // updated. - return register_get(&target->reg_cache->reg_list[GDB_REGNO_MSTATUS]); + get_register(target, 0, GDB_REGNO_MSTATUS); + return ERROR_OK; } /*** OpenOCD target functions. ***/ @@ -1275,58 +1246,6 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum) return ERROR_OK; } -static int register_get(struct reg *reg) -{ - struct target *target = (struct target *) reg->arch_info; - riscv011_info_t *info = get_info(target); - - maybe_write_tselect(target); - riscv_reg_t value = ~0; - - if (reg->number <= GDB_REGNO_XPR31) { - value = reg_cache_get(target, reg->number); - LOG_DEBUG("%s=0x%" PRIx64, reg->name, reg_cache_get(target, reg->number)); - } else if (reg->number == GDB_REGNO_PC) { - value = info->dpc; - LOG_DEBUG("%s=0x%" PRIx64 " (cached)", reg->name, info->dpc); - } else if (reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) { - int result = update_mstatus_actual(target); - if (result != ERROR_OK) { - return result; - } - unsigned i = 0; - if ((info->mstatus_actual & MSTATUS_FS) == 0) { - info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); - cache_set_load(target, i++, S0, SLOT1); - cache_set32(target, i++, csrw(S0, CSR_MSTATUS)); - cache_set(target, SLOT1, info->mstatus_actual); - } - - if (riscv_xlen(target) == 32) { - cache_set32(target, i++, fsw(reg->number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); - } else { - cache_set32(target, i++, fsd(reg->number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); - } - cache_set_jump(target, i++); - - if (cache_write(target, 4, true) != ERROR_OK) { - return ERROR_FAIL; - } - } else if (reg->number == GDB_REGNO_PRIV) { - value = get_field(info->dcsr, DCSR_PRV); - } else { - if (register_read(target, &value, reg->number) != ERROR_OK) - return ERROR_FAIL; - } - buf_set_u64(reg->value, 0, riscv_xlen(target), value); - - if (reg->number == GDB_REGNO_MSTATUS) { - reg->valid = true; - } - - return ERROR_OK; -} - // Write the register. No caching or games. static int register_write(struct target *target, unsigned int number, uint64_t value) @@ -1399,33 +1318,53 @@ static int register_write(struct target *target, unsigned int number, return ERROR_OK; } -static int register_set(struct reg *reg, uint8_t *buf) -{ - struct target *target = (struct target *) reg->arch_info; - - uint64_t value = buf_get_u64(buf, 0, riscv_xlen(target)); - - LOG_DEBUG("write 0x%" PRIx64 " to %s", value, reg->name); - struct reg *r = &target->reg_cache->reg_list[reg->number]; - r->valid = true; - memcpy(r->value, buf, (r->size + 7) / 8); - - return register_write(target, reg->number, value); -} - -static struct reg_arch_type riscv_reg_arch_type = { - .get = register_get, - .set = register_set -}; - static riscv_reg_t get_register(struct target *target, int hartid, int regid) { assert(hartid == 0); - riscv_reg_t value; - if (register_read(target, &value, regid) != ERROR_OK) { - // TODO: propagate errors - value = ~0; + riscv011_info_t *info = get_info(target); + + maybe_write_tselect(target); + riscv_reg_t value = ~0; + + if (regid <= GDB_REGNO_XPR31) { + value = reg_cache_get(target, regid); + } else if (regid == GDB_REGNO_PC) { + value = info->dpc; + } else if (regid >= GDB_REGNO_FPR0 && regid <= GDB_REGNO_FPR31) { + int result = update_mstatus_actual(target); + if (result != ERROR_OK) { + return ~0; + } + unsigned i = 0; + if ((info->mstatus_actual & MSTATUS_FS) == 0) { + info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); + cache_set_load(target, i++, S0, SLOT1); + cache_set32(target, i++, csrw(S0, CSR_MSTATUS)); + cache_set(target, SLOT1, info->mstatus_actual); + } + + if (riscv_xlen(target) == 32) { + cache_set32(target, i++, fsw(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); + } else { + cache_set32(target, i++, fsd(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); + } + cache_set_jump(target, i++); + + if (cache_write(target, 4, true) != ERROR_OK) { + return ~0; + } + } else if (regid == GDB_REGNO_PRIV) { + value = get_field(info->dcsr, DCSR_PRV); + } else { + if (register_read(target, &value, regid) != ERROR_OK) { + value = ~0; + } } + + if (regid == GDB_REGNO_MSTATUS) { + target->reg_cache->reg_list[regid].valid = true; + } + return value; } @@ -1466,45 +1405,10 @@ static int init_target(struct command_context *cmd_ctx, generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); if (!generic_info->version_specific) return ERROR_FAIL; - riscv011_info_t *info = get_info(target); - target->reg_cache = calloc(1, sizeof(*target->reg_cache)); - target->reg_cache->name = "RISC-V registers"; - target->reg_cache->num_regs = GDB_REGNO_COUNT; - - target->reg_cache->reg_list = calloc(GDB_REGNO_COUNT, sizeof(struct reg)); - - const unsigned int max_reg_name_len = 12; - info->reg_names = calloc(1, GDB_REGNO_COUNT * max_reg_name_len); - char *reg_name = info->reg_names; - info->reg_values = NULL; - - for (unsigned int i = 0; i < GDB_REGNO_COUNT; i++) { - struct reg *r = &target->reg_cache->reg_list[i]; - r->number = i; - r->caller_save = true; - r->dirty = false; - r->valid = false; - r->exist = true; - r->type = &riscv_reg_arch_type; - r->arch_info = target; - if (i <= GDB_REGNO_XPR31) { - sprintf(reg_name, "x%d", i); - } else if (i == GDB_REGNO_PC) { - sprintf(reg_name, "pc"); - } else if (i >= GDB_REGNO_FPR0 && i <= GDB_REGNO_FPR31) { - sprintf(reg_name, "f%d", i - GDB_REGNO_FPR0); - } else if (i >= GDB_REGNO_CSR0 && i <= GDB_REGNO_CSR4095) { - sprintf(reg_name, "csr%d", i - GDB_REGNO_CSR0); - } else if (i == GDB_REGNO_PRIV) { - sprintf(reg_name, "priv"); - } - if (reg_name[0]) { - r->name = reg_name; - } - reg_name += strlen(reg_name) + 1; - assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len); - } + // Assume 32-bit until we discover the real value in examine(). + generic_info->xlen[0] = 32; + riscv_init_registers(target); return ERROR_OK; } @@ -1690,9 +1594,6 @@ static int examine(struct target *target) } LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target)); - // Update register list to match discovered XLEN. - update_reg_list(target); - if (read_csr(target, &r->misa, CSR_MISA) != ERROR_OK) { const unsigned old_csr_misa = 0xf10; LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA, @@ -1705,6 +1606,9 @@ static int examine(struct target *target) } } + // Update register list to match discovered XLEN/supported extensions. + riscv_init_registers(target); + info->never_halted = true; int result = riscv011_poll(target); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 1c48e5566..f22ef714c 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -150,12 +150,6 @@ typedef struct { /* We only need the address so that we know the alignment of the buffer. */ riscv_addr_t progbuf_address; - /* Single buffer that contains all register names, instead of calling - * malloc for each register. Needs to be freed when reg_list is freed. */ - char *reg_names; - /* Single buffer that contains all register values. */ - void *reg_values; - // Number of run-test/idle cycles the target requests we do after each dbus // access. unsigned int dtmcontrol_idle; @@ -290,10 +284,6 @@ static riscv013_info_t *get_info(const struct target *target) return (riscv013_info_t *) info->version_specific; } -/*** Necessary prototypes. ***/ - -static int register_get(struct reg *reg); - /*** Utility functions. ***/ static void select_dmi(struct target *target) @@ -1070,225 +1060,6 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t /*** OpenOCD target functions. ***/ -static int register_get(struct reg *reg) -{ - struct target *target = (struct target *) reg->arch_info; - uint64_t value = riscv_get_register(target, reg->number); - buf_set_u64(reg->value, 0, reg->size, value); - return ERROR_OK; -} - -static int register_write(struct target *target, unsigned int number, - uint64_t value) -{ - riscv_set_register(target, number, value); - return ERROR_OK; -} - -static int register_set(struct reg *reg, uint8_t *buf) -{ - struct target *target = (struct target *) reg->arch_info; - - uint64_t value = buf_get_u64(buf, 0, reg->size); - - LOG_DEBUG("write 0x%" PRIx64 " to %s", value, reg->name); - struct reg *r = &target->reg_cache->reg_list[reg->number]; - r->valid = true; - memcpy(r->value, buf, (r->size + 7) / 8); - - return register_write(target, reg->number, value); -} - -static struct reg_arch_type riscv_reg_arch_type = { - .get = register_get, - .set = register_set -}; - -struct csr_info { - unsigned number; - const char *name; -}; - -static int cmp_csr_info(const void *p1, const void *p2) -{ - return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number); -} - -static int init_registers(struct target *target) -{ - riscv013_info_t *info = get_info(target); - - if (target->reg_cache) { - if (target->reg_cache->reg_list) - free(target->reg_cache->reg_list); - free(target->reg_cache); - } - - target->reg_cache = calloc(1, sizeof(*target->reg_cache)); - target->reg_cache->name = "RISC-V Registers"; - target->reg_cache->num_regs = GDB_REGNO_COUNT; - - target->reg_cache->reg_list = calloc(GDB_REGNO_COUNT, sizeof(struct reg)); - - const unsigned int max_reg_name_len = 12; - if (info->reg_names) - free(info->reg_names); - info->reg_names = calloc(1, GDB_REGNO_COUNT * max_reg_name_len); - char *reg_name = info->reg_names; - info->reg_values = NULL; - - static struct reg_feature feature_cpu = { - .name = "org.gnu.gdb.riscv.cpu" - }; - static struct reg_feature feature_fpu = { - .name = "org.gnu.gdb.riscv.fpu" - }; - static struct reg_feature feature_csr = { - .name = "org.gnu.gdb.riscv.csr" - }; - static struct reg_feature feature_virtual = { - .name = "org.gnu.gdb.riscv.virtual" - }; - - static struct reg_data_type type_ieee_single = { - .type = REG_TYPE_IEEE_SINGLE, - .id = "ieee_single" - }; - static struct reg_data_type type_ieee_double = { - .type = REG_TYPE_IEEE_DOUBLE, - .id = "ieee_double" - }; - struct csr_info csr_info[] = { -#define DECLARE_CSR(name, number) { number, #name }, -#include "encoding.h" -#undef DECLARE_CSR - }; - // encoding.h does not contain the registers in sorted order. - qsort(csr_info, DIM(csr_info), sizeof(*csr_info), cmp_csr_info); - unsigned csr_info_index = 0; - - // When gdb request register N, gdb_get_register_packet() assumes that this - // is register at index N in reg_list. So if there are certain registers - // that don't exist, we need to leave holes in the list (or renumber, but - // it would be nice not to have yet another set of numbers to translate - // between). - for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) { - struct reg *r = &target->reg_cache->reg_list[number]; - r->caller_save = true; - r->dirty = false; - r->valid = false; - r->exist = true; - r->type = &riscv_reg_arch_type; - r->arch_info = target; - r->number = number; - // r->size is set in riscv_invalidate_register_cache, maybe because the - // target is in theory allowed to change XLEN on us. But I expect a lot - // of other things to break in that case as well. - if (number <= GDB_REGNO_XPR31) { - switch (number) { - case GDB_REGNO_ZERO: r->name = "zero"; break; - case GDB_REGNO_RA: r->name = "ra"; break; - case GDB_REGNO_SP: r->name = "sp"; break; - case GDB_REGNO_GP: r->name = "gp"; break; - case GDB_REGNO_TP: r->name = "tp"; break; - case GDB_REGNO_T0: r->name = "t0"; break; - case GDB_REGNO_T1: r->name = "t1"; break; - case GDB_REGNO_T2: r->name = "t2"; break; - case GDB_REGNO_FP: r->name = "fp"; break; - case GDB_REGNO_S1: r->name = "s1"; break; - case GDB_REGNO_A0: r->name = "a0"; break; - case GDB_REGNO_A1: r->name = "a1"; break; - case GDB_REGNO_A2: r->name = "a2"; break; - case GDB_REGNO_A3: r->name = "a3"; break; - case GDB_REGNO_A4: r->name = "a4"; break; - case GDB_REGNO_A5: r->name = "a5"; break; - case GDB_REGNO_A6: r->name = "a6"; break; - case GDB_REGNO_A7: r->name = "a7"; break; - case GDB_REGNO_S2: r->name = "s2"; break; - case GDB_REGNO_S3: r->name = "s3"; break; - case GDB_REGNO_S4: r->name = "s4"; break; - case GDB_REGNO_S5: r->name = "s5"; break; - case GDB_REGNO_S6: r->name = "s6"; break; - case GDB_REGNO_S7: r->name = "s7"; break; - case GDB_REGNO_S8: r->name = "s8"; break; - case GDB_REGNO_S9: r->name = "s9"; break; - case GDB_REGNO_S10: r->name = "s10"; break; - case GDB_REGNO_S11: r->name = "s11"; break; - case GDB_REGNO_T3: r->name = "t3"; break; - case GDB_REGNO_T4: r->name = "t4"; break; - case GDB_REGNO_T5: r->name = "t5"; break; - case GDB_REGNO_T6: r->name = "t6"; break; - } - r->group = "general"; - r->feature = &feature_cpu; - } else if (number == GDB_REGNO_PC) { - sprintf(reg_name, "pc"); - r->group = "general"; - r->feature = &feature_cpu; - } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (riscv_supports_extension(target, 'D')) { - r->reg_data_type = &type_ieee_double; - } else if (riscv_supports_extension(target, 'F')) { - r->reg_data_type = &type_ieee_single; - } else { - r->exist = false; - } - sprintf(reg_name, "f%d", number - GDB_REGNO_FPR0); - r->group = "float"; - r->feature = &feature_fpu; - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - r->group = "csr"; - r->feature = &feature_csr; - r->exist = true; - unsigned csr_number = number - GDB_REGNO_CSR0; - - while (csr_info[csr_info_index].number < csr_number) { - csr_info_index++; - } - if (csr_info[csr_info_index].number == csr_number) { - r->name = csr_info[csr_info_index].name; - } else { - sprintf(reg_name, "csr%d", csr_number); - // Assume unnamed registers don't exist, unless we have some - // configuration that tells us otherwise. That's important - // because eg. Eclipse crashes if a target has too many - // registers, and apparently has no way of only showing a - // subset of registers in any case. - r->exist = false; - } - - switch (csr_number) { - case CSR_FFLAGS: - r->exist = riscv_supports_extension(target, 'F'); - r->group = "float"; - r->feature = &feature_fpu; - break; - case CSR_FRM: - r->exist = riscv_supports_extension(target, 'F'); - r->group = "float"; - r->feature = &feature_fpu; - break; - case CSR_FCSR: - r->exist = riscv_supports_extension(target, 'F'); - r->group = "float"; - r->feature = &feature_fpu; - break; - } - } else if (number == GDB_REGNO_PRIV) { - sprintf(reg_name, "priv"); - r->group = "general"; - r->feature = &feature_virtual; - } - if (reg_name[0]) { - r->name = reg_name; - } - reg_name += strlen(reg_name) + 1; - assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len); - } - - return ERROR_OK; -} - static int init_target(struct command_context *cmd_ctx, struct target *target) { @@ -1438,12 +1209,24 @@ static int examine(struct target *target) break; } } + // Reset hartid to one that exists. Set coreid to avoid assert in + // riscv_set_current_hartid(). (TODO) + target->coreid = 0; + riscv_set_current_hartid(target, 0); + target->coreid = original_coreid; LOG_DEBUG("Enumerated %d harts", r->hart_count); + // Assume 32-bit until we discover the real value in examine(). + for (int i = 0; i < riscv_count_harts(target); ++i) { + if (riscv_hart_enabled(target, i)) { + r->xlen[i] = 32; + } + LOG_DEBUG(">>> temporary XLEN for hart %d is %d", i, r->xlen[i]); + } // Get a functional register cache going. - if (init_registers(target) != ERROR_OK) + if (riscv_init_registers(target) != ERROR_OK) return ERROR_FAIL; /* Halt every hart so we can probe them. */ @@ -1484,7 +1267,7 @@ static int examine(struct target *target) target->state = TARGET_RUNNING; // Now reinit registers based on what we discovered. - if (init_registers(target) != ERROR_OK) + if (riscv_init_registers(target) != ERROR_OK) return ERROR_FAIL; target_set_examined(target); diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a196fdce8..46571890b 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -415,7 +415,6 @@ static int add_trigger(struct target *target, struct trigger *trigger) int result = ERROR_OK; for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { - LOG_DEBUG(">>> hartid=%d", hartid); if (!riscv_hart_enabled(target, hartid)) continue; if (hartid > first_hart) { @@ -1248,6 +1247,7 @@ void riscv_info_init(struct target *target, riscv_info_t *r) memset(r, 0, sizeof(*r)); r->dtm_version = 1; r->registers_initialized = false; + LOG_DEBUG(">>> current_hartid=%d", target->coreid); r->current_hartid = target->coreid; memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id)); @@ -1360,6 +1360,7 @@ int riscv_xlen(const struct target *target) int riscv_xlen_of_hart(const struct target *target, int hartid) { RISCV_INFO(r); + LOG_DEBUG(">>> xlen[%d] = %d", hartid, r->xlen[hartid]); assert(r->xlen[hartid] != -1); return r->xlen[hartid]; } @@ -1406,21 +1407,7 @@ void riscv_invalidate_register_cache(struct target *target) register_cache_invalidate(target->reg_cache); for (size_t i = 0; i < GDB_REGNO_COUNT; ++i) { struct reg *reg = &target->reg_cache->reg_list[i]; - - reg->value = &r->reg_cache_values[i]; reg->valid = false; - - if (reg->number == GDB_REGNO_PRIV) { - reg->size = 8; - } else if (reg->number >= GDB_REGNO_FPR0 && reg->number <= GDB_REGNO_FPR31) { - if (riscv_supports_extension(target, 'D')) { - reg->size = 64; - } else if (riscv_supports_extension(target, 'F')) { - reg->size = 32; - } - } else { - reg->size = riscv_xlen(target); - } } r->registers_initialized = true; @@ -1460,6 +1447,7 @@ bool riscv_has_register(struct target *target, int hartid, int regid) void riscv_set_register(struct target *target, enum gdb_regno r, riscv_reg_t v) { + // TODO: propagate errors return riscv_set_register_on_hart(target, riscv_current_hartid(target), r, v); } @@ -1690,3 +1678,220 @@ const char *gdb_regno_name(enum gdb_regno regno) return buf; } } + +static int register_get(struct reg *reg) +{ + struct target *target = (struct target *) reg->arch_info; + uint64_t value = riscv_get_register(target, reg->number); + buf_set_u64(reg->value, 0, reg->size, value); + return ERROR_OK; +} + +static int register_set(struct reg *reg, uint8_t *buf) +{ + struct target *target = (struct target *) reg->arch_info; + + uint64_t value = buf_get_u64(buf, 0, reg->size); + + LOG_DEBUG("write 0x%" PRIx64 " to %s", value, reg->name); + struct reg *r = &target->reg_cache->reg_list[reg->number]; + r->valid = true; + memcpy(r->value, buf, (r->size + 7) / 8); + + riscv_set_register(target, reg->number, value); + return ERROR_OK; +} + +static struct reg_arch_type riscv_reg_arch_type = { + .get = register_get, + .set = register_set +}; + +struct csr_info { + unsigned number; + const char *name; +}; + +static int cmp_csr_info(const void *p1, const void *p2) +{ + return (int) (((struct csr_info *)p1)->number) - (int) (((struct csr_info *)p2)->number); +} + +int riscv_init_registers(struct target *target) +{ + RISCV_INFO(info); + + if (target->reg_cache) { + if (target->reg_cache->reg_list) + free(target->reg_cache->reg_list); + free(target->reg_cache); + } + + target->reg_cache = calloc(1, sizeof(*target->reg_cache)); + target->reg_cache->name = "RISC-V Registers"; + target->reg_cache->num_regs = GDB_REGNO_COUNT; + + target->reg_cache->reg_list = calloc(GDB_REGNO_COUNT, sizeof(struct reg)); + + const unsigned int max_reg_name_len = 12; + if (info->reg_names) + free(info->reg_names); + info->reg_names = calloc(1, GDB_REGNO_COUNT * max_reg_name_len); + char *reg_name = info->reg_names; + + static struct reg_feature feature_cpu = { + .name = "org.gnu.gdb.riscv.cpu" + }; + static struct reg_feature feature_fpu = { + .name = "org.gnu.gdb.riscv.fpu" + }; + static struct reg_feature feature_csr = { + .name = "org.gnu.gdb.riscv.csr" + }; + static struct reg_feature feature_virtual = { + .name = "org.gnu.gdb.riscv.virtual" + }; + + static struct reg_data_type type_ieee_single = { + .type = REG_TYPE_IEEE_SINGLE, + .id = "ieee_single" + }; + static struct reg_data_type type_ieee_double = { + .type = REG_TYPE_IEEE_DOUBLE, + .id = "ieee_double" + }; + struct csr_info csr_info[] = { +#define DECLARE_CSR(name, number) { number, #name }, +#include "encoding.h" +#undef DECLARE_CSR + }; + // encoding.h does not contain the registers in sorted order. + qsort(csr_info, DIM(csr_info), sizeof(*csr_info), cmp_csr_info); + unsigned csr_info_index = 0; + + // When gdb request register N, gdb_get_register_packet() assumes that this + // is register at index N in reg_list. So if there are certain registers + // that don't exist, we need to leave holes in the list (or renumber, but + // it would be nice not to have yet another set of numbers to translate + // between). + for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) { + struct reg *r = &target->reg_cache->reg_list[number]; + r->caller_save = true; + r->dirty = false; + r->valid = false; + r->exist = true; + r->type = &riscv_reg_arch_type; + r->arch_info = target; + r->number = number; + r->size = riscv_xlen(target); + // r->size is set in riscv_invalidate_register_cache, maybe because the + // target is in theory allowed to change XLEN on us. But I expect a lot + // of other things to break in that case as well. + if (number <= GDB_REGNO_XPR31) { + switch (number) { + case GDB_REGNO_ZERO: r->name = "zero"; break; + case GDB_REGNO_RA: r->name = "ra"; break; + case GDB_REGNO_SP: r->name = "sp"; break; + case GDB_REGNO_GP: r->name = "gp"; break; + case GDB_REGNO_TP: r->name = "tp"; break; + case GDB_REGNO_T0: r->name = "t0"; break; + case GDB_REGNO_T1: r->name = "t1"; break; + case GDB_REGNO_T2: r->name = "t2"; break; + case GDB_REGNO_FP: r->name = "fp"; break; + case GDB_REGNO_S1: r->name = "s1"; break; + case GDB_REGNO_A0: r->name = "a0"; break; + case GDB_REGNO_A1: r->name = "a1"; break; + case GDB_REGNO_A2: r->name = "a2"; break; + case GDB_REGNO_A3: r->name = "a3"; break; + case GDB_REGNO_A4: r->name = "a4"; break; + case GDB_REGNO_A5: r->name = "a5"; break; + case GDB_REGNO_A6: r->name = "a6"; break; + case GDB_REGNO_A7: r->name = "a7"; break; + case GDB_REGNO_S2: r->name = "s2"; break; + case GDB_REGNO_S3: r->name = "s3"; break; + case GDB_REGNO_S4: r->name = "s4"; break; + case GDB_REGNO_S5: r->name = "s5"; break; + case GDB_REGNO_S6: r->name = "s6"; break; + case GDB_REGNO_S7: r->name = "s7"; break; + case GDB_REGNO_S8: r->name = "s8"; break; + case GDB_REGNO_S9: r->name = "s9"; break; + case GDB_REGNO_S10: r->name = "s10"; break; + case GDB_REGNO_S11: r->name = "s11"; break; + case GDB_REGNO_T3: r->name = "t3"; break; + case GDB_REGNO_T4: r->name = "t4"; break; + case GDB_REGNO_T5: r->name = "t5"; break; + case GDB_REGNO_T6: r->name = "t6"; break; + } + r->group = "general"; + r->feature = &feature_cpu; + } else if (number == GDB_REGNO_PC) { + sprintf(reg_name, "pc"); + r->group = "general"; + r->feature = &feature_cpu; + } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { + if (riscv_supports_extension(target, 'D')) { + r->reg_data_type = &type_ieee_double; + r->size = 64; + } else if (riscv_supports_extension(target, 'F')) { + r->reg_data_type = &type_ieee_single; + r->size = 32; + } else { + r->exist = false; + } + sprintf(reg_name, "f%d", number - GDB_REGNO_FPR0); + r->group = "float"; + r->feature = &feature_fpu; + } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { + r->group = "csr"; + r->feature = &feature_csr; + unsigned csr_number = number - GDB_REGNO_CSR0; + + while (csr_info[csr_info_index].number < csr_number && + csr_info_index < DIM(csr_info) - 1) { + csr_info_index++; + } + if (csr_info[csr_info_index].number == csr_number) { + r->name = csr_info[csr_info_index].name; + } else { + sprintf(reg_name, "csr%d", csr_number); + // Assume unnamed registers don't exist, unless we have some + // configuration that tells us otherwise. That's important + // because eg. Eclipse crashes if a target has too many + // registers, and apparently has no way of only showing a + // subset of registers in any case. + r->exist = false; + } + + switch (csr_number) { + case CSR_FFLAGS: + r->exist = riscv_supports_extension(target, 'F'); + r->group = "float"; + r->feature = &feature_fpu; + break; + case CSR_FRM: + r->exist = riscv_supports_extension(target, 'F'); + r->group = "float"; + r->feature = &feature_fpu; + break; + case CSR_FCSR: + r->exist = riscv_supports_extension(target, 'F'); + r->group = "float"; + r->feature = &feature_fpu; + break; + } + } else if (number == GDB_REGNO_PRIV) { + sprintf(reg_name, "priv"); + r->group = "general"; + r->feature = &feature_virtual; + } + if (reg_name[0]) { + r->name = reg_name; + } + reg_name += strlen(reg_name) + 1; + assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len); + r->value = &info->reg_cache_values[number]; + } + + return ERROR_OK; +} + diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 8cab47fad..80f6ba204 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -59,7 +59,11 @@ typedef struct { /* The register cache points into here. */ uint64_t reg_cache_values[RISCV_MAX_REGISTERS]; - + + /* Single buffer that contains all register names, instead of calling + * malloc for each register. Needs to be freed when reg_list is freed. */ + char *reg_names; + /* It's possible that each core has a different supported ISA set. */ int xlen[RISCV_MAX_HARTS]; @@ -243,4 +247,6 @@ int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint); int riscv_remove_watchpoint(struct target *target, struct watchpoint *watchpoint); +int riscv_init_registers(struct target *target); + #endif From 37278cf2eca9b1496a5d7c0df88fd3519d7e3c25 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 8 Dec 2017 13:51:40 -0800 Subject: [PATCH 088/127] Make priv register 8 bits. (It's really only 2 bits, but something wonky happens between gdb and OpenOCD if I make it that size.) Change-Id: I562a65cb0ebe5aa0edcc54c251d0fea0e26f9cb1 --- src/target/riscv/riscv.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 46571890b..f1152a34f 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1883,6 +1883,7 @@ int riscv_init_registers(struct target *target) sprintf(reg_name, "priv"); r->group = "general"; r->feature = &feature_virtual; + r->size = 8; } if (reg_name[0]) { r->name = reg_name; From 120477b2a21d20302df86804f25fb8425be558e6 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 8 Dec 2017 15:11:23 -0800 Subject: [PATCH 089/127] Simplify examine() Now we don't have to play tricks fooling other parts of our code that might assert. Change-Id: Ia574378e1f95ed62d297e6b2e852245e58c9ffc9 --- src/target/riscv/riscv-013.c | 62 ++++++++++-------------------------- 1 file changed, 16 insertions(+), 46 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index f22ef714c..a832494b8 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1193,52 +1193,20 @@ static int examine(struct target *target) RISCV_INFO(r); r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); - int original_coreid = target->coreid; for (int i = 0; i < RISCV_MAX_HARTS; ++i) { - /* Fake being a non-RTOS targeted to this core so we can see if - * it exists. This avoids the assertion in - * riscv_set_current_hartid() that ensures non-RTOS targets - * don't touch the harts they're not assigned to. */ - target->coreid = i; - r->hart_count = i + 1; - riscv_set_current_hartid(target, i); - - uint32_t s = dmi_read(target, DMI_DMSTATUS); - if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) { - r->hart_count--; - break; - } - } - // Reset hartid to one that exists. Set coreid to avoid assert in - // riscv_set_current_hartid(). (TODO) - target->coreid = 0; - riscv_set_current_hartid(target, 0); - - target->coreid = original_coreid; - - LOG_DEBUG("Enumerated %d harts", r->hart_count); - - // Assume 32-bit until we discover the real value in examine(). - for (int i = 0; i < riscv_count_harts(target); ++i) { - if (riscv_hart_enabled(target, i)) { - r->xlen[i] = 32; - } - LOG_DEBUG(">>> temporary XLEN for hart %d is %d", i, r->xlen[i]); - } - // Get a functional register cache going. - if (riscv_init_registers(target) != ERROR_OK) - return ERROR_FAIL; - - /* Halt every hart so we can probe them. */ - riscv_halt_all_harts(target); - - /* Find the address of the program buffer, which must be done without - * knowing anything about the target. */ - for (int i = 0; i < riscv_count_harts(target); ++i) { if (!riscv_hart_enabled(target, i)) continue; riscv_set_current_hartid(target, i); + uint32_t s = dmi_read(target, DMI_DMSTATUS); + if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) { + break; + } + r->hart_count = i + 1; + + if (!riscv_is_halted(target)) { + riscv013_halt_current_hart(target); + } /* Without knowing anything else we can at least mess with the * program buffer. */ @@ -1251,25 +1219,27 @@ static int examine(struct target *target) r->xlen[i] = 32; } - r->misa = riscv_get_register_on_hart(target, i, GDB_REGNO_MISA); + // Now init registers based on what we discovered. + if (riscv_init_registers(target) != ERROR_OK) + return ERROR_FAIL; + r->misa = riscv_get_register_on_hart(target, i, GDB_REGNO_MISA); /* Display this as early as possible to help people who are using * really slow simulators. */ LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, i, r->xlen[i], r->misa); } + LOG_DEBUG("Enumerated %d harts", r->hart_count); + /* Then we check the number of triggers availiable to each hart. */ riscv_enumerate_triggers(target); /* Resumes all the harts, so the debugger can later pause them. */ + // TODO: Only do this if the harts were halted to start with. riscv_resume_all_harts(target); target->state = TARGET_RUNNING; - // Now reinit registers based on what we discovered. - if (riscv_init_registers(target) != ERROR_OK) - return ERROR_FAIL; - target_set_examined(target); if (target->rtos) { From 46715c7d8adfda02d50fcd9d19ff8899ab1f69bf Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 11 Dec 2017 12:52:48 -0800 Subject: [PATCH 090/127] Remove no-longer-true comment. Change-Id: I888680e73682582438a0de0496238867f1604754 --- src/target/riscv/riscv.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index f1152a34f..ef241afde 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1403,7 +1403,6 @@ void riscv_invalidate_register_cache(struct target *target) { RISCV_INFO(r); - /* Update the register list's widths. */ register_cache_invalidate(target->reg_cache); for (size_t i = 0; i < GDB_REGNO_COUNT; ++i) { struct reg *reg = &target->reg_cache->reg_list[i]; From ec1c814017af4a4dab865be99dcc31c63d45da36 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 11 Dec 2017 14:21:41 -0800 Subject: [PATCH 091/127] Don't rely on hart count until it's correct. Change-Id: I4e05eb091823b2e0fb481ca0b599072ba1ca70f2 --- src/target/riscv/riscv-013.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index a832494b8..1fff99016 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1194,7 +1194,7 @@ static int examine(struct target *target) r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); for (int i = 0; i < RISCV_MAX_HARTS; ++i) { - if (!riscv_hart_enabled(target, i)) + if (!riscv_rtos_enabled(target) && i != target->coreid) continue; riscv_set_current_hartid(target, i); From 10c17fdf17548d5ee32ae23023bb62e532bfef03 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 11 Dec 2017 14:59:11 -0800 Subject: [PATCH 092/127] Read misa before using it to check for extensions. Change-Id: I7a172d83055d8bd833e3349a5b22b47dd5f31f5c --- src/target/riscv/riscv-013.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 1fff99016..6083ba8f5 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1219,11 +1219,12 @@ static int examine(struct target *target) r->xlen[i] = 32; } + register_read_direct(target, &r->misa, GDB_REGNO_MISA); + // Now init registers based on what we discovered. if (riscv_init_registers(target) != ERROR_OK) return ERROR_FAIL; - r->misa = riscv_get_register_on_hart(target, i, GDB_REGNO_MISA); /* Display this as early as possible to help people who are using * really slow simulators. */ LOG_DEBUG(" hart %d: XLEN=%d, misa=0x%" PRIx64, i, r->xlen[i], From 56ad0e5b300c9f2c68637922972e12e6ff2d06dd Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 11 Dec 2017 15:32:01 -0800 Subject: [PATCH 093/127] Avoid another assertion failure. Change-Id: Ia54f778152974164697b712c360918e17a127d95 --- src/target/riscv/riscv-013.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6083ba8f5..98a63522f 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1193,11 +1193,15 @@ static int examine(struct target *target) RISCV_INFO(r); r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); + // Don't call any riscv_* functions until after we've counted the number of + // cores and initialized registers. for (int i = 0; i < RISCV_MAX_HARTS; ++i) { if (!riscv_rtos_enabled(target) && i != target->coreid) continue; - riscv_set_current_hartid(target, i); + r->current_hartid = i; + riscv013_select_current_hart(target); + uint32_t s = dmi_read(target, DMI_DMSTATUS); if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) { break; From c7cddd2b5c4d78e72c617919f40dd2cc26ed1e91 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 11 Dec 2017 15:32:15 -0800 Subject: [PATCH 094/127] Remove some debug printfs. Change-Id: I09989d4c0e102889ecb0eedbd3f4138f8b7bdb8c --- src/target/riscv/riscv.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index ef241afde..85876214a 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1247,7 +1247,6 @@ void riscv_info_init(struct target *target, riscv_info_t *r) memset(r, 0, sizeof(*r)); r->dtm_version = 1; r->registers_initialized = false; - LOG_DEBUG(">>> current_hartid=%d", target->coreid); r->current_hartid = target->coreid; memset(r->trigger_unique_id, 0xff, sizeof(r->trigger_unique_id)); @@ -1360,7 +1359,6 @@ int riscv_xlen(const struct target *target) int riscv_xlen_of_hart(const struct target *target, int hartid) { RISCV_INFO(r); - LOG_DEBUG(">>> xlen[%d] = %d", hartid, r->xlen[hartid]); assert(r->xlen[hartid] != -1); return r->xlen[hartid]; } From f55d1a20305d6acf801db3aff024a8b4eed2acad Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 14 Dec 2017 13:06:31 -0800 Subject: [PATCH 095/127] Give FPRs ABI names. Change-Id: If198d10e16671b9868836e23386aaf8d4b05f317 --- src/target/riscv/gdb_regs.h | 34 +++++++++++++++++++++++++++++++++- src/target/riscv/riscv.c | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h index 3f60d018d..731f3e36c 100644 --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -41,7 +41,39 @@ enum gdb_regno { GDB_REGNO_PC = 32, GDB_REGNO_FPR0 = 33, - GDB_REGNO_FPR31 = GDB_REGNO_FPR0 + 31, + GDB_REGNO_FT0 = GDB_REGNO_FPR0, + GDB_REGNO_FT1, + GDB_REGNO_FT2, + GDB_REGNO_FT3, + GDB_REGNO_FT4, + GDB_REGNO_FT5, + GDB_REGNO_FT6, + GDB_REGNO_FT7, + GDB_REGNO_FS0, + GDB_REGNO_FS1, + GDB_REGNO_FA0, + GDB_REGNO_FA1, + GDB_REGNO_FA2, + GDB_REGNO_FA3, + GDB_REGNO_FA4, + GDB_REGNO_FA5, + GDB_REGNO_FA6, + GDB_REGNO_FA7, + GDB_REGNO_FS2, + GDB_REGNO_FS3, + GDB_REGNO_FS4, + GDB_REGNO_FS5, + GDB_REGNO_FS6, + GDB_REGNO_FS7, + GDB_REGNO_FS8, + GDB_REGNO_FS9, + GDB_REGNO_FS10, + GDB_REGNO_FS11, + GDB_REGNO_FT8, + GDB_REGNO_FT9, + GDB_REGNO_FT10, + GDB_REGNO_FT11, + GDB_REGNO_FPR31 = GDB_REGNO_FT11, GDB_REGNO_CSR0 = 65, GDB_REGNO_TSELECT = CSR_TSELECT + GDB_REGNO_CSR0, GDB_REGNO_TDATA1 = CSR_TDATA1 + GDB_REGNO_CSR0, diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 85876214a..6d41620f9 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1835,7 +1835,40 @@ int riscv_init_registers(struct target *target) } else { r->exist = false; } - sprintf(reg_name, "f%d", number - GDB_REGNO_FPR0); + switch (number) { + case GDB_REGNO_FT0: r->name = "ft0"; break; + case GDB_REGNO_FT1: r->name = "ft1"; break; + case GDB_REGNO_FT2: r->name = "ft2"; break; + case GDB_REGNO_FT3: r->name = "ft3"; break; + case GDB_REGNO_FT4: r->name = "ft4"; break; + case GDB_REGNO_FT5: r->name = "ft5"; break; + case GDB_REGNO_FT6: r->name = "ft6"; break; + case GDB_REGNO_FT7: r->name = "ft7"; break; + case GDB_REGNO_FS0: r->name = "fs0"; break; + case GDB_REGNO_FS1: r->name = "fs1"; break; + case GDB_REGNO_FA0: r->name = "fa0"; break; + case GDB_REGNO_FA1: r->name = "fa1"; break; + case GDB_REGNO_FA2: r->name = "fa2"; break; + case GDB_REGNO_FA3: r->name = "fa3"; break; + case GDB_REGNO_FA4: r->name = "fa4"; break; + case GDB_REGNO_FA5: r->name = "fa5"; break; + case GDB_REGNO_FA6: r->name = "fa6"; break; + case GDB_REGNO_FA7: r->name = "fa7"; break; + case GDB_REGNO_FS2: r->name = "fs2"; break; + case GDB_REGNO_FS3: r->name = "fs3"; break; + case GDB_REGNO_FS4: r->name = "fs4"; break; + case GDB_REGNO_FS5: r->name = "fs5"; break; + case GDB_REGNO_FS6: r->name = "fs6"; break; + case GDB_REGNO_FS7: r->name = "fs7"; break; + case GDB_REGNO_FS8: r->name = "fs8"; break; + case GDB_REGNO_FS9: r->name = "fs9"; break; + case GDB_REGNO_FS10: r->name = "fs10"; break; + case GDB_REGNO_FS11: r->name = "fs11"; break; + case GDB_REGNO_FT8: r->name = "ft8"; break; + case GDB_REGNO_FT9: r->name = "ft9"; break; + case GDB_REGNO_FT10: r->name = "ft10"; break; + case GDB_REGNO_FT11: r->name = "ft11"; break; + } r->group = "float"; r->feature = &feature_fpu; } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { From 5f86f7208d60ed92e70a04602462015751dff621 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 14 Dec 2017 13:43:14 -0800 Subject: [PATCH 096/127] Hide supervisor registers if there is no S mode. Also update encoding.h. Change-Id: I275be7de0aa1af64d13ea191b9f4ff391cfb16dc --- src/target/riscv/encoding.h | 40 ++++++++++++++++++------------------- src/target/riscv/riscv.c | 20 +++++++++++-------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/src/target/riscv/encoding.h b/src/target/riscv/encoding.h index 8ec134596..c109ce189 100644 --- a/src/target/riscv/encoding.h +++ b/src/target/riscv/encoding.h @@ -113,19 +113,19 @@ #define PRV_H 2 #define PRV_M 3 -#define SPTBR32_MODE 0x80000000 -#define SPTBR32_ASID 0x7FC00000 -#define SPTBR32_PPN 0x003FFFFF -#define SPTBR64_MODE 0xF000000000000000 -#define SPTBR64_ASID 0x0FFFF00000000000 -#define SPTBR64_PPN 0x00000FFFFFFFFFFF +#define SATP32_MODE 0x80000000 +#define SATP32_ASID 0x7FC00000 +#define SATP32_PPN 0x003FFFFF +#define SATP64_MODE 0xF000000000000000 +#define SATP64_ASID 0x0FFFF00000000000 +#define SATP64_PPN 0x00000FFFFFFFFFFF -#define SPTBR_MODE_OFF 0 -#define SPTBR_MODE_SV32 1 -#define SPTBR_MODE_SV39 8 -#define SPTBR_MODE_SV48 9 -#define SPTBR_MODE_SV57 10 -#define SPTBR_MODE_SV64 11 +#define SATP_MODE_OFF 0 +#define SATP_MODE_SV32 1 +#define SATP_MODE_SV39 8 +#define SATP_MODE_SV48 9 +#define SATP_MODE_SV57 10 +#define SATP_MODE_SV64 11 #define PMP_R 0x01 #define PMP_W 0x02 @@ -177,12 +177,12 @@ # define MSTATUS_SD MSTATUS64_SD # define SSTATUS_SD SSTATUS64_SD # define RISCV_PGLEVEL_BITS 9 -# define SPTBR_MODE SPTBR64_MODE +# define SATP_MODE SATP64_MODE #else # define MSTATUS_SD MSTATUS32_SD # define SSTATUS_SD SSTATUS32_SD # define RISCV_PGLEVEL_BITS 10 -# define SPTBR_MODE SPTBR32_MODE +# define SATP_MODE SATP32_MODE #endif #define RISCV_PGSHIFT 12 #define RISCV_PGSIZE (1 << RISCV_PGSHIFT) @@ -790,9 +790,9 @@ #define CSR_SSCRATCH 0x140 #define CSR_SEPC 0x141 #define CSR_SCAUSE 0x142 -#define CSR_SBADADDR 0x143 +#define CSR_STVAL 0x143 #define CSR_SIP 0x144 -#define CSR_SPTBR 0x180 +#define CSR_SATP 0x180 #define CSR_MSTATUS 0x300 #define CSR_MISA 0x301 #define CSR_MEDELEG 0x302 @@ -803,7 +803,7 @@ #define CSR_MSCRATCH 0x340 #define CSR_MEPC 0x341 #define CSR_MCAUSE 0x342 -#define CSR_MBADADDR 0x343 +#define CSR_MTVAL 0x343 #define CSR_MIP 0x344 #define CSR_PMPCFG0 0x3a0 #define CSR_PMPCFG1 0x3a1 @@ -1282,9 +1282,9 @@ DECLARE_CSR(scounteren, CSR_SCOUNTEREN) DECLARE_CSR(sscratch, CSR_SSCRATCH) DECLARE_CSR(sepc, CSR_SEPC) DECLARE_CSR(scause, CSR_SCAUSE) -DECLARE_CSR(sbadaddr, CSR_SBADADDR) +DECLARE_CSR(stval, CSR_STVAL) DECLARE_CSR(sip, CSR_SIP) -DECLARE_CSR(sptbr, CSR_SPTBR) +DECLARE_CSR(satp, CSR_SATP) DECLARE_CSR(mstatus, CSR_MSTATUS) DECLARE_CSR(misa, CSR_MISA) DECLARE_CSR(medeleg, CSR_MEDELEG) @@ -1295,7 +1295,7 @@ DECLARE_CSR(mcounteren, CSR_MCOUNTEREN) DECLARE_CSR(mscratch, CSR_MSCRATCH) DECLARE_CSR(mepc, CSR_MEPC) DECLARE_CSR(mcause, CSR_MCAUSE) -DECLARE_CSR(mbadaddr, CSR_MBADADDR) +DECLARE_CSR(mtval, CSR_MTVAL) DECLARE_CSR(mip, CSR_MIP) DECLARE_CSR(pmpcfg0, CSR_PMPCFG0) DECLARE_CSR(pmpcfg1, CSR_PMPCFG1) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 6d41620f9..e7ead4ceb 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1894,20 +1894,24 @@ int riscv_init_registers(struct target *target) switch (csr_number) { case CSR_FFLAGS: - r->exist = riscv_supports_extension(target, 'F'); - r->group = "float"; - r->feature = &feature_fpu; - break; case CSR_FRM: - r->exist = riscv_supports_extension(target, 'F'); - r->group = "float"; - r->feature = &feature_fpu; - break; case CSR_FCSR: r->exist = riscv_supports_extension(target, 'F'); r->group = "float"; r->feature = &feature_fpu; break; + case CSR_SSTATUS: + case CSR_STVEC: + case CSR_SIP: + case CSR_SIE: + case CSR_SCOUNTEREN: + case CSR_SSCRATCH: + case CSR_SEPC: + case CSR_SCAUSE: + case CSR_STVAL: + case CSR_SATP: + r->exist = riscv_supports_extension(target, 'S'); + break; } } else if (number == GDB_REGNO_PRIV) { sprintf(reg_name, "priv"); From 11c261cd50d35e70ccf6fbdc76f23230d5b9b557 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 15 Dec 2017 13:27:26 -0800 Subject: [PATCH 097/127] Add `riscv expose_csrs` command. This lets users tell OpenOCD which non-standard CSRs exist on their target, that will also be accessible and whose existence will be communicated to gdb. Change-Id: I56163a9fcb84ad7ebe815ae74fbd9fcc208f5a9d --- src/target/riscv/riscv.c | 110 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index e7ead4ceb..2f1084f83 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -188,6 +188,14 @@ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; bool riscv_use_scratch_ram = false; uint64_t riscv_scratch_ram_address = 0; +/* In addition to the ones in the standard spec, we'll also expose additional + * CSRs in this list. + * The list is either NULL, or a series of ranges (inclusive), terminated with + * 1,0. */ +struct { + uint16_t low, high; +} *expose_csr; + static uint32_t dtmcontrol_scan(struct target *target, uint32_t out) { struct scan_field field; @@ -1165,6 +1173,88 @@ COMMAND_HANDLER(riscv_set_scratch_ram) return ERROR_OK; } +void parse_error(const char *string, char c, unsigned position) +{ + char buf[position+2]; + for (unsigned i = 0; i < position; i++) + buf[i] = ' '; + buf[position] = '^'; + buf[position + 1] = 0; + + LOG_ERROR("Parse error at character %c in:", c); + LOG_ERROR("%s", string); + LOG_ERROR("%s", buf); +} + +COMMAND_HANDLER(riscv_set_expose_csrs) +{ + if (CMD_ARGC != 1) { + LOG_ERROR("Command takes exactly 1 parameter"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + for (unsigned pass = 0; pass < 2; pass++) { + unsigned range = 0; + unsigned low = 0; + bool parse_low = true; + unsigned high = 0; + for (unsigned i = 0; i == 0 || CMD_ARGV[0][i-1]; i++) { + char c = CMD_ARGV[0][i]; + if isspace(c) { + // Ignore whitespace. + continue; + } + + if (parse_low) { + if (isdigit(c)) { + low *= 10; + low += c - '0'; + } else if (c == '-') { + parse_low = false; + } else if (c == ',' || c == 0) { + if (pass == 1) { + expose_csr[range].low = low; + expose_csr[range].high = low; + } + low = 0; + range++; + } else { + parse_error(CMD_ARGV[0], c, i); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + } else { + if (isdigit(c)) { + high *= 10; + high += c - '0'; + } else if (c == ',' || c == 0) { + parse_low = true; + if (pass == 1) { + expose_csr[range].low = low; + expose_csr[range].high = high; + } + low = 0; + high = 0; + range++; + } else { + parse_error(CMD_ARGV[0], c, i); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + } + + if (pass == 0) { + if (expose_csr) + free(expose_csr); + expose_csr = calloc(range + 2, sizeof(*expose_csr)); + } else { + expose_csr[range].low = 1; + expose_csr[range].high = 0; + } + } + return ERROR_OK; +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "set_command_timeout_sec", @@ -1187,6 +1277,15 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "riscv set_scratch_ram none|[address]", .help = "Set address of 16 bytes of scratch RAM the debugger can use, or 'none'." }, + { + .name = "expose_csrs", + .handler = riscv_set_expose_csrs, + .mode = COMMAND_ANY, + .usage = "riscv expose_csrs n0[-m0][,n0[-m0]]...", + .help = "Configure a list of inclusive ranges for CSRs to expose in " + "addition to the standard ones. This must be executed before " + "`init`." + }, COMMAND_REGISTRATION_DONE }; @@ -1913,6 +2012,17 @@ int riscv_init_registers(struct target *target) r->exist = riscv_supports_extension(target, 'S'); break; } + + if (!r->exist && expose_csr) { + for (unsigned i = 0; expose_csr[i].low <= expose_csr[i].high; i++) { + if (csr_number >= expose_csr[i].low && csr_number <= expose_csr[i].high) { + LOG_INFO("Exposing additional CSR %d", csr_number); + r->exist = true; + break; + } + } + } + } else if (number == GDB_REGNO_PRIV) { sprintf(reg_name, "priv"); r->group = "general"; From 84d68579eb55c1b4aba4fddc11b33ae746f84d23 Mon Sep 17 00:00:00 2001 From: Jiri Kastner Date: Sat, 16 Dec 2017 22:17:52 +0100 Subject: [PATCH 098/127] configs for Marvell Armada 3700 Change-Id: I367f39c9bc9e58380d6d5b500d5368d5173d96bd Signed-off-by: Jiri Kastner Signed-off-by: Forest Crossman Reviewed-on: http://openocd.zylin.com/4302 Tested-by: jenkins Reviewed-by: Paul Fertser --- tcl/target/marvell/88f3710.cfg | 5 +++ tcl/target/marvell/88f3720.cfg | 5 +++ tcl/target/marvell/88f37x0.cfg | 68 ++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 tcl/target/marvell/88f3710.cfg create mode 100644 tcl/target/marvell/88f3720.cfg create mode 100644 tcl/target/marvell/88f37x0.cfg diff --git a/tcl/target/marvell/88f3710.cfg b/tcl/target/marvell/88f3710.cfg new file mode 100644 index 000000000..6e35f293d --- /dev/null +++ b/tcl/target/marvell/88f3710.cfg @@ -0,0 +1,5 @@ +# Marvell Armada 3710 + +set CORES 1 + +source [find target/marvell/88f37x0.cfg] diff --git a/tcl/target/marvell/88f3720.cfg b/tcl/target/marvell/88f3720.cfg new file mode 100644 index 000000000..799d614ba --- /dev/null +++ b/tcl/target/marvell/88f3720.cfg @@ -0,0 +1,5 @@ +# Marvell Armada 3720 + +set CORES 2 + +source [find target/marvell/88f37x0.cfg] diff --git a/tcl/target/marvell/88f37x0.cfg b/tcl/target/marvell/88f37x0.cfg new file mode 100644 index 000000000..dba7da21e --- /dev/null +++ b/tcl/target/marvell/88f37x0.cfg @@ -0,0 +1,68 @@ +# Main file for Marvell Armada 3700 series targets +# +# !!!!!! +# +# This file should not be included directly. Instead, please include +# either marvell/88f3710.cfg or marvell/88f3720.cfg, which set the needed +# variables to the appropriate values. +# +# !!!!!! + +# Armada 3700 supports both JTAG and SWD transports. +source [find target/swj-dp.tcl] + +if { [info exists CORES] } { + set _cores $CORES +} else { + error "CORES not set. Please do not include marvell/88f37x0.cfg directly, but the specific chip configuration file (marvell/88f3710.cfg, marvell/88f3720.cfg, etc.)." +} + +if { [info exists CHIPNAME] } { + set _CHIPNAME $CHIPNAME +} else { + set _CHIPNAME [format a37%s0 $_cores] +} + +set _ctis {0x80820000 0x80920000} + +# +# Main DAP +# +if { [info exists DAP_TAPID] } { + set _DAP_TAPID $DAP_TAPID +} else { + set _DAP_TAPID 0x4ba00477 +} + +# declare the one JTAG tap to access the DAP +swj_newdap $_CHIPNAME dap -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_DAP_TAPID -ignore-version -enable + +# declare the main application cores +set _TARGETNAME $_CHIPNAME.cpu +set _smp_command "" + +for { set _core 0 } { $_core < $_cores } { incr _core 1 } { + + set _command "target create ${_TARGETNAME}$_core aarch64 \ + -chain-position $_CHIPNAME.dap -coreid $_core \ + -ctibase [lindex $_ctis $_core]" + + if { $_core != 0 } { + # non-boot core examination may fail + set _command "$_command -defer-examine" + set _smp_command "$_smp_command ${_TARGETNAME}$_core" + } else { + # uncomment when "hawt" rtos is merged + # set _command "$_command -rtos hawt" + set _smp_command "target smp ${_TARGETNAME}$_core" + } + + eval $_command +} + +eval $_smp_command + +# declare the auxiliary Cortex-M3 core on AP #3 +target create ${_TARGETNAME}.m3 cortex_m -chain-position $_CHIPNAME.dap -ap-num 3 -defer-examine + +targets ${_TARGETNAME}0 From 1c2e3d41de30c5e47d3fc8eda3de0a0a8229895a Mon Sep 17 00:00:00 2001 From: Jiri Kastner Date: Sat, 16 Dec 2017 22:21:14 +0100 Subject: [PATCH 099/127] config for ESPRESSObin from Globalscale Tech. Inc. Change-Id: I77f536a9d2e901ebcef0a7dd0f205e5332b1d382 Signed-off-by: Jiri Kastner Reviewed-on: http://openocd.zylin.com/4303 Tested-by: jenkins Reviewed-by: Forest Crossman Reviewed-by: Tomas Vanek --- tcl/board/gti/espressobin.cfg | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tcl/board/gti/espressobin.cfg diff --git a/tcl/board/gti/espressobin.cfg b/tcl/board/gti/espressobin.cfg new file mode 100644 index 000000000..20d0452fd --- /dev/null +++ b/tcl/board/gti/espressobin.cfg @@ -0,0 +1,7 @@ +# config for ESPRESSObin from +# Globalscale Technologies Inc. + +# srst is isolated through missing resistor +reset_config trst_only + +source [find target/marvell/88f3720.cfg] From fa385bdcd5c2825dc625d6a8f6678108146e9866 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 21 Dec 2017 12:43:22 -0800 Subject: [PATCH 100/127] Use parens after if. I'm surprised this built with gcc before. Fixes Issue #150. Change-Id: I24d2957783c66ad53d5b532a4e930349a2059a97 --- src/target/riscv/riscv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 2f1084f83..0af503217 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1200,7 +1200,7 @@ COMMAND_HANDLER(riscv_set_expose_csrs) unsigned high = 0; for (unsigned i = 0; i == 0 || CMD_ARGV[0][i-1]; i++) { char c = CMD_ARGV[0][i]; - if isspace(c) { + if (isspace(c)) { // Ignore whitespace. continue; } From 5892b2625913449ff3712631ace3f3b1b2f88fad Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 21 Dec 2017 15:05:12 -0800 Subject: [PATCH 101/127] Update debug_defines to the one used with spike. Change-Id: I627c6ee557d98239227324c33f9b89f6280cbf93 --- src/target/riscv/debug_defines.h | 70 ++++++++++++++++++++++---------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index 6067dbec0..1d3e1c092 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -544,6 +544,19 @@ #define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET) #define DMI_DMSTATUS 0x11 /* +* Gets set if the Debug Module was accessed incorrectly. +* +* 0 (none): No error. +* +* 1 (badaddr): There was an access to an unimplemented Debug Module +* address. +* +* 7 (other): An access failed for another reason. + */ +#define DMI_DMSTATUS_DMERR_OFFSET 24 +#define DMI_DMSTATUS_DMERR_LENGTH 3 +#define DMI_DMSTATUS_DMERR (0x7U << DMI_DMSTATUS_DMERR_OFFSET) +/* * If 1, then there is an implicit {\tt ebreak} instruction at the * non-existent word immediately after the Program Buffer. This saves * the debugger from having to write the {\tt ebreak} itself, and @@ -555,26 +568,27 @@ #define DMI_DMSTATUS_IMPEBREAK_LENGTH 1 #define DMI_DMSTATUS_IMPEBREAK (0x1U << DMI_DMSTATUS_IMPEBREAK_OFFSET) /* -* Gets set if the Debug Module was accessed incorrectly. -* -* 0 (none): No error. -* -* 1 (badaddr): There was an access to an unimplemented Debug Module -* address. -* -* 7 (other): An access failed for another reason. +* This field is 1 when all currently selected harts have been reset but the reset has not been acknowledged. */ -#define DMI_DMSTATUS_DMERR_OFFSET 18 -#define DMI_DMSTATUS_DMERR_LENGTH 3 -#define DMI_DMSTATUS_DMERR (0x7U << DMI_DMSTATUS_DMERR_OFFSET) +#define DMI_DMSTATUS_ALLHAVERESET_OFFSET 19 +#define DMI_DMSTATUS_ALLHAVERESET_LENGTH 1 +#define DMI_DMSTATUS_ALLHAVERESET (0x1U << DMI_DMSTATUS_ALLHAVERESET_OFFSET) /* -* This field is 1 when all currently selected harts have acknowledged the previous \Fresumereq. +* This field is 1 when any currently selected hart has been reset but the reset has not been acknowledged. + */ +#define DMI_DMSTATUS_ANYHAVERESET_OFFSET 18 +#define DMI_DMSTATUS_ANYHAVERESET_LENGTH 1 +#define DMI_DMSTATUS_ANYHAVERESET (0x1U << DMI_DMSTATUS_ANYHAVERESET_OFFSET) +/* +* This field is 1 when all currently selected harts have acknowledged +* the previous resume request. */ #define DMI_DMSTATUS_ALLRESUMEACK_OFFSET 17 #define DMI_DMSTATUS_ALLRESUMEACK_LENGTH 1 #define DMI_DMSTATUS_ALLRESUMEACK (0x1U << DMI_DMSTATUS_ALLRESUMEACK_OFFSET) /* -* This field is 1 when any currently selected hart has acknowledged the previous \Fresumereq. +* This field is 1 when any currently selected hart has acknowledged +* the previous resume request. */ #define DMI_DMSTATUS_ANYRESUMEACK_OFFSET 16 #define DMI_DMSTATUS_ANYRESUMEACK_LENGTH 1 @@ -675,11 +689,12 @@ #define DMI_DMSTATUS_VERSION (0xfU << DMI_DMSTATUS_VERSION_OFFSET) #define DMI_DMCONTROL 0x10 /* -* Halt request signal for all currently selected harts. When set to -* 1, each selected hart will halt if it is not currently halted. +* Writes the halt request bit for all currently selected harts. +* When set to 1, each selected hart will halt if it is not currently +* halted. * * Writing 1 or 0 has no effect on a hart which is already halted, but -* the bit should be cleared to 0 before the hart is resumed. +* the bit must be cleared to 0 before the hart is resumed. * * Writes apply to the new value of \Fhartsel and \Fhasel. */ @@ -687,10 +702,12 @@ #define DMI_DMCONTROL_HALTREQ_LENGTH 1 #define DMI_DMCONTROL_HALTREQ (0x1U << DMI_DMCONTROL_HALTREQ_OFFSET) /* -* Resume request signal for all currently selected harts. When set to 1, -* each selected hart will resume if it is currently halted. +* Writes the resume request bit for all currently selected harts. +* When set to 1, each selected hart will resume if it is currently +* halted. * -* This bit is ignored while \Fhaltreq is set. +* The resume request bit is ignored while the halt request bit is +* set. * * Writes apply to the new value of \Fhartsel and \Fhasel. */ @@ -698,9 +715,9 @@ #define DMI_DMCONTROL_RESUMEREQ_LENGTH 1 #define DMI_DMCONTROL_RESUMEREQ (0x1U << DMI_DMCONTROL_RESUMEREQ_OFFSET) /* -* This optional bit controls reset to all the currently selected harts. -* To perform a reset the debugger writes 1, and then writes 0 to -* deassert the reset signal. +* This optional field writes the reset bit for all the currently +* selected harts. To perform a reset the debugger writes 1, and then +* writes 0 to deassert the reset signal. * * If this feature is not implemented, the bit always stays 0, so * after writing 1 the debugger can read the register back to see if @@ -712,6 +729,15 @@ #define DMI_DMCONTROL_HARTRESET_LENGTH 1 #define DMI_DMCONTROL_HARTRESET (0x1U << DMI_DMCONTROL_HARTRESET_OFFSET) /* +* Writing 1 to this bit clears the {\tt havereset} bits for +* any selected harts. +* +* Writes apply to the new value of \Fhartsel and \Fhasel. + */ +#define DMI_DMCONTROL_ACKHAVERESET_OFFSET 28 +#define DMI_DMCONTROL_ACKHAVERESET_LENGTH 1 +#define DMI_DMCONTROL_ACKHAVERESET (0x1U << DMI_DMCONTROL_ACKHAVERESET_OFFSET) +/* * Selects the definition of currently selected harts. * * 0: There is a single currently selected hart, that selected by \Fhartsel. From fadf2c1b48789d6f84129875afa7fefae130add2 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 21 Dec 2017 16:23:46 -0800 Subject: [PATCH 102/127] Make functions static. Free memory. Change-Id: Iadf7b2a926d6d5abc4c8daa2f5620886bcb09b31 --- src/flash/nor/fespi.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index 9b53d2d89..04f037dfb 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -598,7 +598,7 @@ struct algorithm_steps { uint8_t **steps; }; -struct algorithm_steps *as_new(unsigned size) +static struct algorithm_steps *as_new(unsigned size) { struct algorithm_steps *as = calloc(1, sizeof(struct algorithm_steps)); as->size = size; @@ -606,7 +606,7 @@ struct algorithm_steps *as_new(unsigned size) return as; } -struct algorithm_steps *as_delete(struct algorithm_steps *as) +static struct algorithm_steps *as_delete(struct algorithm_steps *as) { for (unsigned step = 0; step < as->used; step++) { free(as->steps[step]); @@ -616,7 +616,7 @@ struct algorithm_steps *as_delete(struct algorithm_steps *as) return NULL; } -int as_empty(struct algorithm_steps *as) +static int as_empty(struct algorithm_steps *as) { for (unsigned s = 0; s < as->used; s++) { if (as->steps[s][0] != STEP_NOP) @@ -626,7 +626,7 @@ int as_empty(struct algorithm_steps *as) } // Return size of compiled program. -unsigned as_compile(struct algorithm_steps *as, uint8_t *target, +static unsigned as_compile(struct algorithm_steps *as, uint8_t *target, unsigned target_size) { unsigned offset = 0; @@ -693,7 +693,7 @@ unsigned as_compile(struct algorithm_steps *as, uint8_t *target, return offset; } -void as_add_tx(struct algorithm_steps *as, unsigned count, const uint8_t *data) +static void as_add_tx(struct algorithm_steps *as, unsigned count, const uint8_t *data) { LOG_DEBUG("count=%d", count); while (count > 0) { @@ -709,14 +709,14 @@ void as_add_tx(struct algorithm_steps *as, unsigned count, const uint8_t *data) } } -void as_add_tx1(struct algorithm_steps *as, uint8_t byte) +static void as_add_tx1(struct algorithm_steps *as, uint8_t byte) { uint8_t data[1]; data[0] = byte; as_add_tx(as, 1, data); } -void as_add_write_reg(struct algorithm_steps *as, uint8_t offset, uint8_t data) +static void as_add_write_reg(struct algorithm_steps *as, uint8_t offset, uint8_t data) { assert(as->used < as->size); as->steps[as->used] = malloc(3); @@ -726,7 +726,7 @@ void as_add_write_reg(struct algorithm_steps *as, uint8_t offset, uint8_t data) as->used++; } -void as_add_txwm_wait(struct algorithm_steps *as) +static void as_add_txwm_wait(struct algorithm_steps *as) { assert(as->used < as->size); as->steps[as->used] = malloc(1); @@ -734,7 +734,7 @@ void as_add_txwm_wait(struct algorithm_steps *as) as->used++; } -void as_add_wip_wait(struct algorithm_steps *as) +static void as_add_wip_wait(struct algorithm_steps *as) { assert(as->used < as->size); as->steps[as->used] = malloc(1); @@ -742,7 +742,7 @@ void as_add_wip_wait(struct algorithm_steps *as) as->used++; } -void as_add_set_dir(struct algorithm_steps *as, bool dir) +static void as_add_set_dir(struct algorithm_steps *as, bool dir) { assert(as->used < as->size); as->steps[as->used] = malloc(2); @@ -964,6 +964,8 @@ err: target_free_working_area(target, algorithm_wa); } + as_delete(as); + /* Switch to HW mode before return to prompt */ FESPI_ENABLE_HW_MODE(); return retval; From 1f66c7827b739abd3b9ebe16c39cb66cffb19ccd Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 21 Dec 2017 16:41:50 -0800 Subject: [PATCH 103/127] Fix flash/run algorithm with new register names Change-Id: I8f539c880ee5da864956f56943411b228d8a5812 --- src/flash/nor/fespi.c | 4 ++-- src/target/riscv/riscv.c | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index 04f037dfb..15ef66e1e 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -792,8 +792,8 @@ static int steps_execute(struct algorithm_steps *as, int xlen = riscv_xlen(target); struct reg_param reg_params[2]; - init_reg_param(®_params[0], "x10", xlen, PARAM_OUT); - init_reg_param(®_params[1], "x11", xlen, PARAM_OUT); + init_reg_param(®_params[0], "a0", xlen, PARAM_OUT); + init_reg_param(®_params[1], "a1", xlen, PARAM_OUT); buf_set_u64(reg_params[0].value, 0, xlen, ctrl_base); buf_set_u64(reg_params[1].value, 0, xlen, data_wa->address); while (!as_empty(as)) { diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 9078fabd2..053655ca6 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -854,10 +854,13 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, uint8_t mstatus_bytes[8]; LOG_DEBUG("Disabling Interrupts"); - char mstatus_name[20]; - sprintf(mstatus_name, "csr%d", CSR_MSTATUS); struct reg *reg_mstatus = register_get_by_name(target->reg_cache, - mstatus_name, 1); + "mstatus", 1); + if (!reg_mstatus) { + LOG_ERROR("Couldn't find mstatus!"); + return ERROR_FAIL; + } + reg_mstatus->type->get(reg_mstatus); current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size); uint64_t ie_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; From d942bce9964157d5e1a7235fc00445cbb36fa627 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 22 Dec 2017 14:35:38 -0800 Subject: [PATCH 104/127] Conform to OpenOCD style guide. Change-Id: I2b23ac79639ed40e9d59db5c52ea2196df0349bc --- .travis.yml | 4 +- src/flash/nor/fespi.c | 235 ++++++------- src/jtag/drivers/remote_bitbang.c | 6 +- src/rtos/riscv_debug.c | 5 +- src/server/gdb_server.c | 6 +- src/target/riscv/asm.h | 4 +- src/target/riscv/batch.c | 4 +- src/target/riscv/debug_defines.h | 16 +- src/target/riscv/gdb_regs.h | 4 +- src/target/riscv/opcodes.h | 37 ++- src/target/riscv/program.c | 7 +- src/target/riscv/riscv-011.c | 536 +++++++++++++++--------------- src/target/riscv/riscv-013.c | 261 +++++++-------- src/target/riscv/riscv.c | 452 +++++++++++++++---------- src/target/riscv/riscv.h | 2 +- src/target/target.c | 4 +- 16 files changed, 848 insertions(+), 735 deletions(-) diff --git a/.travis.yml b/.travis.yml index 2ec1ede93..35bf8c435 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,7 +28,7 @@ matrix: - os: linux env: - - BUILD=i686-linux-gnu + - BUILD=i686-linux-gnu - CFLAGS=-m32 - EXECUTABLE=openocd compiler: clang @@ -38,7 +38,7 @@ matrix: - gcc-multilib - os: linux - env: + env: - BUILD=i686-w64-mingw - CONFIGURE_ARGS="--build=i686-unknown-linux-gnu --host=i686-w64-mingw32" - EXECUTABLE=openocd.exe diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index 15ef66e1e..a12eb378f 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -1,7 +1,7 @@ /*************************************************************************** * Copyright (C) 2010 by Antonio Borneo * * Modified by Megan Wachs from the original stmsmi.c * - * * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -18,7 +18,7 @@ /* The Freedom E SPI controller is a SPI bus controller * specifically designed for SPI Flash Memories on Freedom E platforms. - * + * * Two working modes are available: * - SW mode: the SPI is controlled by SW. Any custom commands can be sent * on the bus. Writes are only possible in this mode. @@ -127,7 +127,7 @@ int __a; \ uint32_t __v; \ \ - __a = target_read_u32(target, ctrl_base + (a), &__v); \ + __a = target_read_u32(target, ctrl_base + (a), &__v); \ if (__a != ERROR_OK) { \ LOG_ERROR("FESPI_READ_REG error"); \ return __a; \ @@ -139,7 +139,7 @@ { \ int __r; \ \ - __r = target_write_u32(target, ctrl_base + (a), (v)); \ + __r = target_write_u32(target, ctrl_base + (a), (v)); \ if (__r != ERROR_OK) { \ LOG_ERROR("FESPI_WRITE_REG error"); \ return __r; \ @@ -163,7 +163,7 @@ struct fespi_target { uint32_t ctrl_base; }; -//TODO !!! What is the right naming convention here? +/* TODO !!! What is the right naming convention here? */ static const struct fespi_target target_devices[] = { /* name, tap_idcode, ctrl_base */ { "Freedom E300 SPI Flash", 0x10e31913 , 0x10014000 }, @@ -189,16 +189,17 @@ FLASH_BANK_COMMAND_HANDLER(fespi_flash_bank_command) fespi_info->probed = 0; fespi_info->ctrl_base = 0; if (CMD_ARGC >= 7) { - int temp; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[6], temp); - fespi_info->ctrl_base = (uint32_t) temp; - LOG_DEBUG("ASSUMING FESPI device at ctrl_base = 0x%x", fespi_info->ctrl_base); + int temp; + COMMAND_PARSE_NUMBER(int, CMD_ARGV[6], temp); + fespi_info->ctrl_base = (uint32_t) temp; + LOG_DEBUG("ASSUMING FESPI device at ctrl_base = 0x%x", fespi_info->ctrl_base); } return ERROR_OK; } -static int fespi_set_dir (struct flash_bank * bank, bool dir) { +static int fespi_set_dir(struct flash_bank *bank, bool dir) +{ struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; uint32_t ctrl_base = fespi_info->ctrl_base; @@ -211,7 +212,8 @@ static int fespi_set_dir (struct flash_bank * bank, bool dir) { } -static int fespi_txwm_wait(struct flash_bank *bank) { +static int fespi_txwm_wait(struct flash_bank *bank) +{ struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; uint32_t ctrl_base = fespi_info->ctrl_base; @@ -219,9 +221,8 @@ static int fespi_txwm_wait(struct flash_bank *bank) { int64_t start = timeval_ms(); while (1) { - if (FESPI_READ_REG(FESPI_REG_IP) & FESPI_IP_TXWM) { + if (FESPI_READ_REG(FESPI_REG_IP) & FESPI_IP_TXWM) break; - } int64_t now = timeval_ms(); if (now - start > 1000) { LOG_ERROR("ip.txwm didn't get set."); @@ -233,7 +234,8 @@ static int fespi_txwm_wait(struct flash_bank *bank) { } -static int fespi_tx(struct flash_bank *bank, uint8_t in){ +static int fespi_tx(struct flash_bank *bank, uint8_t in) +{ struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; uint32_t ctrl_base = fespi_info->ctrl_base; @@ -241,9 +243,8 @@ static int fespi_tx(struct flash_bank *bank, uint8_t in){ int64_t start = timeval_ms(); while (1) { - if ((int32_t) FESPI_READ_REG(FESPI_REG_TXFIFO) >= 0) { + if ((int32_t) FESPI_READ_REG(FESPI_REG_TXFIFO) >= 0) break; - } int64_t now = timeval_ms(); if (now - start > 1000) { LOG_ERROR("txfifo stayed negative."); @@ -276,14 +277,14 @@ static int fespi_rx(struct flash_bank *bank, uint8_t *out) } } - if (out) { + if (out) *out = value & 0xff; - } + return ERROR_OK; } -//TODO!!! Why don't we need to call this after writing? -static int fespi_wip (struct flash_bank * bank, int timeout) +/* TODO!!! Why don't we need to call this after writing? */ +static int fespi_wip(struct flash_bank *bank, int timeout) { struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; @@ -326,26 +327,34 @@ static int fespi_erase_sector(struct flash_bank *bank, int sector) int retval; retval = fespi_tx(bank, SPIFLASH_WRITE_ENABLE); - if (retval != ERROR_OK) {return retval;} + if (retval != ERROR_OK) + return retval; retval = fespi_txwm_wait(bank); - if (retval != ERROR_OK) {return retval;} - + if (retval != ERROR_OK) + return retval; + FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_HOLD); retval = fespi_tx(bank, fespi_info->dev->erase_cmd); - if (retval != ERROR_OK) {return retval;} + if (retval != ERROR_OK) + return retval; sector = bank->sectors[sector].offset; retval = fespi_tx(bank, sector >> 16); - if (retval != ERROR_OK) {return retval;} + if (retval != ERROR_OK) + return retval; retval = fespi_tx(bank, sector >> 8); - if (retval != ERROR_OK) {return retval;} + if (retval != ERROR_OK) + return retval; retval = fespi_tx(bank, sector); - if (retval != ERROR_OK) {return retval;} + if (retval != ERROR_OK) + return retval; retval = fespi_txwm_wait(bank); - if (retval != ERROR_OK) {return retval;} + if (retval != ERROR_OK) + return retval; FESPI_WRITE_REG(FESPI_REG_CSMODE, FESPI_CSMODE_AUTO); retval = fespi_wip(bank, FESPI_MAX_TIMEOUT); - if (retval != ERROR_OK){return retval;} + if (retval != ERROR_OK) + return retval; return ERROR_OK; } @@ -384,9 +393,9 @@ static int fespi_erase(struct flash_bank *bank, int first, int last) FESPI_WRITE_REG(FESPI_REG_TXCTRL, FESPI_TXWM(1)); retval = fespi_txwm_wait(bank); - if (retval != ERROR_OK){ - LOG_ERROR("WM Didn't go high before attempting."); - return retval; + if (retval != ERROR_OK) { + LOG_ERROR("WM Didn't go high before attempting."); + return retval; } /* Disable Hardware accesses*/ @@ -394,7 +403,7 @@ static int fespi_erase(struct flash_bank *bank, int first, int last) /* poll WIP */ retval = fespi_wip(bank, FESPI_PROBE_TIMEOUT); - if (retval != ERROR_OK) + if (retval != ERROR_OK) return retval; for (sector = first; sector <= last; sector++) { @@ -427,7 +436,7 @@ static int slow_fespi_write_buffer(struct flash_bank *bank, uint32_t ctrl_base = fespi_info->ctrl_base; uint32_t ii; - //TODO!!! assert that len < page size + /* TODO!!! assert that len < page size */ fespi_tx(bank, SPIFLASH_WRITE_ENABLE); fespi_txwm_wait(bank); @@ -440,9 +449,8 @@ static int slow_fespi_write_buffer(struct flash_bank *bank, fespi_tx(bank, offset >> 8); fespi_tx(bank, offset); - for (ii = 0; ii < len; ii++) { + for (ii = 0; ii < len; ii++) fespi_tx(bank, buffer[ii]); - } fespi_txwm_wait(bank); @@ -487,67 +495,67 @@ static int slow_fespi_write_buffer(struct flash_bank *bank, .global _start _start: command_table: - j main // 0 - ebreak // 4 - j tx // 8 - j txwm_wait // 12 - j write_reg // 16 + j main // 0 + ebreak // 4 + j tx // 8 + j txwm_wait // 12 + j write_reg // 16 j wip_wait // 20 - j set_dir // 24 + j set_dir // 24 // Execute the program. main: - lbu t0, 0(a1) - addi a1, a1, 1 - la t1, command_table - add t0, t0, t1 - jr t0 + lbu t0, 0(a1) + addi a1, a1, 1 + la t1, command_table + add t0, t0, t1 + jr t0 // Read 1 byte the contains the number of bytes to transmit. Then read those // bytes from the program and transmit them one by one. tx: - lbu t1, 0(a1) // read number of bytes to transmit - addi a1, a1, 1 + lbu t1, 0(a1) // read number of bytes to transmit + addi a1, a1, 1 1: lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear - bltz t0, 1b - lbu t0, 0(a1) // Load byte to write - sw t0, FESPI_REG_TXFIFO(a0) - addi a1, a1, 1 - addi t1, t1, -1 - bgtz t1, 1b - j main + bltz t0, 1b + lbu t0, 0(a1) // Load byte to write + sw t0, FESPI_REG_TXFIFO(a0) + addi a1, a1, 1 + addi t1, t1, -1 + bgtz t1, 1b + j main // Wait until TXWM is set. txwm_wait: 1: lw t0, FESPI_REG_IP(a0) - andi t0, t0, FESPI_IP_TXWM - beqz t0, 1b - j main + andi t0, t0, FESPI_IP_TXWM + beqz t0, 1b + j main // Read 1 byte that contains the offset of the register to write, and 1 byte // that contains the data to write. write_reg: - lbu t0, 0(a1) // read register to write - add t0, t0, a0 - lbu t1, 1(a1) // read value to write - addi a1, a1, 2 - sw t1, 0(t0) - j main + lbu t0, 0(a1) // read register to write + add t0, t0, a0 + lbu t1, 1(a1) // read value to write + addi a1, a1, 2 + sw t1, 0(t0) + j main wip_wait: li a2, SPIFLASH_READ_STATUS - jal txrx_byte + jal txrx_byte // discard first result 1: li a2, 0 - jal txrx_byte + jal txrx_byte andi t0, a2, SPIFLASH_BSY_BIT bnez t0, 1b j main txrx_byte: // transmit the byte in a2, receive a bit into a2 lw t0, FESPI_REG_TXFIFO(a0) // wait for FIFO clear - bltz t0, txrx_byte - sw a2, FESPI_REG_TXFIFO(a0) + bltz t0, txrx_byte + sw a2, FESPI_REG_TXFIFO(a0) 1: lw a2, FESPI_REG_RXFIFO(a0) bltz a2, 1b ret @@ -556,8 +564,8 @@ set_dir: lw t0, FESPI_REG_FMT(a0) li t1, ~(FESPI_FMT_DIR(0xFFFFFFFF)) and t0, t0, t1 - lbu t1, 0(a1) // read value to OR in - addi a1, a1, 1 + lbu t1, 0(a1) // read value to OR in + addi a1, a1, 1 or t0, t0, t1 sw t0, FESPI_REG_FMT(a0) j main @@ -565,24 +573,24 @@ set_dir: // ALGO_END */ static const uint8_t algorithm_bin[] = { - 0x6f, 0x00, 0xc0, 0x01, 0x73, 0x00, 0x10, 0x00, 0x6f, 0x00, 0xc0, 0x02, - 0x6f, 0x00, 0x00, 0x05, 0x6f, 0x00, 0xc0, 0x05, 0x6f, 0x00, 0x00, 0x07, - 0x6f, 0x00, 0x00, 0x0a, 0x83, 0xc2, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00, - 0x17, 0x03, 0x00, 0x00, 0x13, 0x03, 0xc3, 0xfd, 0xb3, 0x82, 0x62, 0x00, - 0x67, 0x80, 0x02, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00, - 0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe, 0x83, 0xc2, 0x05, 0x00, - 0x23, 0x24, 0x55, 0x04, 0x93, 0x85, 0x15, 0x00, 0x13, 0x03, 0xf3, 0xff, - 0xe3, 0x44, 0x60, 0xfe, 0x6f, 0xf0, 0x5f, 0xfc, 0x83, 0x22, 0x45, 0x07, - 0x93, 0xf2, 0x12, 0x00, 0xe3, 0x8c, 0x02, 0xfe, 0x6f, 0xf0, 0x5f, 0xfb, - 0x83, 0xc2, 0x05, 0x00, 0xb3, 0x82, 0xa2, 0x00, 0x03, 0xc3, 0x15, 0x00, - 0x93, 0x85, 0x25, 0x00, 0x23, 0xa0, 0x62, 0x00, 0x6f, 0xf0, 0xdf, 0xf9, - 0x13, 0x06, 0x50, 0x00, 0xef, 0x00, 0x80, 0x01, 0x13, 0x06, 0x00, 0x00, - 0xef, 0x00, 0x00, 0x01, 0x93, 0x72, 0x16, 0x00, 0xe3, 0x9a, 0x02, 0xfe, - 0x6f, 0xf0, 0x1f, 0xf8, 0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe, - 0x23, 0x24, 0xc5, 0x04, 0x03, 0x26, 0xc5, 0x04, 0xe3, 0x4e, 0x06, 0xfe, - 0x67, 0x80, 0x00, 0x00, 0x83, 0x22, 0x05, 0x04, 0x13, 0x03, 0x70, 0xff, - 0xb3, 0xf2, 0x62, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00, - 0xb3, 0xe2, 0x62, 0x00, 0x23, 0x20, 0x55, 0x04, 0x6f, 0xf0, 0x9f, 0xf4 + 0x6f, 0x00, 0xc0, 0x01, 0x73, 0x00, 0x10, 0x00, 0x6f, 0x00, 0xc0, 0x02, + 0x6f, 0x00, 0x00, 0x05, 0x6f, 0x00, 0xc0, 0x05, 0x6f, 0x00, 0x00, 0x07, + 0x6f, 0x00, 0x00, 0x0a, 0x83, 0xc2, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00, + 0x17, 0x03, 0x00, 0x00, 0x13, 0x03, 0xc3, 0xfd, 0xb3, 0x82, 0x62, 0x00, + 0x67, 0x80, 0x02, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00, + 0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe, 0x83, 0xc2, 0x05, 0x00, + 0x23, 0x24, 0x55, 0x04, 0x93, 0x85, 0x15, 0x00, 0x13, 0x03, 0xf3, 0xff, + 0xe3, 0x44, 0x60, 0xfe, 0x6f, 0xf0, 0x5f, 0xfc, 0x83, 0x22, 0x45, 0x07, + 0x93, 0xf2, 0x12, 0x00, 0xe3, 0x8c, 0x02, 0xfe, 0x6f, 0xf0, 0x5f, 0xfb, + 0x83, 0xc2, 0x05, 0x00, 0xb3, 0x82, 0xa2, 0x00, 0x03, 0xc3, 0x15, 0x00, + 0x93, 0x85, 0x25, 0x00, 0x23, 0xa0, 0x62, 0x00, 0x6f, 0xf0, 0xdf, 0xf9, + 0x13, 0x06, 0x50, 0x00, 0xef, 0x00, 0x80, 0x01, 0x13, 0x06, 0x00, 0x00, + 0xef, 0x00, 0x00, 0x01, 0x93, 0x72, 0x16, 0x00, 0xe3, 0x9a, 0x02, 0xfe, + 0x6f, 0xf0, 0x1f, 0xf8, 0x83, 0x22, 0x85, 0x04, 0xe3, 0xce, 0x02, 0xfe, + 0x23, 0x24, 0xc5, 0x04, 0x03, 0x26, 0xc5, 0x04, 0xe3, 0x4e, 0x06, 0xfe, + 0x67, 0x80, 0x00, 0x00, 0x83, 0x22, 0x05, 0x04, 0x13, 0x03, 0x70, 0xff, + 0xb3, 0xf2, 0x62, 0x00, 0x03, 0xc3, 0x05, 0x00, 0x93, 0x85, 0x15, 0x00, + 0xb3, 0xe2, 0x62, 0x00, 0x23, 0x20, 0x55, 0x04, 0x6f, 0xf0, 0x9f, 0xf4 }; #define STEP_EXIT 4 #define STEP_TX 8 @@ -625,7 +633,7 @@ static int as_empty(struct algorithm_steps *as) return 1; } -// Return size of compiled program. +/* Return size of compiled program. */ static unsigned as_compile(struct algorithm_steps *as, uint8_t *target, unsigned target_size) { @@ -684,9 +692,8 @@ static unsigned as_compile(struct algorithm_steps *as, uint8_t *target, LOG_DEBUG("%d-byte program:", offset); for (unsigned i = 0; i < offset;) { char buf[80]; - for (unsigned x = 0; i < offset && x < 16; x++, i++) { + for (unsigned x = 0; i < offset && x < 16; x++, i++) sprintf(buf + x*3, "%02x ", target[i]); - } LOG_DEBUG("%s", buf); } @@ -771,7 +778,7 @@ static int steps_add_buffer_write(struct algorithm_steps *as, as_add_txwm_wait(as); as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_AUTO); - // fespi_wip() + /* fespi_wip() */ as_add_set_dir(as, FESPI_DIR_RX); as_add_write_reg(as, FESPI_REG_CSMODE, FESPI_CSMODE_HOLD); as_add_wip_wait(as); @@ -908,11 +915,10 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer, cur_count = 4 - (offset & 3); if (cur_count > count) cur_count = count; - if (algorithm_wa) { + if (algorithm_wa) retval = steps_add_buffer_write(as, buffer, offset, cur_count); - } else { + else retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count); - } if (retval != ERROR_OK) goto err; offset += cur_count; @@ -929,11 +935,10 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer, else cur_count = count & ~3; - if (algorithm_wa) { + if (algorithm_wa) retval = steps_add_buffer_write(as, buffer, offset, cur_count); - } else { + else retval = slow_fespi_write_buffer(bank, buffer, offset, cur_count); - } if (retval != ERROR_OK) goto err; @@ -945,18 +950,16 @@ static int fespi_write(struct flash_bank *bank, const uint8_t *buffer, /* buffer tail */ if (count > 0) { - if (algorithm_wa) { + if (algorithm_wa) retval = steps_add_buffer_write(as, buffer, offset, count); - } else { + else retval = slow_fespi_write_buffer(bank, buffer, offset, count); - } if (retval != ERROR_OK) goto err; } - if (algorithm_wa) { + if (algorithm_wa) retval = steps_execute(as, bank, algorithm_wa, data_wa); - } err: if (algorithm_wa) { @@ -1043,27 +1046,27 @@ static int fespi_probe(struct flash_bank *bank) fespi_info->probed = 0; if (fespi_info->ctrl_base == 0) { - for (target_device = target_devices ; target_device->name ; ++target_device) - if (target_device->tap_idcode == target->tap->idcode) - break; + for (target_device = target_devices ; target_device->name ; ++target_device) + if (target_device->tap_idcode == target->tap->idcode) + break; - if (!target_device->name) { - LOG_ERROR("Device ID 0x%" PRIx32 " is not known as FESPI capable", - target->tap->idcode); - return ERROR_FAIL; - } + if (!target_device->name) { + LOG_ERROR("Device ID 0x%" PRIx32 " is not known as FESPI capable", + target->tap->idcode); + return ERROR_FAIL; + } - fespi_info->ctrl_base = target_device->ctrl_base; + fespi_info->ctrl_base = target_device->ctrl_base; - LOG_DEBUG("Valid FESPI on device %s at address 0x%" PRIx32, - target_device->name, bank->base); + LOG_DEBUG("Valid FESPI on device %s at address 0x%" PRIx32, + target_device->name, bank->base); } else { LOG_DEBUG("Assuming FESPI as specified at address 0x%x with ctrl at 0x%x", fespi_info->ctrl_base, bank->base); } - ctrl_base = fespi_info->ctrl_base; + ctrl_base = fespi_info->ctrl_base; /* read and decode flash ID; returns in SW mode */ FESPI_WRITE_REG(FESPI_REG_TXCTRL, FESPI_TXWM(1)); diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c index 4e1995c0c..669e0250c 100644 --- a/src/jtag/drivers/remote_bitbang.c +++ b/src/jtag/drivers/remote_bitbang.c @@ -76,10 +76,8 @@ static void remote_bitbang_fill_buf(void) contiguous_available_space); if (count > 0) { remote_bitbang_end += count; - // TODO: check for overflow. - if (remote_bitbang_end == sizeof(remote_bitbang_buf)) { + if (remote_bitbang_end == sizeof(remote_bitbang_buf)) remote_bitbang_end = 0; - } } else if (count == 0) { return; } else if (count < 0) { @@ -171,7 +169,7 @@ static int remote_bitbang_read_sample(void) { if (remote_bitbang_start != remote_bitbang_end) { int c = remote_bitbang_buf[remote_bitbang_start]; - remote_bitbang_start = + remote_bitbang_start = (remote_bitbang_start + 1) % sizeof(remote_bitbang_buf); return char_to_int(c); } diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c index 7996fb2bd..b84a4f91f 100644 --- a/src/rtos/riscv_debug.c +++ b/src/rtos/riscv_debug.c @@ -79,7 +79,7 @@ static int riscv_gdb_thread_packet(struct connection *connection, const char *pa if (strncmp(packet, "qfThreadInfo", 12) == 0) { riscv_update_threads(target->rtos); r->qs_thread_info_offset = 1; - + char m[16]; snprintf(m, 16, "m%08x", (int)rtos->thread_details[0].threadid); gdb_put_packet(connection, m, strlen(m)); @@ -305,8 +305,7 @@ static int riscv_get_symbol_list_to_lookup(symbol_table_elem_t *symbol_list[]) return JIM_OK; } -const struct rtos_type riscv_rtos = -{ +const struct rtos_type riscv_rtos = { .name = "riscv", .detect_rtos = riscv_detect_rtos, .create = riscv_create_rtos, diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index 09e7bb9f9..f0adf1d34 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -1286,10 +1286,10 @@ static int gdb_get_register_packet(struct connection *connection, } if (!reg_list[reg_num]->valid) { - retval = reg_list[reg_num]->type->get(reg_list[reg_num]); + retval = reg_list[reg_num]->type->get(reg_list[reg_num]); if (retval != ERROR_OK) { LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name); - free (reg_list); + free(reg_list); return gdb_error(connection, retval); } } @@ -1347,7 +1347,7 @@ static int gdb_set_register_packet(struct connection *connection, gdb_target_to_reg(target, separator + 1, chars, bin_buf); retval = reg_list[reg_num]->type->set(reg_list[reg_num], bin_buf); - if (retval != ERROR_OK){ + if (retval != ERROR_OK) { LOG_DEBUG("Couldn't set register %s.", reg_list[reg_num]->name); free(bin_buf); free(reg_list); diff --git a/src/target/riscv/asm.h b/src/target/riscv/asm.h index f976e2065..d81aa0285 100644 --- a/src/target/riscv/asm.h +++ b/src/target/riscv/asm.h @@ -17,7 +17,7 @@ static uint32_t load(const struct target *target, unsigned int rd, return ld(rd, base, offset); } assert(0); - return 0; // Silence -Werror=return-type + return 0; /* Silence -Werror=return-type */ } static uint32_t store(const struct target *target, unsigned int src, @@ -32,7 +32,7 @@ static uint32_t store(const struct target *target, unsigned int src, return sd(src, base, offset); } assert(0); - return 0; // Silence -Werror=return-type + return 0; /* Silence -Werror=return-type */ } #endif diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index 1e6db42b8..f32be3493 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -138,8 +138,8 @@ void riscv_batch_add_nop(struct riscv_batch *batch) void dump_field(const struct scan_field *field) { - static const char *op_string[] = {"-", "r", "w", "?"}; - static const char *status_string[] = {"+", "?", "F", "b"}; + static const char * const op_string[] = {"-", "r", "w", "?"}; + static const char * const status_string[] = {"+", "?", "F", "b"}; if (debug_level < LOG_LVL_DEBUG) return; diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index 1d3e1c092..e970293bf 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -295,7 +295,7 @@ * * Other values are reserved for future use. */ -#define CSR_TDATA1_TYPE_OFFSET XLEN-4 +#define CSR_TDATA1_TYPE_OFFSET (XLEN-4) #define CSR_TDATA1_TYPE_LENGTH 4 #define CSR_TDATA1_TYPE (0xfULL << CSR_TDATA1_TYPE_OFFSET) /* @@ -307,14 +307,14 @@ * * This bit is only writable from Debug Mode. */ -#define CSR_TDATA1_DMODE_OFFSET XLEN-5 +#define CSR_TDATA1_DMODE_OFFSET (XLEN-5) #define CSR_TDATA1_DMODE_LENGTH 1 #define CSR_TDATA1_DMODE (0x1ULL << CSR_TDATA1_DMODE_OFFSET) /* * Trigger-specific data. */ #define CSR_TDATA1_DATA_OFFSET 0 -#define CSR_TDATA1_DATA_LENGTH XLEN - 5 +#define CSR_TDATA1_DATA_LENGTH (XLEN - 5) #define CSR_TDATA1_DATA (((1L<> lo) & ((1 << (hi+1-lo)) - 1); } -static uint32_t bit(uint32_t value, unsigned int b) { +static uint32_t bit(uint32_t value, unsigned int b) +{ return (value >> b) & 1; } static uint32_t jal(unsigned int rd, uint32_t imm) __attribute__ ((unused)); -static uint32_t jal(unsigned int rd, uint32_t imm) { +static uint32_t jal(unsigned int rd, uint32_t imm) +{ return (bit(imm, 20) << 31) | (bits(imm, 10, 1) << 21) | (bit(imm, 11) << 20) | @@ -24,7 +27,8 @@ static uint32_t jal(unsigned int rd, uint32_t imm) { } static uint32_t csrsi(unsigned int csr, uint16_t imm) __attribute__ ((unused)); -static uint32_t csrsi(unsigned int csr, uint16_t imm) { +static uint32_t csrsi(unsigned int csr, uint16_t imm) +{ return (csr << 20) | (bits(imm, 4, 0) << 15) | MATCH_CSRRSI; @@ -107,7 +111,8 @@ static uint32_t lb(unsigned int rd, unsigned int base, uint16_t offset) } static uint32_t csrw(unsigned int source, unsigned int csr) __attribute__ ((unused)); -static uint32_t csrw(unsigned int source, unsigned int csr) { +static uint32_t csrw(unsigned int source, unsigned int csr) +{ return (csr << 20) | (source << 15) | MATCH_CSRRW; } @@ -121,17 +126,20 @@ static uint32_t addi(unsigned int dest, unsigned int src, uint16_t imm) } static uint32_t csrr(unsigned int rd, unsigned int csr) __attribute__ ((unused)); -static uint32_t csrr(unsigned int rd, unsigned int csr) { +static uint32_t csrr(unsigned int rd, unsigned int csr) +{ return (csr << 20) | (rd << 7) | MATCH_CSRRS; } static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused)); -static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) { +static uint32_t csrrs(unsigned int rd, unsigned int rs, unsigned int csr) +{ return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRS; } static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) __attribute__ ((unused)); -static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) { +static uint32_t csrrw(unsigned int rd, unsigned int rs, unsigned int csr) +{ return (csr << 20) | (rs << 15) | (rd << 7) | MATCH_CSRRW; } @@ -206,9 +214,15 @@ static uint32_t fmv_d_x(unsigned dest, unsigned src) } static uint32_t ebreak(void) __attribute__ ((unused)); -static uint32_t ebreak(void) { return MATCH_EBREAK; } +static uint32_t ebreak(void) +{ + return MATCH_EBREAK; +} static uint32_t ebreak_c(void) __attribute__ ((unused)); -static uint32_t ebreak_c(void) { return MATCH_C_EBREAK; } +static uint32_t ebreak_c(void) +{ + return MATCH_C_EBREAK; +} static uint32_t fence_i(void) __attribute__ ((unused)); static uint32_t fence_i(void) @@ -226,7 +240,8 @@ static uint32_t lui(unsigned int dest, uint32_t imm) /* static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused)); -static uint32_t csrci(unsigned int csr, uint16_t imm) { +static uint32_t csrci(unsigned int csr, uint16_t imm) +{ return (csr << 20) | (bits(imm, 4, 0) << 15) | MATCH_CSRRCI; diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 0c0dbd8bf..76f63b8fd 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -18,11 +18,10 @@ int riscv_program_init(struct riscv_program *p, struct target *target) p->target = target; p->instruction_count = 0; p->target_xlen = riscv_xlen(target); - for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) { + for (size_t i = 0; i < RISCV_REGISTER_COUNT; ++i) p->writes_xreg[i] = 0; - } - for(size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i) + for (size_t i = 0; i < RISCV_MAX_DEBUG_BUFFER_SIZE; ++i) p->debug_buffer[i] = -1; return ERROR_OK; @@ -54,7 +53,7 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) if (riscv_program_ebreak(p) != ERROR_OK) { LOG_ERROR("Unable to write ebreak"); - for(size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) + for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]); abort(); return ERROR_FAIL; diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 6692a9de1..9490f7a58 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -34,32 +34,32 @@ * Code structure * * At the bottom of the stack are the OpenOCD JTAG functions: - * jtag_add_[id]r_scan - * jtag_execute_query - * jtag_add_runtest + * jtag_add_[id]r_scan + * jtag_execute_query + * jtag_add_runtest * * There are a few functions to just instantly shift a register and get its * value: - * dtmcontrol_scan - * idcode_scan - * dbus_scan + * dtmcontrol_scan + * idcode_scan + * dbus_scan * * Because doing one scan and waiting for the result is slow, most functions * batch up a bunch of dbus writes and then execute them all at once. They use * the scans "class" for this: - * scans_new - * scans_delete - * scans_execute - * scans_add_... + * scans_new + * scans_delete + * scans_execute + * scans_add_... * Usually you new(), call a bunch of add functions, then execute() and look * at the results by calling scans_get...() * * Optimized functions will directly use the scans class above, but slightly * lazier code will use the cache functions that in turn use the scans * functions: - * cache_get... - * cache_set... - * cache_write + * cache_get... + * cache_set... + * cache_write * cache_set... update a local structure, which is then synced to the target * with cache_write(). Only Debug RAM words that are actually changed are sent * to the target. Afterwards use cache_get... to read results. @@ -70,7 +70,7 @@ #define DIM(x) (sizeof(x)/sizeof(*x)) -// Constants for legacy SiFive hardware breakpoints. +/* Constants for legacy SiFive hardware breakpoints. */ #define CSR_BPCONTROL_X (1<<0) #define CSR_BPCONTROL_W (1<<1) #define CSR_BPCONTROL_R (1<<2) @@ -189,19 +189,19 @@ typedef struct { struct memory_cache_line dram_cache[DRAM_CACHE_SIZE]; - // Number of run-test/idle cycles the target requests we do after each dbus - // access. + /* Number of run-test/idle cycles the target requests we do after each dbus + * access. */ unsigned int dtmcontrol_idle; - // This value is incremented every time a dbus access comes back as "busy". - // It's used to determine how many run-test/idle cycles to feed the target - // in between accesses. + /* This value is incremented every time a dbus access comes back as "busy". + * It's used to determine how many run-test/idle cycles to feed the target + * in between accesses. */ unsigned int dbus_busy_delay; - // This value is incremented every time we read the debug interrupt as - // high. It's used to add extra run-test/idle cycles after setting debug - // interrupt high, so ideally we never have to perform a whole extra scan - // before the interrupt is cleared. + /* This value is incremented every time we read the debug interrupt as + * high. It's used to add extra run-test/idle cycles after setting debug + * interrupt high, so ideally we never have to perform a whole extra scan + * before the interrupt is cleared. */ unsigned int interrupt_high_delay; bool need_strict_step; @@ -249,7 +249,7 @@ static unsigned int slot_offset(const struct target *target, slot_t slot) LOG_ERROR("slot_offset called with xlen=%d, slot=%d", riscv_xlen(target), slot); assert(0); - return 0; // Silence -Werror=return-type + return 0; /* Silence -Werror=return-type */ } static uint32_t load_slot(const struct target *target, unsigned int dest, @@ -368,19 +368,17 @@ static void add_dbus_scan(const struct target *target, struct scan_field *field, jtag_add_dr_scan(target->tap, 1, field, TAP_IDLE); int idle_count = info->dtmcontrol_idle + info->dbus_busy_delay; - if (data & DMCONTROL_INTERRUPT) { + if (data & DMCONTROL_INTERRUPT) idle_count += info->interrupt_high_delay; - } - if (idle_count) { + if (idle_count) jtag_add_runtest(idle_count, TAP_IDLE); - } } static void dump_field(const struct scan_field *field) { - static const char *op_string[] = {"nop", "r", "w", "?"}; - static const char *status_string[] = {"+", "?", "F", "b"}; + static const char * const op_string[] = {"nop", "r", "w", "?"}; + static const char * const status_string[] = {"+", "?", "F", "b"}; if (debug_level < LOG_LVL_DEBUG) return; @@ -431,9 +429,8 @@ static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in, int idle_count = info->dtmcontrol_idle + info->dbus_busy_delay; - if (idle_count) { + if (idle_count) jtag_add_runtest(idle_count, TAP_IDLE); - } int retval = jtag_execute_queue(); if (retval != ERROR_OK) { @@ -441,13 +438,11 @@ static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in, return retval; } - if (data_in) { + if (data_in) *data_in = buf_get_u64(in, DBUS_DATA_START, DBUS_DATA_SIZE); - } - if (address_in) { + if (address_in) *address_in = buf_get_u32(in, DBUS_ADDRESS_START, info->addrbits); - } dump_field(&field); @@ -463,15 +458,13 @@ static uint64_t dbus_read(struct target *target, uint16_t address) unsigned i = 0; do { status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0); - if (status == DBUS_STATUS_BUSY) { + if (status == DBUS_STATUS_BUSY) increase_dbus_busy_delay(target); - } } while (((status == DBUS_STATUS_BUSY) || (address_in != address)) && i++ < 256); - if (status != DBUS_STATUS_SUCCESS) { + if (status != DBUS_STATUS_SUCCESS) LOG_ERROR("failed read from 0x%x; value=0x%" PRIx64 ", status=%d\n", address, value, status); - } return value; } @@ -482,21 +475,19 @@ static void dbus_write(struct target *target, uint16_t address, uint64_t value) unsigned i = 0; while (status == DBUS_STATUS_BUSY && i++ < 256) { status = dbus_scan(target, NULL, NULL, DBUS_OP_WRITE, address, value); - if (status == DBUS_STATUS_BUSY) { + if (status == DBUS_STATUS_BUSY) increase_dbus_busy_delay(target); - } } - if (status != DBUS_STATUS_SUCCESS) { + if (status != DBUS_STATUS_SUCCESS) LOG_ERROR("failed to write 0x%" PRIx64 " to 0x%x; status=%d\n", value, address, status); - } } /*** scans "class" ***/ typedef struct { - // Number of scans that space is reserved for. + /* Number of scans that space is reserved for. */ unsigned int scan_count; - // Size reserved in memory for each scan, in bytes. + /* Size reserved in memory for each scan, in bytes. */ unsigned int scan_size; unsigned int next_scan; uint8_t *in; @@ -509,7 +500,7 @@ static scans_t *scans_new(struct target *target, unsigned int scan_count) { scans_t *scans = malloc(sizeof(scans_t)); scans->scan_count = scan_count; - // This code also gets called before xlen is detected. + /* This code also gets called before xlen is detected. */ if (riscv_xlen(target)) scans->scan_size = 2 + riscv_xlen(target) / 8; else @@ -539,9 +530,8 @@ static void scans_reset(scans_t *scans) static void scans_dump(scans_t *scans) { - for (unsigned int i = 0; i < scans->next_scan; i++) { + for (unsigned int i = 0; i < scans->next_scan; i++) dump_field(&scans->field[i]); - } } static int scans_execute(scans_t *scans) @@ -699,17 +689,16 @@ static int wait_for_debugint_clear(struct target *target, bool ignore_first) { time_t start = time(NULL); if (ignore_first) { - // Throw away the results of the first read, since they'll contain the - // result of the read that happened just before debugint was set. - // (Assuming the last scan before calling this function was one that - // sets debugint.) + /* Throw away the results of the first read, since they'll contain the + * result of the read that happened just before debugint was set. + * (Assuming the last scan before calling this function was one that + * sets debugint.) */ read_bits(target); } while (1) { bits_t bits = read_bits(target); - if (!bits.interrupt) { + if (!bits.interrupt) return ERROR_OK; - } if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out waiting for debug int to clear." "Increase timeout with riscv set_command_timeout_sec."); @@ -736,7 +725,7 @@ static void cache_set32(struct target *target, unsigned int index, uint32_t data riscv011_info_t *info = get_info(target); if (info->dram_cache[index].valid && info->dram_cache[index].data == data) { - // This is already preset on the target. + /* This is already preset on the target. */ LOG_DEBUG("cache[0x%x] = 0x%08x: DASM(0x%x) (hit)", index, data, data); return; } @@ -750,9 +739,8 @@ static void cache_set(struct target *target, slot_t slot, uint64_t data) { unsigned int offset = slot_offset(target, slot); cache_set32(target, offset, data); - if (riscv_xlen(target) > 32) { + if (riscv_xlen(target) > 32) cache_set32(target, offset + 1, data >> 32); - } } static void cache_set_jump(struct target *target, unsigned int index) @@ -799,9 +787,8 @@ static void cache_clean(struct target *target) { riscv011_info_t *info = get_info(target); for (unsigned int i = 0; i < info->dramsize; i++) { - if (i >= 4) { + if (i >= 4) info->dram_cache[i].valid = false; - } info->dram_cache[i].dirty = false; } } @@ -813,9 +800,8 @@ static int cache_check(struct target *target) for (unsigned int i = 0; i < info->dramsize; i++) { if (info->dram_cache[i].valid && !info->dram_cache[i].dirty) { - if (dram_check32(target, i, info->dram_cache[i].data) != ERROR_OK) { + if (dram_check32(target, i, info->dram_cache[i].data) != ERROR_OK) error++; - } } } @@ -838,13 +824,12 @@ static int cache_write(struct target *target, unsigned int address, bool run) unsigned int last = info->dramsize; for (unsigned int i = 0; i < info->dramsize; i++) { - if (info->dram_cache[i].dirty) { + if (info->dram_cache[i].dirty) last = i; - } } if (last == info->dramsize) { - // Nothing needs to be written to RAM. + /* Nothing needs to be written to RAM. */ dbus_write(target, DMCONTROL, DMCONTROL_HALTNOT | (run ? DMCONTROL_INTERRUPT : 0)); } else { @@ -858,12 +843,12 @@ static int cache_write(struct target *target, unsigned int address, bool run) } if (run || address < CACHE_NO_READ) { - // Throw away the results of the first read, since it'll contain the - // result of the read that happened just before debugint was set. + /* Throw away the results of the first read, since it'll contain the + * result of the read that happened just before debugint was set. */ scans_add_read32(scans, address, false); - // This scan contains the results of the read the caller requested, as - // well as an interrupt bit worth looking at. + /* This scan contains the results of the read the caller requested, as + * well as an interrupt bit worth looking at. */ scans_add_read32(scans, address, false); } @@ -895,19 +880,17 @@ static int cache_write(struct target *target, unsigned int address, bool run) if (errors) { increase_dbus_busy_delay(target); - // Try again, using the slow careful code. - // Write all RAM, just to be extra cautious. + /* Try again, using the slow careful code. + * Write all RAM, just to be extra cautious. */ for (unsigned int i = 0; i < info->dramsize; i++) { - if (i == last && run) { + if (i == last && run) dram_write32(target, last, info->dram_cache[last].data, true); - } else { + else dram_write32(target, i, info->dram_cache[i].data, false); - } info->dram_cache[i].dirty = false; } - if (run) { + if (run) cache_clean(target); - } if (wait_for_debugint_clear(target, true) != ERROR_OK) { LOG_ERROR("Debug interrupt didn't clear."); @@ -919,9 +902,8 @@ static int cache_write(struct target *target, unsigned int address, bool run) if (run) { cache_clean(target); } else { - for (unsigned int i = 0; i < info->dramsize; i++) { + for (unsigned int i = 0; i < info->dramsize; i++) info->dram_cache[i].dirty = false; - } } if (run || address < CACHE_NO_READ) { @@ -929,14 +911,14 @@ static int cache_write(struct target *target, unsigned int address, bool run) DBUS_DATA_START + 33, 1); if (interrupt) { increase_interrupt_high_delay(target); - // Slow path wait for it to clear. + /* Slow path wait for it to clear. */ if (wait_for_debugint_clear(target, false) != ERROR_OK) { LOG_ERROR("Debug interrupt didn't clear."); dump_debug_ram(target); return ERROR_FAIL; } } else { - // We read a useful value in that last scan. + /* We read a useful value in that last scan. */ unsigned int read_addr = scans_get_u32(scans, scans->next_scan-1, DBUS_ADDRESS_START, info->addrbits); if (read_addr != address) { @@ -970,9 +952,8 @@ static uint64_t cache_get(struct target *target, slot_t slot) { unsigned int offset = slot_offset(target, slot); uint64_t value = cache_get32(target, offset); - if (riscv_xlen(target) > 32) { + if (riscv_xlen(target) > 32) value |= ((uint64_t) cache_get32(target, offset + 1)) << 32; - } return value; } @@ -991,12 +972,10 @@ static int wait_for_state(struct target *target, enum target_state state) time_t start = time(NULL); while (1) { int result = riscv011_poll(target); - if (result != ERROR_OK) { + if (result != ERROR_OK) return result; - } - if (target->state == state) { + if (target->state == state) return ERROR_OK; - } if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out waiting for state %d. " "Increase timeout with riscv set_command_timeout_sec.", state); @@ -1011,9 +990,8 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr) cache_set32(target, 0, csrr(S0, csr)); cache_set_store(target, 1, S0, SLOT0); cache_set_jump(target, 2); - if (cache_write(target, 4, true) != ERROR_OK) { + if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; - } *value = cache_get(target, SLOT0); LOG_DEBUG("csr 0x%x = 0x%" PRIx64, csr, *value); @@ -1034,9 +1012,8 @@ static int write_csr(struct target *target, uint32_t csr, uint64_t value) cache_set32(target, 1, csrw(S0, csr)); cache_set_jump(target, 2); cache_set(target, SLOT0, value); - if (cache_write(target, 4, true) != ERROR_OK) { + if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; - } return ERROR_OK; } @@ -1046,9 +1023,8 @@ static int write_gpr(struct target *target, unsigned int gpr, uint64_t value) cache_set_load(target, 0, gpr, SLOT0); cache_set_jump(target, 1); cache_set(target, SLOT0, value); - if (cache_write(target, 4, true) != ERROR_OK) { + if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; - } return ERROR_OK; } @@ -1088,15 +1064,14 @@ static int execute_resume(struct target *target, bool step) maybe_write_tselect(target); - // TODO: check if dpc is dirty (which also is true if an exception was hit - // at any time) + /* TODO: check if dpc is dirty (which also is true if an exception was hit + * at any time) */ cache_set_load(target, 0, S0, SLOT0); cache_set32(target, 1, csrw(S0, CSR_DPC)); cache_set_jump(target, 2); cache_set(target, SLOT0, info->dpc); - if (cache_write(target, 4, true) != ERROR_OK) { + if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; - } struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS]; if (mstatus_reg->valid) { @@ -1106,27 +1081,25 @@ static int execute_resume(struct target *target, bool step) cache_set32(target, 1, csrw(S0, CSR_MSTATUS)); cache_set_jump(target, 2); cache_set(target, SLOT0, mstatus_user); - if (cache_write(target, 4, true) != ERROR_OK) { + if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; - } } } info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU; info->dcsr &= ~DCSR_HALT; - if (step) { + if (step) info->dcsr |= DCSR_STEP; - } else { + else info->dcsr &= ~DCSR_STEP; - } dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); dram_write32(target, 1, csrw(S0, CSR_DCSR), false); dram_write32(target, 2, fence_i(), false); dram_write_jump(target, 3, false); - // Write DCSR value, set interrupt and clear haltnot. + /* Write DCSR value, set interrupt and clear haltnot. */ uint64_t dbus_value = DMCONTROL_INTERRUPT | info->dcsr; dbus_write(target, dram_address(4), dbus_value); @@ -1143,7 +1116,7 @@ static int execute_resume(struct target *target, bool step) return ERROR_OK; } -// Execute a step, and wait for reentry into Debug Mode. +/* Execute a step, and wait for reentry into Debug Mode. */ static int full_step(struct target *target, bool announce) { int result = execute_resume(target, true); @@ -1158,7 +1131,7 @@ static int full_step(struct target *target, bool announce) break; if (time(NULL) - start > riscv_command_timeout_sec) { LOG_ERROR("Timed out waiting for step to complete." - "Increase timeout with riscv set_command_timeout_sec"); + "Increase timeout with riscv set_command_timeout_sec"); return ERROR_FAIL; } } @@ -1200,12 +1173,12 @@ static int update_mstatus_actual(struct target *target) { struct reg *mstatus_reg = &target->reg_cache->reg_list[GDB_REGNO_MSTATUS]; if (mstatus_reg->valid) { - // We previously made it valid. + /* We previously made it valid. */ return ERROR_OK; } - // Force reading the register. In that process mstatus_actual will be - // updated. + /* Force reading the register. In that process mstatus_actual will be + * updated. */ get_register(target, 0, GDB_REGNO_MSTATUS); return ERROR_OK; } @@ -1224,9 +1197,8 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum) return ERROR_FAIL; } - if (cache_write(target, 4, true) != ERROR_OK) { + if (cache_write(target, 4, true) != ERROR_OK) return ERROR_FAIL; - } uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { @@ -1239,14 +1211,13 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum) *value = cache_get(target, SLOT0); LOG_DEBUG("reg[%d]=0x%" PRIx64, regnum, *value); - if (regnum == GDB_REGNO_MSTATUS) { + if (regnum == GDB_REGNO_MSTATUS) info->mstatus_actual = *value; - } return ERROR_OK; } -// Write the register. No caching or games. +/* Write the register. No caching or games. */ static int register_write(struct target *target, unsigned int number, uint64_t value) { @@ -1270,9 +1241,8 @@ static int register_write(struct target *target, unsigned int number, return ERROR_OK; } else if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { int result = update_mstatus_actual(target); - if (result != ERROR_OK) { + if (result != ERROR_OK) return result; - } unsigned i = 0; if ((info->mstatus_actual & MSTATUS_FS) == 0) { info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); @@ -1281,20 +1251,18 @@ static int register_write(struct target *target, unsigned int number, cache_set(target, SLOT1, info->mstatus_actual); } - if (riscv_xlen(target) == 32) { + if (riscv_xlen(target) == 32) cache_set32(target, i++, flw(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); - } else { + else cache_set32(target, i++, fld(number - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); - } cache_set_jump(target, i++); } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { cache_set_load(target, 0, S0, SLOT0); cache_set32(target, 1, csrw(S0, number - GDB_REGNO_CSR0)); cache_set_jump(target, 2); - if (number == GDB_REGNO_MSTATUS) { + if (number == GDB_REGNO_MSTATUS) info->mstatus_actual = value; - } } else if (number == GDB_REGNO_PRIV) { info->dcsr = set_field(info->dcsr, DCSR_PRV, value); return ERROR_OK; @@ -1304,9 +1272,8 @@ static int register_write(struct target *target, unsigned int number, } cache_set(target, SLOT0, value); - if (cache_write(target, info->dramsize - 1, true) != ERROR_OK) { + if (cache_write(target, info->dramsize - 1, true) != ERROR_OK) return ERROR_FAIL; - } uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { @@ -1332,9 +1299,8 @@ static riscv_reg_t get_register(struct target *target, int hartid, int regid) value = info->dpc; } else if (regid >= GDB_REGNO_FPR0 && regid <= GDB_REGNO_FPR31) { int result = update_mstatus_actual(target); - if (result != ERROR_OK) { + if (result != ERROR_OK) return ~0; - } unsigned i = 0; if ((info->mstatus_actual & MSTATUS_FS) == 0) { info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); @@ -1343,27 +1309,22 @@ static riscv_reg_t get_register(struct target *target, int hartid, int regid) cache_set(target, SLOT1, info->mstatus_actual); } - if (riscv_xlen(target) == 32) { + if (riscv_xlen(target) == 32) cache_set32(target, i++, fsw(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); - } else { + else cache_set32(target, i++, fsd(regid - GDB_REGNO_FPR0, 0, DEBUG_RAM_START + 16)); - } cache_set_jump(target, i++); - if (cache_write(target, 4, true) != ERROR_OK) { + if (cache_write(target, 4, true) != ERROR_OK) return ~0; - } } else if (regid == GDB_REGNO_PRIV) { value = get_field(info->dcsr, DCSR_PRV); - } else { - if (register_read(target, &value, regid) != ERROR_OK) { - value = ~0; - } + } else if (register_read(target, &value, regid) != ERROR_OK) { + value = ~0; } - if (regid == GDB_REGNO_MSTATUS) { + if (regid == GDB_REGNO_MSTATUS) target->reg_cache->reg_list[regid].valid = true; - } return value; } @@ -1372,7 +1333,7 @@ static void set_register(struct target *target, int hartid, int regid, uint64_t value) { assert(hartid == 0); - // TODO: propagate errors + /* TODO: propagate errors */ register_write(target, regid, value); } @@ -1406,7 +1367,7 @@ static int init_target(struct command_context *cmd_ctx, if (!generic_info->version_specific) return ERROR_FAIL; - // Assume 32-bit until we discover the real value in examine(). + /* Assume 32-bit until we discover the real value in examine(). */ generic_info->xlen[0] = 32; riscv_init_registers(target); @@ -1490,7 +1451,7 @@ static int step(struct target *target, int current, target_addr_t address, static int examine(struct target *target) { - // Don't need to select dbus, since the first thing we do is read dtmcontrol. + /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ uint32_t dtmcontrol = dtmcontrol_scan(target, 0); LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); @@ -1514,7 +1475,7 @@ static int examine(struct target *target) info->addrbits = get_field(dtmcontrol, DTMCONTROL_ADDRBITS); info->dtmcontrol_idle = get_field(dtmcontrol, DTMCONTROL_IDLE); if (info->dtmcontrol_idle == 0) { - // Some old SiFive cores don't set idle but need it to be 1. + /* Some old SiFive cores don't set idle but need it to be 1. */ uint32_t idcode = idcode_scan(target); if (idcode == 0x10e31913) info->dtmcontrol_idle = 1; @@ -1549,29 +1510,27 @@ static int examine(struct target *target) return ERROR_FAIL; } - // Pretend this is a 32-bit system until we have found out the true value. + /* Pretend this is a 32-bit system until we have found out the true value. */ r->xlen[0] = 32; - // Figure out XLEN, and test writing all of Debug RAM while we're at it. + /* Figure out XLEN, and test writing all of Debug RAM while we're at it. */ cache_set32(target, 0, xori(S1, ZERO, -1)); - // 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff + /* 0xffffffff 0xffffffff:ffffffff 0xffffffff:ffffffff:ffffffff:ffffffff */ cache_set32(target, 1, srli(S1, S1, 31)); - // 0x00000001 0x00000001:ffffffff 0x00000001:ffffffff:ffffffff:ffffffff + /* 0x00000001 0x00000001:ffffffff 0x00000001:ffffffff:ffffffff:ffffffff */ cache_set32(target, 2, sw(S1, ZERO, DEBUG_RAM_START)); cache_set32(target, 3, srli(S1, S1, 31)); - // 0x00000000 0x00000000:00000003 0x00000000:00000003:ffffffff:ffffffff + /* 0x00000000 0x00000000:00000003 0x00000000:00000003:ffffffff:ffffffff */ cache_set32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4)); cache_set_jump(target, 5); - for (unsigned i = 6; i < info->dramsize; i++) { + for (unsigned i = 6; i < info->dramsize; i++) cache_set32(target, i, i * 0x01020304); - } cache_write(target, 0, false); - // Check that we can actually read/write dram. - if (cache_check(target) != ERROR_OK) { + /* Check that we can actually read/write dram. */ + if (cache_check(target) != ERROR_OK) return ERROR_FAIL; - } cache_write(target, 0, true); cache_invalidate(target); @@ -1599,22 +1558,21 @@ static int examine(struct target *target) LOG_WARNING("Failed to read misa at 0x%x; trying 0x%x.", CSR_MISA, old_csr_misa); if (read_csr(target, &r->misa, old_csr_misa) != ERROR_OK) { - // Maybe this is an old core that still has $misa at the old - // address. + /* Maybe this is an old core that still has $misa at the old + * address. */ LOG_ERROR("Failed to read misa at 0x%x.", old_csr_misa); return ERROR_FAIL; } } - // Update register list to match discovered XLEN/supported extensions. + /* Update register list to match discovered XLEN/supported extensions. */ riscv_init_registers(target); info->never_halted = true; int result = riscv011_poll(target); - if (result != ERROR_OK) { + if (result != ERROR_OK) return result; - } target_set_examined(target); riscv_set_current_hartid(target, 0); @@ -1632,41 +1590,40 @@ static riscv_error_t handle_halt_routine(struct target *target) scans_t *scans = scans_new(target, 256); - // Read all GPRs as fast as we can, because gdb is going to ask for them - // anyway. Reading them one at a time is much slower. + /* Read all GPRs as fast as we can, because gdb is going to ask for them + * anyway. Reading them one at a time is much slower. */ - // Write the jump back to address 1. + /* Write the jump back to address 1. */ scans_add_write_jump(scans, 1, false); for (int reg = 1; reg < 32; reg++) { - if (reg == S0 || reg == S1) { + if (reg == S0 || reg == S1) continue; - } - // Write store instruction. + /* Write store instruction. */ scans_add_write_store(scans, 0, reg, SLOT0, true); - // Read value. + /* Read value. */ scans_add_read(scans, SLOT0, false); } - // Write store of s0 at index 1. + /* Write store of s0 at index 1. */ scans_add_write_store(scans, 1, S0, SLOT0, false); - // Write jump at index 2. + /* Write jump at index 2. */ scans_add_write_jump(scans, 2, false); - // Read S1 from debug RAM + /* Read S1 from debug RAM */ scans_add_write_load(scans, 0, S0, SLOT_LAST, true); - // Read value. + /* Read value. */ scans_add_read(scans, SLOT0, false); - // Read S0 from dscratch + /* Read S0 from dscratch */ unsigned int csr[] = {CSR_DSCRATCH, CSR_DPC, CSR_DCSR}; for (unsigned int i = 0; i < DIM(csr); i++) { scans_add_write32(scans, 0, csrr(S0, csr[i]), true); scans_add_read(scans, SLOT0, false); } - // Final read to get the last value out. + /* Final read to get the last value out. */ scans_add_read32(scans, 4, false); int retval = scans_execute(scans); @@ -1680,8 +1637,8 @@ static riscv_error_t handle_halt_routine(struct target *target) unsigned result = 0; uint64_t value = 0; reg_cache_set(target, 0, 0); - // The first scan result is the result from something old we don't care - // about. + /* The first scan result is the result from something old we don't care + * about. */ for (unsigned int i = 1; i < scans->next_scan && dbus_busy == 0; i++) { dbus_status_t status = scans_get_u32(scans, i, DBUS_OP_START, DBUS_OP_SIZE); @@ -1708,43 +1665,109 @@ static riscv_error_t handle_halt_routine(struct target *target) if (address == 4 || address == 5) { unsigned int reg; switch (result) { - case 0: reg = 1; break; - case 1: reg = 2; break; - case 2: reg = 3; break; - case 3: reg = 4; break; - case 4: reg = 5; break; - case 5: reg = 6; break; - case 6: reg = 7; break; - // S0 - // S1 - case 7: reg = 10; break; - case 8: reg = 11; break; - case 9: reg = 12; break; - case 10: reg = 13; break; - case 11: reg = 14; break; - case 12: reg = 15; break; - case 13: reg = 16; break; - case 14: reg = 17; break; - case 15: reg = 18; break; - case 16: reg = 19; break; - case 17: reg = 20; break; - case 18: reg = 21; break; - case 19: reg = 22; break; - case 20: reg = 23; break; - case 21: reg = 24; break; - case 22: reg = 25; break; - case 23: reg = 26; break; - case 24: reg = 27; break; - case 25: reg = 28; break; - case 26: reg = 29; break; - case 27: reg = 30; break; - case 28: reg = 31; break; - case 29: reg = S1; break; - case 30: reg = S0; break; - case 31: reg = CSR_DPC; break; - case 32: reg = CSR_DCSR; break; + case 0: + reg = 1; + break; + case 1: + reg = 2; + break; + case 2: + reg = 3; + break; + case 3: + reg = 4; + break; + case 4: + reg = 5; + break; + case 5: + reg = 6; + break; + case 6: + reg = 7; + break; + /* S0 */ + /* S1 */ + case 7: + reg = 10; + break; + case 8: + reg = 11; + break; + case 9: + reg = 12; + break; + case 10: + reg = 13; + break; + case 11: + reg = 14; + break; + case 12: + reg = 15; + break; + case 13: + reg = 16; + break; + case 14: + reg = 17; + break; + case 15: + reg = 18; + break; + case 16: + reg = 19; + break; + case 17: + reg = 20; + break; + case 18: + reg = 21; + break; + case 19: + reg = 22; + break; + case 20: + reg = 23; + break; + case 21: + reg = 24; + break; + case 22: + reg = 25; + break; + case 23: + reg = 26; + break; + case 24: + reg = 27; + break; + case 25: + reg = 28; + break; + case 26: + reg = 29; + break; + case 27: + reg = 30; + break; + case 28: + reg = 31; + break; + case 29: + reg = S1; + break; + case 30: + reg = S0; + break; + case 31: + reg = CSR_DPC; + break; + case 32: + reg = CSR_DCSR; + break; default: - assert(0); + assert(0); } if (riscv_xlen(target) == 32) { reg_cache_set(target, reg, data & 0xffffffff); @@ -1770,7 +1793,7 @@ static riscv_error_t handle_halt_routine(struct target *target) return RE_AGAIN; } - // TODO: get rid of those 2 variables and talk to the cache directly. + /* TODO: get rid of those 2 variables and talk to the cache directly. */ info->dpc = reg_cache_get(target, CSR_DPC); info->dcsr = reg_cache_get(target, CSR_DCSR); @@ -1806,8 +1829,8 @@ static int handle_halt(struct target *target, bool announce) break; case DCSR_CAUSE_HWBP: target->debug_reason = DBG_REASON_WPTANDBKPT; - // If we halted because of a data trigger, gdb doesn't know to do - // the disable-breakpoints-step-enable-breakpoints dance. + /* If we halted because of a data trigger, gdb doesn't know to do + * the disable-breakpoints-step-enable-breakpoints dance. */ info->need_strict_step = true; break; case DCSR_CAUSE_DEBUGINT: @@ -1831,9 +1854,8 @@ static int handle_halt(struct target *target, bool announce) riscv_enumerate_triggers(target); } - if (announce) { + if (announce) target_call_event_callbacks(target, TARGET_EVENT_HALTED); - } const char *cause_string[] = { "none", @@ -1843,10 +1865,10 @@ static int handle_halt(struct target *target, bool announce) "step", "halt" }; - // This is logged to the user so that gdb will show it when a user types - // 'monitor reset init'. At that time gdb appears to have the pc cached - // still so if a user manually inspects the pc it will still have the old - // value. + /* This is logged to the user so that gdb will show it when a user types + * 'monitor reset init'. At that time gdb appears to have the pc cached + * still so if a user manually inspects the pc it will still have the old + * value. */ LOG_USER("halted at 0x%" PRIx64 " due to %s", info->dpc, cause_string[cause]); return ERROR_OK; @@ -1856,12 +1878,11 @@ static int poll_target(struct target *target, bool announce) { jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - // Inhibit debug logging during poll(), which isn't usually interesting and - // just fills up the screen/logs with clutter. + /* Inhibit debug logging during poll(), which isn't usually interesting and + * just fills up the screen/logs with clutter. */ int old_debug_level = debug_level; - if (debug_level >= LOG_LVL_DEBUG) { + if (debug_level >= LOG_LVL_DEBUG) debug_level = LOG_LVL_INFO; - } bits_t bits = read_bits(target); debug_level = old_debug_level; @@ -1869,11 +1890,10 @@ static int poll_target(struct target *target, bool announce) target->state = TARGET_DEBUG_RUNNING; LOG_DEBUG("debug running"); } else if (bits.haltnot && !bits.interrupt) { - if (target->state != TARGET_HALTED) { + if (target->state != TARGET_HALTED) return handle_halt(target, announce); - } } else if (!bits.haltnot && bits.interrupt) { - // Target is halting. There is no state for that, so don't change anything. + /* Target is halting. There is no state for that, so don't change anything. */ LOG_DEBUG("halting"); } else if (!bits.haltnot && !bits.interrupt) { target->state = TARGET_RUNNING; @@ -1916,28 +1936,27 @@ static int riscv011_resume(struct target *target, int current, static int assert_reset(struct target *target) { riscv011_info_t *info = get_info(target); - // TODO: Maybe what I implemented here is more like soft_reset_halt()? + /* TODO: Maybe what I implemented here is more like soft_reset_halt()? */ jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - // The only assumption we can make is that the TAP was reset. + /* The only assumption we can make is that the TAP was reset. */ if (wait_for_debugint_clear(target, true) != ERROR_OK) { LOG_ERROR("Debug interrupt didn't clear."); return ERROR_FAIL; } - // Not sure what we should do when there are multiple cores. - // Here just reset the single hart we're talking to. + /* Not sure what we should do when there are multiple cores. + * Here just reset the single hart we're talking to. */ info->dcsr |= DCSR_EBREAKM | DCSR_EBREAKH | DCSR_EBREAKS | DCSR_EBREAKU | DCSR_HALT; - if (target->reset_halt) { + if (target->reset_halt) info->dcsr |= DCSR_NDRESET; - } else { + else info->dcsr |= DCSR_FULLRESET; - } dram_write32(target, 0, lw(S0, ZERO, DEBUG_RAM_START + 16), false); dram_write32(target, 1, csrw(S0, CSR_DCSR), false); - // We shouldn't actually need the jump because a reset should happen. + /* We shouldn't actually need the jump because a reset should happen. */ dram_write_jump(target, 2, false); dram_write32(target, 4, info->dcsr, true); cache_invalidate(target); @@ -1950,11 +1969,10 @@ static int assert_reset(struct target *target) static int deassert_reset(struct target *target) { jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - if (target->reset_halt) { + if (target->reset_halt) return wait_for_state(target, TARGET_HALTED); - } else { + else return wait_for_state(target, TARGET_RUNNING); - } } static int read_memory(struct target *target, target_addr_t address, @@ -1995,13 +2013,13 @@ static int read_memory(struct target *target, target_addr_t address, for (unsigned int j = 0; j < batch_size; j++) { if (i + j == count) { - // Just insert a read so we can scan out the last value. + /* Just insert a read so we can scan out the last value. */ scans_add_read32(scans, 4, false); } else if (i + j >= count + 1) { - // And check for errors. + /* And check for errors. */ scans_add_read32(scans, info->dramsize-1, false); } else { - // Write the next address and set interrupt. + /* Write the next address and set interrupt. */ uint32_t offset = size * (i + j); scans_add_write32(scans, 4, address + offset, true); } @@ -2033,9 +2051,8 @@ static int read_memory(struct target *target, target_addr_t address, } uint64_t data = scans_get_u64(scans, j, DBUS_DATA_START, DBUS_DATA_SIZE); - if (data & DMCONTROL_INTERRUPT) { + if (data & DMCONTROL_INTERRUPT) execute_busy++; - } if (i + j == count + 2) { result_value = data; } else if (i + j > 1) { @@ -2058,16 +2075,14 @@ static int read_memory(struct target *target, target_addr_t address, } LOG_DEBUG("j=%d status=%d data=%09" PRIx64, j, status, data); } - if (dbus_busy) { + if (dbus_busy) increase_dbus_busy_delay(target); - } - if (execute_busy) { + if (execute_busy) increase_interrupt_high_delay(target); - } if (dbus_busy || execute_busy) { wait_for_debugint_clear(target, false); - // Retry. + /* Retry. */ LOG_INFO("Retrying memory read starting from 0x%" TARGET_PRIxADDR " with more delays", address + size * i); } else { @@ -2129,21 +2144,19 @@ static int write_memory(struct target *target, target_addr_t address, riscv011_info_t *info = get_info(target); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - // Set up the address. + /* Set up the address. */ cache_set_store(target, 0, T0, SLOT1); cache_set_load(target, 1, T0, SLOT0); cache_set_jump(target, 2); cache_set(target, SLOT0, address); - if (cache_write(target, 5, true) != ERROR_OK) { + if (cache_write(target, 5, true) != ERROR_OK) return ERROR_FAIL; - } uint64_t t0 = cache_get(target, SLOT1); LOG_DEBUG("t0 is 0x%" PRIx64, t0); - if (setup_write_memory(target, size) != ERROR_OK) { + if (setup_write_memory(target, size) != ERROR_OK) return ERROR_FAIL; - } const unsigned max_batch_size = 256; scans_t *scans = scans_new(target, max_batch_size); @@ -2156,10 +2169,10 @@ static int write_memory(struct target *target, target_addr_t address, for (unsigned int j = 0; j < batch_size; j++) { if (i + j >= count) { - // Check for an exception. + /* Check for an exception. */ scans_add_read32(scans, info->dramsize-1, false); } else { - // Write the next value and set interrupt. + /* Write the next value and set interrupt. */ uint32_t value; uint32_t offset = size * (i + j); switch (size) { @@ -2209,37 +2222,31 @@ static int write_memory(struct target *target, target_addr_t address, return ERROR_FAIL; } int interrupt = scans_get_u32(scans, j, DBUS_DATA_START + 33, 1); - if (interrupt) { + if (interrupt) execute_busy++; - } - if (i + j == count + 1) { + if (i + j == count + 1) result_value = scans_get_u32(scans, j, DBUS_DATA_START, 32); - } } - if (dbus_busy) { + if (dbus_busy) increase_dbus_busy_delay(target); - } - if (execute_busy) { + if (execute_busy) increase_interrupt_high_delay(target); - } if (dbus_busy || execute_busy) { wait_for_debugint_clear(target, false); - // Retry. - // Set t0 back to what it should have been at the beginning of this - // batch. + /* Retry. + * Set t0 back to what it should have been at the beginning of this + * batch. */ LOG_INFO("Retrying memory write starting from 0x%" TARGET_PRIxADDR " with more delays", address + size * i); cache_clean(target); - if (write_gpr(target, T0, address + size * i) != ERROR_OK) { + if (write_gpr(target, T0, address + size * i) != ERROR_OK) goto error; - } - if (setup_write_memory(target, size) != ERROR_OK) { + if (setup_write_memory(target, size) != ERROR_OK) goto error; - } } else { i += batch_size; } @@ -2271,8 +2278,7 @@ static int arch_state(struct target *target) return ERROR_OK; } -struct target_type riscv011_target = -{ +struct target_type riscv011_target = { .name = "riscv", .init_target = init_target, diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 98a63522f..e703728f6 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -150,20 +150,20 @@ typedef struct { /* We only need the address so that we know the alignment of the buffer. */ riscv_addr_t progbuf_address; - // Number of run-test/idle cycles the target requests we do after each dbus - // access. + /* Number of run-test/idle cycles the target requests we do after each dbus + * access. */ unsigned int dtmcontrol_idle; - // This value is incremented every time a dbus access comes back as "busy". - // It's used to determine how many run-test/idle cycles to feed the target - // in between accesses. + /* This value is incremented every time a dbus access comes back as "busy". + * It's used to determine how many run-test/idle cycles to feed the target + * in between accesses. */ unsigned int dmi_busy_delay; - // This value is increased every time we tried to execute two commands - // consecutively, and the second one failed because the previous hadn't - // completed yet. It's used to add extra run-test/idle cycles after - // starting a command, so we don't have to waste time checking for busy to - // go low. + /* This value is increased every time we tried to execute two commands + * consecutively, and the second one failed because the previous hadn't + * completed yet. It's used to add extra run-test/idle cycles after + * starting a command, so we don't have to waste time checking for busy to + * go low. */ unsigned int ac_busy_delay; bool need_strict_step; @@ -173,12 +173,12 @@ typedef struct { bool abstract_read_fpr_supported; bool abstract_write_fpr_supported; - // When a function returns some error due to a failure indicated by the - // target in cmderr, the caller can look here to see what that error was. - // (Compare with errno.) + /* When a function returns some error due to a failure indicated by the + * target in cmderr, the caller can look here to see what that error was. + * (Compare with errno.) */ uint8_t cmderr; - // Some fields from hartinfo. + /* Some fields from hartinfo. */ uint8_t datasize; uint8_t dataaccess; int16_t dataaddr; @@ -232,7 +232,7 @@ static void decode_dmi(char *text, unsigned address, unsigned data) if (i > 0) *(text++) = ' '; if (mask & (mask >> 1)) { - // If the field is more than 1 bit wide. + /* If the field is more than 1 bit wide. */ sprintf(text, "%s=%d", description[i].name, value); } else { strcpy(text, description[i].name); @@ -245,8 +245,8 @@ static void decode_dmi(char *text, unsigned address, unsigned data) static void dump_field(const struct scan_field *field) { - static const char *op_string[] = {"-", "r", "w", "?"}; - static const char *status_string[] = {"+", "?", "F", "b"}; + static const char * const op_string[] = {"-", "r", "w", "?"}; + static const char * const status_string[] = {"+", "?", "F", "b"}; if (debug_level < LOG_LVL_DEBUG) return; @@ -371,9 +371,8 @@ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, if (exec) idle_count += info->ac_busy_delay; - if (idle_count) { + if (idle_count) jtag_add_runtest(idle_count, TAP_IDLE); - } int retval = jtag_execute_queue(); if (retval != ERROR_OK) { @@ -381,13 +380,11 @@ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, return DMI_STATUS_FAILED; } - if (data_in) { + if (data_in) *data_in = buf_get_u64(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); - } - if (address_in) { + if (address_in) *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); - } dump_field(&field); @@ -403,9 +400,9 @@ static uint64_t dmi_read(struct target *target, uint16_t address) unsigned i = 0; - // This first loop ensures that the read request was actually sent - // to the target. Note that if for some reason this stays busy, - // it is actually due to the previous dmi_read or dmi_write. + /* This first loop ensures that the read request was actually sent + * to the target. Note that if for some reason this stays busy, + * it is actually due to the previous dmi_read or dmi_write. */ for (i = 0; i < 256; i++) { status = dmi_scan(target, NULL, NULL, DMI_OP_READ, address, 0, false); @@ -424,9 +421,9 @@ static uint64_t dmi_read(struct target *target, uint16_t address) abort(); } - // This second loop ensures that we got the read - // data back. Note that NOP can result in a 'busy' result as well, but - // that would be noticed on the next DMI access we do. + /* This second loop ensures that we got the read + * data back. Note that NOP can result in a 'busy' result as well, but + * that would be noticed on the next DMI access we do. */ uint64_t value; for (i = 0; i < 256; i++) { status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0, @@ -456,7 +453,7 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value) dmi_status_t status = DMI_STATUS_BUSY; unsigned i = 0; - // The first loop ensures that we successfully sent the write request. + /* The first loop ensures that we successfully sent the write request. */ for (i = 0; i < 256; i++) { status = dmi_scan(target, NULL, NULL, DMI_OP_WRITE, address, value, address == DMI_COMMAND); @@ -476,8 +473,9 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value) abort(); } - // The second loop isn't strictly necessary, but would ensure that - // the write is complete/ has no non-busy errors before returning from this function. + /* The second loop isn't strictly necessary, but would ensure that the + * write is complete/ has no non-busy errors before returning from this + * function. */ for (i = 0; i < 256; i++) { status = dmi_scan(target, NULL, NULL, DMI_OP_NOP, address, 0, false); @@ -529,9 +527,8 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) while (1) { *abstractcs = dmi_read(target, DMI_ABSTRACTCS); - if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0) { + if (get_field(*abstractcs, DMI_ABSTRACTCS_BUSY) == 0) return ERROR_OK; - } if (time(NULL) - start > riscv_command_timeout_sec) { info->cmderr = get_field(*abstractcs, DMI_ABSTRACTCS_CMDERR); @@ -551,9 +548,9 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs) } LOG_ERROR("Timed out after %ds waiting for busy to go low (abstractcs=0x%x). " - "Increase the timeout with riscv set_command_timeout_sec.", - riscv_command_timeout_sec, - *abstractcs); + "Increase the timeout with riscv set_command_timeout_sec.", + riscv_command_timeout_sec, + *abstractcs); return ERROR_FAIL; } } @@ -574,7 +571,7 @@ static int execute_abstract_command(struct target *target, uint32_t command) info->cmderr = get_field(cs, DMI_ABSTRACTCS_CMDERR); if (info->cmderr != 0) { LOG_DEBUG("command 0x%x failed; abstractcs=0x%x", command, cs); - // Clear the error. + /* Clear the error. */ dmi_write(target, DMI_ABSTRACTCS, set_field(0, DMI_ABSTRACTCS_CMDERR, info->cmderr)); return ERROR_FAIL; @@ -704,9 +701,8 @@ static int register_write_abstract(struct target *target, uint32_t number, AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); - if (write_abstract_arg(target, 0, value) != ERROR_OK) { + if (write_abstract_arg(target, 0, value) != ERROR_OK) return ERROR_FAIL; - } int result = execute_abstract_command(target, command); if (result != ERROR_OK) { @@ -732,7 +728,7 @@ static int examine_progbuf(struct target *target) if (info->progbuf_writable != YNM_MAYBE) return ERROR_OK; - // Figure out if progbuf is writable. + /* Figure out if progbuf is writable. */ if (info->progbufsize < 1) { info->progbuf_writable = YNM_NO; @@ -761,8 +757,8 @@ static int examine_progbuf(struct target *target) return ERROR_FAIL; if (result != ERROR_OK) { - // This program might have failed if the program buffer is not - // writable. + /* This program might have failed if the program buffer is not + * writable. */ info->progbuf_writable = YNM_NO; return ERROR_OK; } @@ -789,11 +785,11 @@ typedef enum { } memory_space_t; typedef struct { - // How can the debugger access this memory? + /* How can the debugger access this memory? */ memory_space_t memory_space; - // Memory address to access the scratch memory from the hart. + /* Memory address to access the scratch memory from the hart. */ riscv_addr_t hart_address; - // Memory address to access the scratch memory from the debugger. + /* Memory address to access the scratch memory from the debugger. */ riscv_addr_t debug_address; } scratch_mem_t; @@ -812,12 +808,11 @@ static int scratch_find(struct target *target, alignment *= 2; if (info->dataaccess == 1) { - // Sign extend dataaddr. + /* Sign extend dataaddr. */ scratch->hart_address = info->dataaddr; - if (info->dataaddr & (1<<11)) { + if (info->dataaddr & (1<<11)) scratch->hart_address |= 0xfffffffffffff000ULL; - } - // Align. + /* Align. */ scratch->hart_address = (scratch->hart_address + alignment - 1) & ~(alignment - 1); if ((size_bytes + scratch->hart_address - info->dataaddr + 3) / 4 >= @@ -831,8 +826,8 @@ static int scratch_find(struct target *target, if (examine_progbuf(target) != ERROR_OK) return ERROR_FAIL; - // Allow for ebreak at the end of the program. - unsigned program_size = (program->instruction_count + 1 ) * 4; + /* Allow for ebreak at the end of the program. */ + unsigned program_size = (program->instruction_count + 1) * 4; scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) & ~(alignment - 1); if ((size_bytes + scratch->hart_address - info->progbuf_address + 3) / 4 >= @@ -961,11 +956,10 @@ static int register_write_direct(struct target *target, unsigned number, return ERROR_FAIL; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - if (riscv_supports_extension(target, 'D')) { + if (riscv_supports_extension(target, 'D')) riscv_program_insert(&program, fmv_d_x(number - GDB_REGNO_FPR0, S0)); - } else { + else riscv_program_insert(&program, fmv_w_x(number - GDB_REGNO_FPR0, S0)); - } } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { riscv_program_csrw(&program, S0, number); } else { @@ -976,7 +970,7 @@ static int register_write_direct(struct target *target, unsigned number, int exec_out = riscv_program_exec(&program, target); - // Restore S0. + /* Restore S0. */ if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; @@ -1004,10 +998,10 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - // Write program to move data into s0. + /* Write program to move data into s0. */ if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - // TODO: Possibly set F in mstatus. + /* TODO: Possibly set F in mstatus. */ if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a * register, so we need to use some scratch RAM. */ @@ -1033,19 +1027,19 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t abort(); } - // Execute program. + /* Execute program. */ result = riscv_program_exec(&program, target); if (use_scratch) { if (scratch_read64(target, &scratch, value) != ERROR_OK) return ERROR_FAIL; } else { - // Read S0 + /* Read S0 */ if (register_read_direct(target, value, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; } - // Restore S0. + /* Restore S0. */ if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; } @@ -1094,11 +1088,11 @@ static int init_target(struct command_context *cmd_ctx, info->dmi_busy_delay = 0; info->ac_busy_delay = 0; - // Assume all these abstract commands are supported until we learn - // otherwise. - // TODO: The spec allows eg. one CSR to be able to be accessed abstractly - // while another one isn't. We don't track that this closely here, but in - // the future we probably should. + /* Assume all these abstract commands are supported until we learn + * otherwise. + * TODO: The spec allows eg. one CSR to be able to be accessed abstractly + * while another one isn't. We don't track that this closely here, but in + * the future we probably should. */ info->abstract_read_csr_supported = true; info->abstract_write_csr_supported = true; info->abstract_read_fpr_supported = true; @@ -1117,7 +1111,7 @@ static void deinit_target(struct target *target) static int examine(struct target *target) { - // Don't need to select dbus, since the first thing we do is read dtmcontrol. + /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ uint32_t dtmcontrol = dtmcontrol_scan(target, 0); LOG_DEBUG("dtmcontrol=0x%x", dtmcontrol); @@ -1147,7 +1141,7 @@ static int examine(struct target *target) return ERROR_FAIL; } - // Reset the Debug Module. + /* Reset the Debug Module. */ dmi_write(target, DMI_DMCONTROL, 0); dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); @@ -1184,7 +1178,7 @@ static int examine(struct target *target) return ERROR_FAIL; } - // Check that abstract data registers are accessible. + /* Check that abstract data registers are accessible. */ uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); @@ -1193,8 +1187,8 @@ static int examine(struct target *target) RISCV_INFO(r); r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); - // Don't call any riscv_* functions until after we've counted the number of - // cores and initialized registers. + /* Don't call any riscv_* functions until after we've counted the number of + * cores and initialized registers. */ for (int i = 0; i < RISCV_MAX_HARTS; ++i) { if (!riscv_rtos_enabled(target) && i != target->coreid) continue; @@ -1203,29 +1197,26 @@ static int examine(struct target *target) riscv013_select_current_hart(target); uint32_t s = dmi_read(target, DMI_DMSTATUS); - if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) { + if (get_field(s, DMI_DMSTATUS_ANYNONEXISTENT)) break; - } r->hart_count = i + 1; - if (!riscv_is_halted(target)) { + if (!riscv_is_halted(target)) riscv013_halt_current_hart(target); - } /* Without knowing anything else we can at least mess with the * program buffer. */ r->debug_buffer_size[i] = info->progbufsize; int result = register_read_abstract(target, NULL, GDB_REGNO_S0, 64); - if (result == ERROR_OK) { + if (result == ERROR_OK) r->xlen[i] = 64; - } else { + else r->xlen[i] = 32; - } register_read_direct(target, &r->misa, GDB_REGNO_MISA); - // Now init registers based on what we discovered. + /* Now init registers based on what we discovered. */ if (riscv_init_registers(target) != ERROR_OK) return ERROR_FAIL; @@ -1241,19 +1232,18 @@ static int examine(struct target *target) riscv_enumerate_triggers(target); /* Resumes all the harts, so the debugger can later pause them. */ - // TODO: Only do this if the harts were halted to start with. + /* TODO: Only do this if the harts were halted to start with. */ riscv_resume_all_harts(target); target->state = TARGET_RUNNING; target_set_examined(target); - if (target->rtos) { + if (target->rtos) riscv_update_threads(target->rtos); - } - // Some regression suites rely on seeing 'Examined RISC-V core' to know - // when they can connect with gdb/telnet. - // We will need to update those suites if we want to change that text. + /* Some regression suites rely on seeing 'Examined RISC-V core' to know + * when they can connect with gdb/telnet. + * We will need to update those suites if we want to change that text. */ LOG_INFO("Examined RISC-V core; found %d harts", riscv_count_harts(target)); for (int i = 0; i < riscv_count_harts(target); ++i) { @@ -1276,12 +1266,12 @@ static int assert_reset(struct target *target) uint32_t control_base = set_field(0, DMI_DMCONTROL_DMACTIVE, 1); if (target->rtos) { - // There's only one target, and OpenOCD thinks each hart is a thread. - // We must reset them all. + /* There's only one target, and OpenOCD thinks each hart is a thread. + * We must reset them all. */ - // TODO: Try to use hasel in dmcontrol + /* TODO: Try to use hasel in dmcontrol */ - // Set haltreq/resumereq for each hart. + /* Set haltreq/resumereq for each hart. */ uint32_t control = control_base; for (int i = 0; i < riscv_count_harts(target); ++i) { if (!riscv_hart_enabled(target, i)) @@ -1292,12 +1282,12 @@ static int assert_reset(struct target *target) target->reset_halt ? 1 : 0); dmi_write(target, DMI_DMCONTROL, control); } - // Assert ndmreset + /* Assert ndmreset */ control = set_field(control, DMI_DMCONTROL_NDMRESET, 1); dmi_write(target, DMI_DMCONTROL, control); } else { - // Reset just this hart. + /* Reset just this hart. */ uint32_t control = set_field(control_base, DMI_DMCONTROL_HARTSEL, r->current_hartid); control = set_field(control, DMI_DMCONTROL_HALTREQ, @@ -1305,11 +1295,11 @@ static int assert_reset(struct target *target) control = set_field(control, DMI_DMCONTROL_HARTRESET, 1); dmi_write(target, DMI_DMCONTROL, control); - // Read back to check if hartreset is supported. + /* Read back to check if hartreset is supported. */ uint32_t rb = dmi_read(target, DMI_DMCONTROL); if (!get_field(rb, DMI_DMCONTROL_HARTRESET)) { - // Use ndmreset instead. That will reset the entire device, but - // that's probably what OpenOCD wants anyway. + /* Use ndmreset instead. That will reset the entire device, but + * that's probably what OpenOCD wants anyway. */ control = set_field(control, DMI_DMCONTROL_HARTRESET, 0); control = set_field(control, DMI_DMCONTROL_NDMRESET, 1); dmi_write(target, DMI_DMCONTROL, control); @@ -1329,7 +1319,7 @@ static int deassert_reset(struct target *target) LOG_DEBUG("%d", r->current_hartid); - // Clear the reset, but make sure haltreq is still set + /* Clear the reset, but make sure haltreq is still set */ uint32_t control = 0; control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); control = set_field(control, DMI_DMCONTROL_HARTSEL, r->current_hartid); @@ -1405,7 +1395,8 @@ static void write_to_buf(uint8_t *buffer, uint64_t value, unsigned size) } } -static int execute_fence(struct target *target) { +static int execute_fence(struct target *target) +{ struct riscv_program program; riscv_program_init(&program, target); riscv_program_fence(&program); @@ -1441,7 +1432,7 @@ static int read_memory(struct target *target, target_addr_t address, if (execute_fence(target) != ERROR_OK) return ERROR_FAIL; - // Write the program (load, increment) + /* Write the program (load, increment) */ struct riscv_program program; riscv_program_init(&program, target); switch (size) { @@ -1464,7 +1455,7 @@ static int read_memory(struct target *target, target_addr_t address, return ERROR_FAIL; riscv_program_write(&program); - // Write address to S0, and execute buffer. + /* Write address to S0, and execute buffer. */ if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) return ERROR_FAIL; uint32_t command = access_register_command(GDB_REGNO_S1, riscv_xlen(target), @@ -1473,27 +1464,27 @@ static int read_memory(struct target *target, target_addr_t address, if (execute_abstract_command(target, command) != ERROR_OK) return ERROR_FAIL; - // First read has just triggered. Result is in s1. + /* First read has just triggered. Result is in s1. */ dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); - // read_addr is the next address that the hart will read from, which is the - // value in s0. + /* read_addr is the next address that the hart will read from, which is the + * value in s0. */ riscv_addr_t read_addr = address + size; - // The next address that we need to receive data for. + /* The next address that we need to receive data for. */ riscv_addr_t receive_addr = address; riscv_addr_t fin_addr = address + (count * size); unsigned skip = 1; while (read_addr < fin_addr) { LOG_DEBUG("read_addr=0x%" PRIx64 ", receive_addr=0x%" PRIx64 ", fin_addr=0x%" PRIx64, read_addr, receive_addr, fin_addr); - // The pipeline looks like this: - // memory -> s1 -> dm_data0 -> debugger - // It advances every time the debugger reads dmdata0. - // So at any time the debugger has just read mem[s0 - 3*size], - // dm_data0 contains mem[s0 - 2*size] - // s1 contains mem[s0-size] + /* The pipeline looks like this: + * memory -> s1 -> dm_data0 -> debugger + * It advances every time the debugger reads dmdata0. + * So at any time the debugger has just read mem[s0 - 3*size], + * dm_data0 contains mem[s0 - 2*size] + * s1 contains mem[s0-size] */ LOG_DEBUG("creating burst to read from 0x%" TARGET_PRIxADDR " up to 0x%" TARGET_PRIxADDR, read_addr, fin_addr); @@ -1512,8 +1503,8 @@ static int read_memory(struct target *target, target_addr_t address, riscv_batch_run(batch); - // Wait for the target to finish performing the last abstract command, - // and update our copy of cmderr. + /* Wait for the target to finish performing the last abstract command, + * and update our copy of cmderr. */ uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) abstractcs = dmi_read(target, DMI_ABSTRACTCS); @@ -1538,7 +1529,7 @@ static int read_memory(struct target *target, target_addr_t address, +#include + #include - + #include "debug_module.h" @@ -398,6 +400,15 @@ bool debug_module_t::perform_abstract_command() // Since the next instruction is what we will use, just use nother NOP @@ -1562,17 +1553,17 @@ static int read_memory(struct target *target, target_addr_t address, dmi_write(target, DMI_ABSTRACTAUTO, 0); - // This is definitely a good version of the value that we - // attempted to read when we discovered that the target was - // busy. + /* This is definitely a good version of the value that we + * attempted to read when we discovered that the target was + * busy. */ dmi_data0 = dmi_read(target, DMI_DATA0); - // Clobbers DMI_DATA0. + /* Clobbers DMI_DATA0. */ if (register_read_direct(target, &next_read_addr, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - // Restore the command, and execute it. - // Now DMI_DATA0 contains the next value just as it would if no - // error had occurred. + /* Restore the command, and execute it. + * Now DMI_DATA0 contains the next value just as it would if no + * error had occurred. */ dmi_write(target, DMI_COMMAND, command); dmi_write(target, DMI_ABSTRACTAUTO, @@ -1588,11 +1579,10 @@ static int read_memory(struct target *target, target_addr_t address, return ERROR_FAIL; } - // Now read whatever we got out of the batch. + /* Now read whatever we got out of the batch. */ for (size_t i = 0; i < reads; i++) { - if (read_addr >= next_read_addr) { + if (read_addr >= next_read_addr) break; - } read_addr += size; @@ -1625,14 +1615,14 @@ static int read_memory(struct target *target, target_addr_t address, dmi_write(target, DMI_ABSTRACTAUTO, 0); if (count > 1) { - // Read the penultimate word. + /* Read the penultimate word. */ uint64_t value = dmi_read(target, DMI_DATA0); write_to_buf(buffer + receive_addr - address, value, size); LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value); receive_addr += size; } - // Read the last word. + /* Read the last word. */ uint64_t value; if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; @@ -1664,7 +1654,7 @@ static int write_memory(struct target *target, target_addr_t address, if (register_read_direct(target, &s1, GDB_REGNO_S1) != ERROR_OK) return ERROR_FAIL; - // Write the program (store, increment) + /* Write the program (store, increment) */ struct riscv_program program; riscv_program_init(&program, target); @@ -1736,12 +1726,12 @@ static int write_memory(struct target *target, target_addr_t address, address + offset) != ERROR_OK) return ERROR_FAIL; - // Write value. + /* Write value. */ dmi_write(target, DMI_DATA0, value); - // Write and execute command that moves value into S1 and - // executes program buffer. - uint32_t command = access_register_command(GDB_REGNO_S1, 32, + /* Write and execute command that moves value into S1 and + * executes program buffer. */ + uint32_t command = access_register_command(GDB_REGNO_S1, 32, AC_ACCESS_REGISTER_POSTEXEC | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); @@ -1749,7 +1739,7 @@ static int write_memory(struct target *target, target_addr_t address, if (result != ERROR_OK) return result; - // Turn on autoexec + /* Turn on autoexec */ dmi_write(target, DMI_ABSTRACTAUTO, 1 << DMI_ABSTRACTAUTO_AUTOEXECDATA_OFFSET); @@ -1764,9 +1754,9 @@ static int write_memory(struct target *target, target_addr_t address, riscv_batch_run(batch); riscv_batch_free(batch); - // Note that if the scan resulted in a Busy DMI response, it - // is this read to abstractcs that will cause the dmi_busy_delay - // to be incremented if necessary. + /* Note that if the scan resulted in a Busy DMI response, it + * is this read to abstractcs that will cause the dmi_busy_delay + * to be incremented if necessary. */ uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) @@ -1815,8 +1805,7 @@ static int arch_state(struct target *target) return ERROR_OK; } -struct target_type riscv013_target = -{ +struct target_type riscv013_target = { .name = "riscv", .init_target = init_target, @@ -2102,7 +2091,7 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste void riscv013_clear_abstract_error(struct target *target) { - // Wait for busy to go away. + /* Wait for busy to go away. */ time_t start = time(NULL); uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); while (get_field(abstractcs, DMI_ABSTRACTCS_BUSY)) { @@ -2117,6 +2106,6 @@ void riscv013_clear_abstract_error(struct target *target) break; } } - // Clear the error status. + /* Clear the error status. */ dmi_write(target, DMI_ABSTRACTCS, abstractcs & DMI_ABSTRACTCS_CMDERR); } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 053655ca6..efc30e202 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -65,7 +65,7 @@ #define DIM(x) (sizeof(x)/sizeof(*x)) -// Constants for legacy SiFive hardware breakpoints. +/* Constants for legacy SiFive hardware breakpoints. */ #define CSR_BPCONTROL_X (1<<0) #define CSR_BPCONTROL_W (1<<1) #define CSR_BPCONTROL_R (1<<2) @@ -185,8 +185,8 @@ int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC; /* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/ int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC; -bool riscv_use_scratch_ram = false; -uint64_t riscv_scratch_ram_address = 0; +bool riscv_use_scratch_ram; +uint64_t riscv_scratch_ram_address; /* In addition to the ones in the standard spec, we'll also expose additional * CSRs in this list. @@ -284,7 +284,7 @@ static void trigger_from_breakpoint(struct trigger *trigger, trigger->read = false; trigger->write = false; trigger->execute = true; - // unique_id is unique across both breakpoints and watchpoints. + /* unique_id is unique across both breakpoints and watchpoints. */ trigger->unique_id = breakpoint->unique_id; } @@ -304,7 +304,7 @@ static int maybe_add_trigger_t1(struct target *target, unsigned hartid, const uint32_t bpcontrol_bpaction = 0xff << 11; if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) { - // Trigger is already in use, presumably by user code. + /* Trigger is already in use, presumably by user code. */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -315,8 +315,8 @@ static int maybe_add_trigger_t1(struct target *target, unsigned hartid, tdata1 = set_field(tdata1, bpcontrol_s, !!(r->misa & (1 << ('S' - 'A')))); tdata1 = set_field(tdata1, bpcontrol_h, !!(r->misa & (1 << ('H' - 'A')))); tdata1 |= bpcontrol_m; - tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); // exact match - tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); // cause bp exception + tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ + tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */ riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, tdata1); @@ -342,13 +342,13 @@ static int maybe_add_trigger_t2(struct target *target, unsigned hartid, { RISCV_INFO(r); - // tselect is already set + /* tselect is already set */ if (tdata1 & (MCONTROL_EXECUTE | MCONTROL_STORE | MCONTROL_LOAD)) { - // Trigger is already in use, presumably by user code. + /* Trigger is already in use, presumably by user code. */ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - // address/data match trigger + /* address/data match trigger */ tdata1 |= MCONTROL_DMODE(riscv_xlen(target)); tdata1 = set_field(tdata1, MCONTROL_ACTION, MCONTROL_ACTION_DEBUG_MODE); @@ -390,12 +390,12 @@ static int add_trigger(struct target *target, struct trigger *trigger) { RISCV_INFO(r); - // In RTOS mode, we need to set the same trigger in the same slot on every - // hart, to keep up the illusion that each hart is a thread running on the - // same core. + /* In RTOS mode, we need to set the same trigger in the same slot on every + * hart, to keep up the illusion that each hart is a thread running on the + * same core. */ - // Otherwise, we just set the trigger on the one hart this target deals - // with. + /* Otherwise, we just set the trigger on the one hart this target deals + * with. */ riscv_reg_t tselect[RISCV_MAX_HARTS]; @@ -412,9 +412,8 @@ static int add_trigger(struct target *target, struct trigger *trigger) unsigned int i; for (i = 0; i < r->trigger_count[first_hart]; i++) { - if (r->trigger_unique_id[i] != -1) { + if (r->trigger_unique_id[i] != -1) continue; - } riscv_set_register_on_hart(target, first_hart, GDB_REGNO_TSELECT, i); @@ -425,9 +424,8 @@ static int add_trigger(struct target *target, struct trigger *trigger) for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { if (!riscv_hart_enabled(target, hartid)) continue; - if (hartid > first_hart) { + if (hartid > first_hart) riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i); - } switch (type) { case 1: result = maybe_add_trigger_t1(target, hartid, trigger, tdata1); @@ -440,14 +438,12 @@ static int add_trigger(struct target *target, struct trigger *trigger) continue; } - if (result != ERROR_OK) { + if (result != ERROR_OK) continue; - } } - if (result != ERROR_OK) { + if (result != ERROR_OK) continue; - } LOG_DEBUG("Using trigger %d (type %d) for bp %d", i, type, trigger->unique_id); @@ -481,11 +477,10 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) } int retval; - if (breakpoint->length == 4) { + if (breakpoint->length == 4) retval = target_write_u32(target, breakpoint->address, ebreak()); - } else { + else retval = target_write_u16(target, breakpoint->address, ebreak_c()); - } if (retval != ERROR_OK) { LOG_ERROR("Failed to write %d-byte breakpoint instruction at 0x%" TARGET_PRIxADDR, breakpoint->length, breakpoint->address); @@ -496,9 +491,8 @@ int riscv_add_breakpoint(struct target *target, struct breakpoint *breakpoint) struct trigger trigger; trigger_from_breakpoint(&trigger, breakpoint); int result = add_trigger(target, &trigger); - if (result != ERROR_OK) { + if (result != ERROR_OK) return result; - } } else { LOG_INFO("OpenOCD only supports hardware and software breakpoints."); @@ -527,9 +521,8 @@ static int remove_trigger(struct target *target, struct trigger *trigger) unsigned int i; for (i = 0; i < r->trigger_count[first_hart]; i++) { - if (r->trigger_unique_id[i] == trigger->unique_id) { + if (r->trigger_unique_id[i] == trigger->unique_id) break; - } } if (i >= r->trigger_count[first_hart]) { LOG_ERROR("Couldn't find the hardware resources used by hardware " @@ -565,9 +558,8 @@ int riscv_remove_breakpoint(struct target *target, struct trigger trigger; trigger_from_breakpoint(&trigger, breakpoint); int result = remove_trigger(target, &trigger); - if (result != ERROR_OK) { + if (result != ERROR_OK) return result; - } } else { LOG_INFO("OpenOCD only supports hardware and software breakpoints."); @@ -589,7 +581,7 @@ static void trigger_from_watchpoint(struct trigger *trigger, trigger->read = (watchpoint->rw == WPT_READ || watchpoint->rw == WPT_ACCESS); trigger->write = (watchpoint->rw == WPT_WRITE || watchpoint->rw == WPT_ACCESS); trigger->execute = false; - // unique_id is unique across both breakpoints and watchpoints. + /* unique_id is unique across both breakpoints and watchpoints. */ trigger->unique_id = watchpoint->unique_id; } @@ -599,9 +591,8 @@ int riscv_add_watchpoint(struct target *target, struct watchpoint *watchpoint) trigger_from_watchpoint(&trigger, watchpoint); int result = add_trigger(target, &trigger); - if (result != ERROR_OK) { + if (result != ERROR_OK) return result; - } watchpoint->set = true; return ERROR_OK; @@ -614,9 +605,8 @@ int riscv_remove_watchpoint(struct target *target, trigger_from_watchpoint(&trigger, watchpoint); int result = remove_trigger(target, &trigger); - if (result != ERROR_OK) { + if (result != ERROR_OK) return result; - } watchpoint->set = false; return ERROR_OK; @@ -651,7 +641,7 @@ static int riscv_examine(struct target *target) return ERROR_OK; } - // Don't need to select dbus, since the first thing we do is read dtmcontrol. + /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ riscv_info_t *info = (riscv_info_t *) target->arch_info; uint32_t dtmcontrol = dtmcontrol_scan(target, 0); @@ -775,9 +765,8 @@ static int riscv_get_gdb_reg_list(struct target *target, } *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); - if (!*reg_list) { + if (!*reg_list) return ERROR_FAIL; - } for (int i = 0; i < *reg_list_size; i++) { assert(!target->reg_cache->reg_list[i].valid || @@ -794,7 +783,7 @@ static int riscv_arch_state(struct target *target) return tt->arch_state(target); } -// Algorithm must end with a software breakpoint instruction. +/* Algorithm must end with a software breakpoint instruction. */ static int riscv_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, @@ -812,11 +801,10 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, return ERROR_TARGET_NOT_HALTED; } - /// Save registers + /* Save registers */ struct reg *reg_pc = register_get_by_name(target->reg_cache, "pc", 1); - if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK) { + if (!reg_pc || reg_pc->type->get(reg_pc) != ERROR_OK) return ERROR_FAIL; - } uint64_t saved_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); uint64_t saved_regs[32]; @@ -839,17 +827,15 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, return ERROR_FAIL; } - if (r->type->get(r) != ERROR_OK) { + if (r->type->get(r) != ERROR_OK) return ERROR_FAIL; - } saved_regs[r->number] = buf_get_u64(r->value, 0, r->size); - if (r->type->set(r, reg_params[i].value) != ERROR_OK) { + if (r->type->set(r, reg_params[i].value) != ERROR_OK) return ERROR_FAIL; - } } - // Disable Interrupts before attempting to run the algorithm. + /* Disable Interrupts before attempting to run the algorithm. */ uint64_t current_mstatus; uint8_t mstatus_bytes[8]; @@ -869,11 +855,10 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, reg_mstatus->type->set(reg_mstatus, mstatus_bytes); - /// Run algorithm + /* Run algorithm */ LOG_DEBUG("resume at 0x%" TARGET_PRIxADDR, entry_point); - if (oldriscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK) { + if (oldriscv_resume(target, 0, entry_point, 0, 0) != ERROR_OK) return ERROR_FAIL; - } int64_t start = timeval_ms(); while (target->state != TARGET_HALTED) { @@ -889,14 +874,12 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, } int result = old_or_new_riscv_poll(target); - if (result != ERROR_OK) { + if (result != ERROR_OK) return result; - } } - if (reg_pc->type->get(reg_pc) != ERROR_OK) { + if (reg_pc->type->get(reg_pc) != ERROR_OK) return ERROR_FAIL; - } uint64_t final_pc = buf_get_u64(reg_pc->value, 0, reg_pc->size); if (final_pc != exit_point) { LOG_ERROR("PC ended up at 0x%" PRIx64 " instead of 0x%" @@ -904,37 +887,35 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, return ERROR_FAIL; } - // Restore Interrupts + /* Restore Interrupts */ LOG_DEBUG("Restoring Interrupts"); buf_set_u64(mstatus_bytes, 0, info->xlen[0], current_mstatus); reg_mstatus->type->set(reg_mstatus, mstatus_bytes); - /// Restore registers + /* Restore registers */ uint8_t buf[8]; buf_set_u64(buf, 0, info->xlen[0], saved_pc); - if (reg_pc->type->set(reg_pc, buf) != ERROR_OK) { + if (reg_pc->type->set(reg_pc, buf) != ERROR_OK) return ERROR_FAIL; - } for (int i = 0; i < num_reg_params; i++) { LOG_DEBUG("restore %s", reg_params[i].reg_name); struct reg *r = register_get_by_name(target->reg_cache, reg_params[i].reg_name, 0); buf_set_u64(buf, 0, info->xlen[0], saved_regs[r->number]); - if (r->type->set(r, buf) != ERROR_OK) { + if (r->type->set(r, buf) != ERROR_OK) return ERROR_FAIL; - } } return ERROR_OK; } -/* Should run code on the target to perform CRC of +/* Should run code on the target to perform CRC of memory. Not yet implemented. */ static int riscv_checksum_memory(struct target *target, target_addr_t address, uint32_t count, - uint32_t* checksum) + uint32_t *checksum) { *checksum = 0xFFFFFFFF; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -945,10 +926,10 @@ block holds all-ones (because this is generally called on NOR flash which is 1 when "blank") Not yet implemented. */ -int riscv_blank_check_memory(struct target * target, +int riscv_blank_check_memory(struct target *target, target_addr_t address, uint32_t count, - uint32_t * blank, + uint32_t *blank, uint8_t erased_value) { *blank = 0; @@ -1031,7 +1012,7 @@ int riscv_openocd_poll(struct target *target) target->debug_reason = DBG_REASON_SINGLESTEP; break; } - + if (riscv_rtos_enabled(target)) { target->rtos->current_threadid = triggered_hart + 1; target->rtos->current_thread = triggered_hart + 1; @@ -1075,9 +1056,8 @@ int riscv_openocd_resume( ) { LOG_DEBUG("resuming all harts"); - if (!current) { + if (!current) riscv_set_register(target, GDB_REGNO_PC, address); - } int out = riscv_resume_all_harts(target); if (out != ERROR_OK) { @@ -1099,9 +1079,8 @@ int riscv_openocd_step( ) { LOG_DEBUG("stepping rtos hart"); - if (!current) { + if (!current) riscv_set_register(target, GDB_REGNO_PC, address); - } int out = riscv_step_rtos_hart(target); if (out != ERROR_OK) { @@ -1126,7 +1105,7 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec) return ERROR_COMMAND_SYNTAX_ERROR; } int timeout = atoi(CMD_ARGV[0]); - if (timeout <= 0){ + if (timeout <= 0) { LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); return ERROR_FAIL; } @@ -1143,7 +1122,7 @@ COMMAND_HANDLER(riscv_set_reset_timeout_sec) return ERROR_COMMAND_SYNTAX_ERROR; } int timeout = atoi(CMD_ARGV[0]); - if (timeout <= 0){ + if (timeout <= 0) { LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); return ERROR_FAIL; } @@ -1204,7 +1183,7 @@ COMMAND_HANDLER(riscv_set_expose_csrs) for (unsigned i = 0; i == 0 || CMD_ARGV[0][i-1]; i++) { char c = CMD_ARGV[0][i]; if (isspace(c)) { - // Ignore whitespace. + /* Ignore whitespace. */ continue; } @@ -1303,8 +1282,7 @@ const struct command_registration riscv_command_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct target_type riscv_target = -{ +struct target_type riscv_target = { .name = "riscv", .init_target = riscv_init_target, @@ -1443,13 +1421,12 @@ bool riscv_supports_extension(struct target *target, char letter) { RISCV_INFO(r); unsigned num; - if (letter >= 'a' && letter <= 'z') { + if (letter >= 'a' && letter <= 'z') num = letter - 'a'; - } else if (letter >= 'A' && letter <= 'Z') { + else if (letter >= 'A' && letter <= 'Z') num = letter - 'A'; - } else { + else return false; - } return r->misa & (1 << num); } @@ -1533,9 +1510,11 @@ void riscv_set_rtos_hartid(struct target *target, int hartid) int riscv_count_harts(struct target *target) { - if (target == NULL) return 1; + if (target == NULL) + return 1; RISCV_INFO(r); - if (r == NULL) return 1; + if (r == NULL) + return 1; return r->hart_count; } @@ -1546,7 +1525,7 @@ bool riscv_has_register(struct target *target, int hartid, int regid) void riscv_set_register(struct target *target, enum gdb_regno r, riscv_reg_t v) { - // TODO: propagate errors + /* TODO: propagate errors */ return riscv_set_register_on_hart(target, riscv_current_hartid(target), r, v); } @@ -1697,8 +1676,8 @@ int riscv_enumerate_triggers(struct target *target) riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, t); uint64_t tselect_rb = riscv_get_register_on_hart(target, hartid, GDB_REGNO_TSELECT); - // Mask off the top bit, which is used as tdrmode in old - // implementations. + /* Mask off the top bit, which is used as tdrmode in old + * implementations. */ tselect_rb &= ~(1ULL << (riscv_xlen(target)-1)); if (tselect_rb != t) break; @@ -1707,14 +1686,13 @@ int riscv_enumerate_triggers(struct target *target) int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); switch (type) { case 1: - // On these older cores we don't support software using - // triggers. + /* On these older cores we don't support software using + * triggers. */ riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); break; case 2: - if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) { + if (tdata1 & MCONTROL_DMODE(riscv_xlen(target))) riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); - } break; } } @@ -1765,15 +1743,14 @@ const char *gdb_regno_name(enum gdb_regno regno) case GDB_REGNO_PRIV: return "priv"; default: - if (regno <= GDB_REGNO_XPR31) { + if (regno <= GDB_REGNO_XPR31) sprintf(buf, "x%d", regno - GDB_REGNO_ZERO); - } else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { + else if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) sprintf(buf, "csr%d", regno - GDB_REGNO_CSR0); - } else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) { + else if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) sprintf(buf, "f%d", regno - GDB_REGNO_FPR0); - } else { + else sprintf(buf, "gdb_regno_%d", regno); - } return buf; } } @@ -1864,15 +1841,15 @@ int riscv_init_registers(struct target *target) #include "encoding.h" #undef DECLARE_CSR }; - // encoding.h does not contain the registers in sorted order. + /* encoding.h does not contain the registers in sorted order. */ qsort(csr_info, DIM(csr_info), sizeof(*csr_info), cmp_csr_info); unsigned csr_info_index = 0; - // When gdb request register N, gdb_get_register_packet() assumes that this - // is register at index N in reg_list. So if there are certain registers - // that don't exist, we need to leave holes in the list (or renumber, but - // it would be nice not to have yet another set of numbers to translate - // between). + /* When gdb request register N, gdb_get_register_packet() assumes that this + * is register at index N in reg_list. So if there are certain registers + * that don't exist, we need to leave holes in the list (or renumber, but + * it would be nice not to have yet another set of numbers to translate + * between). */ for (uint32_t number = 0; number < GDB_REGNO_COUNT; number++) { struct reg *r = &target->reg_cache->reg_list[number]; r->caller_save = true; @@ -1883,43 +1860,107 @@ int riscv_init_registers(struct target *target) r->arch_info = target; r->number = number; r->size = riscv_xlen(target); - // r->size is set in riscv_invalidate_register_cache, maybe because the - // target is in theory allowed to change XLEN on us. But I expect a lot - // of other things to break in that case as well. + /* r->size is set in riscv_invalidate_register_cache, maybe because the + * target is in theory allowed to change XLEN on us. But I expect a lot + * of other things to break in that case as well. */ if (number <= GDB_REGNO_XPR31) { switch (number) { - case GDB_REGNO_ZERO: r->name = "zero"; break; - case GDB_REGNO_RA: r->name = "ra"; break; - case GDB_REGNO_SP: r->name = "sp"; break; - case GDB_REGNO_GP: r->name = "gp"; break; - case GDB_REGNO_TP: r->name = "tp"; break; - case GDB_REGNO_T0: r->name = "t0"; break; - case GDB_REGNO_T1: r->name = "t1"; break; - case GDB_REGNO_T2: r->name = "t2"; break; - case GDB_REGNO_FP: r->name = "fp"; break; - case GDB_REGNO_S1: r->name = "s1"; break; - case GDB_REGNO_A0: r->name = "a0"; break; - case GDB_REGNO_A1: r->name = "a1"; break; - case GDB_REGNO_A2: r->name = "a2"; break; - case GDB_REGNO_A3: r->name = "a3"; break; - case GDB_REGNO_A4: r->name = "a4"; break; - case GDB_REGNO_A5: r->name = "a5"; break; - case GDB_REGNO_A6: r->name = "a6"; break; - case GDB_REGNO_A7: r->name = "a7"; break; - case GDB_REGNO_S2: r->name = "s2"; break; - case GDB_REGNO_S3: r->name = "s3"; break; - case GDB_REGNO_S4: r->name = "s4"; break; - case GDB_REGNO_S5: r->name = "s5"; break; - case GDB_REGNO_S6: r->name = "s6"; break; - case GDB_REGNO_S7: r->name = "s7"; break; - case GDB_REGNO_S8: r->name = "s8"; break; - case GDB_REGNO_S9: r->name = "s9"; break; - case GDB_REGNO_S10: r->name = "s10"; break; - case GDB_REGNO_S11: r->name = "s11"; break; - case GDB_REGNO_T3: r->name = "t3"; break; - case GDB_REGNO_T4: r->name = "t4"; break; - case GDB_REGNO_T5: r->name = "t5"; break; - case GDB_REGNO_T6: r->name = "t6"; break; + case GDB_REGNO_ZERO: + r->name = "zero"; + break; + case GDB_REGNO_RA: + r->name = "ra"; + break; + case GDB_REGNO_SP: + r->name = "sp"; + break; + case GDB_REGNO_GP: + r->name = "gp"; + break; + case GDB_REGNO_TP: + r->name = "tp"; + break; + case GDB_REGNO_T0: + r->name = "t0"; + break; + case GDB_REGNO_T1: + r->name = "t1"; + break; + case GDB_REGNO_T2: + r->name = "t2"; + break; + case GDB_REGNO_FP: + r->name = "fp"; + break; + case GDB_REGNO_S1: + r->name = "s1"; + break; + case GDB_REGNO_A0: + r->name = "a0"; + break; + case GDB_REGNO_A1: + r->name = "a1"; + break; + case GDB_REGNO_A2: + r->name = "a2"; + break; + case GDB_REGNO_A3: + r->name = "a3"; + break; + case GDB_REGNO_A4: + r->name = "a4"; + break; + case GDB_REGNO_A5: + r->name = "a5"; + break; + case GDB_REGNO_A6: + r->name = "a6"; + break; + case GDB_REGNO_A7: + r->name = "a7"; + break; + case GDB_REGNO_S2: + r->name = "s2"; + break; + case GDB_REGNO_S3: + r->name = "s3"; + break; + case GDB_REGNO_S4: + r->name = "s4"; + break; + case GDB_REGNO_S5: + r->name = "s5"; + break; + case GDB_REGNO_S6: + r->name = "s6"; + break; + case GDB_REGNO_S7: + r->name = "s7"; + break; + case GDB_REGNO_S8: + r->name = "s8"; + break; + case GDB_REGNO_S9: + r->name = "s9"; + break; + case GDB_REGNO_S10: + r->name = "s10"; + break; + case GDB_REGNO_S11: + r->name = "s11"; + break; + case GDB_REGNO_T3: + r->name = "t3"; + break; + case GDB_REGNO_T4: + r->name = "t4"; + break; + case GDB_REGNO_T5: + r->name = "t5"; + break; + case GDB_REGNO_T6: + r->name = "t6"; + break; } r->group = "general"; r->feature = &feature_cpu; @@ -1938,38 +1979,102 @@ int riscv_init_registers(struct target *target) r->exist = false; } switch (number) { - case GDB_REGNO_FT0: r->name = "ft0"; break; - case GDB_REGNO_FT1: r->name = "ft1"; break; - case GDB_REGNO_FT2: r->name = "ft2"; break; - case GDB_REGNO_FT3: r->name = "ft3"; break; - case GDB_REGNO_FT4: r->name = "ft4"; break; - case GDB_REGNO_FT5: r->name = "ft5"; break; - case GDB_REGNO_FT6: r->name = "ft6"; break; - case GDB_REGNO_FT7: r->name = "ft7"; break; - case GDB_REGNO_FS0: r->name = "fs0"; break; - case GDB_REGNO_FS1: r->name = "fs1"; break; - case GDB_REGNO_FA0: r->name = "fa0"; break; - case GDB_REGNO_FA1: r->name = "fa1"; break; - case GDB_REGNO_FA2: r->name = "fa2"; break; - case GDB_REGNO_FA3: r->name = "fa3"; break; - case GDB_REGNO_FA4: r->name = "fa4"; break; - case GDB_REGNO_FA5: r->name = "fa5"; break; - case GDB_REGNO_FA6: r->name = "fa6"; break; - case GDB_REGNO_FA7: r->name = "fa7"; break; - case GDB_REGNO_FS2: r->name = "fs2"; break; - case GDB_REGNO_FS3: r->name = "fs3"; break; - case GDB_REGNO_FS4: r->name = "fs4"; break; - case GDB_REGNO_FS5: r->name = "fs5"; break; - case GDB_REGNO_FS6: r->name = "fs6"; break; - case GDB_REGNO_FS7: r->name = "fs7"; break; - case GDB_REGNO_FS8: r->name = "fs8"; break; - case GDB_REGNO_FS9: r->name = "fs9"; break; - case GDB_REGNO_FS10: r->name = "fs10"; break; - case GDB_REGNO_FS11: r->name = "fs11"; break; - case GDB_REGNO_FT8: r->name = "ft8"; break; - case GDB_REGNO_FT9: r->name = "ft9"; break; - case GDB_REGNO_FT10: r->name = "ft10"; break; - case GDB_REGNO_FT11: r->name = "ft11"; break; + case GDB_REGNO_FT0: + r->name = "ft0"; + break; + case GDB_REGNO_FT1: + r->name = "ft1"; + break; + case GDB_REGNO_FT2: + r->name = "ft2"; + break; + case GDB_REGNO_FT3: + r->name = "ft3"; + break; + case GDB_REGNO_FT4: + r->name = "ft4"; + break; + case GDB_REGNO_FT5: + r->name = "ft5"; + break; + case GDB_REGNO_FT6: + r->name = "ft6"; + break; + case GDB_REGNO_FT7: + r->name = "ft7"; + break; + case GDB_REGNO_FS0: + r->name = "fs0"; + break; + case GDB_REGNO_FS1: + r->name = "fs1"; + break; + case GDB_REGNO_FA0: + r->name = "fa0"; + break; + case GDB_REGNO_FA1: + r->name = "fa1"; + break; + case GDB_REGNO_FA2: + r->name = "fa2"; + break; + case GDB_REGNO_FA3: + r->name = "fa3"; + break; + case GDB_REGNO_FA4: + r->name = "fa4"; + break; + case GDB_REGNO_FA5: + r->name = "fa5"; + break; + case GDB_REGNO_FA6: + r->name = "fa6"; + break; + case GDB_REGNO_FA7: + r->name = "fa7"; + break; + case GDB_REGNO_FS2: + r->name = "fs2"; + break; + case GDB_REGNO_FS3: + r->name = "fs3"; + break; + case GDB_REGNO_FS4: + r->name = "fs4"; + break; + case GDB_REGNO_FS5: + r->name = "fs5"; + break; + case GDB_REGNO_FS6: + r->name = "fs6"; + break; + case GDB_REGNO_FS7: + r->name = "fs7"; + break; + case GDB_REGNO_FS8: + r->name = "fs8"; + break; + case GDB_REGNO_FS9: + r->name = "fs9"; + break; + case GDB_REGNO_FS10: + r->name = "fs10"; + break; + case GDB_REGNO_FS11: + r->name = "fs11"; + break; + case GDB_REGNO_FT8: + r->name = "ft8"; + break; + case GDB_REGNO_FT9: + r->name = "ft9"; + break; + case GDB_REGNO_FT10: + r->name = "ft10"; + break; + case GDB_REGNO_FT11: + r->name = "ft11"; + break; } r->group = "float"; r->feature = &feature_fpu; @@ -1986,11 +2091,11 @@ int riscv_init_registers(struct target *target) r->name = csr_info[csr_info_index].name; } else { sprintf(reg_name, "csr%d", csr_number); - // Assume unnamed registers don't exist, unless we have some - // configuration that tells us otherwise. That's important - // because eg. Eclipse crashes if a target has too many - // registers, and apparently has no way of only showing a - // subset of registers in any case. + /* Assume unnamed registers don't exist, unless we have some + * configuration that tells us otherwise. That's important + * because eg. Eclipse crashes if a target has too many + * registers, and apparently has no way of only showing a + * subset of registers in any case. */ r->exist = false; } @@ -2032,9 +2137,8 @@ int riscv_init_registers(struct target *target) r->feature = &feature_virtual; r->size = 8; } - if (reg_name[0]) { + if (reg_name[0]) r->name = reg_name; - } reg_name += strlen(reg_name) + 1; assert(reg_name < info->reg_names + GDB_REGNO_COUNT * max_reg_name_len); r->value = &info->reg_cache_values[number]; diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 80f6ba204..2af312561 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -141,7 +141,7 @@ int riscv_openocd_resume( struct target *target, int current, target_addr_t address, - int handle_breakpoints, + int handle_breakpoints, int debug_execution ); diff --git a/src/target/target.c b/src/target/target.c index ded20f232..12457fa57 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -2830,8 +2830,8 @@ COMMAND_HANDLER(handle_reg_command) retval = reg->type->set(reg, buf); if (retval != ERROR_OK) { - LOG_DEBUG("Couldn't set register %s.", reg->name); - free (buf); + LOG_DEBUG("Couldn't set register %s.", reg->name); + free(buf); return retval; } From 4fa3d819d2167141e0a62e79267d5dc5df0c90f3 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 26 Dec 2017 14:27:44 -0800 Subject: [PATCH 105/127] Remove unused code. Change-Id: Ibc72945ac76513c84d62616c0210e6013b21f7ef --- src/target/riscv/riscv.c | 16 ---------------- src/target/riscv/riscv.h | 2 -- 2 files changed, 18 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index efc30e202..cda16f35b 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1597,22 +1597,6 @@ riscv_insn_t riscv_read_debug_buffer(struct target *target, int index) return r->read_debug_buffer(target, index); } -riscv_addr_t riscv_read_debug_buffer_x(struct target *target, int index) -{ - riscv_addr_t out = 0; - switch (riscv_xlen(target)) { - case 64: - out |= (uint64_t)riscv_read_debug_buffer(target, index + 1) << 32; - case 32: - out |= riscv_read_debug_buffer(target, index + 0) << 0; - break; - default: - LOG_ERROR("unsupported XLEN %d", riscv_xlen(target)); - abort(); - } - return out; -} - int riscv_execute_debug_buffer(struct target *target) { RISCV_INFO(r); diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 2af312561..71c68a2a7 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -222,9 +222,7 @@ int riscv_count_triggers_of_hart(struct target *target, int hartid); size_t riscv_debug_buffer_size(struct target *target); riscv_insn_t riscv_read_debug_buffer(struct target *target, int index); -riscv_addr_t riscv_read_debug_buffer_x(struct target *target, int index); int riscv_write_debug_buffer(struct target *target, int index, riscv_insn_t insn); -int riscv_write_debug_buffer_x(struct target *target, int index, riscv_addr_t data); int riscv_execute_debug_buffer(struct target *target); void riscv_fill_dmi_nop_u64(struct target *target, char *buf); From 06445f5743a9b65819866b4a36edb809bc8396ee Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 26 Dec 2017 15:04:02 -0800 Subject: [PATCH 106/127] Propagate error instead of calling abort(). As part of this I improved the memory read/write fatal error handling a bit. Now at least we try to leave autoexec turned off, and will even restore the temp registers if the situation isn't too hosed for that. Partly addresses Issue #142 Change-Id: I79fe3f862f11c6d20441f39162423357e73a40c1 --- src/target/riscv/batch.c | 8 ++-- src/target/riscv/batch.h | 2 +- src/target/riscv/riscv-013.c | 86 +++++++++++++++++++++++------------- 3 files changed, 62 insertions(+), 34 deletions(-) diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index f32be3493..117119dd6 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -42,11 +42,11 @@ bool riscv_batch_full(struct riscv_batch *batch) return batch->used_scans > (batch->allocated_scans - 4); } -void riscv_batch_run(struct riscv_batch *batch) +int riscv_batch_run(struct riscv_batch *batch) { if (batch->used_scans == 0) { LOG_DEBUG("Ignoring empty batch."); - return; + return ERROR_OK; } keep_alive(); @@ -63,11 +63,13 @@ void riscv_batch_run(struct riscv_batch *batch) LOG_DEBUG("executing queue"); if (jtag_execute_queue() != ERROR_OK) { LOG_ERROR("Unable to execute JTAG queue"); - abort(); + return ERROR_FAIL; } for (size_t i = 0; i < batch->used_scans; ++i) dump_field(batch->fields + i); + + return ERROR_OK; } void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data) diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 835829b2b..70690a601 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -48,7 +48,7 @@ void riscv_batch_free(struct riscv_batch *batch); bool riscv_batch_full(struct riscv_batch *batch); /* Executes this scan batch. */ -void riscv_batch_run(struct riscv_batch *batch); +int riscv_batch_run(struct riscv_batch *batch); /* Adds a DMI write to this batch. */ void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index e703728f6..25a875b56 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1415,6 +1415,8 @@ static int read_memory(struct target *target, target_addr_t address, { RISCV013_INFO(info); + int result = ERROR_OK; + LOG_DEBUG("reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, size, address); @@ -1456,13 +1458,15 @@ static int read_memory(struct target *target, target_addr_t address, riscv_program_write(&program); /* Write address to S0, and execute buffer. */ - if (register_write_direct(target, GDB_REGNO_S0, address) != ERROR_OK) - return ERROR_FAIL; + result = register_write_direct(target, GDB_REGNO_S0, address); + if (result != ERROR_OK) + goto error; uint32_t command = access_register_command(GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); - if (execute_abstract_command(target, command) != ERROR_OK) - return ERROR_FAIL; + result = execute_abstract_command(target, command); + if (result != ERROR_OK) + goto error; /* First read has just triggered. Result is in s1. */ @@ -1559,8 +1563,12 @@ static int read_memory(struct target *target, target_addr_t address, dmi_data0 = dmi_read(target, DMI_DATA0); /* Clobbers DMI_DATA0. */ - if (register_read_direct(target, &next_read_addr, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; + result = register_read_direct(target, &next_read_addr, + GDB_REGNO_S0); + if (result != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } /* Restore the command, and execute it. * Now DMI_DATA0 contains the next value just as it would if no * error had occurred. */ @@ -1571,12 +1579,10 @@ static int read_memory(struct target *target, target_addr_t address, break; default: LOG_ERROR("error when reading memory, abstractcs=0x%08lx", (long)abstractcs); - dmi_write(target, DMI_ABSTRACTAUTO, 0); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); riscv013_clear_abstract_error(target); riscv_batch_free(batch); - return ERROR_FAIL; + result = ERROR_FAIL; + goto error; } /* Now read whatever we got out of the batch. */ @@ -1624,8 +1630,9 @@ static int read_memory(struct target *target, target_addr_t address, /* Read the last word. */ uint64_t value; - if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) - return ERROR_FAIL; + result = register_read_direct(target, &value, GDB_REGNO_S1); + if (result != ERROR_OK) + goto error; write_to_buf(buffer + receive_addr - address, value, size); LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value); receive_addr += size; @@ -1633,6 +1640,13 @@ static int read_memory(struct target *target, target_addr_t address, riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); return ERROR_OK; + +error: + dmi_write(target, DMI_ABSTRACTAUTO, 0); + + riscv_set_register(target, GDB_REGNO_S0, s0); + riscv_set_register(target, GDB_REGNO_S1, s1); + return result; } static int write_memory(struct target *target, target_addr_t address, @@ -1648,6 +1662,7 @@ static int write_memory(struct target *target, target_addr_t address, * s1 holds the next data value to write */ + int result = ERROR_OK; uint64_t s0, s1; if (register_read_direct(target, &s0, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; @@ -1670,13 +1685,15 @@ static int write_memory(struct target *target, target_addr_t address, break; default: LOG_ERROR("Unsupported size: %d", size); - return ERROR_FAIL; + result = ERROR_FAIL; + goto error; } riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size); - if (riscv_program_ebreak(&program) != ERROR_OK) - return ERROR_FAIL; + result = riscv_program_ebreak(&program); + if (result != ERROR_OK) + goto error; riscv_program_write(&program); riscv_addr_t cur_addr = address; @@ -1715,16 +1732,21 @@ static int write_memory(struct target *target, target_addr_t address, break; default: LOG_ERROR("unsupported access size: %d", size); - return ERROR_FAIL; + riscv_batch_free(batch); + result = ERROR_FAIL; + goto error; } LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value); cur_addr += size; if (setup_needed) { - if (register_write_direct(target, GDB_REGNO_S0, - address + offset) != ERROR_OK) - return ERROR_FAIL; + result = register_write_direct(target, GDB_REGNO_S0, + address + offset); + if (result != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } /* Write value. */ dmi_write(target, DMI_DATA0, value); @@ -1735,9 +1757,11 @@ static int write_memory(struct target *target, target_addr_t address, AC_ACCESS_REGISTER_POSTEXEC | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); - int result = execute_abstract_command(target, command); - if (result != ERROR_OK) - return result; + result = execute_abstract_command(target, command); + if (result != ERROR_OK) { + riscv_batch_free(batch); + goto error; + } /* Turn on autoexec */ dmi_write(target, DMI_ABSTRACTAUTO, @@ -1751,8 +1775,10 @@ static int write_memory(struct target *target, target_addr_t address, } } - riscv_batch_run(batch); + result = riscv_batch_run(batch); riscv_batch_free(batch); + if (result != ERROR_OK) + goto error; /* Note that if the scan resulted in a Busy DMI response, it * is this read to abstractcs that will cause the dmi_busy_delay @@ -1772,21 +1798,21 @@ static int write_memory(struct target *target, target_addr_t address, increase_ac_busy_delay(target); dmi_write(target, DMI_ABSTRACTAUTO, 0); - if (register_read_direct(target, &cur_addr, GDB_REGNO_S0) != ERROR_OK) - return ERROR_FAIL; + result = register_read_direct(target, &cur_addr, GDB_REGNO_S0); + if (result != ERROR_OK) + goto error; setup_needed = true; break; default: LOG_ERROR("error when writing memory, abstractcs=0x%08lx", (long)abstractcs); - dmi_write(target, DMI_ABSTRACTAUTO, 0); riscv013_clear_abstract_error(target); - riscv_set_register(target, GDB_REGNO_S0, s0); - riscv_set_register(target, GDB_REGNO_S1, s1); - return ERROR_FAIL; + result = ERROR_FAIL; + goto error; } } +error: dmi_write(target, DMI_ABSTRACTAUTO, 0); if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) @@ -1797,7 +1823,7 @@ static int write_memory(struct target *target, target_addr_t address, if (execute_fence(target) != ERROR_OK) return ERROR_FAIL; - return ERROR_OK; + return result; } static int arch_state(struct target *target) From 365c79c3ff5ed0c1927ade8b1c09dd356f1d6415 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 27 Dec 2017 13:04:30 -0800 Subject: [PATCH 107/127] Get rid of abort() calls. Also changed a few asserts that could trigger due to broken hardware. Fixes Issue #142. Change-Id: Ia2b99baa82f30ebcb2fd7e4902f0e67046ce4ed2 --- src/target/riscv/program.c | 3 +- src/target/riscv/riscv-011.c | 5 +-- src/target/riscv/riscv-013.c | 76 +++++++++++++++++++++--------------- src/target/riscv/riscv.c | 32 +++++++++------ src/target/riscv/riscv.h | 15 +++---- 5 files changed, 77 insertions(+), 54 deletions(-) diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index 76f63b8fd..a7a2e859d 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -55,7 +55,6 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) LOG_ERROR("Unable to write ebreak"); for (size_t i = 0; i < riscv_debug_buffer_size(p->target); ++i) LOG_ERROR("ram[%02x]: DASM(0x%08lx) [0x%08lx]", (int)i, (long)p->debug_buffer[i], (long)p->debug_buffer[i]); - abort(); return ERROR_FAIL; } @@ -152,7 +151,7 @@ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) LOG_ERROR("Unable to insert instruction:"); LOG_ERROR(" instruction_count=%d", (int)p->instruction_count); LOG_ERROR(" buffer size =%d", (int)riscv_debug_buffer_size(p->target)); - abort(); + return ERROR_FAIL; } p->debug_buffer[p->instruction_count] = i; diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 9490f7a58..18e31c730 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -1329,12 +1329,11 @@ static riscv_reg_t get_register(struct target *target, int hartid, int regid) return value; } -static void set_register(struct target *target, int hartid, int regid, +static int set_register(struct target *target, int hartid, int regid, uint64_t value) { assert(hartid == 0); - /* TODO: propagate errors */ - register_write(target, regid, value); + return register_write(target, regid, value); } static int halt(struct target *target) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 25a875b56..6251765de 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -31,22 +31,22 @@ #define DMI_PROGBUF1 (DMI_PROGBUF0 + 1) static void riscv013_on_step_or_resume(struct target *target, bool step); -static void riscv013_step_or_resume_current_hart(struct target *target, bool step); +static int riscv013_step_or_resume_current_hart(struct target *target, bool step); static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ static riscv_reg_t riscv013_get_register(struct target *target, int hartid, int regid); -static void riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value); +static int riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value); static void riscv013_select_current_hart(struct target *target); -static void riscv013_halt_current_hart(struct target *target); -static void riscv013_resume_current_hart(struct target *target); -static void riscv013_step_current_hart(struct target *target); +static int riscv013_halt_current_hart(struct target *target); +static int riscv013_resume_current_hart(struct target *target); +static int riscv013_step_current_hart(struct target *target); static void riscv013_on_halt(struct target *target); static void riscv013_on_step(struct target *target); static void riscv013_on_resume(struct target *target); static bool riscv013_is_halted(struct target *target); static enum riscv_halt_reason riscv013_halt_reason(struct target *target); -static void riscv013_write_debug_buffer(struct target *target, unsigned index, +static int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t d); static riscv_insn_t riscv013_read_debug_buffer(struct target *target, unsigned index); @@ -418,7 +418,7 @@ static uint64_t dmi_read(struct target *target, uint16_t address) if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("Failed read from 0x%x; status=%d", address, status); - abort(); + return ~0ULL; } /* This second loop ensures that we got the read @@ -441,13 +441,13 @@ static uint64_t dmi_read(struct target *target, uint16_t address) if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("Failed read (NOP) from 0x%x; value=0x%" PRIx64 ", status=%d", address, value, status); - abort(); + return ~0ULL; } return value; } -static void dmi_write(struct target *target, uint16_t address, uint64_t value) +static int dmi_write(struct target *target, uint16_t address, uint64_t value) { select_dmi(target); dmi_status_t status = DMI_STATUS_BUSY; @@ -470,7 +470,7 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value) if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("Failed write to 0x%x;, status=%d", address, status); - abort(); + return ERROR_FAIL; } /* The second loop isn't strictly necessary, but would ensure that the @@ -490,8 +490,10 @@ static void dmi_write(struct target *target, uint16_t address, uint64_t value) } if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("failed to write (NOP) 0x%" PRIx64 " to 0x%x; status=%d", value, address, status); - abort(); + return ERROR_FAIL; } + + return ERROR_OK; } static void increase_ac_busy_delay(struct target *target) @@ -964,7 +966,7 @@ static int register_write_direct(struct target *target, unsigned number, riscv_program_csrw(&program, S0, number); } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); - abort(); + return ERROR_FAIL; } } @@ -1024,7 +1026,7 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t riscv_program_csrr(&program, S0, number); } else { LOG_ERROR("Unsupported register (enum gdb_regno)(%d)", number); - abort(); + return ERROR_FAIL; } /* Execute program. */ @@ -1885,7 +1887,7 @@ static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid return out; } -static void riscv013_set_register(struct target *target, int hid, int rid, uint64_t value) +static int riscv013_set_register(struct target *target, int hid, int rid, uint64_t value) { LOG_DEBUG("writing 0x%" PRIx64 " to register %s on hart %d", value, gdb_regno_name(rid), hid); @@ -1893,22 +1895,28 @@ static void riscv013_set_register(struct target *target, int hid, int rid, uint6 riscv_set_current_hartid(target, hid); if (rid <= GDB_REGNO_XPR31) { - register_write_direct(target, rid, value); + return register_write_direct(target, rid, value); } else if (rid == GDB_REGNO_PC) { LOG_DEBUG("writing PC to DPC: 0x%016" PRIx64, value); register_write_direct(target, GDB_REGNO_DPC, value); uint64_t actual_value; register_read_direct(target, &actual_value, GDB_REGNO_DPC); LOG_DEBUG(" actual DPC written: 0x%016" PRIx64, actual_value); - assert(value == actual_value); + if (value != actual_value) { + LOG_ERROR("Written PC (0x%" PRIx64 ") does not match read back " + "value (0x%" PRIx64 ")", value, actual_value); + return ERROR_FAIL; + } } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; register_read_direct(target, &dcsr, GDB_REGNO_DCSR); dcsr = set_field(dcsr, CSR_DCSR_PRV, value); - register_write_direct(target, GDB_REGNO_DCSR, dcsr); + return register_write_direct(target, GDB_REGNO_DCSR, dcsr); } else { - register_write_direct(target, rid, value); + return register_write_direct(target, rid, value); } + + return ERROR_OK; } static void riscv013_select_current_hart(struct target *target) @@ -1920,11 +1928,12 @@ static void riscv013_select_current_hart(struct target *target) dmi_write(target, DMI_DMCONTROL, dmcontrol); } -static void riscv013_halt_current_hart(struct target *target) +static int riscv013_halt_current_hart(struct target *target) { RISCV_INFO(r); LOG_DEBUG("halting hart %d", r->current_hartid); - assert(!riscv_is_halted(target)); + if (riscv_is_halted(target)) + LOG_ERROR("Hart %d is already halted!", r->current_hartid); /* Issue the halt command, and then wait for the current hart to halt. */ uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); @@ -1941,19 +1950,21 @@ static void riscv013_halt_current_hart(struct target *target) LOG_ERROR("unable to halt hart %d", r->current_hartid); LOG_ERROR(" dmcontrol=0x%08x", dmcontrol); LOG_ERROR(" dmstatus =0x%08x", dmstatus); - abort(); + return ERROR_FAIL; } dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HALTREQ, 0); dmi_write(target, DMI_DMCONTROL, dmcontrol); + + return ERROR_OK; } -static void riscv013_resume_current_hart(struct target *target) +static int riscv013_resume_current_hart(struct target *target) { return riscv013_step_or_resume_current_hart(target, false); } -static void riscv013_step_current_hart(struct target *target) +static int riscv013_step_current_hart(struct target *target) { return riscv013_step_or_resume_current_hart(target, true); } @@ -1998,10 +2009,10 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) LOG_ERROR("Unknown DCSR cause field: %x", (int)get_field(dcsr, CSR_DCSR_CAUSE)); LOG_ERROR(" dcsr=0x%016lx", (long)dcsr); - abort(); + return RISCV_HALT_UNKNOWN; } -void riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) +int riscv013_write_debug_buffer(struct target *target, unsigned index, riscv_insn_t data) { return dmi_write(target, DMI_PROGBUF0 + index, data); } @@ -2070,17 +2081,20 @@ static void riscv013_on_step_or_resume(struct target *target, bool step) riscv_set_register(target, GDB_REGNO_DCSR, dcsr); } -static void riscv013_step_or_resume_current_hart(struct target *target, bool step) +static int riscv013_step_or_resume_current_hart(struct target *target, bool step) { RISCV_INFO(r); LOG_DEBUG("resuming hart %d (for step?=%d)", r->current_hartid, step); - assert(riscv_is_halted(target)); + if (!riscv_is_halted(target)) { + LOG_ERROR("Hart %d is not halted!", r->current_hartid); + return ERROR_FAIL; + } struct riscv_program program; riscv_program_init(&program, target); riscv_program_fence_i(&program); if (riscv_program_exec(&program, target) != ERROR_OK) - abort(); + return ERROR_FAIL; /* Issue the resume command, and then wait for the current hart to resume. */ uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); @@ -2097,7 +2111,7 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_RESUMEREQ, 0); dmi_write(target, DMI_DMCONTROL, dmcontrol); - return; + return ERROR_OK; } uint32_t dmstatus = dmi_read(target, DMI_DMSTATUS); @@ -2109,10 +2123,10 @@ static void riscv013_step_or_resume_current_hart(struct target *target, bool ste if (step) { LOG_ERROR(" was stepping, halting"); riscv013_halt_current_hart(target); - return; + return ERROR_OK; } - abort(); + return ERROR_FAIL; } void riscv013_clear_abstract_error(struct target *target) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index cda16f35b..009bc3a68 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -1011,6 +1011,9 @@ int riscv_openocd_poll(struct target *target) case RISCV_HALT_SINGLESTEP: target->debug_reason = DBG_REASON_SINGLESTEP; break; + case RISCV_HALT_UNKNOWN: + target->debug_reason = DBG_REASON_UNDEFINED; + break; } if (riscv_rtos_enabled(target)) { @@ -1361,8 +1364,7 @@ int riscv_halt_one_hart(struct target *target, int hartid) return ERROR_OK; } - r->halt_current_hart(target); - return ERROR_OK; + return r->halt_current_hart(target); } int riscv_resume_all_harts(struct target *target) @@ -1389,8 +1391,7 @@ int riscv_resume_one_hart(struct target *target, int hartid) } r->on_resume(target); - r->resume_current_hart(target); - return ERROR_OK; + return r->resume_current_hart(target); } int riscv_step_rtos_hart(struct target *target) @@ -1407,13 +1408,20 @@ int riscv_step_rtos_hart(struct target *target) riscv_set_current_hartid(target, hartid); LOG_DEBUG("stepping hart %d", hartid); - assert(riscv_is_halted(target)); + if (!riscv_is_halted(target)) { + LOG_ERROR("Hart isn't halted before single step!"); + return ERROR_FAIL; + } riscv_invalidate_register_cache(target); r->on_step(target); - r->step_current_hart(target); + if (r->step_current_hart(target) != ERROR_OK) + return ERROR_FAIL; riscv_invalidate_register_cache(target); r->on_halt(target); - assert(riscv_is_halted(target)); + if (!riscv_is_halted(target)) { + LOG_ERROR("Hart was not halted after single step!"); + return ERROR_FAIL; + } return ERROR_OK; } @@ -1523,13 +1531,12 @@ bool riscv_has_register(struct target *target, int hartid, int regid) return 1; } -void riscv_set_register(struct target *target, enum gdb_regno r, riscv_reg_t v) +int riscv_set_register(struct target *target, enum gdb_regno r, riscv_reg_t v) { - /* TODO: propagate errors */ return riscv_set_register_on_hart(target, riscv_current_hartid(target), r, v); } -void riscv_set_register_on_hart(struct target *target, int hartid, +int riscv_set_register_on_hart(struct target *target, int hartid, enum gdb_regno regid, uint64_t value) { RISCV_INFO(r); @@ -1562,7 +1569,10 @@ enum riscv_halt_reason riscv_halt_reason(struct target *target, int hartid) { RISCV_INFO(r); riscv_set_current_hartid(target, hartid); - assert(riscv_is_halted(target)); + if (!riscv_is_halted(target)) { + LOG_ERROR("Hart is not halted!"); + return RISCV_HALT_UNKNOWN; + } return r->halt_reason(target); } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 71c68a2a7..dc3c6f5d1 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -30,6 +30,7 @@ enum riscv_halt_reason { RISCV_HALT_INTERRUPT, RISCV_HALT_BREAKPOINT, RISCV_HALT_SINGLESTEP, + RISCV_HALT_UNKNOWN }; typedef struct { @@ -88,18 +89,18 @@ typedef struct { /* Helper functions that target the various RISC-V debug spec * implementations. */ riscv_reg_t (*get_register)(struct target *, int hartid, int regid); - void (*set_register)(struct target *, int hartid, int regid, + int (*set_register)(struct target *, int hartid, int regid, uint64_t value); void (*select_current_hart)(struct target *); bool (*is_halted)(struct target *target); - void (*halt_current_hart)(struct target *); - void (*resume_current_hart)(struct target *target); - void (*step_current_hart)(struct target *target); + int (*halt_current_hart)(struct target *); + int (*resume_current_hart)(struct target *target); + int (*step_current_hart)(struct target *target); void (*on_halt)(struct target *target); void (*on_resume)(struct target *target); void (*on_step)(struct target *target); enum riscv_halt_reason (*halt_reason)(struct target *target); - void (*write_debug_buffer)(struct target *target, unsigned index, + int (*write_debug_buffer)(struct target *target, unsigned index, riscv_insn_t d); riscv_insn_t (*read_debug_buffer)(struct target *target, unsigned index); int (*execute_debug_buffer)(struct target *target); @@ -202,8 +203,8 @@ bool riscv_has_register(struct target *target, int hartid, int regid); /* Returns the value of the given register on the given hart. 32-bit registers * are zero extended to 64 bits. */ -void riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); -void riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v); +int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); +int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v); riscv_reg_t riscv_get_register(struct target *target, enum gdb_regno i); riscv_reg_t riscv_get_register_on_hart(struct target *target, int hid, enum gdb_regno rid); From 52368d6ea1d6689222a050abfd32810bf5f1fd58 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 28 Dec 2017 11:52:59 -0800 Subject: [PATCH 108/127] Fix typo. Issue #164 Change-Id: I083ba0d7df72a83a802297baa25753f8d274519a --- src/rtos/riscv_debug.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c index b84a4f91f..bc46754a4 100644 --- a/src/rtos/riscv_debug.c +++ b/src/rtos/riscv_debug.c @@ -264,7 +264,7 @@ static int riscv_gdb_v_packet(struct connection *connection, const char *packet, static int riscv_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char **hex_reg_list) { - LOG_DEBUG("Updating RISC-V regiser list for hart %d", (int)(thread_id - 1)); + LOG_DEBUG("Updating RISC-V register list for hart %d", (int)(thread_id - 1)); #if 0 LOG_ERROR(" Not actually updating"); From 8150358cde70a42184ad250795192856f818a5f8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 28 Dec 2017 16:10:41 -0800 Subject: [PATCH 109/127] Add config files for SiFive RISC-V hardware. Copied from https://github.com/gnu-mcu-eclipse/openocd Change-Id: Ia0b3e192ca8b3bae6035623d605c9980e9bccd2c --- tcl/board/sifive-coreplexip-e31-arty.cfg | 31 +++++++++++++++++++++ tcl/board/sifive-coreplexip-e51-arty.cfg | 31 +++++++++++++++++++++ tcl/board/sifive-freedom-e300-hifive1.cfg | 34 +++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 tcl/board/sifive-coreplexip-e31-arty.cfg create mode 100644 tcl/board/sifive-coreplexip-e51-arty.cfg create mode 100644 tcl/board/sifive-freedom-e300-hifive1.cfg diff --git a/tcl/board/sifive-coreplexip-e31-arty.cfg b/tcl/board/sifive-coreplexip-e31-arty.cfg new file mode 100644 index 000000000..8b382dc50 --- /dev/null +++ b/tcl/board/sifive-coreplexip-e31-arty.cfg @@ -0,0 +1,31 @@ +# JTAG adapter setup +adapter_khz 10000 + +interface ftdi +ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" +ftdi_vid_pid 0x15ba 0x002a + +ftdi_layout_init 0x0808 0x0a1b +ftdi_layout_signal nSRST -oe 0x0200 +#ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100 +ftdi_layout_signal LED -data 0x0800 + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +# Un-comment these two flash lines if you have a SPI flash and want to write +# it. +flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 +init +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z +} +halt +flash protect 0 64 last off +echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-coreplexip-e51-arty.cfg b/tcl/board/sifive-coreplexip-e51-arty.cfg new file mode 100644 index 000000000..8b382dc50 --- /dev/null +++ b/tcl/board/sifive-coreplexip-e51-arty.cfg @@ -0,0 +1,31 @@ +# JTAG adapter setup +adapter_khz 10000 + +interface ftdi +ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" +ftdi_vid_pid 0x15ba 0x002a + +ftdi_layout_init 0x0808 0x0a1b +ftdi_layout_signal nSRST -oe 0x0200 +#ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100 +ftdi_layout_signal LED -data 0x0800 + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +# Un-comment these two flash lines if you have a SPI flash and want to write +# it. +flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 +init +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z +} +halt +flash protect 0 64 last off +echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-freedom-e300-hifive1.cfg b/tcl/board/sifive-freedom-e300-hifive1.cfg new file mode 100644 index 000000000..b0a8e2652 --- /dev/null +++ b/tcl/board/sifive-freedom-e300-hifive1.cfg @@ -0,0 +1,34 @@ +adapter_khz 10000 + +interface ftdi +ftdi_device_desc "Dual RS232-HS" +ftdi_vid_pid 0x0403 0x6010 + +ftdi_layout_init 0x0008 0x001b +ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020 + +#Reset Stretcher logic on FE310 is ~1 second long +#This doesn't apply if you use +# ftdi_set_signal, but still good to document +#adapter_nsrst_delay 1500 + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME +$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME +init +#reset -- This type of reset is not implemented yet +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z + #Wait for the reset stretcher + #It will work without this, but + #will incur lots of delays for later commands. + sleep 1500 +} +halt +flash protect 0 64 last off From bd566a98bceab70038cf151a82593ffaaa0336cf Mon Sep 17 00:00:00 2001 From: Liviu Ionescu Date: Fri, 29 Dec 2017 17:36:54 +0200 Subject: [PATCH 110/127] add configs for the SiFive boards - the HiFive1 board definition includes the FTDI interface - the Arty boards require external interface definitions --- tcl/board/sifive-e31arty.cfg | 22 ++++++++++++++++++++++ tcl/board/sifive-e51arty.cfg | 22 ++++++++++++++++++++++ tcl/board/sifive-hifive1.cfg | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 78 insertions(+) create mode 100644 tcl/board/sifive-e31arty.cfg create mode 100644 tcl/board/sifive-e51arty.cfg create mode 100644 tcl/board/sifive-hifive1.cfg diff --git a/tcl/board/sifive-e31arty.cfg b/tcl/board/sifive-e31arty.cfg new file mode 100644 index 000000000..ec10b27c3 --- /dev/null +++ b/tcl/board/sifive-e31arty.cfg @@ -0,0 +1,22 @@ +# +# Be sure you include the speed and interface before this file +# Example: +# -c "adapter_khz 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e31arty.cfg" + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 +init +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z +} +halt +flash protect 0 64 last off +echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-e51arty.cfg b/tcl/board/sifive-e51arty.cfg new file mode 100644 index 000000000..ffd83a058 --- /dev/null +++ b/tcl/board/sifive-e51arty.cfg @@ -0,0 +1,22 @@ +# +# Be sure you include the speed and interface before this file +# Example: +# -c "adapter_khz 5000" -f "interface/ftdi/olimex-arm-usb-tiny-h.cfg" -f "board/sifive-e51arty.cfg" + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 + +set _TARGETNAME $_CHIPNAME.cpu + +target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME +$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 +init +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z +} +halt +flash protect 0 64 last off +echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-hifive1.cfg b/tcl/board/sifive-hifive1.cfg new file mode 100644 index 000000000..9bc66701c --- /dev/null +++ b/tcl/board/sifive-hifive1.cfg @@ -0,0 +1,34 @@ +adapter_khz 10000 + +interface ftdi +ftdi_device_desc "Dual RS232-HS" +ftdi_vid_pid 0x0403 0x6010 + +ftdi_layout_init 0x0008 0x001b +ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020 + +#Reset Stretcher logic on FE310 is ~1 second long +#This doesn't apply if you use +# ftdi_set_signal, but still good to document +#adapter_nsrst_delay 1500 + +set _CHIPNAME riscv +jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 + +set _TARGETNAME $_CHIPNAME.cpu +target create $_TARGETNAME riscv -chain-position $_TARGETNAME +$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 + +flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME +init +#reset -- This type of reset is not implemented yet +if {[ info exists pulse_srst]} { + ftdi_set_signal nSRST 0 + ftdi_set_signal nSRST z + #Wait for the reset stretcher + #It will work without this, but + #will incur lots of delays for later commands. + sleep 1500 +} +halt +flash protect 0 64 last off From 1ddbe7044309f2c8642d290e489fa7ddf6a670ef Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 29 Dec 2017 13:11:27 -0800 Subject: [PATCH 111/127] Remove board files that I shouldn't have added There are 3 other ones for the SiFive target. Change-Id: I987331a82186a3738096cc390c91889118bf9ac2 --- tcl/board/sifive-coreplexip-e31-arty.cfg | 31 --------------------- tcl/board/sifive-coreplexip-e51-arty.cfg | 31 --------------------- tcl/board/sifive-freedom-e300-hifive1.cfg | 34 ----------------------- 3 files changed, 96 deletions(-) delete mode 100644 tcl/board/sifive-coreplexip-e31-arty.cfg delete mode 100644 tcl/board/sifive-coreplexip-e51-arty.cfg delete mode 100644 tcl/board/sifive-freedom-e300-hifive1.cfg diff --git a/tcl/board/sifive-coreplexip-e31-arty.cfg b/tcl/board/sifive-coreplexip-e31-arty.cfg deleted file mode 100644 index 8b382dc50..000000000 --- a/tcl/board/sifive-coreplexip-e31-arty.cfg +++ /dev/null @@ -1,31 +0,0 @@ -# JTAG adapter setup -adapter_khz 10000 - -interface ftdi -ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" -ftdi_vid_pid 0x15ba 0x002a - -ftdi_layout_init 0x0808 0x0a1b -ftdi_layout_signal nSRST -oe 0x0200 -#ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100 -ftdi_layout_signal LED -data 0x0800 - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 - -set _TARGETNAME $_CHIPNAME.cpu - -target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME -$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 - -# Un-comment these two flash lines if you have a SPI flash and want to write -# it. -flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 -init -if {[ info exists pulse_srst]} { - ftdi_set_signal nSRST 0 - ftdi_set_signal nSRST z -} -halt -flash protect 0 64 last off -echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-coreplexip-e51-arty.cfg b/tcl/board/sifive-coreplexip-e51-arty.cfg deleted file mode 100644 index 8b382dc50..000000000 --- a/tcl/board/sifive-coreplexip-e51-arty.cfg +++ /dev/null @@ -1,31 +0,0 @@ -# JTAG adapter setup -adapter_khz 10000 - -interface ftdi -ftdi_device_desc "Olimex OpenOCD JTAG ARM-USB-TINY-H" -ftdi_vid_pid 0x15ba 0x002a - -ftdi_layout_init 0x0808 0x0a1b -ftdi_layout_signal nSRST -oe 0x0200 -#ftdi_layout_signal nTRST -data 0x0100 -oe 0x0100 -ftdi_layout_signal LED -data 0x0800 - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x20000001 - -set _TARGETNAME $_CHIPNAME.cpu - -target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME -$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 - -# Un-comment these two flash lines if you have a SPI flash and want to write -# it. -flash bank spi0 fespi 0x40000000 0 0 0 $_TARGETNAME.0 0x20004000 -init -if {[ info exists pulse_srst]} { - ftdi_set_signal nSRST 0 - ftdi_set_signal nSRST z -} -halt -flash protect 0 64 last off -echo "Ready for Remote Connections" diff --git a/tcl/board/sifive-freedom-e300-hifive1.cfg b/tcl/board/sifive-freedom-e300-hifive1.cfg deleted file mode 100644 index b0a8e2652..000000000 --- a/tcl/board/sifive-freedom-e300-hifive1.cfg +++ /dev/null @@ -1,34 +0,0 @@ -adapter_khz 10000 - -interface ftdi -ftdi_device_desc "Dual RS232-HS" -ftdi_vid_pid 0x0403 0x6010 - -ftdi_layout_init 0x0008 0x001b -ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020 - -#Reset Stretcher logic on FE310 is ~1 second long -#This doesn't apply if you use -# ftdi_set_signal, but still good to document -#adapter_nsrst_delay 1500 - -set _CHIPNAME riscv -jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913 - -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME riscv -chain-position $_TARGETNAME -$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1 - -flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME -init -#reset -- This type of reset is not implemented yet -if {[ info exists pulse_srst]} { - ftdi_set_signal nSRST 0 - ftdi_set_signal nSRST z - #Wait for the reset stretcher - #It will work without this, but - #will incur lots of delays for later commands. - sleep 1500 -} -halt -flash protect 0 64 last off From 2eddd8e092d40d59dba0b9bff081464862ce8a2b Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 2 Jan 2018 12:58:46 -0800 Subject: [PATCH 112/127] Parse 64-bit CRC addrs even on 32-bit hosts Change-Id: I38720163eff292b2c24f25da4e25feb8245ff672 --- src/server/gdb_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c index f0adf1d34..ed17f5046 100644 --- a/src/server/gdb_server.c +++ b/src/server/gdb_server.c @@ -2444,7 +2444,7 @@ static int gdb_query_packet(struct connection *connection, /* skip command character */ packet += 5; - addr = strtoul(packet, &separator, 16); + addr = strtoull(packet, &separator, 16); if (*separator != ',') { LOG_ERROR("incomplete read memory packet received, dropping connection"); From 07e19e17cbbee22533d9fccb5a6dde523e4baa04 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 4 Jan 2018 13:27:18 -0800 Subject: [PATCH 113/127] Use register names instead of numbers in warnings Change-Id: Ie2295d30fd9dfeb7590f5e34d572497a93a3ce7b --- src/target/riscv/riscv-011.c | 10 +++++----- src/target/riscv/riscv.c | 1 - 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 18e31c730..aa14a2bc9 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -997,7 +997,8 @@ static int read_csr(struct target *target, uint64_t *value, uint32_t csr) uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { - LOG_WARNING("Got exception 0x%x when reading CSR 0x%x", exception, csr); + LOG_WARNING("Got exception 0x%x when reading %s", exception, + gdb_regno_name(GDB_REGNO_CSR0 + csr)); *value = ~0; return ERROR_FAIL; } @@ -1202,8 +1203,7 @@ static int register_read(struct target *target, riscv_reg_t *value, int regnum) uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { - LOG_WARNING("Got exception 0x%x when reading register %d", exception, - regnum); + LOG_WARNING("Got exception 0x%x when reading %s", exception, gdb_regno_name(regnum)); *value = ~0; return ERROR_FAIL; } @@ -1277,8 +1277,8 @@ static int register_write(struct target *target, unsigned int number, uint32_t exception = cache_get32(target, info->dramsize-1); if (exception) { - LOG_WARNING("Got exception 0x%x when writing register %d", exception, - number); + LOG_WARNING("Got exception 0x%x when writing %s", exception, + gdb_regno_name(number)); return ERROR_FAIL; } diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 009bc3a68..1c0f18572 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -2140,4 +2140,3 @@ int riscv_init_registers(struct target *target) return ERROR_OK; } - From 33aad3524bdfb31e155805adf25522fa8955a5f1 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Thu, 4 Jan 2018 13:27:35 -0800 Subject: [PATCH 114/127] Add a comment in dbus_read This just comments the current behavior --- src/target/riscv/riscv-011.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 18e31c730..db7622e89 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -454,7 +454,12 @@ static uint64_t dbus_read(struct target *target, uint16_t address) uint64_t value; dbus_status_t status; uint16_t address_in; - + + /* If the previous read/write was to the same address, we will get the read data + * from the previous access. + * While somewhat nonintuitive, this is an efficient way to get the data. + */ + unsigned i = 0; do { status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0); From 097d62d1596a76cde0bf75758afce33686ba64ae Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 4 Jan 2018 13:36:53 -0800 Subject: [PATCH 115/127] Make delay update messages debug instead of info. They confuse users otherwise. Change-Id: I3bc491352f5384e36c54696a0ecbf11ac623dd83 --- src/target/riscv/riscv-011.c | 4 ++-- src/target/riscv/riscv-013.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 18e31c730..fe998b75f 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -335,7 +335,7 @@ static void increase_dbus_busy_delay(struct target *target) { riscv011_info_t *info = get_info(target); info->dbus_busy_delay += info->dbus_busy_delay / 10 + 1; - LOG_INFO("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d", + LOG_DEBUG("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d", info->dtmcontrol_idle, info->dbus_busy_delay, info->interrupt_high_delay); @@ -346,7 +346,7 @@ static void increase_interrupt_high_delay(struct target *target) { riscv011_info_t *info = get_info(target); info->interrupt_high_delay += info->interrupt_high_delay / 10 + 1; - LOG_INFO("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d", + LOG_DEBUG("dtmcontrol_idle=%d, dbus_busy_delay=%d, interrupt_high_delay=%d", info->dtmcontrol_idle, info->dbus_busy_delay, info->interrupt_high_delay); } diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 6251765de..3d826801e 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -334,7 +334,7 @@ static void increase_dmi_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); info->dmi_busy_delay += info->dmi_busy_delay / 10 + 1; - LOG_INFO("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", + LOG_DEBUG("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", info->dtmcontrol_idle, info->dmi_busy_delay, info->ac_busy_delay); @@ -500,7 +500,7 @@ static void increase_ac_busy_delay(struct target *target) { riscv013_info_t *info = get_info(target); info->ac_busy_delay += info->ac_busy_delay / 10 + 1; - LOG_INFO("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", + LOG_DEBUG("dtmcontrol_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d", info->dtmcontrol_idle, info->dmi_busy_delay, info->ac_busy_delay); } From 6f3913cedcc0fc2399937e70f44b45c5fbff25a8 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 4 Jan 2018 17:12:01 -0800 Subject: [PATCH 116/127] Select current hart before reading memory. This avoids trying to read memory from the wrong hart, if the current hart was changed by an earlier call (eg. to poll()). Change-Id: I73da1e01c8d01d68f01ac7fdd6c548380a70cfd3 --- src/target/riscv/riscv.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 009bc3a68..5ea0c94b9 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -720,9 +720,19 @@ static int old_or_new_riscv_resume( return riscv_openocd_resume(target, current, address, handle_breakpoints, debug_execution); } +static void riscv_select_current_hart(struct target *target) +{ + RISCV_INFO(r); + if (r->rtos_hartid != -1 && riscv_rtos_enabled(target)) + riscv_set_current_hartid(target, r->rtos_hartid); + else + riscv_set_current_hartid(target, target->coreid); +} + static int riscv_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { + riscv_select_current_hart(target); struct target_type *tt = get_target_type(target); return tt->read_memory(target, address, size, count, buffer); } @@ -730,6 +740,7 @@ static int riscv_read_memory(struct target *target, target_addr_t address, static int riscv_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { + riscv_select_current_hart(target); struct target_type *tt = get_target_type(target); return tt->write_memory(target, address, size, count, buffer); } @@ -747,10 +758,7 @@ static int riscv_get_gdb_reg_list(struct target *target, return ERROR_FAIL; } - if (r->rtos_hartid != -1 && riscv_rtos_enabled(target)) - riscv_set_current_hartid(target, r->rtos_hartid); - else - riscv_set_current_hartid(target, target->coreid); + riscv_select_current_hart(target); switch (reg_class) { case REG_CLASS_GENERAL: From 37434ffd77cc6b38fb4832b5f38cc42eeeade888 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 5 Jan 2018 13:05:33 -0800 Subject: [PATCH 117/127] Rename dummy variable to be correct. Change-Id: I329404894227bb3cf563382e1adf0edda702543b --- src/target/riscv/riscv-013.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 3d826801e..1cb820baa 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -565,8 +565,8 @@ static int execute_abstract_command(struct target *target, uint32_t command) dmi_write(target, DMI_COMMAND, command); { - uint32_t dmstatus = 0; - wait_for_idle(target, &dmstatus); + uint32_t abstractcs = 0; + wait_for_idle(target, &abstractcs); } uint32_t cs = dmi_read(target, DMI_ABSTRACTCS); From fd506fa839892cddf8aab06192f4259fba81037c Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 29 Dec 2017 14:35:49 -0800 Subject: [PATCH 118/127] Propagate register read errors. Change-Id: Idda111377873a2236b5b91e4ffdabd2be384b47a --- src/rtos/riscv_debug.c | 7 +++- src/target/riscv/program.c | 4 ++- src/target/riscv/riscv-011.c | 29 +++++++++------- src/target/riscv/riscv-013.c | 56 +++++++++++++++++------------- src/target/riscv/riscv.c | 66 ++++++++++++++++++++++++++---------- src/target/riscv/riscv.h | 15 ++++---- 6 files changed, 115 insertions(+), 62 deletions(-) diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c index bc46754a4..158160e1e 100644 --- a/src/rtos/riscv_debug.c +++ b/src/rtos/riscv_debug.c @@ -281,7 +281,12 @@ static int riscv_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char *hex_reg_list[0] = '\0'; for (size_t i = 0; i < n_regs; ++i) { if (riscv_has_register(rtos->target, thread_id, i)) { - uint64_t reg_value = riscv_get_register_on_hart(rtos->target, thread_id - 1, i); + uint64_t reg_value; + int result = riscv_get_register_on_hart(rtos->target, ®_value, + thread_id - 1, i); + if (result != ERROR_OK) + return JIM_ERR; + for (size_t byte = 0; byte < xlen / 8; ++byte) { uint8_t reg_byte = reg_value >> (byte * 8); char hex[3] = {'x', 'x', 'x'}; diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index a7a2e859d..25a06760c 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -47,7 +47,9 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) for (size_t i = GDB_REGNO_ZERO + 1; i <= GDB_REGNO_XPR31; ++i) { if (p->writes_xreg[i]) { LOG_DEBUG("Saving register %d as used by program", (int)i); - saved_registers[i] = riscv_get_register(t, i); + int result = riscv_get_register(t, &saved_registers[i], i); + if (result != ERROR_OK) + return result; } } diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index fb459fd37..f455921ef 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -217,7 +217,8 @@ typedef struct { static int poll_target(struct target *target, bool announce); static int riscv011_poll(struct target *target); -static riscv_reg_t get_register(struct target *target, int hartid, int regid); +static int get_register(struct target *target, riscv_reg_t *value, int hartid, + int regid); /*** Utility functions. ***/ @@ -1180,8 +1181,8 @@ static int update_mstatus_actual(struct target *target) /* Force reading the register. In that process mstatus_actual will be * updated. */ - get_register(target, 0, GDB_REGNO_MSTATUS); - return ERROR_OK; + riscv_reg_t mstatus; + return get_register(target, &mstatus, 0, GDB_REGNO_MSTATUS); } /*** OpenOCD target functions. ***/ @@ -1285,22 +1286,22 @@ static int register_write(struct target *target, unsigned int number, return ERROR_OK; } -static riscv_reg_t get_register(struct target *target, int hartid, int regid) +static int get_register(struct target *target, riscv_reg_t *value, int hartid, + int regid) { assert(hartid == 0); riscv011_info_t *info = get_info(target); maybe_write_tselect(target); - riscv_reg_t value = ~0; if (regid <= GDB_REGNO_XPR31) { - value = reg_cache_get(target, regid); + *value = reg_cache_get(target, regid); } else if (regid == GDB_REGNO_PC) { - value = info->dpc; + *value = info->dpc; } else if (regid >= GDB_REGNO_FPR0 && regid <= GDB_REGNO_FPR31) { int result = update_mstatus_actual(target); if (result != ERROR_OK) - return ~0; + return result; unsigned i = 0; if ((info->mstatus_actual & MSTATUS_FS) == 0) { info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); @@ -1316,17 +1317,19 @@ static riscv_reg_t get_register(struct target *target, int hartid, int regid) cache_set_jump(target, i++); if (cache_write(target, 4, true) != ERROR_OK) - return ~0; + return ERROR_FAIL; } else if (regid == GDB_REGNO_PRIV) { - value = get_field(info->dcsr, DCSR_PRV); - } else if (register_read(target, &value, regid) != ERROR_OK) { - value = ~0; + *value = get_field(info->dcsr, DCSR_PRV); + } else { + int result = register_read(target, value, regid); + if (result != ERROR_OK) + return result; } if (regid == GDB_REGNO_MSTATUS) target->reg_cache->reg_list[regid].valid = true; - return value; + return ERROR_OK; } static int set_register(struct target *target, int hartid, int regid, diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 3d826801e..a5b1ee2d4 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -30,20 +30,21 @@ #define DMI_DATA1 (DMI_DATA0 + 1) #define DMI_PROGBUF1 (DMI_PROGBUF0 + 1) -static void riscv013_on_step_or_resume(struct target *target, bool step); +static int riscv013_on_step_or_resume(struct target *target, bool step); static int riscv013_step_or_resume_current_hart(struct target *target, bool step); static void riscv013_clear_abstract_error(struct target *target); /* Implementations of the functions in riscv_info_t. */ -static riscv_reg_t riscv013_get_register(struct target *target, int hartid, int regid); +static int riscv013_get_register(struct target *target, + riscv_reg_t *value, int hid, int rid); static int riscv013_set_register(struct target *target, int hartid, int regid, uint64_t value); static void riscv013_select_current_hart(struct target *target); static int riscv013_halt_current_hart(struct target *target); static int riscv013_resume_current_hart(struct target *target); static int riscv013_step_current_hart(struct target *target); -static void riscv013_on_halt(struct target *target); -static void riscv013_on_step(struct target *target); -static void riscv013_on_resume(struct target *target); +static int riscv013_on_halt(struct target *target); +static int riscv013_on_step(struct target *target); +static int riscv013_on_resume(struct target *target); static bool riscv013_is_halted(struct target *target); static enum riscv_halt_reason riscv013_halt_reason(struct target *target); static int riscv013_write_debug_buffer(struct target *target, unsigned index, @@ -1855,36 +1856,37 @@ struct target_type riscv013_target = { }; /*** 0.13-specific implementations of various RISC-V helper functions. ***/ -static riscv_reg_t riscv013_get_register(struct target *target, int hid, int rid) +static int riscv013_get_register(struct target *target, + riscv_reg_t *value, int hid, int rid) { LOG_DEBUG("reading register %s on hart %d", gdb_regno_name(rid), hid); riscv_set_current_hartid(target, hid); - uint64_t out; riscv013_info_t *info = get_info(target); + int result = ERROR_OK; if (rid <= GDB_REGNO_XPR31) { - register_read_direct(target, &out, rid); + result = register_read_direct(target, value, rid); } else if (rid == GDB_REGNO_PC) { - register_read_direct(target, &out, GDB_REGNO_DPC); - LOG_DEBUG("read PC from DPC: 0x%016" PRIx64, out); + result = register_read_direct(target, value, GDB_REGNO_DPC); + LOG_DEBUG("read PC from DPC: 0x%016" PRIx64, *value); } else if (rid == GDB_REGNO_PRIV) { uint64_t dcsr; - register_read_direct(target, &dcsr, GDB_REGNO_DCSR); - buf_set_u64((unsigned char *)&out, 0, 8, get_field(dcsr, CSR_DCSR_PRV)); + result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); + buf_set_u64((unsigned char *)value, 0, 8, get_field(dcsr, CSR_DCSR_PRV)); } else { - int result = register_read_direct(target, &out, rid); + result = register_read_direct(target, value, rid); if (result != ERROR_OK) { LOG_ERROR("Unable to read register %d", rid); - out = -1; + *value = -1; } if (rid == GDB_REGNO_MSTATUS) - info->mstatus_actual = out; + info->mstatus_actual = *value; } - return out; + return result; } static int riscv013_set_register(struct target *target, int hid, int rid, uint64_t value) @@ -1969,18 +1971,19 @@ static int riscv013_step_current_hart(struct target *target) return riscv013_step_or_resume_current_hart(target, true); } -static void riscv013_on_resume(struct target *target) +static int riscv013_on_resume(struct target *target) { return riscv013_on_step_or_resume(target, false); } -static void riscv013_on_step(struct target *target) +static int riscv013_on_step(struct target *target) { return riscv013_on_step_or_resume(target, true); } -static void riscv013_on_halt(struct target *target) +static int riscv013_on_halt(struct target *target) { + return ERROR_OK; } static bool riscv013_is_halted(struct target *target) @@ -1995,7 +1998,11 @@ static bool riscv013_is_halted(struct target *target) static enum riscv_halt_reason riscv013_halt_reason(struct target *target) { - uint64_t dcsr = riscv_get_register(target, GDB_REGNO_DCSR); + riscv_reg_t dcsr; + int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); + if (result != ERROR_OK) + return RISCV_HALT_UNKNOWN; + switch (get_field(dcsr, CSR_DCSR_CAUSE)) { case CSR_DCSR_CAUSE_SWBP: case CSR_DCSR_CAUSE_TRIGGER: @@ -2064,7 +2071,7 @@ int riscv013_dmi_write_u64_bits(struct target *target) } /* Helper Functions. */ -static void riscv013_on_step_or_resume(struct target *target, bool step) +static int riscv013_on_step_or_resume(struct target *target, bool step) { struct riscv_program program; riscv_program_init(&program, target); @@ -2073,12 +2080,15 @@ static void riscv013_on_step_or_resume(struct target *target, bool step) LOG_ERROR("Unable to execute fence.i"); /* We want to twiddle some bits in the debug CSR so debugging works. */ - uint64_t dcsr = riscv_get_register(target, GDB_REGNO_DCSR); + riscv_reg_t dcsr; + int result = register_read_direct(target, &dcsr, GDB_REGNO_DCSR); + if (result != ERROR_OK) + return result; dcsr = set_field(dcsr, CSR_DCSR_STEP, step); dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, 1); dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, 1); dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, 1); - riscv_set_register(target, GDB_REGNO_DCSR, dcsr); + return riscv_set_register(target, GDB_REGNO_DCSR, dcsr); } static int riscv013_step_or_resume_current_hart(struct target *target, bool step) diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index 10baac528..f8a273958 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -320,8 +320,10 @@ static int maybe_add_trigger_t1(struct target *target, unsigned hartid, riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, tdata1); - riscv_reg_t tdata1_rb = riscv_get_register_on_hart(target, hartid, - GDB_REGNO_TDATA1); + riscv_reg_t tdata1_rb; + if (riscv_get_register_on_hart(target, &tdata1_rb, hartid, + GDB_REGNO_TDATA1) != ERROR_OK) + return ERROR_FAIL; LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); if (tdata1 != tdata1_rb) { @@ -370,7 +372,10 @@ static int maybe_add_trigger_t2(struct target *target, unsigned hartid, riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, tdata1); - uint64_t tdata1_rb = riscv_get_register_on_hart(target, hartid, GDB_REGNO_TDATA1); + uint64_t tdata1_rb; + int result = riscv_get_register_on_hart(target, &tdata1_rb, hartid, GDB_REGNO_TDATA1); + if (result != ERROR_OK) + return result; LOG_DEBUG("tdata1=0x%" PRIx64, tdata1_rb); if (tdata1 != tdata1_rb) { @@ -405,8 +410,10 @@ static int add_trigger(struct target *target, struct trigger *trigger) continue; if (first_hart < 0) first_hart = hartid; - tselect[hartid] = riscv_get_register_on_hart(target, hartid, - GDB_REGNO_TSELECT); + int result = riscv_get_register_on_hart(target, &tselect[hartid], + hartid, GDB_REGNO_TSELECT); + if (result != ERROR_OK) + return result; } assert(first_hart >= 0); @@ -417,10 +424,14 @@ static int add_trigger(struct target *target, struct trigger *trigger) riscv_set_register_on_hart(target, first_hart, GDB_REGNO_TSELECT, i); - uint64_t tdata1 = riscv_get_register_on_hart(target, first_hart, GDB_REGNO_TDATA1); + uint64_t tdata1; + int result = riscv_get_register_on_hart(target, &tdata1, first_hart, + GDB_REGNO_TDATA1); + if (result != ERROR_OK) + return result; int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); - int result = ERROR_OK; + result = ERROR_OK; for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { if (!riscv_hart_enabled(target, hartid)) continue; @@ -533,7 +544,10 @@ static int remove_trigger(struct target *target, struct trigger *trigger) for (int hartid = first_hart; hartid < riscv_count_harts(target); ++hartid) { if (!riscv_hart_enabled(target, hartid)) continue; - riscv_reg_t tselect = riscv_get_register_on_hart(target, hartid, GDB_REGNO_TSELECT); + riscv_reg_t tselect; + int result = riscv_get_register_on_hart(target, &tselect, hartid, GDB_REGNO_TSELECT); + if (result != ERROR_OK) + return result; riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, i); riscv_set_register_on_hart(target, hartid, GDB_REGNO_TDATA1, 0); riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, tselect); @@ -1553,17 +1567,20 @@ int riscv_set_register_on_hart(struct target *target, int hartid, return r->set_register(target, hartid, regid, value); } -riscv_reg_t riscv_get_register(struct target *target, enum gdb_regno r) +int riscv_get_register(struct target *target, riscv_reg_t *value, + enum gdb_regno r) { - return riscv_get_register_on_hart(target, riscv_current_hartid(target), r); + return riscv_get_register_on_hart(target, value, + riscv_current_hartid(target), r); } -uint64_t riscv_get_register_on_hart(struct target *target, int hartid, enum gdb_regno regid) +int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, + int hartid, enum gdb_regno regid) { RISCV_INFO(r); - uint64_t value = r->get_register(target, hartid, regid); - LOG_DEBUG("[%d] %s: %" PRIx64, hartid, gdb_regno_name(regid), value); - return value; + int result = r->get_register(target, value, hartid, regid); + LOG_DEBUG("[%d] %s: %" PRIx64, hartid, gdb_regno_name(regid), *value); + return result; } bool riscv_is_halted(struct target *target) @@ -1669,22 +1686,32 @@ int riscv_enumerate_triggers(struct target *target) if (!riscv_hart_enabled(target, hartid)) continue; - riscv_reg_t tselect = riscv_get_register_on_hart(target, hartid, + riscv_reg_t tselect; + int result = riscv_get_register_on_hart(target, &tselect, hartid, GDB_REGNO_TSELECT); + if (result != ERROR_OK) + return result; for (unsigned t = 0; t < RISCV_MAX_TRIGGERS; ++t) { r->trigger_count[hartid] = t; riscv_set_register_on_hart(target, hartid, GDB_REGNO_TSELECT, t); - uint64_t tselect_rb = riscv_get_register_on_hart(target, hartid, + uint64_t tselect_rb; + result = riscv_get_register_on_hart(target, &tselect_rb, hartid, GDB_REGNO_TSELECT); + if (result != ERROR_OK) + return result; /* Mask off the top bit, which is used as tdrmode in old * implementations. */ tselect_rb &= ~(1ULL << (riscv_xlen(target)-1)); if (tselect_rb != t) break; - uint64_t tdata1 = riscv_get_register_on_hart(target, hartid, + uint64_t tdata1; + result = riscv_get_register_on_hart(target, &tdata1, hartid, GDB_REGNO_TDATA1); + if (result != ERROR_OK) + return result; + int type = get_field(tdata1, MCONTROL_TYPE(riscv_xlen(target))); switch (type) { case 1: @@ -1760,7 +1787,10 @@ const char *gdb_regno_name(enum gdb_regno regno) static int register_get(struct reg *reg) { struct target *target = (struct target *) reg->arch_info; - uint64_t value = riscv_get_register(target, reg->number); + uint64_t value; + int result = riscv_get_register(target, &value, reg->number); + if (result != ERROR_OK) + return result; buf_set_u64(reg->value, 0, reg->size, value); return ERROR_OK; } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index dc3c6f5d1..5d3a21257 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -88,7 +88,8 @@ typedef struct { /* Helper functions that target the various RISC-V debug spec * implementations. */ - riscv_reg_t (*get_register)(struct target *, int hartid, int regid); + int (*get_register)(struct target *target, + riscv_reg_t *value, int hid, int rid); int (*set_register)(struct target *, int hartid, int regid, uint64_t value); void (*select_current_hart)(struct target *); @@ -96,9 +97,9 @@ typedef struct { int (*halt_current_hart)(struct target *); int (*resume_current_hart)(struct target *target); int (*step_current_hart)(struct target *target); - void (*on_halt)(struct target *target); - void (*on_resume)(struct target *target); - void (*on_step)(struct target *target); + int (*on_halt)(struct target *target); + int (*on_resume)(struct target *target); + int (*on_step)(struct target *target); enum riscv_halt_reason (*halt_reason)(struct target *target); int (*write_debug_buffer)(struct target *target, unsigned index, riscv_insn_t d); @@ -205,8 +206,10 @@ bool riscv_has_register(struct target *target, int hartid, int regid); * are zero extended to 64 bits. */ int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v); int riscv_set_register_on_hart(struct target *target, int hid, enum gdb_regno rid, uint64_t v); -riscv_reg_t riscv_get_register(struct target *target, enum gdb_regno i); -riscv_reg_t riscv_get_register_on_hart(struct target *target, int hid, enum gdb_regno rid); +int riscv_get_register(struct target *target, riscv_reg_t *value, + enum gdb_regno r); +int riscv_get_register_on_hart(struct target *target, riscv_reg_t *value, + int hartid, enum gdb_regno regid); /* Checks the state of the current hart -- "is_halted" checks the actual * on-device register. */ From 29c7a767082909bef17d4e3259d9b20da46b6835 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 3 Jan 2018 12:23:22 -0800 Subject: [PATCH 119/127] Muck with mstatus to always be able to read FPRs Change-Id: I7ff8bde4578c9ddd175c5cca370295c790cfbba7 --- src/target/riscv/riscv-013.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index a5b1ee2d4..9f3708917 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1003,8 +1003,15 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t /* Write program to move data into s0. */ + uint64_t mstatus; if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - /* TODO: Possibly set F in mstatus. */ + if (register_read_direct(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) + return ERROR_FAIL; + if ((mstatus & MSTATUS_FS) == 0) + if (register_write_direct(target, GDB_REGNO_MSTATUS, + set_field(mstatus, MSTATUS_FS, 1)) != ERROR_OK) + return ERROR_FAIL; + if (riscv_supports_extension(target, 'D') && riscv_xlen(target) < 64) { /* There are no instructions to move all the bits from a * register, so we need to use some scratch RAM. */ @@ -1042,6 +1049,11 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t return ERROR_FAIL; } + if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && + (mstatus & MSTATUS_FS) == 0) + if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus) != ERROR_OK) + return ERROR_FAIL; + /* Restore S0. */ if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) return ERROR_FAIL; From 7f368468c8eedf65b1ed5320828daccf31823a30 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 15 Jan 2018 12:07:20 -0800 Subject: [PATCH 120/127] Remove dead code. Change-Id: Ic90598b3dd4128dabb18ac4dc1285ca721a6a441 --- src/target/riscv/riscv-013.c | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 46248027c..d3d9f5042 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -142,10 +142,6 @@ typedef struct { unsigned datacount; /* Number of words in the Program Buffer. */ unsigned progbufsize; - /* The value that mstatus actually has on the target right now. This is not - * the value we present to the user. That one may be stored in the - * reg_cache. */ - uint64_t mstatus_actual; yes_no_maybe_t progbuf_writable; /* We only need the address so that we know the alignment of the buffer. */ @@ -1875,8 +1871,6 @@ static int riscv013_get_register(struct target *target, riscv_set_current_hartid(target, hid); - riscv013_info_t *info = get_info(target); - int result = ERROR_OK; if (rid <= GDB_REGNO_XPR31) { result = register_read_direct(target, value, rid); @@ -1893,9 +1887,6 @@ static int riscv013_get_register(struct target *target, LOG_ERROR("Unable to read register %d", rid); *value = -1; } - - if (rid == GDB_REGNO_MSTATUS) - info->mstatus_actual = *value; } return result; From 1ab7e910fd19e2a201da1362f2850e93686d162a Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 19 Jan 2018 11:41:17 -0800 Subject: [PATCH 121/127] Make compilation command specify architecture. Fixes issue #180. Change-Id: Icf180ae87db92840930044f1aa3129466cf43fad --- src/flash/nor/fespi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index a12eb378f..83d533f30 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -465,8 +465,9 @@ static int slow_fespi_write_buffer(struct flash_bank *bank, * Here's the source for the algorithm. * You can turn it into the array below using: sed -n '/ALGO_START$/,/ALGO_END/ p' fespi.c | \ - riscv32-unknown-elf-gcc -x assembler-with-cpp - -nostdlib -nostartfiles -o tmp.o && \ - riscv32-unknown-elf-objcopy -O binary tmp.o algorithm.bin && \ + riscv64-unknown-elf-gcc -march=rv32i -mabi=ilp32 -x \ + assembler-with-cpp - -nostdlib -nostartfiles -o tmp.o && \ + riscv64-unknown-elf-objcopy -O binary tmp.o algorithm.bin && \ xxd -i algorithm.bin // ALGO_START From 3839cbf0ad49763e657a2662b757b1dfceaf00df Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 19 Jan 2018 13:58:02 -0800 Subject: [PATCH 122/127] Add some error checking to examine(). Fixes #183. Change-Id: I6fb45adf4c97ea339c9d4ca3b372a09b18e3b56e --- src/target/riscv/riscv-013.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index d3d9f5042..8bef5883a 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1212,8 +1212,12 @@ static int examine(struct target *target) break; r->hart_count = i + 1; - if (!riscv_is_halted(target)) - riscv013_halt_current_hart(target); + if (!riscv_is_halted(target)) { + if (riscv013_halt_current_hart(target) != ERROR_OK) { + LOG_ERROR("Fatal: Hart %d failed to halt during examine()", i); + return ERROR_FAIL; + } + } /* Without knowing anything else we can at least mess with the * program buffer. */ @@ -1225,7 +1229,10 @@ static int examine(struct target *target) else r->xlen[i] = 32; - register_read_direct(target, &r->misa, GDB_REGNO_MISA); + if (register_read_direct(target, &r->misa, GDB_REGNO_MISA)) { + LOG_ERROR("Fatal: Failed to read MISA from hart %d.", i); + return ERROR_FAIL; + } /* Now init registers based on what we discovered. */ if (riscv_init_registers(target) != ERROR_OK) From 5e22040b6780e92ceac7e6c3130bc86cbd76fe72 Mon Sep 17 00:00:00 2001 From: Megan Wachs Date: Sat, 20 Jan 2018 13:34:53 -0800 Subject: [PATCH 123/127] SPI Flash: add 256Mb SPI Part by ISSI --- src/flash/nor/spi.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/flash/nor/spi.c b/src/flash/nor/spi.c index ac5ef6b39..b255edba6 100644 --- a/src/flash/nor/spi.c +++ b/src/flash/nor/spi.c @@ -72,6 +72,7 @@ const struct flash_device flash_devices[] = { FLASH_ID("micron n25q256 3v", 0xd8, 0xc7, 0x0019ba20, 0x100, 0x10000, 0x2000000), FLASH_ID("micron n25q256 1.8v", 0xd8, 0xc7, 0x0019bb20, 0x100, 0x10000, 0x2000000), FLASH_ID("issi is25lp128", 0xd8, 0xc7, 0x0018609d, 0x100, 0x10000, 0x1000000), + FLASH_ID("issi is25wp256d", 0xd8, 0xc7, 0x0019709d, 0x100, 0x10000, 0x2000000), FLASH_ID("win w25q80bv", 0xd8, 0xc7, 0x001440ef, 0x100, 0x10000, 0x100000), FLASH_ID("win w25q32fv", 0xd8, 0xc7, 0x001640ef, 0x100, 0x10000, 0x400000), FLASH_ID("win w25q32dw", 0xd8, 0xc7, 0x001660ef, 0x100, 0x10000, 0x400000), From 553a63808c8c188ea3590779aa66f7e87996b7bd Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Mon, 22 Jan 2018 11:44:36 -0800 Subject: [PATCH 124/127] Fix some niggles found by clang's static analysis. Change-Id: Id476227e1bd02e067f0cc4da9bc7ffb3d9d30535 --- src/flash/nor/fespi.c | 3 ++- src/rtos/riscv_debug.c | 12 +++++++----- src/target/riscv/riscv-011.c | 19 ++++++++++++++++--- src/target/riscv/riscv-013.c | 11 ++++++----- 4 files changed, 31 insertions(+), 14 deletions(-) diff --git a/src/flash/nor/fespi.c b/src/flash/nor/fespi.c index a12eb378f..2d6312680 100644 --- a/src/flash/nor/fespi.c +++ b/src/flash/nor/fespi.c @@ -795,7 +795,6 @@ static int steps_execute(struct algorithm_steps *as, struct target *target = bank->target; struct fespi_flash_bank *fespi_info = bank->driver_priv; uint32_t ctrl_base = fespi_info->ctrl_base; - uint8_t *data_buf = malloc(data_wa->size); int xlen = riscv_xlen(target); struct reg_param reg_params[2]; @@ -805,9 +804,11 @@ static int steps_execute(struct algorithm_steps *as, buf_set_u64(reg_params[1].value, 0, xlen, data_wa->address); while (!as_empty(as)) { keep_alive(); + uint8_t *data_buf = malloc(data_wa->size); unsigned bytes = as_compile(as, data_buf, data_wa->size); int retval = target_write_buffer(target, data_wa->address, bytes, data_buf); + free(data_buf); if (retval != ERROR_OK) { LOG_ERROR("Failed to write data to 0x%" TARGET_PRIxADDR ": %d", data_wa->address, retval); diff --git a/src/rtos/riscv_debug.c b/src/rtos/riscv_debug.c index 158160e1e..b1a714d48 100644 --- a/src/rtos/riscv_debug.c +++ b/src/rtos/riscv_debug.c @@ -279,7 +279,9 @@ static int riscv_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char ssize_t hex_reg_list_length = n_regs * reg_chars + 2; *hex_reg_list = malloc(hex_reg_list_length); *hex_reg_list[0] = '\0'; + char *p = hex_reg_list[0]; for (size_t i = 0; i < n_regs; ++i) { + assert(p - hex_reg_list[0] > 3); if (riscv_has_register(rtos->target, thread_id, i)) { uint64_t reg_value; int result = riscv_get_register_on_hart(rtos->target, ®_value, @@ -289,13 +291,13 @@ static int riscv_get_thread_reg_list(struct rtos *rtos, int64_t thread_id, char for (size_t byte = 0; byte < xlen / 8; ++byte) { uint8_t reg_byte = reg_value >> (byte * 8); - char hex[3] = {'x', 'x', 'x'}; - snprintf(hex, 3, "%02x", reg_byte); - strncat(*hex_reg_list, hex, hex_reg_list_length); + p += snprintf(p, 3, "%02x", reg_byte); } } else { - for (size_t byte = 0; byte < xlen / 8; ++byte) - strncat(*hex_reg_list, "xx", hex_reg_list_length); + for (size_t byte = 0; byte < xlen / 8; ++byte) { + strcpy(p, "xx"); + p += 2; + } } } LOG_DEBUG("%s", *hex_reg_list); diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index c3be0d1ab..632567f35 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -436,7 +436,7 @@ static dbus_status_t dbus_scan(struct target *target, uint16_t *address_in, int retval = jtag_execute_queue(); if (retval != ERROR_OK) { LOG_ERROR("dbus_scan failed jtag scan"); - return retval; + return DBUS_STATUS_FAILED; } if (data_in) @@ -466,6 +466,10 @@ static uint64_t dbus_read(struct target *target, uint16_t address) status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0); if (status == DBUS_STATUS_BUSY) increase_dbus_busy_delay(target); + if (status == DBUS_STATUS_FAILED) { + LOG_ERROR("dbus_read(0x%x) failed!", address); + return 0; + } } while (((status == DBUS_STATUS_BUSY) || (address_in != address)) && i++ < 256); @@ -675,6 +679,9 @@ static bits_t read_bits(struct target *target) return err_result; } increase_dbus_busy_delay(target); + } else if (status == DBUS_STATUS_FAILED) { + // TODO: return an actual error + return err_result; } } while (status == DBUS_STATUS_BUSY && i++ < 256); @@ -860,6 +867,7 @@ static int cache_write(struct target *target, unsigned int address, bool run) int retval = scans_execute(scans); if (retval != ERROR_OK) { + scans_delete(scans); LOG_ERROR("JTAG execute failed."); return retval; } @@ -873,12 +881,14 @@ static int cache_write(struct target *target, unsigned int address, bool run) break; case DBUS_STATUS_FAILED: LOG_ERROR("Debug RAM write failed. Hardware error?"); + scans_delete(scans); return ERROR_FAIL; case DBUS_STATUS_BUSY: errors++; break; default: LOG_ERROR("Got invalid bus access status: %d", status); + scans_delete(scans); return ERROR_FAIL; } } @@ -901,6 +911,7 @@ static int cache_write(struct target *target, unsigned int address, bool run) if (wait_for_debugint_clear(target, true) != ERROR_OK) { LOG_ERROR("Debug interrupt didn't clear."); dump_debug_ram(target); + scans_delete(scans); return ERROR_FAIL; } @@ -921,6 +932,7 @@ static int cache_write(struct target *target, unsigned int address, bool run) if (wait_for_debugint_clear(target, false) != ERROR_OK) { LOG_ERROR("Debug interrupt didn't clear."); dump_debug_ram(target); + scans_delete(scans); return ERROR_FAIL; } } else { @@ -1804,14 +1816,14 @@ static riscv_error_t handle_halt_routine(struct target *target) info->dpc = reg_cache_get(target, CSR_DPC); info->dcsr = reg_cache_get(target, CSR_DCSR); - scans = scans_delete(scans); + scans_delete(scans); cache_invalidate(target); return RE_OK; error: - scans = scans_delete(scans); + scans_delete(scans); return RE_FAIL; } @@ -2271,6 +2283,7 @@ static int write_memory(struct target *target, target_addr_t address, goto error; } + scans_delete(scans); cache_clean(target); return register_write(target, T0, t0); diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index d3d9f5042..b57d98d25 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -436,8 +436,12 @@ static uint64_t dmi_read(struct target *target, uint16_t address) } if (status != DMI_STATUS_SUCCESS) { - LOG_ERROR("Failed read (NOP) from 0x%x; value=0x%" PRIx64 ", status=%d", - address, value, status); + if (status == DMI_STATUS_FAILED) { + LOG_ERROR("Failed read (NOP) from 0x%x; status=%d", address, status); + } else { + LOG_ERROR("Failed read (NOP) from 0x%x; value=0x%" PRIx64 ", status=%d", + address, value, status); + } return ~0ULL; } @@ -985,8 +989,6 @@ static int register_read_direct(struct target *target, uint64_t *value, uint32_t if (result != ERROR_OK) { assert(number != GDB_REGNO_S0); - result = ERROR_OK; - struct riscv_program program; riscv_program_init(&program, target); @@ -1646,7 +1648,6 @@ static int read_memory(struct target *target, target_addr_t address, goto error; write_to_buf(buffer + receive_addr - address, value, size); LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value); - receive_addr += size; riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); From 2d263bae84f7b84fbd4a8030a0addaeaef5b6a81 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Wed, 24 Jan 2018 13:53:11 -0800 Subject: [PATCH 125/127] Make all memory logging lines consistent. Also reduce a few 64-bit variables to 32 bits, which is all they need. Change-Id: I23e431b7eed4a63803add93a1bb328a3631631d6 --- src/target/riscv/riscv-013.c | 45 ++++++++++++++++++++++-------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index a6c21fc9d..48390a6f0 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -343,7 +343,7 @@ static void increase_dmi_busy_delay(struct target *target) * run-test/idle cycles may be required. */ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, - uint64_t *data_in, dmi_op_t op, uint16_t address_out, uint64_t data_out, + uint32_t *data_in, dmi_op_t op, uint16_t address_out, uint32_t data_out, bool exec) { riscv013_info_t *info = get_info(target); @@ -357,9 +357,9 @@ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, assert(info->abits != 0); - buf_set_u64(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); - buf_set_u64(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); - buf_set_u64(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); + buf_set_u32(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); + buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); + buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); /* Assume dbus is already selected. */ jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); @@ -378,7 +378,7 @@ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, } if (data_in) - *data_in = buf_get_u64(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); + *data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); if (address_in) *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); @@ -388,7 +388,7 @@ static dmi_status_t dmi_scan(struct target *target, uint16_t *address_in, return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } -static uint64_t dmi_read(struct target *target, uint16_t address) +static uint32_t dmi_read(struct target *target, uint16_t address) { select_dmi(target); @@ -415,13 +415,13 @@ static uint64_t dmi_read(struct target *target, uint16_t address) if (status != DMI_STATUS_SUCCESS) { LOG_ERROR("Failed read from 0x%x; status=%d", address, status); - return ~0ULL; + return ~0; } /* This second loop ensures that we got the read * data back. Note that NOP can result in a 'busy' result as well, but * that would be noticed on the next DMI access we do. */ - uint64_t value; + uint32_t value; for (i = 0; i < 256; i++) { status = dmi_scan(target, &address_in, &value, DMI_OP_NOP, address, 0, false); @@ -439,10 +439,10 @@ static uint64_t dmi_read(struct target *target, uint16_t address) if (status == DMI_STATUS_FAILED) { LOG_ERROR("Failed read (NOP) from 0x%x; status=%d", address, status); } else { - LOG_ERROR("Failed read (NOP) from 0x%x; value=0x%" PRIx64 ", status=%d", + LOG_ERROR("Failed read (NOP) from 0x%x; value=0x%x, status=%d", address, value, status); } - return ~0ULL; + return ~0; } return value; @@ -1426,6 +1426,19 @@ static int execute_fence(struct target *target) return result; } +static void log_memory_access(target_addr_t address, uint64_t value, + unsigned size_bytes, bool read) +{ + if (debug_level < LOG_LVL_DEBUG) + return; + + char fmt[80]; + sprintf(fmt, "M[0x%" TARGET_PRIxADDR "] %ss 0x%%0%d" PRIx64, + address, read ? "read" : "write", size_bytes * 2); + value &= (((uint64_t) 0x1) << (size_bytes * 8)) - 1; + LOG_DEBUG(fmt, value); +} + /** * Read the requested memory, taking care to execute every read exactly once, * even if cmderr=busy is encountered. @@ -1621,8 +1634,7 @@ static int read_memory(struct target *target, target_addr_t address, uint64_t dmi_out = riscv_batch_get_dmi_read(batch, i); uint32_t value = get_field(dmi_out, DTM_DMI_DATA); write_to_buf(buffer + offset, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", receive_addr, - value); + log_memory_access(receive_addr, value, size, true); receive_addr += size; } @@ -1631,8 +1643,7 @@ static int read_memory(struct target *target, target_addr_t address, if (cmderr == CMDERR_BUSY) { riscv_addr_t offset = receive_addr - address; write_to_buf(buffer + offset, dmi_data0, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%08x", receive_addr, - dmi_data0); + log_memory_access(receive_addr, dmi_data0, size, true); read_addr += size; receive_addr += size; } @@ -1644,7 +1655,7 @@ static int read_memory(struct target *target, target_addr_t address, /* Read the penultimate word. */ uint64_t value = dmi_read(target, DMI_DATA0); write_to_buf(buffer + receive_addr - address, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value); + log_memory_access(receive_addr, value, size, true); receive_addr += size; } @@ -1654,7 +1665,7 @@ static int read_memory(struct target *target, target_addr_t address, if (result != ERROR_OK) goto error; write_to_buf(buffer + receive_addr - address, value, size); - LOG_DEBUG("M[0x%" TARGET_PRIxADDR "] reads 0x%" PRIx64, receive_addr, value); + log_memory_access(receive_addr, value, size, true); riscv_set_register(target, GDB_REGNO_S0, s0); riscv_set_register(target, GDB_REGNO_S1, s1); @@ -1756,7 +1767,7 @@ static int write_memory(struct target *target, target_addr_t address, goto error; } - LOG_DEBUG("M[0x%08" PRIx64 "] writes 0x%08x", address + offset, value); + log_memory_access(address + offset, value, size, false); cur_addr += size; if (setup_needed) { From 6a98fb7076f8b49561d4250d4c0ebce1e3473be5 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Fri, 26 Jan 2018 16:39:58 -0800 Subject: [PATCH 126/127] Detect hartsellen, limiting which harts we probe Tested with doctored spike with hartsellens of 0, 1, 3, and 10. Change-Id: I97f57c7d03b076792d5ecd66545d9b9e853ed515 --- src/target/riscv/debug_defines.h | 127 +++++++++++++++++-------------- src/target/riscv/riscv-013.c | 80 ++++++++++--------- 2 files changed, 116 insertions(+), 91 deletions(-) diff --git a/src/target/riscv/debug_defines.h b/src/target/riscv/debug_defines.h index e970293bf..04500e572 100644 --- a/src/target/riscv/debug_defines.h +++ b/src/target/riscv/debug_defines.h @@ -441,12 +441,6 @@ #define CSR_MCONTROL_M_LENGTH 1 #define CSR_MCONTROL_M (0x1ULL << CSR_MCONTROL_M_OFFSET) /* -* When set, enable this trigger in H mode. - */ -#define CSR_MCONTROL_H_OFFSET 5 -#define CSR_MCONTROL_H_LENGTH 1 -#define CSR_MCONTROL_H (0x1ULL << CSR_MCONTROL_H_OFFSET) -/* * When set, enable this trigger in S mode. */ #define CSR_MCONTROL_S_OFFSET 4 @@ -487,7 +481,7 @@ /* * When count is decremented to 0, the trigger fires. Instead of * changing \Fcount from 1 to 0, it is also acceptable for hardware to -* clear \Fm, \Fh, \Fs, and \Fu. This allows \Fcount to be hard-wired +* clear \Fm, \Fs, and \Fu. This allows \Fcount to be hard-wired * to 1 if this register just exists for single step. */ #define CSR_ICOUNT_COUNT_OFFSET 10 @@ -501,13 +495,6 @@ #define CSR_ICOUNT_M_LENGTH 1 #define CSR_ICOUNT_M (0x1ULL << CSR_ICOUNT_M_OFFSET) /* -* When set, every instruction completed or exception taken in in H mode decrements \Fcount -* by 1. - */ -#define CSR_ICOUNT_H_OFFSET 8 -#define CSR_ICOUNT_H_LENGTH 1 -#define CSR_ICOUNT_H (0x1ULL << CSR_ICOUNT_H_OFFSET) -/* * When set, every instruction completed or exception taken in S mode decrements \Fcount * by 1. */ @@ -544,19 +531,6 @@ #define CSR_ICOUNT_ACTION (0x3fULL << CSR_ICOUNT_ACTION_OFFSET) #define DMI_DMSTATUS 0x11 /* -* Gets set if the Debug Module was accessed incorrectly. -* -* 0 (none): No error. -* -* 1 (badaddr): There was an access to an unimplemented Debug Module -* address. -* -* 7 (other): An access failed for another reason. - */ -#define DMI_DMSTATUS_DMERR_OFFSET 24 -#define DMI_DMSTATUS_DMERR_LENGTH 3 -#define DMI_DMSTATUS_DMERR (0x7U << DMI_DMSTATUS_DMERR_OFFSET) -/* * If 1, then there is an implicit {\tt ebreak} instruction at the * non-existent word immediately after the Program Buffer. This saves * the debugger from having to write the {\tt ebreak} itself, and @@ -700,7 +674,7 @@ */ #define DMI_DMCONTROL_HALTREQ_OFFSET 31 #define DMI_DMCONTROL_HALTREQ_LENGTH 1 -#define DMI_DMCONTROL_HALTREQ (0x1U << DMI_DMCONTROL_HALTREQ_OFFSET) +#define DMI_DMCONTROL_HALTREQ (0x1ULL << DMI_DMCONTROL_HALTREQ_OFFSET) /* * Writes the resume request bit for all currently selected harts. * When set to 1, each selected hart will resume if it is currently @@ -713,7 +687,7 @@ */ #define DMI_DMCONTROL_RESUMEREQ_OFFSET 30 #define DMI_DMCONTROL_RESUMEREQ_LENGTH 1 -#define DMI_DMCONTROL_RESUMEREQ (0x1U << DMI_DMCONTROL_RESUMEREQ_OFFSET) +#define DMI_DMCONTROL_RESUMEREQ (0x1ULL << DMI_DMCONTROL_RESUMEREQ_OFFSET) /* * This optional field writes the reset bit for all the currently * selected harts. To perform a reset the debugger writes 1, and then @@ -727,7 +701,7 @@ */ #define DMI_DMCONTROL_HARTRESET_OFFSET 29 #define DMI_DMCONTROL_HARTRESET_LENGTH 1 -#define DMI_DMCONTROL_HARTRESET (0x1U << DMI_DMCONTROL_HARTRESET_OFFSET) +#define DMI_DMCONTROL_HARTRESET (0x1ULL << DMI_DMCONTROL_HARTRESET_OFFSET) /* * Writing 1 to this bit clears the {\tt havereset} bits for * any selected harts. @@ -736,7 +710,7 @@ */ #define DMI_DMCONTROL_ACKHAVERESET_OFFSET 28 #define DMI_DMCONTROL_ACKHAVERESET_LENGTH 1 -#define DMI_DMCONTROL_ACKHAVERESET (0x1U << DMI_DMCONTROL_ACKHAVERESET_OFFSET) +#define DMI_DMCONTROL_ACKHAVERESET (0x1ULL << DMI_DMCONTROL_ACKHAVERESET_OFFSET) /* * Selects the definition of currently selected harts. * @@ -752,14 +726,14 @@ */ #define DMI_DMCONTROL_HASEL_OFFSET 26 #define DMI_DMCONTROL_HASEL_LENGTH 1 -#define DMI_DMCONTROL_HASEL (0x1U << DMI_DMCONTROL_HASEL_OFFSET) +#define DMI_DMCONTROL_HASEL (0x1ULL << DMI_DMCONTROL_HASEL_OFFSET) /* * The DM-specific index of the hart to select. This hart is always part of the * currently selected harts. */ #define DMI_DMCONTROL_HARTSEL_OFFSET 16 -#define DMI_DMCONTROL_HARTSEL_LENGTH 10 -#define DMI_DMCONTROL_HARTSEL (0x3ffU << DMI_DMCONTROL_HARTSEL_OFFSET) +#define DMI_DMCONTROL_HARTSEL_LENGTH HARTSELLEN +#define DMI_DMCONTROL_HARTSEL (((1L<arch_info; + return (riscv013_info_t *) info->version_specific; +} + +static uint32_t hartsel_mask(const struct target *target) +{ + RISCV013_INFO(info); + return ((1L<hartsellen)-1) << DMI_DMCONTROL_HARTSEL_OFFSET; +} + static void decode_dmi(char *text, unsigned address, unsigned data) { static const struct { @@ -192,7 +207,7 @@ static void decode_dmi(char *text, unsigned address, unsigned data) { DMI_DMCONTROL, DMI_DMCONTROL_RESUMEREQ, "resumereq" }, { DMI_DMCONTROL, DMI_DMCONTROL_HARTRESET, "hartreset" }, { DMI_DMCONTROL, DMI_DMCONTROL_HASEL, "hasel" }, - { DMI_DMCONTROL, DMI_DMCONTROL_HARTSEL, "hartsel" }, + { DMI_DMCONTROL, ((1L<<10)-1) << DMI_DMCONTROL_HARTSEL_OFFSET, "hartsel" }, { DMI_DMCONTROL, DMI_DMCONTROL_NDMRESET, "ndmreset" }, { DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE, "dmactive" }, @@ -275,12 +290,6 @@ static void dump_field(const struct scan_field *field) } } -static riscv013_info_t *get_info(const struct target *target) -{ - riscv_info_t *info = (riscv_info_t *) target->arch_info; - return (riscv013_info_t *) info->version_specific; -} - /*** Utility functions. ***/ static void select_dmi(struct target *target) @@ -1155,54 +1164,50 @@ static int examine(struct target *target) } /* Reset the Debug Module. */ - dmi_write(target, DMI_DMCONTROL, 0); - dmi_write(target, DMI_DMCONTROL, DMI_DMCONTROL_DMACTIVE); + uint32_t max_hartsel_mask = ((1L<<10)-1) << DMI_DMCONTROL_HARTSEL_OFFSET; + dmi_write(target, DMI_DMCONTROL, max_hartsel_mask); + dmi_write(target, DMI_DMCONTROL, max_hartsel_mask | DMI_DMCONTROL_DMACTIVE); uint32_t dmcontrol = dmi_read(target, DMI_DMCONTROL); - uint32_t hartinfo = dmi_read(target, DMI_HARTINFO); - - LOG_DEBUG("dmcontrol: 0x%08x", dmcontrol); - LOG_DEBUG("dmstatus: 0x%08x", dmstatus); - LOG_DEBUG("hartinfo: 0x%08x", hartinfo); - - info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); - info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); - info->dataaddr = get_field(hartinfo, DMI_HARTINFO_DATAADDR); - if (!get_field(dmcontrol, DMI_DMCONTROL_DMACTIVE)) { LOG_ERROR("Debug Module did not become active. dmcontrol=0x%x", dmcontrol); return ERROR_FAIL; } + uint32_t hartsel = get_field(dmcontrol, max_hartsel_mask); + info->hartsellen = 0; + while (hartsel & 1) { + info->hartsellen++; + hartsel >>= 1; + } + LOG_DEBUG("hartsellen=%d", info->hartsellen); + + uint32_t hartinfo = dmi_read(target, DMI_HARTINFO); + + info->datasize = get_field(hartinfo, DMI_HARTINFO_DATASIZE); + info->dataaccess = get_field(hartinfo, DMI_HARTINFO_DATAACCESS); + info->dataaddr = get_field(hartinfo, DMI_HARTINFO_DATAADDR); + if (!get_field(dmstatus, DMI_DMSTATUS_AUTHENTICATED)) { LOG_ERROR("Authentication required by RISC-V core but not " "supported by OpenOCD. dmcontrol=0x%x", dmcontrol); return ERROR_FAIL; } - if (get_field(dmstatus, DMI_DMSTATUS_ANYUNAVAIL)) { - LOG_ERROR("The hart is unavailable."); - return ERROR_FAIL; - } - - if (get_field(dmstatus, DMI_DMSTATUS_ANYNONEXISTENT)) { - LOG_ERROR("The hart doesn't exist."); - return ERROR_FAIL; - } - /* Check that abstract data registers are accessible. */ uint32_t abstractcs = dmi_read(target, DMI_ABSTRACTCS); info->datacount = get_field(abstractcs, DMI_ABSTRACTCS_DATACOUNT); info->progbufsize = get_field(abstractcs, DMI_ABSTRACTCS_PROGBUFSIZE); - /* Before doing anything else we must first enumerate the harts. */ RISCV_INFO(r); r->impebreak = get_field(dmstatus, DMI_DMSTATUS_IMPEBREAK); + /* Before doing anything else we must first enumerate the harts. */ + /* Don't call any riscv_* functions until after we've counted the number of * cores and initialized registers. */ - for (int i = 0; i < RISCV_MAX_HARTS; ++i) { + for (int i = 0; i < MIN(RISCV_MAX_HARTS, 1 << info->hartsellen); ++i) { if (!riscv_rtos_enabled(target) && i != target->coreid) continue; @@ -1248,6 +1253,11 @@ static int examine(struct target *target) LOG_DEBUG("Enumerated %d harts", r->hart_count); + if (r->hart_count == 0) { + LOG_ERROR("No harts found!"); + return ERROR_FAIL; + } + /* Then we check the number of triggers availiable to each hart. */ riscv_enumerate_triggers(target); @@ -1297,7 +1307,7 @@ static int assert_reset(struct target *target) if (!riscv_hart_enabled(target, i)) continue; - control = set_field(control_base, DMI_DMCONTROL_HARTSEL, i); + control = set_field(control_base, hartsel_mask(target), i); control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); dmi_write(target, DMI_DMCONTROL, control); @@ -1308,7 +1318,7 @@ static int assert_reset(struct target *target) } else { /* Reset just this hart. */ - uint32_t control = set_field(control_base, DMI_DMCONTROL_HARTSEL, + uint32_t control = set_field(control_base, hartsel_mask(target), r->current_hartid); control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); @@ -1342,7 +1352,7 @@ static int deassert_reset(struct target *target) /* Clear the reset, but make sure haltreq is still set */ uint32_t control = 0; control = set_field(control, DMI_DMCONTROL_HALTREQ, target->reset_halt ? 1 : 0); - control = set_field(control, DMI_DMCONTROL_HARTSEL, r->current_hartid); + control = set_field(control, hartsel_mask(target), r->current_hartid); control = set_field(control, DMI_DMCONTROL_DMACTIVE, 1); dmi_write(target, DMI_DMCONTROL, control); @@ -1948,7 +1958,7 @@ static void riscv013_select_current_hart(struct target *target) RISCV_INFO(r); uint64_t dmcontrol = dmi_read(target, DMI_DMCONTROL); - dmcontrol = set_field(dmcontrol, DMI_DMCONTROL_HARTSEL, r->current_hartid); + dmcontrol = set_field(dmcontrol, hartsel_mask(target), r->current_hartid); dmi_write(target, DMI_DMCONTROL, dmcontrol); } From 6f0d70f5c82e6bd2d441fc8b982f8a4578d179a4 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Tue, 30 Jan 2018 12:30:39 -0800 Subject: [PATCH 127/127] Mention register name instead of number in error Change-Id: I5be5e57418e672fc76383fc24635cdbfb1e65578 --- src/target/riscv/riscv-013.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 730d76f5b..760adb381 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -1913,7 +1913,7 @@ static int riscv013_get_register(struct target *target, } else { result = register_read_direct(target, value, rid); if (result != ERROR_OK) { - LOG_ERROR("Unable to read register %d", rid); + LOG_ERROR("Unable to read %s", gdb_regno_name(rid)); *value = -1; } }