aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/checkpatch.yml8
-rw-r--r--contrib/coresight-trace.txt68
-rw-r--r--doc/openocd.texi30
-rw-r--r--src/flash/nor/ambiqmicro.c2
-rw-r--r--src/flash/nor/at91sam7.c4
-rw-r--r--src/flash/nor/core.h10
-rw-r--r--src/flash/nor/driver.h8
-rw-r--r--src/flash/nor/kinetis.c4
-rw-r--r--src/flash/nor/max32xxx.c2
-rw-r--r--src/flash/nor/msp432.c2
-rw-r--r--src/flash/nor/nrf5.c573
-rw-r--r--src/flash/nor/pic32mx.c2
-rw-r--r--src/flash/nor/stellaris.c2
-rw-r--r--src/flash/nor/stm32f2x.c2
-rw-r--r--src/flash/nor/tcl.c1
-rw-r--r--src/helper/startup.tcl4
-rw-r--r--src/jtag/commands.h6
-rw-r--r--src/jtag/drivers/angie.c2
-rw-r--r--src/jtag/drivers/ftdi.c4
-rw-r--r--src/jtag/drivers/nulink_usb.c60
-rw-r--r--src/jtag/drivers/remote_bitbang.c9
-rw-r--r--src/jtag/drivers/rlink.c6
-rw-r--r--src/jtag/drivers/stlink_usb.c206
-rw-r--r--src/jtag/drivers/ti_icdi_usb.c36
-rw-r--r--src/jtag/drivers/ulink.c2
-rw-r--r--src/jtag/hla/hla_interface.c2
-rw-r--r--src/jtag/hla/hla_interface.h6
-rw-r--r--src/jtag/hla/hla_layout.c6
-rw-r--r--src/jtag/hla/hla_layout.h22
-rw-r--r--src/jtag/tcl.c5
-rw-r--r--src/pld/intel.c177
-rw-r--r--src/server/gdb_server.c52
-rw-r--r--src/target/arc_jtag.c4
-rw-r--r--src/target/arm_tpiu_swo.c6
-rw-r--r--src/target/armv7m_trace.c22
-rw-r--r--src/target/armv7m_trace.h2
-rw-r--r--src/target/armv8.c180
-rw-r--r--src/target/armv8_dpm.c4
-rw-r--r--src/target/cortex_m.c10
-rw-r--r--src/target/hla_target.c28
-rw-r--r--src/target/riscv/Makefile.am7
-rw-r--r--src/target/riscv/batch.c16
-rw-r--r--src/target/riscv/batch.h71
-rw-r--r--src/target/riscv/gdb_regs.h4
-rw-r--r--src/target/riscv/program.h2
-rw-r--r--src/target/riscv/riscv-011.c36
-rw-r--r--src/target/riscv/riscv-011.h15
-rw-r--r--src/target/riscv/riscv-011_reg.c61
-rw-r--r--src/target/riscv/riscv-011_reg.h19
-rw-r--r--src/target/riscv/riscv-013.c504
-rw-r--r--src/target/riscv/riscv-013.h23
-rw-r--r--src/target/riscv/riscv-013_reg.c162
-rw-r--r--src/target/riscv/riscv-013_reg.h31
-rw-r--r--src/target/riscv/riscv.c1450
-rw-r--r--src/target/riscv/riscv.h44
-rw-r--r--src/target/riscv/riscv_reg.c976
-rw-r--r--src/target/riscv/riscv_reg.h38
-rw-r--r--src/target/riscv/riscv_reg_impl.h214
-rw-r--r--src/target/riscv/riscv_semihosting.c11
-rw-r--r--src/target/target.c15
-rw-r--r--src/target/xtensa/xtensa.c2
-rw-r--r--src/target/xtensa/xtensa.h4
-rw-r--r--tcl/board/digilent_nexys2.cfg30
-rw-r--r--tcl/board/nxp/frdm-kv11z-jlink.cfg21
-rw-r--r--tcl/board/nxp/frdm-kv31f-jlink.cfg21
-rw-r--r--tcl/chip/st/spear/spear3xx_ddr.tcl4
-rw-r--r--tcl/fpga/altera-arriaii.cfg27
-rw-r--r--tcl/fpga/altera-cyclone10.cfg44
-rw-r--r--tcl/fpga/altera-cycloneiii.cfg43
-rw-r--r--tcl/fpga/altera-cycloneiv.cfg53
-rw-r--r--tcl/fpga/altera-cyclonev.cfg58
-rw-r--r--tcl/fpga/altera_common_init.cfg9
-rw-r--r--tcl/fpga/xilinx-dna.cfg6
-rw-r--r--tcl/fpga/xilinx-xc3s.cfg43
-rw-r--r--tcl/interface/raspberrypi-gpio-connector.cfg22
-rw-r--r--tcl/interface/raspberrypi-native.cfg12
-rw-r--r--tcl/interface/raspberrypi5-gpiod.cfg29
-rw-r--r--tcl/memory.tcl4
-rw-r--r--tcl/target/c100helper.tcl4
-rw-r--r--tcl/target/nrf53.cfg146
-rw-r--r--tcl/target/nrf91.cfg63
-rw-r--r--tcl/target/nrf_common.cfg86
82 files changed, 3406 insertions, 2603 deletions
diff --git a/.github/workflows/checkpatch.yml b/.github/workflows/checkpatch.yml
index 00d1d71..11f4271 100644
--- a/.github/workflows/checkpatch.yml
+++ b/.github/workflows/checkpatch.yml
@@ -23,10 +23,4 @@ jobs:
sudo apt-get install patchutils python3-ply python3-git
- name: Run checkpatch
run: |
- git diff --patch FETCH_HEAD \
- | filterdiff \
- -x "a/src/jtag/drivers/libjaylink/*" \
- -x "a/tools/git2cl/*" \
- -x "a/.github/*" \
- -x "a/HACKING" \
- | ./tools/scripts/checkpatch.pl --no-signoff -
+ ./tools/scripts/checkpatch.pl --no-signoff --git FETCH_HEAD..HEAD
diff --git a/contrib/coresight-trace.txt b/contrib/coresight-trace.txt
deleted file mode 100644
index 517119b..0000000
--- a/contrib/coresight-trace.txt
+++ /dev/null
@@ -1,68 +0,0 @@
-+OpenOCD and CoreSight Tracing
-+
-Many recent ARM chips (Using e..g. Cortex-M3 and
-Cortex-M4 cores) support CoreSight debug/trace.
-This note sketches an approach currently planned for those cores
-with OpenOCD.
-
- This tracing data can help debug and tune ARM software, but not
-all cores support tracing. Some support more extensive tracing
-other cores with trace support +should be able to use the same
-approach and maybe some of the same analysis code.
-
-+the Cortex-M3 is assumed here to be the
-+core in use, for simplicity and to reflect current OpenOCD users.
-
-
-This note summarizes a software model to generate, collect, and
-analyze such trace data . That is not fully implemented as of early
-January 2011, +and thus is not *yet* usable.
-+
-+
-+Some microcontroller cores support a low pin-count Single-wire trace,
-with a mode where +trace data is emitted (usually to a UART. To use
-this mode, +SWD must be in use.
-+At this writing, OpenOCD SWD support is not yet complete either.
-
-(There are also multi-wire trace ports requiring more complex debug
-adapters than OpenOCD currently supports, and offering richer data.
-+
-+
-+* ENABLING involves activating SWD and (single wire) trace.
-+
-+current expectations are that OpenOCD itself will handle enabling;
-activating single wire trace involves a debug adapter interaction, and
-collecting that trace data requires particular (re)wiring.
-+
-+* CONFIGURATION involves setting up ITM and/or ETM modules to emit the
-+desired data from the Cortex core. (This might include dumping
-+event counters printf-style messages; code profiling; and more. Not all
-+cores offer the same trace capabilities.
-+
-+current expectations are that Tcl scripts will be used to configure these
-+modules for the desired tracing, by direct writes to registers. In some
-+cases (as with RTOS event tracking and similar messaging, this might
-+be augmented or replaced by user code running on the ARM core.
-+
-+COLLECTION involves reading that trace data, probably through UART, and
-+saving it in a useful format to analyse For now, deferred analysis modes
-are assumed, not than real-time or interactive ones.
-+
-+
-+current expectations are to to dump data in text using contrib/itmdump.c
-+or derived tools, and to post-process it into reports. Such reports might
-+include program messaging (such as application data streams via ITM, maybe
-+using printf type messaging; code coverage analysis or so forth. Recent
-+versions of CMSIS software reserve some ITM codespace for RTOS event
-tracing and include ITM messaging support.
-Clearly some of that data would be valuable for interactive debugging.
-+
-+Should someone get ambitious, GUI reports should be possible. GNU tools
-+for simpler reports like gprof may be simpler to support at first.
-+In any case, OpenOCD is not currently GUI-oriented. Accordingly, we now
-+expect any such graphics to come from postprocessing.
-
- measurements for RTOS event timings should also be easy to collect.
-+Examples include context and message switch times, as well as times
-for application interactions.
-+
diff --git a/doc/openocd.texi b/doc/openocd.texi
index 8ffbcf3..5bd4e89 100644
--- a/doc/openocd.texi
+++ b/doc/openocd.texi
@@ -7345,12 +7345,13 @@ flash bank $_FLASHNAME npcx 0x64000000 0 0 0 $_TARGETNAME
@end deffn
@deffn {Flash Driver} {nrf5}
-All members of the nRF51 microcontroller families from Nordic Semiconductor
-include internal flash and use ARM Cortex-M0 core. nRF52 family powered
-by ARM Cortex-M4 or M4F core is supported too. nRF52832 is fully supported
-including BPROT flash protection scheme. nRF52833 and nRF52840 devices are
-supported with the exception of security extensions (flash access control list
-- ACL).
+Supports all members of the nRF51, nRF52 and nRF53 microcontroller families from
+Nordic Semiconductor. nRF91 family is supported too. One driver handles both
+the main flash and the UICR area.
+
+Flash protection is handled on nRF51 family and nRF52805, nRF52810, nRF52811,
+nRF52832 devices. Flash access control list (ACL) protection scheme of the newer
+devices is not supported.
@example
flash bank $_FLASHNAME nrf5 0 0x00000000 0 0 $_TARGETNAME
@@ -8827,8 +8828,8 @@ The file format must be inferred by the driver.
@section PLD/FPGA Drivers, Options, and Commands
-Drivers may support PLD-specific options to the @command{pld device}
-definition command, and may also define commands usable only with
+Drivers may support PLD-specific options to the @command{pld create}
+command, and may also define commands usable only with
that particular type of PLD.
@deffn {FPGA Driver} {virtex2} [@option{-no_jstart}]
@@ -8914,13 +8915,12 @@ For the option @option{-family} @var{name} is one of @var{trion|titanium}.
@end deffn
-@deffn {FPGA Driver} {intel} [@option{-family} <name>]
+@deffn {FPGA Driver} {intel} @option{-family} <name>
This driver can be used to load the bitstream into Intel (former Altera) FPGAs.
-The families Cyclone III, Cyclone IV, Cyclone V, Cyclone 10, Arria II are supported.
+The families Cyclone III, Cyclone IV, Cyclone V, Cyclone 10 and Arria II are supported.
@c Arria V and Arria 10, MAX II, MAX V, MAX10)
-For the option @option{-family} @var{name} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}.
-This is needed when the JTAG ID of the device is ambiguous (same ID is used for chips in different families).
+The option @option{-family} @var{name} is one of @var{cycloneiii cycloneiv cyclonev cyclone10 arriaii}.
As input file format the driver supports a '.rbf' (raw bitstream file) file. The '.rbf' file can be generated
from a '.sof' file with @verb{|quartus_cpf -c blinker.sof blinker.rbf|}
@@ -11290,11 +11290,6 @@ Set the wall-clock timeout (in seconds) for individual commands. The default
should work fine for all but the slowest targets (eg. simulators).
@end deffn
-@deffn {Command} {riscv set_reset_timeout_sec} [seconds]
-Set the maximum time to wait for a hart to come out of reset after reset is
-deasserted.
-@end deffn
-
@deffn {Command} {riscv set_mem_access} method1 [method2] [method3]
Specify which RISC-V memory access method(s) shall be used, and in which order
of priority. At least one method must be specified.
@@ -11376,7 +11371,6 @@ tunneled DR scan consists of:
@item A width+1 stream of bits for the tunneled TDI. The plus one is because there is a one-clock skew between TDI of Xilinx chain and TDO from tunneled chain.
@item 3 bits of zero that the tunnel uses to go back to idle state.
@end enumerate
-
@end deffn
@deffn {Command} {riscv set_bscan_tunnel_ir} value
diff --git a/src/flash/nor/ambiqmicro.c b/src/flash/nor/ambiqmicro.c
index 2b458bc..bb89377 100644
--- a/src/flash/nor/ambiqmicro.c
+++ b/src/flash/nor/ambiqmicro.c
@@ -124,7 +124,7 @@ FLASH_BANK_COMMAND_HANDLER(ambiqmicro_flash_bank_command)
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
- ambiqmicro_info = calloc(sizeof(struct ambiqmicro_flash_bank), 1);
+ ambiqmicro_info = calloc(1, sizeof(struct ambiqmicro_flash_bank));
bank->driver_priv = ambiqmicro_info;
diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c
index 6879a1b..86c8076 100644
--- a/src/flash/nor/at91sam7.c
+++ b/src/flash/nor/at91sam7.c
@@ -560,7 +560,7 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
if (bnk > 0) {
if (!t_bank->next) {
/* create a new flash bank element */
- struct flash_bank *fb = calloc(sizeof(struct flash_bank), 1);
+ struct flash_bank *fb = calloc(1, sizeof(struct flash_bank));
if (!fb) {
LOG_ERROR("No memory for flash bank");
return ERROR_FAIL;
@@ -748,7 +748,7 @@ FLASH_BANK_COMMAND_HANDLER(at91sam7_flash_bank_command)
if (bnk > 0) {
if (!t_bank->next) {
/* create a new bank element */
- struct flash_bank *fb = calloc(sizeof(struct flash_bank), 1);
+ struct flash_bank *fb = calloc(1, sizeof(struct flash_bank));
if (!fb) {
LOG_ERROR("No memory for flash bank");
return ERROR_FAIL;
diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h
index 80911f7..ff175a1 100644
--- a/src/flash/nor/core.h
+++ b/src/flash/nor/core.h
@@ -32,18 +32,18 @@ struct flash_sector {
uint32_t size;
/**
* Indication of erasure status: 0 = not erased, 1 = erased,
- * other = unknown. Set by @c flash_driver_s::erase_check only.
+ * other = unknown. Set by @c flash_driver::erase_check only.
*
* This information must be considered stale immediately.
- * Don't set it in flash_driver_s::erase or a device mass_erase
- * Don't clear it in flash_driver_s::write
+ * Don't set it in flash_driver::erase or a device mass_erase
+ * Don't clear it in flash_driver::write
* The flag is not used in a protection block
*/
int is_erased;
/**
* Indication of protection status: 0 = unprotected/unlocked,
* 1 = protected/locked, other = unknown. Set by
- * @c flash_driver_s::protect_check.
+ * @c flash_driver::protect_check.
*
* This information must be considered stale immediately.
* A million things could make it stale: power cycle,
@@ -67,7 +67,7 @@ struct flash_sector {
* a major interface.
*
* This structure will be passed as a parameter to the callbacks in the
- * flash_driver_s structure, some of which may modify the contents of
+ * flash_driver structure, some of which may modify the contents of
* this structure of the area of flash that it defines. Driver writers
* may use the @c driver_priv member to store additional data on a
* per-bank basis, if required.
diff --git a/src/flash/nor/driver.h b/src/flash/nor/driver.h
index 7d6f8c5..211661e 100644
--- a/src/flash/nor/driver.h
+++ b/src/flash/nor/driver.h
@@ -29,7 +29,7 @@ struct flash_bank;
* flash bank DRIVERNAME ...parameters...
* @endcode
*
- * OpenOCD will search for the driver with a @c flash_driver_s::name
+ * OpenOCD will search for the driver with a @c flash_driver::name
* that matches @c DRIVERNAME.
*
* The flash subsystem calls some of the other drivers routines a using
@@ -170,7 +170,7 @@ struct flash_driver {
/**
* Check the erasure status of a flash bank.
* When called, the driver routine must perform the required
- * checks and then set the @c flash_sector_s::is_erased field
+ * checks and then set the @c flash_sector::is_erased field
* for each of the flash banks's sectors.
*
* @param bank The bank to check
@@ -182,7 +182,7 @@ struct flash_driver {
* Determine if the specific bank is "protected" or not.
* When called, the driver routine must must perform the
* required protection check(s) and then set the @c
- * flash_sector_s::is_protected field for each of the flash
+ * flash_sector::is_protected field for each of the flash
* bank's sectors.
*
* If protection is not implemented, set method to NULL
@@ -204,7 +204,7 @@ struct flash_driver {
int (*info)(struct flash_bank *bank, struct command_invocation *cmd);
/**
- * A more gentle flavor of flash_driver_s::probe, performing
+ * A more gentle flavor of flash_driver::probe, performing
* setup with less noise. Generally, driver routines should test
* to see if the bank has already been probed; if it has, the
* driver probably should not perform its probe a second time.
diff --git a/src/flash/nor/kinetis.c b/src/flash/nor/kinetis.c
index e8074e3..fee3644 100644
--- a/src/flash/nor/kinetis.c
+++ b/src/flash/nor/kinetis.c
@@ -930,7 +930,7 @@ FLASH_BANK_COMMAND_HANDLER(kinetis_flash_bank_command)
k_chip = kinetis_get_chip(target);
if (!k_chip) {
- k_chip = calloc(sizeof(struct kinetis_chip), 1);
+ k_chip = calloc(1, sizeof(struct kinetis_chip));
if (!k_chip) {
LOG_ERROR("No memory");
return ERROR_FAIL;
@@ -1031,7 +1031,7 @@ static int kinetis_create_missing_banks(struct kinetis_chip *k_chip)
bank_idx - k_chip->num_pflash_blocks);
}
- bank = calloc(sizeof(struct flash_bank), 1);
+ bank = calloc(1, sizeof(struct flash_bank));
if (!bank)
return ERROR_FAIL;
diff --git a/src/flash/nor/max32xxx.c b/src/flash/nor/max32xxx.c
index 51d6ae2..59a14af 100644
--- a/src/flash/nor/max32xxx.c
+++ b/src/flash/nor/max32xxx.c
@@ -87,7 +87,7 @@ FLASH_BANK_COMMAND_HANDLER(max32xxx_flash_bank_command)
return ERROR_FLASH_BANK_INVALID;
}
- info = calloc(sizeof(struct max32xxx_flash_bank), 1);
+ info = calloc(1, sizeof(struct max32xxx_flash_bank));
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], info->flash_size);
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[6], info->flc_base);
COMMAND_PARSE_NUMBER(uint, CMD_ARGV[7], info->sector_size);
diff --git a/src/flash/nor/msp432.c b/src/flash/nor/msp432.c
index 5e2935d..b5e2b0b 100644
--- a/src/flash/nor/msp432.c
+++ b/src/flash/nor/msp432.c
@@ -937,7 +937,7 @@ static int msp432_probe(struct flash_bank *bank)
if (is_main && MSP432P4 == msp432_bank->family_type) {
/* Create the info flash bank needed by MSP432P4 variants */
- struct flash_bank *info = calloc(sizeof(struct flash_bank), 1);
+ struct flash_bank *info = calloc(1, sizeof(struct flash_bank));
if (!info)
return ERROR_FAIL;
diff --git a/src/flash/nor/nrf5.c b/src/flash/nor/nrf5.c
index bf8c9da..f07433e 100644
--- a/src/flash/nor/nrf5.c
+++ b/src/flash/nor/nrf5.c
@@ -19,8 +19,7 @@
#include <helper/time_support.h>
#include <helper/bits.h>
-/* Both those values are constant across the current spectrum ofr nRF5 devices */
-#define WATCHDOG_REFRESH_REGISTER 0x40010600
+/* The refresh code is constant across the current spectrum of nRF5 devices */
#define WATCHDOG_REFRESH_VALUE 0x6e524635
enum {
@@ -28,12 +27,9 @@ enum {
};
enum nrf5_ficr_registers {
- NRF5_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */
+ NRF51_52_FICR_BASE = 0x10000000, /* Factory Information Configuration Registers */
-#define NRF5_FICR_REG(offset) (NRF5_FICR_BASE + offset)
-
- NRF5_FICR_CODEPAGESIZE = NRF5_FICR_REG(0x010),
- NRF5_FICR_CODESIZE = NRF5_FICR_REG(0x014),
+#define NRF5_FICR_REG(offset) (NRF51_52_FICR_BASE + (offset))
NRF51_FICR_CLENR0 = NRF5_FICR_REG(0x028),
NRF51_FICR_PPFC = NRF5_FICR_REG(0x02C),
@@ -42,39 +38,23 @@ enum nrf5_ficr_registers {
NRF51_FICR_SIZERAMBLOCK1 = NRF5_FICR_REG(0x03C),
NRF51_FICR_SIZERAMBLOCK2 = NRF5_FICR_REG(0x040),
NRF51_FICR_SIZERAMBLOCK3 = NRF5_FICR_REG(0x044),
-
- /* CONFIGID is documented on nRF51 series only.
- * On nRF52 is present but not documented */
- NRF5_FICR_CONFIGID = NRF5_FICR_REG(0x05C),
-
- /* Following registers are available on nRF52 and on nRF51 since rev 3 */
- NRF5_FICR_INFO_PART = NRF5_FICR_REG(0x100),
- NRF5_FICR_INFO_VARIANT = NRF5_FICR_REG(0x104),
- NRF5_FICR_INFO_PACKAGE = NRF5_FICR_REG(0x108),
- NRF5_FICR_INFO_RAM = NRF5_FICR_REG(0x10C),
- NRF5_FICR_INFO_FLASH = NRF5_FICR_REG(0x110),
};
enum nrf5_uicr_registers {
- NRF5_UICR_BASE = 0x10001000, /* User Information
+ NRF51_52_UICR_BASE = 0x10001000, /* User Information
* Configuration Registers */
-#define NRF5_UICR_REG(offset) (NRF5_UICR_BASE + offset)
+#define NRF5_UICR_REG(offset) (NRF51_52_UICR_BASE + (offset))
NRF51_UICR_CLENR0 = NRF5_UICR_REG(0x000),
};
enum nrf5_nvmc_registers {
- NRF5_NVMC_BASE = 0x4001E000, /* Non-Volatile Memory
- * Controller Registers */
-
-#define NRF5_NVMC_REG(offset) (NRF5_NVMC_BASE + offset)
-
- 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),
+ NRF5_NVMC_READY = 0x400,
+ NRF5_NVMC_CONFIG = 0x504,
+ NRF5_NVMC_ERASEPAGE = 0x508,
+ NRF5_NVMC_ERASEALL = 0x50C,
+ NRF5_NVMC_ERASEUICR = 0x514,
NRF5_BPROT_BASE = 0x40000000,
};
@@ -99,6 +79,9 @@ enum nrf5_features {
NRF5_FEATURE_SERIES_52 = BIT(1),
NRF5_FEATURE_BPROT = BIT(2),
NRF5_FEATURE_ACL_PROT = BIT(3),
+ NRF5_FEATURE_SERIES_53 = BIT(4),
+ NRF5_FEATURE_SERIES_91 = BIT(5),
+ NRF5_FEATURE_ERASE_BY_FLASH_WR = BIT(6),
};
struct nrf5_device_spec {
@@ -110,6 +93,28 @@ struct nrf5_device_spec {
enum nrf5_features features;
};
+/* FICR registers offsets */
+struct nrf5_ficr_map {
+ uint32_t codepagesize;
+ uint32_t codesize;
+ uint32_t configid;
+ uint32_t info_part;
+ uint32_t info_variant;
+ uint32_t info_package;
+ uint32_t info_ram;
+ uint32_t info_flash;
+};
+
+/* Map of device */
+struct nrf5_map {
+ uint32_t flash_base;
+ uint32_t ficr_base;
+ uint32_t uicr_base;
+ uint32_t nvmc_base;
+
+ uint32_t watchdog_refresh_addr;
+};
+
struct nrf5_info {
unsigned int refcount;
@@ -127,6 +132,9 @@ struct nrf5_info {
enum nrf5_features features;
unsigned int flash_size_kb;
unsigned int ram_size_kb;
+
+ const struct nrf5_map *map;
+ const struct nrf5_ficr_map *ficr_offsets;
};
#define NRF51_DEVICE_DEF(id, pt, var, bcode, fsize) \
@@ -238,6 +246,96 @@ static const struct nrf5_device_package nrf52_packages_table[] = {
{ 0x2009, "CF" },
};
+static const struct nrf5_ficr_map nrf51_52_ficr_offsets = {
+ .codepagesize = 0x10,
+ .codesize = 0x14,
+
+ /* CONFIGID is documented on nRF51 series only.
+ * On nRF52 is present but not documented */
+ .configid = 0x5c,
+
+ /* Following registers are available on nRF52 and on nRF51 since rev 3 */
+ .info_part = 0x100,
+ .info_variant = 0x104,
+ .info_package = 0x108,
+ .info_ram = 0x10c,
+ .info_flash = 0x110,
+};
+
+static const struct nrf5_map nrf51_52_map = {
+ .flash_base = NRF5_FLASH_BASE,
+ .ficr_base = NRF51_52_FICR_BASE,
+ .uicr_base = NRF51_52_UICR_BASE,
+ .nvmc_base = 0x4001E000,
+
+ .watchdog_refresh_addr = 0x40010600,
+};
+
+
+/* Third generation devices (nRF53, nRF91) */
+
+static const struct nrf5_ficr_map nrf53_91_ficr_offsets = {
+ .codepagesize = 0x220,
+ .codesize = 0x224,
+ .configid = 0x200,
+ .info_part = 0x20c,
+ .info_variant = 0x210,
+ .info_package = 0x214,
+ .info_ram = 0x218,
+ .info_flash = 0x21c,
+};
+
+/* Since nRF9160 Product Specification v2.1 there is
+ * a new UICR field SIPINFO, which should be preferred.
+ * The original INFO fields describe just a part of the chip
+ * (PARTNO=9120 at nRF9161)
+ */
+static const struct nrf5_ficr_map nrf91new_ficr_offsets = {
+ .codepagesize = 0x220,
+ .codesize = 0x224,
+ .configid = 0x200,
+ .info_part = 0x140, /* SIPINFO.PARTNO */
+ .info_variant = 0x148, /* SIPINFO.VARIANT */
+ .info_package = 0x214,
+ .info_ram = 0x218,
+ .info_flash = 0x21c,
+};
+
+enum {
+ NRF53APP_91_FICR_BASE = 0x00FF0000,
+ NRF53APP_91_UICR_BASE = 0x00FF8000,
+ NRF53NET_FLASH_BASE = 0x01000000,
+ NRF53NET_FICR_BASE = 0x01FF0000,
+ NRF53NET_UICR_BASE = 0x01FF8000,
+};
+
+static const struct nrf5_map nrf53app_91_map = {
+ .flash_base = NRF5_FLASH_BASE,
+ .ficr_base = NRF53APP_91_FICR_BASE,
+ .uicr_base = NRF53APP_91_UICR_BASE,
+ .nvmc_base = 0x50039000,
+
+ .watchdog_refresh_addr = 0x50018600,
+};
+
+/* nRF53 duality:
+ * SoC consists of two Cortex-M33 cores:
+ * - application core with security extensions
+ * - network core
+ * Each core has its own RAM, flash, FICR and UICR
+ * The flash driver probes and handles flash and UICR of one core
+ * independently of those dedicated to the other core.
+ */
+static const struct nrf5_map nrf53net_map = {
+ .flash_base = NRF53NET_FLASH_BASE,
+ .ficr_base = NRF53NET_FICR_BASE,
+ .uicr_base = NRF53NET_UICR_BASE,
+ .nvmc_base = 0x41080000,
+
+ .watchdog_refresh_addr = 0x41080000,
+};
+
+
const struct flash_driver nrf5_flash, nrf51_flash;
static bool nrf5_bank_is_probed(const struct flash_bank *bank)
@@ -248,6 +346,24 @@ static bool nrf5_bank_is_probed(const struct flash_bank *bank)
return nbank->probed;
}
+static bool nrf5_bank_is_uicr(const struct nrf5_bank *nbank)
+{
+ struct nrf5_info *chip = nbank->chip;
+ assert(chip);
+
+ return nbank == &chip->bank[1];
+}
+
+static int nrf5_nvmc_read_u32(struct nrf5_info *chip, uint32_t reg_offset, uint32_t *value)
+{
+ return target_read_u32(chip->target, chip->map->nvmc_base + reg_offset, value);
+}
+
+static int nrf5_nvmc_write_u32(struct nrf5_info *chip, uint32_t reg_offset, uint32_t value)
+{
+ return target_write_u32(chip->target, chip->map->nvmc_base + reg_offset, value);
+}
+
static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
{
uint32_t ready;
@@ -256,7 +372,13 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
int64_t ts_start = timeval_ms();
do {
- res = target_read_u32(chip->target, NRF5_NVMC_READY, &ready);
+ res = nrf5_nvmc_read_u32(chip, NRF5_NVMC_READY, &ready);
+ if (res == ERROR_WAIT) {
+ /* The adapter does not handle SWD WAIT properly,
+ * add some delay to reduce number of error messages */
+ alive_sleep(10);
+ continue;
+ }
if (res != ERROR_OK) {
LOG_ERROR("Error waiting NVMC_READY: generic flash write/erase error (check protection etc...)");
return res;
@@ -276,7 +398,7 @@ static int nrf5_wait_for_nvmc(struct nrf5_info *chip)
static int nrf5_nvmc_erase_enable(struct nrf5_info *chip)
{
int res;
- res = target_write_u32(chip->target,
+ res = nrf5_nvmc_write_u32(chip,
NRF5_NVMC_CONFIG,
NRF5_NVMC_CONFIG_EEN);
@@ -299,7 +421,7 @@ static int nrf5_nvmc_erase_enable(struct nrf5_info *chip)
static int nrf5_nvmc_write_enable(struct nrf5_info *chip)
{
int res;
- res = target_write_u32(chip->target,
+ res = nrf5_nvmc_write_u32(chip,
NRF5_NVMC_CONFIG,
NRF5_NVMC_CONFIG_WEN);
@@ -322,12 +444,12 @@ static int nrf5_nvmc_write_enable(struct nrf5_info *chip)
static int nrf5_nvmc_read_only(struct nrf5_info *chip)
{
int res;
- res = target_write_u32(chip->target,
+ res = nrf5_nvmc_write_u32(chip,
NRF5_NVMC_CONFIG,
NRF5_NVMC_CONFIG_REN);
if (res != ERROR_OK) {
- LOG_ERROR("Failed to enable read-only operation");
+ LOG_ERROR("Failed to disable write/erase operation");
return res;
}
/*
@@ -341,36 +463,8 @@ static int nrf5_nvmc_read_only(struct nrf5_info *chip)
return res;
}
-static int nrf5_nvmc_generic_erase(struct nrf5_info *chip,
- uint32_t erase_register, uint32_t erase_value)
-{
- int res;
-
- res = nrf5_nvmc_erase_enable(chip);
- if (res != ERROR_OK)
- goto error;
-
- res = target_write_u32(chip->target,
- erase_register,
- erase_value);
- if (res != ERROR_OK)
- goto set_read_only;
-
- res = nrf5_wait_for_nvmc(chip);
- if (res != ERROR_OK)
- goto set_read_only;
-
- return nrf5_nvmc_read_only(chip);
-
-set_read_only:
- 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 nrf5_protect_check_clenr0(struct flash_bank *bank)
+/* nRF51 series only */
+static int nrf51_protect_check_clenr0(struct flash_bank *bank)
{
int res;
uint32_t clenr0;
@@ -403,7 +497,8 @@ static int nrf5_protect_check_clenr0(struct flash_bank *bank)
return ERROR_OK;
}
-static int nrf5_protect_check_bprot(struct flash_bank *bank)
+/* nRF52 series only */
+static int nrf52_protect_check_bprot(struct flash_bank *bank)
{
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
@@ -432,26 +527,27 @@ static int nrf5_protect_check_bprot(struct flash_bank *bank)
static int nrf5_protect_check(struct flash_bank *bank)
{
- /* UICR cannot be write protected so just return early */
- if (bank->base == NRF5_UICR_BASE)
- return ERROR_OK;
-
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
struct nrf5_info *chip = nbank->chip;
assert(chip);
+ /* UICR cannot be write protected so just return early */
+ if (nrf5_bank_is_uicr(nbank))
+ return ERROR_OK;
+
if (chip->features & NRF5_FEATURE_BPROT)
- return nrf5_protect_check_bprot(bank);
+ return nrf52_protect_check_bprot(bank);
if (chip->features & NRF5_FEATURE_SERIES_51)
- return nrf5_protect_check_clenr0(bank);
+ return nrf51_protect_check_clenr0(bank);
LOG_WARNING("Flash protection of this nRF device is not supported");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
-static int nrf5_protect_clenr0(struct flash_bank *bank, int set, unsigned int first,
+/* nRF51 series only */
+static int nrf51_protect_clenr0(struct flash_bank *bank, int set, unsigned int first,
unsigned int last)
{
int res;
@@ -517,8 +613,13 @@ error:
static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first,
unsigned int last)
{
+ struct nrf5_bank *nbank = bank->driver_priv;
+ assert(nbank);
+ struct nrf5_info *chip = nbank->chip;
+ assert(chip);
+
/* UICR cannot be write protected so just bail out early */
- if (bank->base == NRF5_UICR_BASE) {
+ if (nrf5_bank_is_uicr(nbank)) {
LOG_ERROR("UICR page does not support protection");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
@@ -528,24 +629,24 @@ static int nrf5_protect(struct flash_bank *bank, int set, unsigned int first,
return ERROR_TARGET_NOT_HALTED;
}
- struct nrf5_bank *nbank = bank->driver_priv;
- assert(nbank);
- struct nrf5_info *chip = nbank->chip;
- assert(chip);
-
if (chip->features & NRF5_FEATURE_SERIES_51)
- return nrf5_protect_clenr0(bank, set, first, last);
+ return nrf51_protect_clenr0(bank, set, first, last);
LOG_ERROR("Flash protection setting is not supported on this nRF5 device");
return ERROR_FLASH_OPER_UNSUPPORTED;
}
-static bool nrf5_info_variant_to_str(uint32_t variant, char *bf)
+static bool nrf5_info_variant_to_str(uint32_t variant, char *bf, bool swap)
{
uint8_t b[4];
- h_u32_to_be(b, variant);
- if (isalnum(b[0]) && isalnum(b[1]) && isalnum(b[2]) && isalnum(b[3])) {
+ if (swap)
+ h_u32_to_le(b, variant);
+ else
+ h_u32_to_be(b, variant);
+
+ if (isalnum(b[0]) && isalnum(b[1]) && isalnum(b[2]) &&
+ (isalnum(b[3]) || b[3] == 0)) {
memcpy(bf, b, 4);
bf[4] = 0;
return true;
@@ -564,7 +665,7 @@ static const char *nrf5_decode_info_package(uint32_t package)
return "xx";
}
-static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsigned int buf_size)
+static int nrf5_get_chip_type_str(const struct nrf5_info *chip, char *buf, unsigned int buf_size)
{
int res;
if (chip->spec) {
@@ -572,11 +673,19 @@ static int get_nrf5_chip_type_str(const struct nrf5_info *chip, char *buf, unsig
chip->spec->part, chip->spec->variant, chip->spec->build_code);
} else if (chip->ficr_info_valid) {
char variant[5];
- nrf5_info_variant_to_str(chip->ficr_info.variant, variant);
- res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s%.2s(build code: %s)",
- chip->ficr_info.part,
- nrf5_decode_info_package(chip->ficr_info.package),
- variant, &variant[2]);
+
+ nrf5_info_variant_to_str(chip->ficr_info.variant, variant,
+ chip->features & NRF5_FEATURE_SERIES_91);
+
+ if (chip->features & (NRF5_FEATURE_SERIES_53 | NRF5_FEATURE_SERIES_91)) {
+ res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s",
+ chip->ficr_info.part, variant);
+ } else {
+ res = snprintf(buf, buf_size, "nRF%" PRIx32 "-%s%.2s(build code: %s)",
+ chip->ficr_info.part,
+ nrf5_decode_info_package(chip->ficr_info.package),
+ variant, &variant[2]);
+ }
} else {
res = snprintf(buf, buf_size, "nRF51xxx (HWID 0x%04" PRIx16 ")", chip->hwid);
}
@@ -597,7 +706,7 @@ static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd)
assert(chip);
char chip_type_str[256];
- if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK)
+ if (nrf5_get_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK)
return ERROR_FAIL;
command_print_sameline(cmd, "%s %ukB Flash, %ukB RAM",
@@ -605,24 +714,27 @@ static int nrf5_info(struct flash_bank *bank, struct command_invocation *cmd)
return ERROR_OK;
}
-static int nrf5_read_ficr_info(struct nrf5_info *chip)
+static int nrf5_read_ficr_info_part(struct nrf5_info *chip, const struct nrf5_map *map,
+ const struct nrf5_ficr_map *ficr_offsets)
{
- int res;
struct target *target = chip->target;
+ uint32_t ficr_base = map->ficr_base;
- chip->ficr_info_valid = false;
-
- res = target_read_u32(target, NRF5_FICR_INFO_PART, &chip->ficr_info.part);
- if (res != ERROR_OK) {
+ int res = target_read_u32(target, ficr_base + ficr_offsets->info_part, &chip->ficr_info.part);
+ if (res != ERROR_OK)
LOG_DEBUG("Couldn't read FICR INFO.PART register");
- return res;
- }
+
+ return res;
+}
+
+static int nrf51_52_partno_check(struct nrf5_info *chip)
+{
uint32_t series = chip->ficr_info.part & 0xfffff000;
switch (series) {
case 0x51000:
chip->features = NRF5_FEATURE_SERIES_51;
- break;
+ return ERROR_OK;
case 0x52000:
chip->features = NRF5_FEATURE_SERIES_52;
@@ -641,41 +753,59 @@ static int nrf5_read_ficr_info(struct nrf5_info *chip)
chip->features |= NRF5_FEATURE_ACL_PROT;
break;
}
- break;
+ return ERROR_OK;
default:
LOG_DEBUG("FICR INFO likely not implemented. Invalid PART value 0x%08"
- PRIx32, chip->ficr_info.part);
+ PRIx32, chip->ficr_info.part);
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
+}
- /* Now we know the device has FICR INFO filled by something relevant:
- * Although it is not documented, the tested nRF51 rev 3 devices
- * have FICR INFO.PART, RAM and FLASH of the same format as nRF52.
- * VARIANT and PACKAGE coding is unknown for a nRF51 device.
- * nRF52 devices have FICR INFO documented and always filled. */
+static int nrf53_91_partno_check(struct nrf5_info *chip)
+{
+ uint32_t series = chip->ficr_info.part & 0xffffff00;
+ switch (series) {
+ case 0x5300:
+ chip->features = NRF5_FEATURE_SERIES_53 | NRF5_FEATURE_ERASE_BY_FLASH_WR;
+ return ERROR_OK;
- res = target_read_u32(target, NRF5_FICR_INFO_VARIANT, &chip->ficr_info.variant);
- if (res != ERROR_OK)
- return res;
+ case 0x9100:
+ chip->features = NRF5_FEATURE_SERIES_91 | NRF5_FEATURE_ERASE_BY_FLASH_WR;
+ return ERROR_OK;
- res = target_read_u32(target, NRF5_FICR_INFO_PACKAGE, &chip->ficr_info.package);
+ default:
+ LOG_DEBUG("Invalid FICR INFO PART value 0x%08"
+ PRIx32, chip->ficr_info.part);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ }
+}
+
+static int nrf5_read_ficr_more_info(struct nrf5_info *chip)
+{
+ int res;
+ struct target *target = chip->target;
+ const struct nrf5_ficr_map *ficr_offsets = chip->ficr_offsets;
+ uint32_t ficr_base = chip->map->ficr_base;
+
+ res = target_read_u32(target, ficr_base + ficr_offsets->info_variant, &chip->ficr_info.variant);
if (res != ERROR_OK)
return res;
- res = target_read_u32(target, NRF5_FICR_INFO_RAM, &chip->ficr_info.ram);
+ res = target_read_u32(target, ficr_base + ficr_offsets->info_package, &chip->ficr_info.package);
if (res != ERROR_OK)
return res;
- res = target_read_u32(target, NRF5_FICR_INFO_FLASH, &chip->ficr_info.flash);
+ res = target_read_u32(target, ficr_base + ficr_offsets->info_ram, &chip->ficr_info.ram);
if (res != ERROR_OK)
return res;
- chip->ficr_info_valid = true;
- return ERROR_OK;
+ res = target_read_u32(target, ficr_base + ficr_offsets->info_flash, &chip->ficr_info.flash);
+ return res;
}
-static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size)
+/* nRF51 series only */
+static int nrf51_get_ram_size(struct target *target, uint32_t *ram_size)
{
int res;
@@ -710,7 +840,7 @@ static int nrf5_get_ram_size(struct target *target, uint32_t *ram_size)
static int nrf5_probe(struct flash_bank *bank)
{
- int res;
+ int res = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
struct nrf5_bank *nbank = bank->driver_priv;
assert(nbank);
@@ -718,24 +848,100 @@ static int nrf5_probe(struct flash_bank *bank)
assert(chip);
struct target *target = chip->target;
- uint32_t configid;
- res = target_read_u32(target, NRF5_FICR_CONFIGID, &configid);
+ chip->spec = NULL;
+ chip->ficr_info_valid = false;
+
+ /* First try to detect nRF53/91 */
+ switch (bank->base) {
+ case NRF5_FLASH_BASE:
+ case NRF53APP_91_UICR_BASE:
+ res = nrf5_read_ficr_info_part(chip, &nrf53app_91_map, &nrf91new_ficr_offsets);
+ if (res == ERROR_OK) {
+ res = nrf53_91_partno_check(chip);
+ if (res == ERROR_OK) {
+ chip->map = &nrf53app_91_map;
+ chip->ficr_offsets = &nrf91new_ficr_offsets;
+ break;
+ }
+ }
+
+ res = nrf5_read_ficr_info_part(chip, &nrf53app_91_map, &nrf53_91_ficr_offsets);
+ if (res != ERROR_OK)
+ break;
+
+ res = nrf53_91_partno_check(chip);
+ if (res != ERROR_OK)
+ break;
+
+ chip->map = &nrf53app_91_map;
+ chip->ficr_offsets = &nrf53_91_ficr_offsets;
+ break;
+
+ case NRF53NET_FLASH_BASE:
+ case NRF53NET_UICR_BASE:
+ res = nrf5_read_ficr_info_part(chip, &nrf53net_map, &nrf53_91_ficr_offsets);
+ if (res != ERROR_OK)
+ break;
+
+ res = nrf53_91_partno_check(chip);
+ if (res != ERROR_OK)
+ break;
+
+ chip->map = &nrf53net_map;
+ chip->ficr_offsets = &nrf53_91_ficr_offsets;
+ break;
+
+ default:
+ break;
+ }
+
+ /* If nRF53/91 is not detected, try nRF51/52 */
if (res != ERROR_OK) {
- LOG_ERROR("Couldn't read CONFIGID register");
- return res;
+ /* Guess a nRF51 series if the device has no FICR INFO and we don't know HWID */
+ chip->features = NRF5_FEATURE_SERIES_51;
+ chip->map = &nrf51_52_map;
+ chip->ficr_offsets = &nrf51_52_ficr_offsets;
+
+ /* Don't bail out on error for the case that some old engineering
+ * sample has FICR INFO registers unreadable. We can proceed anyway. */
+ res = nrf5_read_ficr_info_part(chip, chip->map, chip->ficr_offsets);
+ if (res == ERROR_OK)
+ res = nrf51_52_partno_check(chip);
}
- /* HWID is stored in the lower two bytes of the CONFIGID register */
- chip->hwid = configid & 0xFFFF;
+ if (res == ERROR_OK) {
+ /* Now we know the device has FICR INFO filled by something relevant:
+ * Although it is not documented, the tested nRF51 rev 3 devices
+ * have FICR INFO.PART, RAM and FLASH of the same format as nRF52.
+ * VARIANT and PACKAGE coding is unknown for a nRF51 device.
+ * nRF52 devices have FICR INFO documented and always filled. */
+ res = nrf5_read_ficr_more_info(chip);
+ if (res == ERROR_OK) {
+ chip->ficr_info_valid = true;
+ } else if (chip->features & NRF5_FEATURE_SERIES_51) {
+ LOG_DEBUG("Couldn't read some of FICR INFO registers");
+ } else {
+ LOG_ERROR("Couldn't read some of FICR INFO registers");
+ return res;
+ }
+ }
- /* guess a nRF51 series if the device has no FICR INFO and we don't know HWID */
- chip->features = NRF5_FEATURE_SERIES_51;
+ const struct nrf5_ficr_map *ficr_offsets = chip->ficr_offsets;
+ uint32_t ficr_base = chip->map->ficr_base;
+ uint32_t configid = 0;
+ res = target_read_u32(target, ficr_base + ficr_offsets->configid, &configid);
+ if (res != ERROR_OK) {
+ if (chip->features & NRF5_FEATURE_SERIES_51) {
+ LOG_ERROR("Couldn't read FICR CONFIGID register");
+ return res;
+ }
- /* Don't bail out on error for the case that some old engineering
- * sample has FICR INFO registers unreadable. We can proceed anyway. */
- (void)nrf5_read_ficr_info(chip);
+ LOG_DEBUG("Couldn't read FICR CONFIGID register, using FICR INFO");
+ }
+
+ /* HWID is stored in the lower two bytes of the CONFIGID register */
+ chip->hwid = configid & 0xFFFF;
- chip->spec = NULL;
for (size_t i = 0; i < ARRAY_SIZE(nrf5_known_devices_table); i++) {
if (chip->hwid == nrf5_known_devices_table[i].hwid) {
chip->spec = &nrf5_known_devices_table[i];
@@ -753,15 +959,17 @@ static int nrf5_probe(struct flash_bank *bank)
if (chip->ficr_info_valid) {
chip->ram_size_kb = chip->ficr_info.ram;
- } else {
+ } else if (chip->features & NRF5_FEATURE_SERIES_51) {
uint32_t ram_size;
- nrf5_get_ram_size(target, &ram_size);
+ nrf51_get_ram_size(target, &ram_size);
chip->ram_size_kb = ram_size / 1024;
+ } else {
+ chip->ram_size_kb = 0;
}
- /* The value stored in NRF5_FICR_CODEPAGESIZE is the number of bytes in one page of FLASH. */
+ /* The value stored in FICR CODEPAGESIZE is the number of bytes in one page of FLASH. */
uint32_t flash_page_size;
- res = target_read_u32(chip->target, NRF5_FICR_CODEPAGESIZE,
+ res = target_read_u32(chip->target, ficr_base + ficr_offsets->codepagesize,
&flash_page_size);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code page size");
@@ -769,9 +977,10 @@ static int nrf5_probe(struct flash_bank *bank)
}
/* Note the register name is misleading,
- * NRF5_FICR_CODESIZE is the number of pages in flash memory, not the number of bytes! */
+ * 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, NRF5_FICR_CODESIZE, &num_sectors);
+ res = target_read_u32(chip->target, ficr_base + ficr_offsets->codesize,
+ &num_sectors);
if (res != ERROR_OK) {
LOG_ERROR("Couldn't read code memory size");
return res;
@@ -781,7 +990,7 @@ static int nrf5_probe(struct flash_bank *bank)
if (!chip->bank[0].probed && !chip->bank[1].probed) {
char chip_type_str[256];
- if (get_nrf5_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK)
+ if (nrf5_get_chip_type_str(chip, chip_type_str, sizeof(chip_type_str)) != ERROR_OK)
return ERROR_FAIL;
const bool device_is_unknown = (!chip->spec && !chip->ficr_info_valid);
LOG_INFO("%s%s %ukB Flash, %ukB RAM",
@@ -793,7 +1002,7 @@ static int nrf5_probe(struct flash_bank *bank)
free(bank->sectors);
- if (bank->base == NRF5_FLASH_BASE) {
+ if (bank->base == chip->map->flash_base) {
/* Sanity check */
if (chip->spec && chip->flash_size_kb != chip->spec->flash_size_kb)
LOG_WARNING("Chip's reported Flash capacity does not match expected one");
@@ -810,6 +1019,7 @@ static int nrf5_probe(struct flash_bank *bank)
chip->bank[0].probed = true;
} else {
+ /* UICR bank */
bank->num_sectors = 1;
bank->size = flash_page_size;
@@ -833,13 +1043,6 @@ static int nrf5_auto_probe(struct flash_bank *bank)
return nrf5_probe(bank);
}
-static int nrf5_erase_all(struct nrf5_info *chip)
-{
- LOG_DEBUG("Erasing all non-volatile memory");
- return nrf5_nvmc_generic_erase(chip,
- NRF5_NVMC_ERASEALL,
- 0x00000001);
-}
static int nrf5_erase_page(struct flash_bank *bank,
struct nrf5_info *chip,
@@ -849,7 +1052,7 @@ static int nrf5_erase_page(struct flash_bank *bank,
LOG_DEBUG("Erasing page at 0x%"PRIx32, sector->offset);
- if (bank->base == NRF5_UICR_BASE) {
+ if (bank->base == chip->map->uicr_base) {
if (chip->features & NRF5_FEATURE_SERIES_51) {
uint32_t ppfc;
res = target_read_u32(chip->target, NRF51_FICR_PPFC,
@@ -871,17 +1074,37 @@ static int nrf5_erase_page(struct flash_bank *bank,
}
}
- res = nrf5_nvmc_generic_erase(chip,
- NRF5_NVMC_ERASEUICR,
- 0x00000001);
-
+ res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_ERASEUICR, 0x00000001);
+
+ } else if (chip->features & NRF5_FEATURE_ERASE_BY_FLASH_WR) {
+ res = target_write_u32(chip->target, bank->base + sector->offset, 0xffffffff);
+ /* nRF9160 errata [2] NVMC: CPU code execution from RAM halted during
+ * flash page erase operation
+ * https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF9160_Rev1%2FERR%2FnRF9160%2FRev1%2Flatest%2Fanomaly_160_2.html
+ * affects also erasing by debugger MEM-AP write:
+ *
+ * Write to a flash address stalls the bus for 87 ms until
+ * page erase finishes! This makes problems if the adapter does not
+ * handle SWD WAIT properly or does not wait long enough.
+ * Using a target algo would not help, AP gets unresponsive too.
+ * Neither sending AP ABORT helps, the next AP access stalls again.
+ * Simply wait long enough before accessing AP again...
+ *
+ * The same errata was observed in nRF9161
+ */
+ if (chip->features & NRF5_FEATURE_SERIES_91)
+ alive_sleep(90);
} else {
- res = nrf5_nvmc_generic_erase(chip,
- NRF5_NVMC_ERASEPAGE,
- sector->offset);
+ res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_ERASEPAGE, sector->offset);
+ }
+
+ if (res != ERROR_OK) {
+ /* caller logs the error */
+ return res;
}
+ res = nrf5_wait_for_nvmc(chip);
return res;
}
@@ -958,7 +1181,7 @@ static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t address, const u
buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
buf_set_u32(reg_params[3].value, 0, 32, address);
buf_set_u32(reg_params[4].value, 0, 32, WATCHDOG_REFRESH_VALUE);
- buf_set_u32(reg_params[5].value, 0, 32, WATCHDOG_REFRESH_REGISTER);
+ buf_set_u32(reg_params[5].value, 0, 32, chip->map->watchdog_refresh_addr);
retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
0, NULL,
@@ -1008,7 +1231,7 @@ static int nrf5_write(struct flash_bank *bank, const uint8_t *buffer,
* is protected. */
if (chip->features & NRF5_FEATURE_SERIES_51) {
- res = nrf5_protect_check_clenr0(bank);
+ res = nrf51_protect_check_clenr0(bank);
if (res != ERROR_OK)
return res;
@@ -1065,18 +1288,23 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first,
* is protected. */
if (chip->features & NRF5_FEATURE_SERIES_51) {
- res = nrf5_protect_check_clenr0(bank);
+ res = nrf51_protect_check_clenr0(bank);
if (res != ERROR_OK)
return res;
}
+ res = nrf5_nvmc_erase_enable(chip);
+ if (res != ERROR_OK)
+ goto error;
+
/* For each sector to be erased */
for (unsigned int s = first; s <= last; s++) {
if (chip->features & NRF5_FEATURE_SERIES_51
&& bank->sectors[s].is_protected == 1) {
LOG_ERROR("Flash sector %d is protected", s);
- return ERROR_FLASH_PROTECTED;
+ res = ERROR_FLASH_PROTECTED;
+ break;
}
res = nrf5_erase_page(bank, chip, &bank->sectors[s]);
@@ -1086,7 +1314,9 @@ static int nrf5_erase(struct flash_bank *bank, unsigned int first,
}
}
- return ERROR_OK;
+error:
+ nrf5_nvmc_read_only(chip);
+ return res;
}
static void nrf5_free_driver_priv(struct flash_bank *bank)
@@ -1136,7 +1366,10 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
switch (bank->base) {
case NRF5_FLASH_BASE:
- case NRF5_UICR_BASE:
+ case NRF53NET_FLASH_BASE:
+ case NRF51_52_UICR_BASE:
+ case NRF53APP_91_UICR_BASE:
+ case NRF53NET_UICR_BASE:
break;
default:
LOG_ERROR("Invalid bank address " TARGET_ADDR_FMT, bank->base);
@@ -1155,9 +1388,12 @@ FLASH_BANK_COMMAND_HANDLER(nrf5_flash_bank_command)
switch (bank->base) {
case NRF5_FLASH_BASE:
+ case NRF53NET_FLASH_BASE:
nbank = &chip->bank[0];
break;
- case NRF5_UICR_BASE:
+ case NRF51_52_UICR_BASE:
+ case NRF53APP_91_UICR_BASE:
+ case NRF53NET_UICR_BASE:
nbank = &chip->bank[1];
break;
}
@@ -1210,14 +1446,27 @@ COMMAND_HANDLER(nrf5_handle_mass_erase_command)
}
}
- res = nrf5_erase_all(chip);
+ res = nrf5_nvmc_erase_enable(chip);
+ if (res != ERROR_OK)
+ goto error;
+
+ res = nrf5_nvmc_write_u32(chip, NRF5_NVMC_ERASEALL, 0x00000001);
+ if (res != ERROR_OK) {
+ LOG_ERROR("Mass erase failed");
+ goto error;
+ }
+
+ res = nrf5_wait_for_nvmc(chip);
+ if (res != ERROR_OK)
+ LOG_ERROR("Mass erase did not complete");
+
+error:
+ nrf5_nvmc_read_only(chip);
+
if (res == ERROR_OK) {
LOG_INFO("Mass erase completed.");
if (chip->features & NRF5_FEATURE_SERIES_51)
LOG_INFO("A reset or power cycle is required if the flash was protected before.");
-
- } else {
- LOG_ERROR("Failed to erase the chip");
}
return res;
diff --git a/src/flash/nor/pic32mx.c b/src/flash/nor/pic32mx.c
index 0f3937c..982c961 100644
--- a/src/flash/nor/pic32mx.c
+++ b/src/flash/nor/pic32mx.c
@@ -92,7 +92,7 @@ struct pic32mx_flash_bank {
* DEVID values as per PIC32MX Flash Programming Specification Rev N
*/
-static const struct pic32mx_devs_s {
+static const struct pic32mx_devs {
uint32_t devid;
const char *name;
} pic32mx_devs[] = {
diff --git a/src/flash/nor/stellaris.c b/src/flash/nor/stellaris.c
index 972686e..eab6244 100644
--- a/src/flash/nor/stellaris.c
+++ b/src/flash/nor/stellaris.c
@@ -453,7 +453,7 @@ FLASH_BANK_COMMAND_HANDLER(stellaris_flash_bank_command)
if (CMD_ARGC < 6)
return ERROR_COMMAND_SYNTAX_ERROR;
- stellaris_info = calloc(sizeof(struct stellaris_flash_bank), 1);
+ stellaris_info = calloc(1, sizeof(struct stellaris_flash_bank));
bank->base = 0x0;
bank->driver_priv = stellaris_info;
diff --git a/src/flash/nor/stm32f2x.c b/src/flash/nor/stm32f2x.c
index 4e0f731..3bafde5 100644
--- a/src/flash/nor/stm32f2x.c
+++ b/src/flash/nor/stm32f2x.c
@@ -1020,7 +1020,7 @@ static int stm32x_probe(struct flash_bank *bank)
assert(num_sectors > 0);
bank->num_sectors = num_sectors;
- bank->sectors = calloc(sizeof(struct flash_sector), num_sectors);
+ bank->sectors = calloc(num_sectors, sizeof(struct flash_sector));
if (stm32x_otp_is_f7(bank))
bank->size = STM32F7_OTP_SIZE;
diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c
index 1c4e154..15edd1a 100644
--- a/src/flash/nor/tcl.c
+++ b/src/flash/nor/tcl.c
@@ -1299,6 +1299,7 @@ COMMAND_HANDLER(handle_flash_bank_command)
if (retval != ERROR_OK) {
LOG_ERROR("'%s' driver rejected flash bank at " TARGET_ADDR_FMT
"; usage: %s", driver_name, c->base, driver->usage);
+ free(c->name);
free(c);
return retval;
}
diff --git a/src/helper/startup.tcl b/src/helper/startup.tcl
index 5a0d479..e6e76e6 100644
--- a/src/helper/startup.tcl
+++ b/src/helper/startup.tcl
@@ -11,10 +11,10 @@ proc find {filename} {
if {[catch {ocd_find $filename} t]==0} {
return $t
}
- if {[catch {ocd_find [string map {\ /} $filename} t]==0} {
+ if {[catch {ocd_find [string map {\\ /} $filename]} t]==0} {
return $t
}
- if {[catch {ocd_find [string map {/ \\} $filename} t]==0} {
+ if {[catch {ocd_find [string map {/ \\} $filename]} t]==0} {
return $t
}
# make sure error message matches original input string
diff --git a/src/jtag/commands.h b/src/jtag/commands.h
index a1096da..8259077 100644
--- a/src/jtag/commands.h
+++ b/src/jtag/commands.h
@@ -15,7 +15,7 @@
#define OPENOCD_JTAG_COMMANDS_H
/**
- * The inferred type of a scan_command_s structure, indicating whether
+ * The inferred type of a scan_command structure, indicating whether
* the command has the host scan in from the device, the host scan out
* to the device, or both.
*/
@@ -29,7 +29,7 @@ enum scan_type {
};
/**
- * The scan_command provide a means of encapsulating a set of scan_field_s
+ * The scan_command provide a means of encapsulating a set of scan_field
* structures that should be scanned in/out to the device.
*/
struct scan_command {
@@ -123,7 +123,7 @@ union jtag_command_container {
/**
* The type of the @c jtag_command_container contained by a
- * @c jtag_command_s structure.
+ * @c jtag_command structure.
*/
enum jtag_command_type {
JTAG_SCAN = 1,
diff --git a/src/jtag/drivers/angie.c b/src/jtag/drivers/angie.c
index c024667..81dd1af 100644
--- a/src/jtag/drivers/angie.c
+++ b/src/jtag/drivers/angie.c
@@ -1597,7 +1597,7 @@ static int angie_queue_scan(struct angie *device, struct jtag_command *cmd)
/* Allocate TDO buffer if required */
if (type == SCAN_IN || type == SCAN_IO) {
- tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes);
+ tdo_buffer_start = calloc(scan_size_bytes, sizeof(uint8_t));
if (!tdo_buffer_start)
return ERROR_FAIL;
diff --git a/src/jtag/drivers/ftdi.c b/src/jtag/drivers/ftdi.c
index a0b120b..1793cbf 100644
--- a/src/jtag/drivers/ftdi.c
+++ b/src/jtag/drivers/ftdi.c
@@ -1228,7 +1228,7 @@ COMMAND_HANDLER(ftdi_handle_get_signal_command)
uint16_t sig_data = 0;
sig = find_signal_by_name(CMD_ARGV[0]);
if (!sig) {
- LOG_ERROR("interface configuration doesn't define signal '%s'", CMD_ARGV[0]);
+ command_print(CMD, "interface configuration doesn't define signal '%s'", CMD_ARGV[0]);
return ERROR_FAIL;
}
@@ -1236,7 +1236,7 @@ COMMAND_HANDLER(ftdi_handle_get_signal_command)
if (ret != ERROR_OK)
return ret;
- LOG_USER("Signal %s = %#06x", sig->name, sig_data);
+ command_print(CMD, "%#06x", sig_data);
return ERROR_OK;
}
diff --git a/src/jtag/drivers/nulink_usb.c b/src/jtag/drivers/nulink_usb.c
index 4fdb857..66cf25a 100644
--- a/src/jtag/drivers/nulink_usb.c
+++ b/src/jtag/drivers/nulink_usb.c
@@ -34,7 +34,7 @@
#define NULINK2_USB_PID1 (0x5200)
#define NULINK2_USB_PID2 (0x5201)
-struct nulink_usb_handle_s {
+struct nulink_usb_handle {
hid_device *dev_handle;
uint16_t max_packet_size;
uint8_t usbcmdidx;
@@ -87,7 +87,7 @@ enum nulink_connect {
static int nulink_usb_xfer_rw(void *handle, uint8_t *buf)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -107,7 +107,7 @@ static int nulink_usb_xfer_rw(void *handle, uint8_t *buf)
static int nulink1_usb_xfer(void *handle, uint8_t *buf, int size)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -120,7 +120,7 @@ static int nulink1_usb_xfer(void *handle, uint8_t *buf, int size)
static int nulink2_usb_xfer(void *handle, uint8_t *buf, int size)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -133,7 +133,7 @@ static int nulink2_usb_xfer(void *handle, uint8_t *buf, int size)
static void nulink1_usb_init_buffer(void *handle, uint32_t size)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
h->cmdidx = 0;
@@ -149,7 +149,7 @@ static void nulink1_usb_init_buffer(void *handle, uint32_t size)
static void nulink2_usb_init_buffer(void *handle, uint32_t size)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
h->cmdidx = 0;
@@ -165,7 +165,7 @@ static void nulink2_usb_init_buffer(void *handle, uint32_t size)
static inline int nulink_usb_xfer(void *handle, uint8_t *buf, int size)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -174,7 +174,7 @@ static inline int nulink_usb_xfer(void *handle, uint8_t *buf, int size)
static inline void nulink_usb_init_buffer(void *handle, uint32_t size)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -183,7 +183,7 @@ static inline void nulink_usb_init_buffer(void *handle, uint32_t size)
static int nulink_usb_version(void *handle)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_version");
@@ -219,7 +219,7 @@ static int nulink_usb_version(void *handle)
static int nulink_usb_idcode(void *handle, uint32_t *idcode)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_idcode");
@@ -243,7 +243,7 @@ static int nulink_usb_idcode(void *handle, uint32_t *idcode)
static int nulink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_write_debug_reg 0x%08" PRIX32 " 0x%08" PRIX32, addr, val);
@@ -278,7 +278,7 @@ static int nulink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
static enum target_state nulink_usb_state(void *handle)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -299,7 +299,7 @@ static enum target_state nulink_usb_state(void *handle)
static int nulink_usb_assert_srst(void *handle, int srst)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_assert_srst");
@@ -324,7 +324,7 @@ static int nulink_usb_assert_srst(void *handle, int srst)
static int nulink_usb_reset(void *handle)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_reset");
@@ -349,7 +349,7 @@ static int nulink_usb_reset(void *handle)
static int nulink_usb_run(void *handle)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_run");
@@ -365,7 +365,7 @@ static int nulink_usb_run(void *handle)
static int nulink_usb_halt(void *handle)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_halt");
@@ -385,7 +385,7 @@ static int nulink_usb_halt(void *handle)
static int nulink_usb_step(void *handle)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_step");
@@ -405,7 +405,7 @@ static int nulink_usb_step(void *handle)
static int nulink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -444,7 +444,7 @@ static int nulink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
static int nulink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -483,7 +483,7 @@ static int nulink_usb_read_mem8(void *handle, uint32_t addr, uint16_t len,
int res = ERROR_OK;
uint32_t offset = 0;
uint32_t bytes_remaining = 12;
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_read_mem8: addr 0x%08" PRIx32 ", len %" PRId16, addr, len);
@@ -568,7 +568,7 @@ static int nulink_usb_write_mem8(void *handle, uint32_t addr, uint16_t len,
int res = ERROR_OK;
uint32_t offset = 0;
uint32_t bytes_remaining = 12;
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_write_mem8: addr 0x%08" PRIx32 ", len %" PRIu16, addr, len);
@@ -675,7 +675,7 @@ static int nulink_usb_read_mem32(void *handle, uint32_t addr, uint16_t len,
{
int res = ERROR_OK;
uint32_t bytes_remaining = 12;
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -744,7 +744,7 @@ static int nulink_usb_write_mem32(void *handle, uint32_t addr, uint16_t len,
{
int res = ERROR_OK;
uint32_t bytes_remaining = 12;
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
assert(handle);
@@ -819,7 +819,7 @@ static int nulink_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
uint32_t count, uint8_t *buffer)
{
int retval = ERROR_OK;
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
/* calculate byte count */
count *= size;
@@ -879,7 +879,7 @@ static int nulink_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
uint32_t count, const uint8_t *buffer)
{
int retval = ERROR_OK;
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
if (addr < ARM_SRAM_BASE) {
LOG_DEBUG("nulink_usb_write_mem: address below ARM_SRAM_BASE, not supported.\n");
@@ -950,7 +950,7 @@ static int nulink_usb_override_target(const char *targetname)
static int nulink_speed(void *handle, int khz, bool query)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
unsigned long max_ice_clock = khz;
LOG_DEBUG("nulink_speed: query %s", query ? "yes" : "no");
@@ -1004,7 +1004,7 @@ static int nulink_speed(void *handle, int khz, bool query)
static int nulink_usb_close(void *handle)
{
- struct nulink_usb_handle_s *h = handle;
+ struct nulink_usb_handle *h = handle;
LOG_DEBUG("nulink_usb_close");
@@ -1018,7 +1018,7 @@ static int nulink_usb_close(void *handle)
return ERROR_OK;
}
-static int nulink_usb_open(struct hl_interface_param_s *param, void **fd)
+static int nulink_usb_open(struct hl_interface_param *param, void **fd)
{
struct hid_device_info *devs, *cur_dev;
uint16_t target_vid = 0;
@@ -1040,7 +1040,7 @@ static int nulink_usb_open(struct hl_interface_param_s *param, void **fd)
return ERROR_FAIL;
}
- struct nulink_usb_handle_s *h = calloc(1, sizeof(*h));
+ struct nulink_usb_handle *h = calloc(1, sizeof(*h));
if (!h) {
LOG_ERROR("Out of memory");
goto error_open;
@@ -1154,7 +1154,7 @@ error_open:
return ERROR_FAIL;
}
-struct hl_layout_api_s nulink_usb_layout_api = {
+struct hl_layout_api nulink_usb_layout_api = {
.open = nulink_usb_open,
.close = nulink_usb_close,
.idcode = nulink_usb_idcode,
diff --git a/src/jtag/drivers/remote_bitbang.c b/src/jtag/drivers/remote_bitbang.c
index 53d2151..edd36f2 100644
--- a/src/jtag/drivers/remote_bitbang.c
+++ b/src/jtag/drivers/remote_bitbang.c
@@ -114,12 +114,18 @@ static int remote_bitbang_fill_buf(enum block_bool block)
contiguous_available_space);
if (first && block == BLOCK)
socket_nonblock(remote_bitbang_fd);
- first = false;
if (count > 0) {
remote_bitbang_recv_buf_end += count;
if (remote_bitbang_recv_buf_end == sizeof(remote_bitbang_recv_buf))
remote_bitbang_recv_buf_end = 0;
} else if (count == 0) {
+ /* When read_socket returns 0, socket reached EOF and there is
+ * no data to read. But if request was blocking, the caller
+ * expected some data. Such situations should be treated as ERROR. */
+ if (first && block == BLOCK) {
+ LOG_ERROR("remote_bitbang: socket closed by remote");
+ return ERROR_FAIL;
+ }
return ERROR_OK;
} else if (count < 0) {
#ifdef _WIN32
@@ -133,6 +139,7 @@ static int remote_bitbang_fill_buf(enum block_bool block)
return ERROR_FAIL;
}
}
+ first = false;
}
return ERROR_OK;
diff --git a/src/jtag/drivers/rlink.c b/src/jtag/drivers/rlink.c
index 1b1f2e4..afdf16e 100644
--- a/src/jtag/drivers/rlink.c
+++ b/src/jtag/drivers/rlink.c
@@ -286,13 +286,13 @@ static uint8_t dtc_entry_download;
static int dtc_load_from_buffer(struct libusb_device_handle *hdev_param, const uint8_t *buffer,
size_t length)
{
- struct header_s {
+ struct header {
uint8_t type;
uint8_t length;
};
int usb_err;
- struct header_s *header;
+ struct header *header;
uint8_t lut_start = 0xc0;
dtc_entry_download = 0;
@@ -311,7 +311,7 @@ static int dtc_load_from_buffer(struct libusb_device_handle *hdev_param, const u
exit(1);
}
- header = (struct header_s *)buffer;
+ header = (struct header *)buffer;
buffer += sizeof(*header);
length -= sizeof(*header);
diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c
index b14fbf1..8cf3b0c 100644
--- a/src/jtag/drivers/stlink_usb.c
+++ b/src/jtag/drivers/stlink_usb.c
@@ -140,7 +140,7 @@ struct stlink_usb_version {
uint32_t flags;
};
-struct stlink_usb_priv_s {
+struct stlink_usb_priv {
/** */
struct libusb_device_handle *fd;
/** */
@@ -154,7 +154,7 @@ struct stlink_tcp_version {
uint32_t build;
};
-struct stlink_tcp_priv_s {
+struct stlink_tcp_priv {
/** */
int fd;
/** */
@@ -171,9 +171,9 @@ struct stlink_tcp_priv_s {
struct stlink_tcp_version version;
};
-struct stlink_backend_s {
+struct stlink_backend {
/** */
- int (*open)(void *handle, struct hl_interface_param_s *param);
+ int (*open)(void *handle, struct hl_interface_param *param);
/** */
int (*close)(void *handle);
/** */
@@ -245,13 +245,13 @@ struct dap_queue {
};
/** */
-struct stlink_usb_handle_s {
+struct stlink_usb_handle {
/** */
- struct stlink_backend_s *backend;
+ struct stlink_backend *backend;
/** */
union {
- struct stlink_usb_priv_s usb_backend_priv;
- struct stlink_tcp_priv_s tcp_backend_priv;
+ struct stlink_usb_priv usb_backend_priv;
+ struct stlink_tcp_priv tcp_backend_priv;
};
/** */
uint8_t rx_ep;
@@ -294,22 +294,22 @@ struct stlink_usb_handle_s {
};
/** */
-static inline int stlink_usb_open(void *handle, struct hl_interface_param_s *param)
+static inline int stlink_usb_open(void *handle, struct hl_interface_param *param)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
return h->backend->open(handle, param);
}
/** */
static inline int stlink_usb_close(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
return h->backend->close(handle);
}
/** */
static inline int stlink_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
return h->backend->xfer_noerrcheck(handle, buf, size);
}
@@ -567,7 +567,7 @@ static int stlink_usb_open_ap(void *handle, unsigned short apsel);
/** */
static unsigned int stlink_usb_block(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -727,7 +727,7 @@ static int jtag_libusb_bulk_transfer_n(
/** */
static int stlink_usb_xfer_v1_get_status(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int tr, ret;
assert(handle);
@@ -762,7 +762,7 @@ static int stlink_usb_xfer_v1_get_status(void *handle)
#ifdef USE_LIBUSB_ASYNCIO
static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -800,7 +800,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
#else
static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int tr, ret;
assert(handle);
@@ -834,7 +834,7 @@ static int stlink_usb_xfer_rw(void *handle, int cmdsize, const uint8_t *buf, int
static int stlink_usb_xfer_v1_get_sense(void *handle)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -860,7 +860,7 @@ static int stlink_usb_xfer_v1_get_sense(void *handle)
/** */
static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int tr, ret;
ret = jtag_libusb_bulk_read(h->usb_backend_priv.fd, h->trace_ep, (char *)buf, size,
@@ -882,7 +882,7 @@ static int stlink_usb_usb_read_trace(void *handle, const uint8_t *buf, int size)
static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
{
int err, cmdsize = STLINK_CMD_SIZE_V2;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -915,7 +915,7 @@ static int stlink_usb_usb_xfer_noerrcheck(void *handle, const uint8_t *buf, int
static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool check_tcp_status)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -980,7 +980,7 @@ static int stlink_tcp_send_cmd(void *handle, int send_size, int recv_size, bool
/** */
static int stlink_tcp_xfer_noerrcheck(void *handle, const uint8_t *buf, int size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int send_size = STLINK_TCP_USB_CMD_SIZE;
int recv_size = STLINK_TCP_SS_SIZE;
@@ -1040,7 +1040,7 @@ static int stlink_tcp_xfer_noerrcheck(void *handle, const uint8_t *buf, int size
/** */
static int stlink_tcp_read_trace(void *handle, const uint8_t *buf, int size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
stlink_usb_init_buffer(h, h->trace_ep, 0);
return stlink_tcp_xfer_noerrcheck(handle, buf, size);
@@ -1052,7 +1052,7 @@ static int stlink_tcp_read_trace(void *handle, const uint8_t *buf, int size)
*/
static int stlink_usb_error_check(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -1162,7 +1162,7 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
{
int retries = 0;
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
while (1) {
if ((h->st_mode != STLINK_MODE_DEBUG_SWIM) || !retries) {
@@ -1191,7 +1191,7 @@ static int stlink_cmd_allow_retry(void *handle, const uint8_t *buf, int size)
/** */
static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -1206,14 +1206,14 @@ static int stlink_usb_read_trace(void *handle, const uint8_t *buf, int size)
*/
static void stlink_usb_set_cbw_transfer_datalength(void *handle, uint32_t size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
buf_set_u32(h->cmdbuf+8, 0, 32, size);
}
static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint32_t size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
/* fill the send buffer */
strcpy((char *)h->cmdbuf, "USBC");
@@ -1234,7 +1234,7 @@ static void stlink_usb_xfer_v1_create_cmd(void *handle, uint8_t direction, uint3
/** */
static void stlink_usb_init_buffer(void *handle, uint8_t direction, uint32_t size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
h->direction = direction;
@@ -1256,7 +1256,7 @@ static int stlink_usb_version(void *handle)
uint8_t v, x, y, jtag, swim, msd, bridge = 0;
char v_str[5 * (1 + 3) + 1]; /* VvJjMmBbSs */
char *p;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -1479,7 +1479,7 @@ static int stlink_usb_version(void *handle)
static int stlink_usb_check_voltage(void *handle, float *target_voltage)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
uint32_t adc_results[2];
/* no error message, simply quit with error */
@@ -1511,7 +1511,7 @@ static int stlink_usb_check_voltage(void *handle, float *target_voltage)
static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -1535,7 +1535,7 @@ static int stlink_usb_set_swdclk(void *handle, uint16_t clk_divisor)
static int stlink_usb_set_jtagclk(void *handle, uint16_t clk_divisor)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -1561,7 +1561,7 @@ static int stlink_usb_set_jtagclk(void *handle, uint16_t clk_divisor)
static int stlink_usb_current_mode(void *handle, uint8_t *mode)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -1583,7 +1583,7 @@ static int stlink_usb_current_mode(void *handle, uint8_t *mode)
static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
{
int rx_size = 0;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -1631,7 +1631,7 @@ static int stlink_usb_mode_enter(void *handle, enum stlink_mode type)
static int stlink_usb_mode_leave(void *handle, enum stlink_mode type)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -1725,7 +1725,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init
int res;
uint8_t mode;
enum stlink_mode emode;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -1829,7 +1829,7 @@ static int stlink_usb_init_mode(void *handle, bool connect_under_reset, int init
/* request status from last swim request */
static int stlink_swim_status(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 4);
@@ -1849,7 +1849,7 @@ static int stlink_swim_status(void *handle)
__attribute__((unused))
static int stlink_swim_cap(void *handle, uint8_t *cap)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 8);
@@ -1866,7 +1866,7 @@ static int stlink_swim_cap(void *handle, uint8_t *cap)
/* debug dongle assert/deassert sreset line */
static int stlink_swim_assert_reset(void *handle, int reset)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
@@ -1887,7 +1887,7 @@ static int stlink_swim_assert_reset(void *handle, int reset)
*/
static int stlink_swim_enter(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
@@ -1902,7 +1902,7 @@ static int stlink_swim_enter(void *handle)
/* switch high/low speed swim */
static int stlink_swim_speed(void *handle, int speed)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
@@ -1924,7 +1924,7 @@ static int stlink_swim_speed(void *handle, int speed)
*/
static int stlink_swim_generate_rst(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
@@ -1943,7 +1943,7 @@ static int stlink_swim_generate_rst(void *handle)
*/
static int stlink_swim_resync(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
stlink_usb_init_buffer(handle, h->rx_ep, 0);
@@ -1957,7 +1957,7 @@ static int stlink_swim_resync(void *handle)
static int stlink_swim_writebytes(void *handle, uint32_t addr, uint32_t len, const uint8_t *data)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
unsigned int i;
unsigned int datalen = 0;
@@ -1993,7 +1993,7 @@ static int stlink_swim_writebytes(void *handle, uint32_t addr, uint32_t len, con
static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint8_t *data)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
if (len > STLINK_SWIM_DATA_SIZE)
@@ -2024,7 +2024,7 @@ static int stlink_swim_readbytes(void *handle, uint32_t addr, uint32_t len, uint
static int stlink_usb_idcode(void *handle, uint32_t *idcode)
{
int res, offset;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2061,7 +2061,7 @@ static int stlink_usb_idcode(void *handle, uint32_t *idcode)
static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *val)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int res;
assert(handle);
@@ -2083,7 +2083,7 @@ static int stlink_usb_v2_read_debug_reg(void *handle, uint32_t addr, uint32_t *v
static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2105,7 +2105,7 @@ static int stlink_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
/** */
static int stlink_usb_trace_read(void *handle, uint8_t *buf, size_t *size)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2156,7 +2156,7 @@ static enum target_state stlink_usb_v2_get_status(void *handle)
static enum target_state stlink_usb_state(void *handle)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2198,7 +2198,7 @@ static enum target_state stlink_usb_state(void *handle)
static int stlink_usb_assert_srst(void *handle, int srst)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2221,7 +2221,7 @@ static int stlink_usb_assert_srst(void *handle, int srst)
static void stlink_usb_trace_disable(void *handle)
{
int res = ERROR_OK;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2243,7 +2243,7 @@ static void stlink_usb_trace_disable(void *handle)
static int stlink_usb_trace_enable(void *handle)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2274,7 +2274,7 @@ static int stlink_usb_trace_enable(void *handle)
/** */
static int stlink_usb_reset(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int retval;
assert(handle);
@@ -2304,7 +2304,7 @@ static int stlink_usb_reset(void *handle)
static int stlink_usb_run(void *handle)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2326,7 +2326,7 @@ static int stlink_usb_run(void *handle)
static int stlink_usb_halt(void *handle)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2347,7 +2347,7 @@ static int stlink_usb_halt(void *handle)
/** */
static int stlink_usb_step(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2371,7 +2371,7 @@ static int stlink_usb_step(void *handle)
static int stlink_usb_read_regs(void *handle)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2396,7 +2396,7 @@ static int stlink_usb_read_regs(void *handle)
static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2436,7 +2436,7 @@ static int stlink_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
/** */
static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2465,7 +2465,7 @@ static int stlink_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
static int stlink_usb_get_rw_status(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2490,7 +2490,7 @@ static int stlink_usb_read_mem8(void *handle, uint8_t ap_num, uint32_t csw,
{
int res;
uint16_t read_len = len;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2534,7 +2534,7 @@ static int stlink_usb_write_mem8(void *handle, uint8_t ap_num, uint32_t csw,
uint32_t addr, uint16_t len, const uint8_t *buffer)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2572,7 +2572,7 @@ static int stlink_usb_read_mem16(void *handle, uint8_t ap_num, uint32_t csw,
uint32_t addr, uint16_t len, uint8_t *buffer)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2620,7 +2620,7 @@ static int stlink_usb_write_mem16(void *handle, uint8_t ap_num, uint32_t csw,
uint32_t addr, uint16_t len, const uint8_t *buffer)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2666,7 +2666,7 @@ static int stlink_usb_read_mem32(void *handle, uint8_t ap_num, uint32_t csw,
uint32_t addr, uint16_t len, uint8_t *buffer)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2711,7 +2711,7 @@ static int stlink_usb_write_mem32(void *handle, uint8_t ap_num, uint32_t csw,
uint32_t addr, uint16_t len, const uint8_t *buffer)
{
int res;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -2752,7 +2752,7 @@ static int stlink_usb_write_mem32(void *handle, uint8_t ap_num, uint32_t csw,
static int stlink_usb_read_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw,
uint32_t addr, uint16_t len, uint8_t *buffer)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle != NULL);
@@ -2794,7 +2794,7 @@ static int stlink_usb_read_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_
static int stlink_usb_write_mem32_noaddrinc(void *handle, uint8_t ap_num, uint32_t csw,
uint32_t addr, uint16_t len, const uint8_t *buffer)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle != NULL);
@@ -2845,7 +2845,7 @@ static int stlink_usb_read_ap_mem(void *handle, uint8_t ap_num, uint32_t csw,
int retval = ERROR_OK;
uint32_t bytes_remaining;
int retries = 0;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
/* calculate byte count */
count *= size;
@@ -2930,7 +2930,7 @@ static int stlink_usb_write_ap_mem(void *handle, uint8_t ap_num, uint32_t csw,
int retval = ERROR_OK;
uint32_t bytes_remaining;
int retries = 0;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
/* calculate byte count */
count *= size;
@@ -3080,7 +3080,7 @@ static int stlink_match_speed_map(const struct speed_map *map, unsigned int map_
static int stlink_speed_swd(void *handle, int khz, bool query)
{
int speed_index;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
/* old firmware cannot change it */
if (!(h->version.flags & STLINK_F_HAS_SWD_SET_FREQ))
@@ -3103,7 +3103,7 @@ static int stlink_speed_swd(void *handle, int khz, bool query)
static int stlink_speed_jtag(void *handle, int khz, bool query)
{
int speed_index;
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
/* old firmware cannot change it */
if (!(h->version.flags & STLINK_F_HAS_JTAG_SET_FREQ))
@@ -3135,7 +3135,7 @@ static void stlink_dump_speed_map(const struct speed_map *map, unsigned int map_
static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int i;
if (h->version.jtag_api != STLINK_JTAG_API_V3) {
@@ -3170,7 +3170,7 @@ static int stlink_get_com_freq(void *handle, bool is_jtag, struct speed_map *map
static int stlink_set_com_freq(void *handle, bool is_jtag, unsigned int frequency)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
if (h->version.jtag_api != STLINK_JTAG_API_V3) {
LOG_ERROR("Unknown command");
@@ -3191,7 +3191,7 @@ static int stlink_set_com_freq(void *handle, bool is_jtag, unsigned int frequenc
static int stlink_speed_v3(void *handle, bool is_jtag, int khz, bool query)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int speed_index;
struct speed_map map[STLINK_V3_MAX_FREQ_NB];
@@ -3211,7 +3211,7 @@ static int stlink_speed_v3(void *handle, bool is_jtag, int khz, bool query)
static int stlink_speed(void *handle, int khz, bool query)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
if (!handle)
return khz;
@@ -3241,7 +3241,7 @@ static int stlink_speed(void *handle, int khz, bool query)
/** */
static int stlink_usb_usb_close(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
if (!h)
return ERROR_OK;
@@ -3262,7 +3262,7 @@ static int stlink_usb_usb_close(void *handle)
/** */
static int stlink_tcp_close(void *handle)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
if (!h)
return ERROR_OK;
@@ -3295,7 +3295,7 @@ static int stlink_tcp_close(void *handle)
static int stlink_close(void *handle)
{
if (handle) {
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
stlink_usb_close(handle);
@@ -3385,9 +3385,9 @@ static char *stlink_usb_get_alternate_serial(struct libusb_device_handle *device
}
/** */
-static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param)
+static int stlink_usb_usb_open(void *handle, struct hl_interface_param *param)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int err, retry_count = 1;
h->cmdbuf = malloc(STLINK_SG_SIZE);
@@ -3496,9 +3496,9 @@ static int stlink_usb_usb_open(void *handle, struct hl_interface_param_s *param)
}
/** */
-static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param)
+static int stlink_tcp_open(void *handle, struct hl_interface_param *param)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int ret;
/* SWIM is not supported using stlink-server */
@@ -3711,27 +3711,27 @@ static int stlink_tcp_open(void *handle, struct hl_interface_param_s *param)
return stlink_usb_version(h);
}
-static struct stlink_backend_s stlink_usb_backend = {
+static struct stlink_backend stlink_usb_backend = {
.open = stlink_usb_usb_open,
.close = stlink_usb_usb_close,
.xfer_noerrcheck = stlink_usb_usb_xfer_noerrcheck,
.read_trace = stlink_usb_usb_read_trace,
};
-static struct stlink_backend_s stlink_tcp_backend = {
+static struct stlink_backend stlink_tcp_backend = {
.open = stlink_tcp_open,
.close = stlink_tcp_close,
.xfer_noerrcheck = stlink_tcp_xfer_noerrcheck,
.read_trace = stlink_tcp_read_trace,
};
-static int stlink_open(struct hl_interface_param_s *param, enum stlink_mode mode, void **fd)
+static int stlink_open(struct hl_interface_param *param, enum stlink_mode mode, void **fd)
{
- struct stlink_usb_handle_s *h;
+ struct stlink_usb_handle *h;
LOG_DEBUG("stlink_open");
- h = calloc(1, sizeof(struct stlink_usb_handle_s));
+ h = calloc(1, sizeof(struct stlink_usb_handle));
if (!h) {
LOG_DEBUG("malloc failed");
@@ -3829,7 +3829,7 @@ error_open:
return ERROR_FAIL;
}
-static int stlink_usb_hl_open(struct hl_interface_param_s *param, void **fd)
+static int stlink_usb_hl_open(struct hl_interface_param *param, void **fd)
{
return stlink_open(param, stlink_get_mode(param->transport), fd);
}
@@ -3839,7 +3839,7 @@ static int stlink_config_trace(void *handle, bool enabled,
unsigned int *trace_freq, unsigned int traceclkin_freq,
uint16_t *prescaler)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
if (!(h->version.flags & STLINK_F_HAS_TRACE)) {
LOG_ERROR("The attached ST-LINK version doesn't support trace");
@@ -3900,7 +3900,7 @@ static int stlink_config_trace(void *handle, bool enabled,
/** */
static int stlink_usb_init_access_port(void *handle, unsigned char ap_num)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -3919,7 +3919,7 @@ static int stlink_usb_init_access_port(void *handle, unsigned char ap_num)
/** */
static int stlink_usb_close_access_port(void *handle, unsigned char ap_num)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -3942,7 +3942,7 @@ static int stlink_usb_close_access_port(void *handle, unsigned char ap_num)
static int stlink_usb_rw_misc_out(void *handle, uint32_t items, const uint8_t *buffer)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
unsigned int buflen = ALIGN_UP(items, 4) + 4 * items;
LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items);
@@ -3963,7 +3963,7 @@ static int stlink_usb_rw_misc_out(void *handle, uint32_t items, const uint8_t *b
static int stlink_usb_rw_misc_in(void *handle, uint32_t items, uint8_t *buffer)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
unsigned int buflen = 2 * 4 * items;
LOG_DEBUG_IO("%s(%" PRIu32 ")", __func__, items);
@@ -3991,7 +3991,7 @@ static int stlink_usb_rw_misc_in(void *handle, uint32_t items, uint8_t *buffer)
static int stlink_read_dap_register(void *handle, unsigned short dap_port,
unsigned short addr, uint32_t *val)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int retval;
assert(handle);
@@ -4015,7 +4015,7 @@ static int stlink_read_dap_register(void *handle, unsigned short dap_port,
static int stlink_write_dap_register(void *handle, unsigned short dap_port,
unsigned short addr, uint32_t val)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
assert(handle);
@@ -4033,7 +4033,7 @@ static int stlink_write_dap_register(void *handle, unsigned short dap_port,
}
/** */
-struct hl_layout_api_s stlink_usb_layout_api = {
+struct hl_layout_api stlink_usb_layout_api = {
/** */
.open = stlink_usb_hl_open,
/** */
@@ -4078,8 +4078,8 @@ struct hl_layout_api_s stlink_usb_layout_api = {
* DAP direct interface
*/
-static struct stlink_usb_handle_s *stlink_dap_handle;
-static struct hl_interface_param_s stlink_dap_param;
+static struct stlink_usb_handle *stlink_dap_handle;
+static struct hl_interface_param stlink_dap_param;
static DECLARE_BITMAP(opened_ap, DP_APSEL_MAX + 1);
static uint32_t last_csw_default[DP_APSEL_MAX + 1];
static int stlink_dap_error = ERROR_OK;
@@ -4107,7 +4107,7 @@ static int stlink_dap_get_error(void)
static int stlink_usb_open_ap(void *handle, unsigned short apsel)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
int retval;
/* nothing to do on old versions */
@@ -4523,7 +4523,7 @@ static int stlink_usb_buf_rw_segment(void *handle, const struct dap_queue *q, un
static int stlink_usb_count_misc_rw_queue(void *handle, const struct dap_queue *q, unsigned int len,
unsigned int *pkt_items)
{
- struct stlink_usb_handle_s *h = handle;
+ struct stlink_usb_handle *h = handle;
unsigned int i, items = 0;
uint32_t ap_num = DP_APSEL_INVALID;
unsigned int misc_max_items = (h->version.stlink == 2) ? STLINK_V2_RW_MISC_SIZE : STLINK_V3_RW_MISC_SIZE;
@@ -5039,7 +5039,7 @@ COMMAND_HANDLER(stlink_dap_backend_command)
COMMAND_HANDLER(stlink_dap_cmd_command)
{
unsigned int rx_n, tx_n;
- struct stlink_usb_handle_s *h = stlink_dap_handle;
+ struct stlink_usb_handle *h = stlink_dap_handle;
if (CMD_ARGC < 2)
return ERROR_COMMAND_SYNTAX_ERROR;
diff --git a/src/jtag/drivers/ti_icdi_usb.c b/src/jtag/drivers/ti_icdi_usb.c
index 4260e2d..0e01171 100644
--- a/src/jtag/drivers/ti_icdi_usb.c
+++ b/src/jtag/drivers/ti_icdi_usb.c
@@ -33,7 +33,7 @@
#define PACKET_START "$"
#define PACKET_END "#"
-struct icdi_usb_handle_s {
+struct icdi_usb_handle {
struct libusb_device_handle *usb_dev;
char *read_buffer;
@@ -108,7 +108,7 @@ static int remote_unescape_input(const char *buffer, int len, char *out_buf, int
static int icdi_send_packet(void *handle, int len)
{
unsigned char cksum = 0;
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
int result, retry = 0;
int transferred = 0;
@@ -220,7 +220,7 @@ static int icdi_send_packet(void *handle, int len)
static int icdi_send_cmd(void *handle, const char *cmd)
{
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
int cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "%s", cmd);
return icdi_send_packet(handle, cmd_len);
@@ -228,7 +228,7 @@ static int icdi_send_cmd(void *handle, const char *cmd)
static int icdi_send_remote_cmd(void *handle, const char *data)
{
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
size_t cmd_len = sprintf(h->write_buffer, PACKET_START "qRcmd,");
cmd_len += hexify(h->write_buffer + cmd_len, (const uint8_t *)data,
@@ -239,7 +239,7 @@ static int icdi_send_remote_cmd(void *handle, const char *data)
static int icdi_get_cmd_result(void *handle)
{
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
int offset = 0;
char ch;
@@ -284,7 +284,7 @@ static int icdi_usb_write_debug_reg(void *handle, uint32_t addr, uint32_t val)
static enum target_state icdi_usb_state(void *handle)
{
int result;
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
uint32_t dhcsr;
uint8_t buf[4];
@@ -303,7 +303,7 @@ static enum target_state icdi_usb_state(void *handle)
static int icdi_usb_version(void *handle)
{
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
char version[20];
@@ -335,7 +335,7 @@ static int icdi_usb_query(void *handle)
{
int result;
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
result = icdi_send_cmd(handle, "qSupported");
if (result != ERROR_OK)
@@ -468,7 +468,7 @@ static int icdi_usb_read_regs(void *handle)
static int icdi_usb_read_reg(void *handle, unsigned int regsel, uint32_t *val)
{
int result;
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
char cmd[10];
snprintf(cmd, sizeof(cmd), "p%x", regsel);
@@ -521,7 +521,7 @@ static int icdi_usb_write_reg(void *handle, unsigned int regsel, uint32_t val)
static int icdi_usb_read_mem_int(void *handle, uint32_t addr, uint32_t len, uint8_t *buffer)
{
int result;
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
char cmd[20];
snprintf(cmd, sizeof(cmd), "x%" PRIx32 ",%" PRIx32, addr, len);
@@ -549,7 +549,7 @@ static int icdi_usb_read_mem_int(void *handle, uint32_t addr, uint32_t len, uint
static int icdi_usb_write_mem_int(void *handle, uint32_t addr, uint32_t len, const uint8_t *buffer)
{
int result;
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
size_t cmd_len = snprintf(h->write_buffer, h->max_packet, PACKET_START "X%" PRIx32 ",%" PRIx32 ":", addr, len);
@@ -581,7 +581,7 @@ static int icdi_usb_read_mem(void *handle, uint32_t addr, uint32_t size,
uint32_t count, uint8_t *buffer)
{
int retval = ERROR_OK;
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
uint32_t bytes_remaining;
/* calculate byte count */
@@ -609,7 +609,7 @@ static int icdi_usb_write_mem(void *handle, uint32_t addr, uint32_t size,
uint32_t count, const uint8_t *buffer)
{
int retval = ERROR_OK;
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
uint32_t bytes_remaining;
/* calculate byte count */
@@ -640,7 +640,7 @@ static int icdi_usb_override_target(const char *targetname)
static int icdi_usb_close(void *handle)
{
- struct icdi_usb_handle_s *h = handle;
+ struct icdi_usb_handle *h = handle;
if (!h)
return ERROR_OK;
@@ -654,15 +654,15 @@ static int icdi_usb_close(void *handle)
return ERROR_OK;
}
-static int icdi_usb_open(struct hl_interface_param_s *param, void **fd)
+static int icdi_usb_open(struct hl_interface_param *param, void **fd)
{
/* TODO: Convert remaining libusb_ calls to jtag_libusb_ */
int retval;
- struct icdi_usb_handle_s *h;
+ struct icdi_usb_handle *h;
LOG_DEBUG("icdi_usb_open");
- h = calloc(1, sizeof(struct icdi_usb_handle_s));
+ h = calloc(1, sizeof(struct icdi_usb_handle));
if (!h) {
LOG_ERROR("unable to allocate memory");
@@ -743,7 +743,7 @@ error_open:
return ERROR_FAIL;
}
-struct hl_layout_api_s icdi_usb_layout_api = {
+struct hl_layout_api icdi_usb_layout_api = {
.open = icdi_usb_open,
.close = icdi_usb_close,
.idcode = icdi_usb_idcode,
diff --git a/src/jtag/drivers/ulink.c b/src/jtag/drivers/ulink.c
index 4f23c6c..0fe8989 100644
--- a/src/jtag/drivers/ulink.c
+++ b/src/jtag/drivers/ulink.c
@@ -1473,7 +1473,7 @@ static int ulink_queue_scan(struct ulink *device, struct jtag_command *cmd)
/* Allocate TDO buffer if required */
if ((type == SCAN_IN) || (type == SCAN_IO)) {
- tdo_buffer_start = calloc(sizeof(uint8_t), scan_size_bytes);
+ tdo_buffer_start = calloc(scan_size_bytes, sizeof(uint8_t));
if (!tdo_buffer_start)
return ERROR_FAIL;
diff --git a/src/jtag/hla/hla_interface.c b/src/jtag/hla/hla_interface.c
index 9c8d0fa..6ac6801 100644
--- a/src/jtag/hla/hla_interface.c
+++ b/src/jtag/hla/hla_interface.c
@@ -23,7 +23,7 @@
#include <target/target.h>
-static struct hl_interface_s hl_if = {
+static struct hl_interface hl_if = {
.param = {
.device_desc = NULL,
.vid = { 0 },
diff --git a/src/jtag/hla/hla_interface.h b/src/jtag/hla/hla_interface.h
index fa49658..c95638b 100644
--- a/src/jtag/hla/hla_interface.h
+++ b/src/jtag/hla/hla_interface.h
@@ -20,7 +20,7 @@ extern const char *hl_transports[];
#define HLA_MAX_USB_IDS 16
-struct hl_interface_param_s {
+struct hl_interface_param {
/** */
const char *device_desc;
/** List of recognised VIDs */
@@ -39,9 +39,9 @@ struct hl_interface_param_s {
uint16_t stlink_tcp_port;
};
-struct hl_interface_s {
+struct hl_interface {
/** */
- struct hl_interface_param_s param;
+ struct hl_interface_param param;
/** */
const struct hl_layout *layout;
/** */
diff --git a/src/jtag/hla/hla_layout.c b/src/jtag/hla/hla_layout.c
index 51671d6..04c963f 100644
--- a/src/jtag/hla/hla_layout.c
+++ b/src/jtag/hla/hla_layout.c
@@ -21,7 +21,7 @@
#include <jtag/hla/hla_transport.h>
#include <jtag/hla/hla_interface.h>
-static int hl_layout_open(struct hl_interface_s *adapter)
+static int hl_layout_open(struct hl_interface *adapter)
{
int res;
@@ -39,7 +39,7 @@ static int hl_layout_open(struct hl_interface_s *adapter)
return ERROR_OK;
}
-static int hl_layout_close(struct hl_interface_s *adapter)
+static int hl_layout_close(struct hl_interface *adapter)
{
return ERROR_OK;
}
@@ -78,7 +78,7 @@ const struct hl_layout *hl_layout_get_list(void)
return hl_layouts;
}
-int hl_layout_init(struct hl_interface_s *adapter)
+int hl_layout_init(struct hl_interface *adapter)
{
LOG_DEBUG("hl_layout_init");
diff --git a/src/jtag/hla/hla_layout.h b/src/jtag/hla/hla_layout.h
index e13da65..71a7563 100644
--- a/src/jtag/hla/hla_layout.h
+++ b/src/jtag/hla/hla_layout.h
@@ -15,18 +15,18 @@
#include <target/arm_tpiu_swo.h>
/** */
-struct hl_interface_s;
-struct hl_interface_param_s;
+struct hl_interface;
+struct hl_interface_param;
/** */
-extern struct hl_layout_api_s stlink_usb_layout_api;
-extern struct hl_layout_api_s icdi_usb_layout_api;
-extern struct hl_layout_api_s nulink_usb_layout_api;
+extern struct hl_layout_api stlink_usb_layout_api;
+extern struct hl_layout_api icdi_usb_layout_api;
+extern struct hl_layout_api nulink_usb_layout_api;
/** */
-struct hl_layout_api_s {
+struct hl_layout_api {
/** */
- int (*open)(struct hl_interface_param_s *param, void **handle);
+ int (*open)(struct hl_interface_param *param, void **handle);
/** */
int (*close)(void *handle);
/** */
@@ -121,16 +121,16 @@ struct hl_layout {
/** */
char *name;
/** */
- int (*open)(struct hl_interface_s *adapter);
+ int (*open)(struct hl_interface *adapter);
/** */
- int (*close)(struct hl_interface_s *adapter);
+ int (*close)(struct hl_interface *adapter);
/** */
- struct hl_layout_api_s *api;
+ struct hl_layout_api *api;
};
/** */
const struct hl_layout *hl_layout_get_list(void);
/** */
-int hl_layout_init(struct hl_interface_s *adapter);
+int hl_layout_init(struct hl_interface *adapter);
#endif /* OPENOCD_JTAG_HLA_HLA_LAYOUT_H */
diff --git a/src/jtag/tcl.c b/src/jtag/tcl.c
index 7995529..1a4c4b7 100644
--- a/src/jtag/tcl.c
+++ b/src/jtag/tcl.c
@@ -760,8 +760,9 @@ static const struct command_registration jtag_subcommand_handlers[] = {
.mode = COMMAND_EXEC,
.handler = handle_jtag_configure,
.help = "Return any Tcl handler for the specified "
- "TAP event.",
- .usage = "tap_name '-event' event_name",
+ "TAP event or the value of the IDCODE found in hardware.",
+ .usage = "tap_name '-event' event_name | "
+ "tap_name '-idcode'",
},
{
.name = "names",
diff --git a/src/pld/intel.c b/src/pld/intel.c
index a39e16c..a4bdabe 100644
--- a/src/pld/intel.c
+++ b/src/pld/intel.c
@@ -37,142 +37,11 @@ struct intel_pld_device {
enum intel_family_e family;
};
-struct intel_device_parameters_elem {
- uint32_t id;
- unsigned int boundary_scan_length;
- int checkpos;
- enum intel_family_e family;
-};
-
-static const struct intel_device_parameters_elem intel_device_parameters[] = {
- {0x020f10dd, 603, 226, INTEL_CYCLONEIII}, /* EP3C5 EP3C10 */
- {0x020f20dd, 1080, 409, INTEL_CYCLONEIII}, /* EP3C16 */
- {0x020f30dd, 732, 286, INTEL_CYCLONEIII}, /* EP3C25 */
- {0x020f40dd, 1632, 604, INTEL_CYCLONEIII}, /* EP3C40 */
- {0x020f50dd, 1164, 442, INTEL_CYCLONEIII}, /* EP3C55 */
- {0x020f60dd, 1314, 502, INTEL_CYCLONEIII}, /* EP3C80 */
- {0x020f70dd, 1620, 613, INTEL_CYCLONEIII}, /* EP3C120*/
- {0x027010dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS70 */
- {0x027000dd, 1314, 226, INTEL_CYCLONEIII}, /* EP3CLS100 */
- {0x027030dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS150 */
- {0x027020dd, 1314, 409, INTEL_CYCLONEIII}, /* EP3CLS200 */
-
- {0x020f10dd, 603, 226, INTEL_CYCLONEIV}, /* EP4CE6 EP4CE10 */
- {0x020f20dd, 1080, 409, INTEL_CYCLONEIV}, /* EP4CE15 */
- {0x020f30dd, 732, 286, INTEL_CYCLONEIV}, /* EP4CE22 */
- {0x020f40dd, 1632, 604, INTEL_CYCLONEIV}, /* EP4CE30 EP4CE40 */
- {0x020f50dd, 1164, 442, INTEL_CYCLONEIV}, /* EP4CE55 */
- {0x020f60dd, 1314, 502, INTEL_CYCLONEIV}, /* EP4CE75 */
- {0x020f70dd, 1620, 613, INTEL_CYCLONEIV}, /* EP4CE115 */
- {0x028010dd, 260, 229, INTEL_CYCLONEIV}, /* EP4CGX15 */
- {0x028120dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX22 */
- {0x028020dd, 494, 463, INTEL_CYCLONEIV}, /* EP4CGX30 */
- {0x028230dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX30 */
- {0x028130dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX50 */
- {0x028030dd, 1006, 943, INTEL_CYCLONEIV}, /* EP4CGX75 */
- {0x028140dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX110 */
- {0x028040dd, 1495, 1438, INTEL_CYCLONEIV}, /* EP4CGX150 */
-
- {0x02b150dd, 864, 163, INTEL_CYCLONEV}, /* 5CEBA2F23 5CEBA2F17 5CEFA2M13 5CEFA2F23 5CEBA2U15 5CEFA2U19 5CEBA2U19 */
- {0x02d020dd, 1485, 19, INTEL_CYCLONEV}, /* 5CSXFC6D6F31 5CSTFD6D5F31 5CSEBA6U23 5CSEMA6U23 5CSEBA6U19 5CSEBA6U23
- 5CSEBA6U19 5CSEMA6F31 5CSXFC6C6U23 */
- {0x02b040dd, 1728, -1, INTEL_CYCLONEV}, /* 5CGXFC9EF35 5CGXBC9AU19 5CGXBC9CF23 5CGTFD9CF23 5CGXFC9AU19 5CGXFC9CF23
- 5CGXFC9EF31 5CGXFC9DF27 5CGXBC9DF27 5CGXBC9EF31 5CGTFD9EF31 5CGTFD9EF35
- 5CGTFD9AU19 5CGXBC9EF35 5CGTFD9DF27 */
- {0x02b050dd, 864, 163, INTEL_CYCLONEV}, /* 5CEFA4U19 5CEFA4F23 5CEFA4M13 5CEBA4F17 5CEBA4U15 5CEBA4U19 5CEBA4F23 */
- {0x02b030dd, 1488, 19, INTEL_CYCLONEV}, /* 5CGXBC7CU19 5CGTFD7CU19 5CGTFD7DF27 5CGXFC7BM15 5CGXFC7DF27 5CGXFC7DF31
- 5CGTFD7CF23 5CGXBC7CF23 5CGXBC7DF31 5CGTFD7BM15 5CGXFC7CU19 5CGTFD7DF31
- 5CGXBC7BM15 5CGXFC7CF23 5CGXBC7DF27 */
- {0x02d120dd, 1485, -1, INTEL_CYCLONEV}, /* 5CSEBA5U23 5CSEBA5U23 5CSTFD5D5F31 5CSEBA5U19 5CSXFC5D6F31 5CSEMA5U23
- 5CSEMA5F31 5CSXFC5C6U23 5CSEBA5U19 */
- {0x02b220dd, 1104, 19, INTEL_CYCLONEV}, /* 5CEBA5U19 5CEFA5U19 5CEFA5M13 5CEBA5F23 5CEFA5F23 */
- {0x02b020dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXBC5CU19 5CGXFC5F6M11 5CGXFC5CM13 5CGTFD5CF23 5CGXBC5CF23 5CGTFD5CF27
- 5CGTFD5F5M11 5CGXFC5CF27 5CGXFC5CU19 5CGTFD5CM13 5CGXFC5CF23 5CGXBC5CF27
- 5CGTFD5CU19 */
- {0x02d010dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA4U23 5CSXFC4C6U23 5CSEMA4U23 5CSEBA4U23 5CSEBA4U19 5CSEBA4U19
- 5CSXFC2C6U23 */
- {0x02b120dd, 1104, 19, INTEL_CYCLONEV}, /* 5CGXFC4CM13 5CGXFC4CU19 5CGXFC4F6M11 5CGXBC4CU19 5CGXFC4CF27 5CGXBC4CF23
- 5CGXBC4CF27 5CGXFC4CF23 */
- {0x02b140dd, 1728, -1, INTEL_CYCLONEV}, /* 5CEFA9F31 5CEBA9F31 5CEFA9F27 5CEBA9U19 5CEBA9F27 5CEFA9U19 5CEBA9F23
- 5CEFA9F23 */
- {0x02b010dd, 720, 19, INTEL_CYCLONEV}, /* 5CGXFC3U15 5CGXBC3U15 5CGXFC3F23 5CGXFC3U19 5CGXBC3U19 5CGXBC3F23 */
- {0x02b130dd, 1488, 19, INTEL_CYCLONEV}, /* 5CEFA7F31 5CEBA7F27 5CEBA7M15 5CEFA7U19 5CEBA7F23 5CEFA7F23 5CEFA7F27
- 5CEFA7M15 5CEBA7U19 5CEBA7F31 */
- {0x02d110dd, 1197, -1, INTEL_CYCLONEV}, /* 5CSEBA2U23 5CSEMA2U23 5CSEBA2U23 5CSEBA2U19 5CSEBA2U19 */
-
- {0x020f10dd, 603, 226, INTEL_CYCLONE10}, /* 10CL006E144 10CL006U256 10CL010M164 10CL010U256 10CL010E144 */
- {0x020f20dd, 1080, 409, INTEL_CYCLONE10}, /* 10CL016U256 10CL016E144 10CL016U484 10CL016F484 10CL016M164 */
- {0x020f30dd, 732, 286, INTEL_CYCLONE10}, /* 10CL025U256 10CL025E144 */
- {0x020f40dd, 1632, 604, INTEL_CYCLONE10}, /* 10CL040F484 10CL040U484 */
- {0x020f50dd, 1164, 442, INTEL_CYCLONE10}, /* 10CL055F484 10CL055U484 */
- {0x020f60dd, 1314, 502, INTEL_CYCLONE10}, /* 10CL080F484 10CL080F780 10CL080U484 */
- {0x020f70dd, 1620, 613, INTEL_CYCLONE10}, /* 10CL120F484 10CL120F780 */
-
- {0x02e120dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX085U484 10CX085F672 */
- {0x02e320dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX105F780 10CX105U484 10CX105F672 */
- {0x02e720dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX150F672 10CX150F780 10CX150U484 */
- {0x02ef20dd, 1339, -1, INTEL_CYCLONE10}, /* 10CX220F672 10CX220F780 10CX220U484 */
-
- {0x025120dd, 1227, 1174, INTEL_ARRIAII}, /* EP2AGX45 */
- {0x025020dd, 1227, -1, INTEL_ARRIAII}, /* EP2AGX65 */
- {0x025130dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX95 */
- {0x025030dd, 1467, -1, INTEL_ARRIAII}, /* EP2AGX125 */
- {0x025140dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX190 */
- {0x025040dd, 1971, -1, INTEL_ARRIAII}, /* EP2AGX260 */
- {0x024810dd, 2274, -1, INTEL_ARRIAII}, /* EP2AGZ225 */
- {0x0240a0dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ300 */
- {0x024820dd, 2682, -1, INTEL_ARRIAII}, /* EP2AGZ350 */
-};
-
-static int intel_fill_device_parameters(struct intel_pld_device *intel_info)
-{
- for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) {
- if (intel_device_parameters[i].id == intel_info->tap->idcode &&
- intel_info->family == intel_device_parameters[i].family) {
- if (intel_info->boundary_scan_length == 0)
- intel_info->boundary_scan_length = intel_device_parameters[i].boundary_scan_length;
-
- if (intel_info->checkpos == -1)
- intel_info->checkpos = intel_device_parameters[i].checkpos;
-
- return ERROR_OK;
- }
- }
-
- return ERROR_FAIL;
-}
-
-static int intel_check_for_unique_id(struct intel_pld_device *intel_info)
-{
- int found = 0;
- for (size_t i = 0; i < ARRAY_SIZE(intel_device_parameters); ++i) {
- if (intel_device_parameters[i].id == intel_info->tap->idcode) {
- ++found;
- intel_info->family = intel_device_parameters[i].family;
- }
- }
-
- return (found == 1) ? ERROR_OK : ERROR_FAIL;
-}
-
static int intel_check_config(struct intel_pld_device *intel_info)
{
- if (!intel_info->tap->has_idcode) {
- LOG_ERROR("no IDCODE");
- return ERROR_FAIL;
- }
-
- if (intel_info->family == INTEL_UNKNOWN) {
- if (intel_check_for_unique_id(intel_info) != ERROR_OK) {
- LOG_ERROR("id is ambiguous, please specify family");
+ if (intel_info->boundary_scan_length == 0) {
+ LOG_ERROR("unknown boundary scan length. Please specify with 'intel set_bscan'.");
return ERROR_FAIL;
- }
- }
-
- if (intel_info->boundary_scan_length == 0 || intel_info->checkpos == -1) {
- int ret = intel_fill_device_parameters(intel_info);
- if (ret != ERROR_OK)
- return ret;
}
if (intel_info->checkpos >= 0 && (unsigned int)intel_info->checkpos >= intel_info->boundary_scan_length) {
@@ -248,9 +117,6 @@ static int intel_load(struct pld_device *pld_device, const char *filename)
if (retval != ERROR_OK)
return retval;
- if (retval != ERROR_OK)
- return retval;
-
retval = intel_set_instr(tap, 0x002);
if (retval != ERROR_OK) {
free(bit_file.data);
@@ -308,6 +174,8 @@ static int intel_load(struct pld_device *pld_device, const char *filename)
LOG_ERROR("Check failed");
return ERROR_FAIL;
}
+ } else {
+ LOG_INFO("unable to check. Please specify with position 'intel set_check_pos'.");
}
retval = intel_set_instr(tap, 0x003);
@@ -420,7 +288,7 @@ COMMAND_HANDLER(intel_set_check_pos_command_handler)
PLD_CREATE_COMMAND_HANDLER(intel_pld_create_command)
{
- if (CMD_ARGC != 4 && CMD_ARGC != 6)
+ if (CMD_ARGC != 6)
return ERROR_COMMAND_SYNTAX_ERROR;
if (strcmp(CMD_ARGV[2], "-chain-position") != 0)
@@ -433,24 +301,23 @@ PLD_CREATE_COMMAND_HANDLER(intel_pld_create_command)
}
enum intel_family_e family = INTEL_UNKNOWN;
- if (CMD_ARGC == 6) {
- if (strcmp(CMD_ARGV[4], "-family") != 0)
- return ERROR_COMMAND_SYNTAX_ERROR;
-
- if (strcmp(CMD_ARGV[5], "cycloneiii") == 0) {
- family = INTEL_CYCLONEIII;
- } else if (strcmp(CMD_ARGV[5], "cycloneiv") == 0) {
- family = INTEL_CYCLONEIV;
- } else if (strcmp(CMD_ARGV[5], "cyclonev") == 0) {
- family = INTEL_CYCLONEV;
- } else if (strcmp(CMD_ARGV[5], "cyclone10") == 0) {
- family = INTEL_CYCLONE10;
- } else if (strcmp(CMD_ARGV[5], "arriaii") == 0) {
- family = INTEL_ARRIAII;
- } else {
- command_print(CMD, "unknown family");
- return ERROR_FAIL;
- }
+
+ if (strcmp(CMD_ARGV[4], "-family") != 0)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (strcmp(CMD_ARGV[5], "cycloneiii") == 0) {
+ family = INTEL_CYCLONEIII;
+ } else if (strcmp(CMD_ARGV[5], "cycloneiv") == 0) {
+ family = INTEL_CYCLONEIV;
+ } else if (strcmp(CMD_ARGV[5], "cyclonev") == 0) {
+ family = INTEL_CYCLONEV;
+ } else if (strcmp(CMD_ARGV[5], "cyclone10") == 0) {
+ family = INTEL_CYCLONE10;
+ } else if (strcmp(CMD_ARGV[5], "arriaii") == 0) {
+ family = INTEL_ARRIAII;
+ } else {
+ command_print(CMD, "unknown family");
+ return ERROR_FAIL;
}
struct intel_pld_device *intel_info = malloc(sizeof(struct intel_pld_device));
diff --git a/src/server/gdb_server.c b/src/server/gdb_server.c
index dbbf027..f4ce5df 100644
--- a/src/server/gdb_server.c
+++ b/src/server/gdb_server.c
@@ -1113,15 +1113,15 @@ static int gdb_new_connection(struct connection *connection)
target_state_name(target));
if (!target_was_examined(target)) {
- LOG_ERROR("Target %s not examined yet, refuse gdb connection %d!",
- target_name(target), gdb_connection->unique_index);
+ LOG_TARGET_ERROR(target, "Target not examined yet, refuse gdb connection %d!",
+ gdb_connection->unique_index);
return ERROR_TARGET_NOT_EXAMINED;
}
gdb_actual_connections++;
if (target->state != TARGET_HALTED)
- LOG_WARNING("GDB connection %d on target %s not halted",
- gdb_actual_connections, target_name(target));
+ LOG_TARGET_WARNING(target, "GDB connection %d not halted",
+ gdb_actual_connections);
/* DANGER! If we fail subsequently, we must remove this handler,
* otherwise we occasionally see crashes as the timer can invoke the
@@ -1148,9 +1148,8 @@ static int gdb_connection_closed(struct connection *connection)
log_remove_callback(gdb_log_callback, connection);
gdb_actual_connections--;
- LOG_DEBUG("{%d} GDB Close, Target: %s, state: %s, gdb_actual_connections=%d",
+ LOG_TARGET_DEBUG(target, "{%d} GDB Close, state: %s, gdb_actual_connections=%d",
gdb_connection->unique_index,
- target_name(target),
target_state_name(target),
gdb_actual_connections);
@@ -1279,6 +1278,8 @@ static int gdb_get_reg_value_as_str(struct target *target, char *tstr, struct re
tstr[len] = '\0';
return ERROR_OK;
}
+ memset(tstr, '0', len);
+ tstr[len] = '\0';
return ERROR_FAIL;
}
@@ -1323,7 +1324,9 @@ static int gdb_get_registers_packet(struct connection *connection,
for (i = 0; i < reg_list_size; i++) {
if (!reg_list[i] || reg_list[i]->exist == false || reg_list[i]->hidden)
continue;
- if (gdb_get_reg_value_as_str(target, reg_packet_p, reg_list[i]) != ERROR_OK) {
+ retval = gdb_get_reg_value_as_str(target, reg_packet_p, reg_list[i]);
+ if (retval != ERROR_OK && gdb_report_register_access_error) {
+ LOG_DEBUG("Couldn't get register %s.", reg_list[i]->name);
free(reg_packet);
free(reg_list);
return gdb_error(connection, retval);
@@ -1446,7 +1449,9 @@ static int gdb_get_register_packet(struct connection *connection,
reg_packet = calloc(DIV_ROUND_UP(reg_list[reg_num]->size, 8) * 2 + 1, 1); /* plus one for string termination null */
- if (gdb_get_reg_value_as_str(target, reg_packet, reg_list[reg_num]) != ERROR_OK) {
+ retval = gdb_get_reg_value_as_str(target, reg_packet, reg_list[reg_num]);
+ if (retval != ERROR_OK && gdb_report_register_access_error) {
+ LOG_DEBUG("Couldn't get register %s.", reg_list[reg_num]->name);
free(reg_packet);
free(reg_list);
return gdb_error(connection, retval);
@@ -2401,7 +2406,7 @@ static int smp_reg_list_noread(struct target *target,
}
}
if (!found) {
- LOG_DEBUG("[%s] %s not found in combined list", target_name(target), a->name);
+ LOG_TARGET_DEBUG(target, "%s not found in combined list", a->name);
if (local_list_size >= combined_allocated) {
combined_allocated *= 2;
local_list = realloc(local_list, combined_allocated * sizeof(struct reg *));
@@ -2449,9 +2454,8 @@ static int smp_reg_list_noread(struct target *target,
}
}
if (!found) {
- LOG_WARNING("Register %s does not exist in %s, which is part of an SMP group where "
- "this register does exist.",
- a->name, target_name(head->target));
+ LOG_TARGET_WARNING(head->target, "Register %s does not exist, which is part of an SMP group where "
+ "this register does exist.", a->name);
}
}
free(reg_list);
@@ -3083,17 +3087,17 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
target = available_target;
}
- LOG_DEBUG("target %s continue", target_name(target));
+ LOG_TARGET_DEBUG(target, "target continue");
gdb_connection->output_flag = GDB_OUTPUT_ALL;
retval = target_resume(target, 1, 0, 0, 0);
if (retval == ERROR_TARGET_NOT_HALTED)
- LOG_INFO("target %s was not halted when resume was requested", target_name(target));
+ LOG_TARGET_INFO(target, "target was not halted when resume was requested");
/* poll target in an attempt to make its internal state consistent */
if (retval != ERROR_OK) {
retval = target_poll(target);
if (retval != ERROR_OK)
- LOG_DEBUG("error polling target %s after failed resume", target_name(target));
+ LOG_TARGET_DEBUG(target, "error polling target after failed resume");
}
/*
@@ -3186,7 +3190,7 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
}
}
- LOG_DEBUG("target %s single-step thread %"PRIx64, target_name(ct), thread_id);
+ LOG_TARGET_DEBUG(ct, "single-step thread %" PRIx64, thread_id);
gdb_connection->output_flag = GDB_OUTPUT_ALL;
target_call_event_callbacks(ct, TARGET_EVENT_GDB_START);
@@ -3229,14 +3233,14 @@ static bool gdb_handle_vcont_packet(struct connection *connection, const char *p
} else {
retval = target_step(ct, current_pc, 0, 0);
if (retval == ERROR_TARGET_NOT_HALTED)
- LOG_INFO("target %s was not halted when step was requested", target_name(ct));
+ LOG_TARGET_INFO(ct, "target was not halted when step was requested");
}
/* if step was successful send a reply back to gdb */
if (retval == ERROR_OK) {
retval = target_poll(ct);
if (retval != ERROR_OK)
- LOG_DEBUG("error polling target %s after successful step", target_name(ct));
+ LOG_TARGET_DEBUG(ct, "error polling target after successful step");
/* send back signal information */
gdb_signal_reply(ct, connection);
/* stop forwarding log packets! */
@@ -3929,7 +3933,7 @@ static int gdb_target_start(struct target *target, const char *port)
if (!gdb_service)
return -ENOMEM;
- LOG_INFO("starting gdb server for %s on %s", target_name(target), port);
+ LOG_TARGET_INFO(target, "starting gdb server on %s", port);
gdb_service->target = target;
gdb_service->core[0] = -1;
@@ -3957,20 +3961,20 @@ static int gdb_target_add_one(struct target *target)
/* skip targets that cannot handle a gdb connections (e.g. mem_ap) */
if (!target_supports_gdb_connection(target)) {
- LOG_DEBUG("skip gdb server for target %s", target_name(target));
+ LOG_TARGET_DEBUG(target, "skip gdb server");
return ERROR_OK;
}
if (target->gdb_port_override) {
if (strcmp(target->gdb_port_override, "disabled") == 0) {
- LOG_INFO("gdb port disabled");
+ LOG_TARGET_INFO(target, "gdb port disabled");
return ERROR_OK;
}
return gdb_target_start(target, target->gdb_port_override);
}
- if (strcmp(gdb_port, "disabled") == 0) {
- LOG_INFO("gdb port disabled");
+ if (strcmp(gdb_port_next, "disabled") == 0) {
+ LOG_TARGET_INFO(target, "gdb port disabled");
return ERROR_OK;
}
@@ -3998,6 +4002,8 @@ static int gdb_target_add_one(struct target *target)
gdb_port_next = strdup("0");
}
}
+ } else if (strcmp(gdb_port_next, "pipe") == 0) {
+ gdb_port_next = "disabled";
}
}
return retval;
diff --git a/src/target/arc_jtag.c b/src/target/arc_jtag.c
index ddb4f62..a186709 100644
--- a/src/target/arc_jtag.c
+++ b/src/target/arc_jtag.c
@@ -298,7 +298,7 @@ static int arc_jtag_read_registers(struct arc_jtag *jtag_info, uint32_t type,
ARC_JTAG_READ_FROM_CORE_REG : ARC_JTAG_READ_FROM_AUX_REG);
arc_jtag_enque_set_transaction(jtag_info, transaction, TAP_DRPAUSE);
- uint8_t *data_buf = calloc(sizeof(uint8_t), count * 4);
+ uint8_t *data_buf = calloc(count * 4, sizeof(uint8_t));
arc_jtag_enque_register_rw(jtag_info, addr, data_buf, NULL, count);
@@ -498,7 +498,7 @@ int arc_jtag_read_memory(struct arc_jtag *jtag_info, uint32_t addr,
if (!count)
return ERROR_OK;
- data_buf = calloc(sizeof(uint8_t), count * 4);
+ data_buf = calloc(count * 4, sizeof(uint8_t));
arc_jtag_enque_reset_transaction(jtag_info);
/* We are reading from memory. */
diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c
index b5a4882..55a9778 100644
--- a/src/target/arm_tpiu_swo.c
+++ b/src/target/arm_tpiu_swo.c
@@ -965,8 +965,7 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const
obj->out_filename = strdup("external");
if (!obj->out_filename) {
LOG_ERROR("Out of memory");
- free(obj);
- return JIM_ERR;
+ goto err_exit;
}
Jim_Obj *n;
@@ -974,8 +973,7 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const
obj->name = strdup(Jim_GetString(n, NULL));
if (!obj->name) {
LOG_ERROR("Out of memory");
- free(obj);
- return JIM_ERR;
+ goto err_exit;
}
/* Do the rest as "configure" options */
diff --git a/src/target/armv7m_trace.c b/src/target/armv7m_trace.c
index 45117d2..556568d 100644
--- a/src/target/armv7m_trace.c
+++ b/src/target/armv7m_trace.c
@@ -92,11 +92,14 @@ COMMAND_HANDLER(handle_itm_port_command)
else
armv7m->trace_config.itm_ter[reg_idx] &= ~(1 << port);
- if (CMD_CTX->mode == COMMAND_EXEC)
- return armv7m_trace_itm_config(target);
+ /*
+ * In config mode ITM is not accessible yet.
+ * Keep the value and it will be programmed at target init.
+ */
+ if (CMD_CTX->mode == COMMAND_CONFIG)
+ return ERROR_OK;
- armv7m->trace_config.itm_deferred_config = true;
- return ERROR_OK;
+ return armv7m_trace_itm_config(target);
}
COMMAND_HANDLER(handle_itm_ports_command)
@@ -112,11 +115,14 @@ COMMAND_HANDLER(handle_itm_ports_command)
memset(armv7m->trace_config.itm_ter, enable ? 0xff : 0,
sizeof(armv7m->trace_config.itm_ter));
- if (CMD_CTX->mode == COMMAND_EXEC)
- return armv7m_trace_itm_config(target);
+ /*
+ * In config mode ITM is not accessible yet.
+ * Keep the value and it will be programmed at target init.
+ */
+ if (CMD_CTX->mode == COMMAND_CONFIG)
+ return ERROR_OK;
- armv7m->trace_config.itm_deferred_config = true;
- return ERROR_OK;
+ return armv7m_trace_itm_config(target);
}
static const struct command_registration itm_command_handlers[] = {
diff --git a/src/target/armv7m_trace.h b/src/target/armv7m_trace.h
index 5abb0b9..02eca93 100644
--- a/src/target/armv7m_trace.h
+++ b/src/target/armv7m_trace.h
@@ -35,8 +35,6 @@ struct armv7m_trace_config {
bool itm_async_timestamps;
/** Enable synchronisation packet transmission (for sync port only) */
bool itm_synchro_packets;
- /** Config ITM after target examine */
- bool itm_deferred_config;
};
extern const struct command_registration armv7m_trace_command_handlers[];
diff --git a/src/target/armv8.c b/src/target/armv8.c
index bf582ff..b54ef13 100644
--- a/src/target/armv8.c
+++ b/src/target/armv8.c
@@ -278,10 +278,14 @@ static int armv8_get_pauth_mask(struct armv8_common *armv8, uint64_t *mask)
static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval)
{
struct arm_dpm *dpm = &armv8->dpm;
+ unsigned int curel = armv8_curel_from_core_mode(dpm->arm->core_mode);
int retval;
uint32_t value;
uint64_t value_64;
+ if (!regval)
+ return ERROR_FAIL;
+
switch (regnum) {
case 0 ... 30:
retval = dpm->instr_read_data_dcc_64(dpm,
@@ -311,46 +315,85 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv
value_64 = value;
break;
case ARMV8_ELR_EL1:
+ if (curel < SYSTEM_CUREL_EL1) {
+ LOG_DEBUG("ELR_EL1 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
retval = dpm->instr_read_data_r0_64(dpm,
ARMV8_MRS(SYSTEM_ELR_EL1, 0), &value_64);
break;
case ARMV8_ELR_EL2:
+ if (curel < SYSTEM_CUREL_EL2) {
+ LOG_DEBUG("ELR_EL2 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
retval = dpm->instr_read_data_r0_64(dpm,
ARMV8_MRS(SYSTEM_ELR_EL2, 0), &value_64);
break;
case ARMV8_ELR_EL3:
+ if (curel < SYSTEM_CUREL_EL3) {
+ LOG_DEBUG("ELR_EL3 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
retval = dpm->instr_read_data_r0_64(dpm,
ARMV8_MRS(SYSTEM_ELR_EL3, 0), &value_64);
break;
case ARMV8_ESR_EL1:
- retval = dpm->instr_read_data_r0(dpm,
- ARMV8_MRS(SYSTEM_ESR_EL1, 0), &value);
- value_64 = value;
+ if (curel < SYSTEM_CUREL_EL1) {
+ LOG_DEBUG("ESR_EL1 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_ESR_EL1, 0), &value_64);
break;
case ARMV8_ESR_EL2:
- retval = dpm->instr_read_data_r0(dpm,
- ARMV8_MRS(SYSTEM_ESR_EL2, 0), &value);
- value_64 = value;
+ if (curel < SYSTEM_CUREL_EL2) {
+ LOG_DEBUG("ESR_EL2 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_ESR_EL2, 0), &value_64);
break;
case ARMV8_ESR_EL3:
- retval = dpm->instr_read_data_r0(dpm,
- ARMV8_MRS(SYSTEM_ESR_EL3, 0), &value);
- value_64 = value;
+ if (curel < SYSTEM_CUREL_EL3) {
+ LOG_DEBUG("ESR_EL3 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_ESR_EL3, 0), &value_64);
break;
case ARMV8_SPSR_EL1:
- retval = dpm->instr_read_data_r0(dpm,
- ARMV8_MRS(SYSTEM_SPSR_EL1, 0), &value);
- value_64 = value;
+ if (curel < SYSTEM_CUREL_EL1) {
+ LOG_DEBUG("SPSR_EL1 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_SPSR_EL1, 0), &value_64);
break;
case ARMV8_SPSR_EL2:
- retval = dpm->instr_read_data_r0(dpm,
- ARMV8_MRS(SYSTEM_SPSR_EL2, 0), &value);
- value_64 = value;
+ if (curel < SYSTEM_CUREL_EL2) {
+ LOG_DEBUG("SPSR_EL2 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_SPSR_EL2, 0), &value_64);
break;
case ARMV8_SPSR_EL3:
- retval = dpm->instr_read_data_r0(dpm,
- ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value);
- value_64 = value;
+ if (curel < SYSTEM_CUREL_EL3) {
+ LOG_DEBUG("SPSR_EL3 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_read_data_r0_64(dpm,
+ ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value_64);
break;
case ARMV8_PAUTH_CMASK:
case ARMV8_PAUTH_DMASK:
@@ -361,10 +404,8 @@ static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regv
break;
}
- if (retval == ERROR_OK && regval)
+ if (retval == ERROR_OK)
*regval = value_64;
- else
- retval = ERROR_FAIL;
return retval;
}
@@ -395,6 +436,7 @@ static int armv8_read_reg_simdfp_aarch64(struct armv8_common *armv8, int regnum,
static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t value_64)
{
struct arm_dpm *dpm = &armv8->dpm;
+ unsigned int curel = armv8_curel_from_core_mode(dpm->arm->core_mode);
int retval;
uint32_t value;
@@ -434,46 +476,85 @@ static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t valu
break;
/* registers clobbered by taking exception in debug state */
case ARMV8_ELR_EL1:
+ if (curel < SYSTEM_CUREL_EL1) {
+ LOG_DEBUG("ELR_EL1 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
retval = dpm->instr_write_data_r0_64(dpm,
ARMV8_MSR_GP(SYSTEM_ELR_EL1, 0), value_64);
break;
case ARMV8_ELR_EL2:
+ if (curel < SYSTEM_CUREL_EL2) {
+ LOG_DEBUG("ELR_EL2 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
retval = dpm->instr_write_data_r0_64(dpm,
ARMV8_MSR_GP(SYSTEM_ELR_EL2, 0), value_64);
break;
case ARMV8_ELR_EL3:
+ if (curel < SYSTEM_CUREL_EL3) {
+ LOG_DEBUG("ELR_EL3 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
retval = dpm->instr_write_data_r0_64(dpm,
ARMV8_MSR_GP(SYSTEM_ELR_EL3, 0), value_64);
break;
case ARMV8_ESR_EL1:
- value = value_64;
- retval = dpm->instr_write_data_r0(dpm,
- ARMV8_MSR_GP(SYSTEM_ESR_EL1, 0), value);
+ if (curel < SYSTEM_CUREL_EL1) {
+ LOG_DEBUG("ESR_EL1 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_write_data_r0_64(dpm,
+ ARMV8_MSR_GP(SYSTEM_ESR_EL1, 0), value_64);
break;
case ARMV8_ESR_EL2:
- value = value_64;
- retval = dpm->instr_write_data_r0(dpm,
- ARMV8_MSR_GP(SYSTEM_ESR_EL2, 0), value);
+ if (curel < SYSTEM_CUREL_EL2) {
+ LOG_DEBUG("ESR_EL2 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_write_data_r0_64(dpm,
+ ARMV8_MSR_GP(SYSTEM_ESR_EL2, 0), value_64);
break;
case ARMV8_ESR_EL3:
- value = value_64;
- retval = dpm->instr_write_data_r0(dpm,
- ARMV8_MSR_GP(SYSTEM_ESR_EL3, 0), value);
+ if (curel < SYSTEM_CUREL_EL3) {
+ LOG_DEBUG("ESR_EL3 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_write_data_r0_64(dpm,
+ ARMV8_MSR_GP(SYSTEM_ESR_EL3, 0), value_64);
break;
case ARMV8_SPSR_EL1:
- value = value_64;
- retval = dpm->instr_write_data_r0(dpm,
- ARMV8_MSR_GP(SYSTEM_SPSR_EL1, 0), value);
+ if (curel < SYSTEM_CUREL_EL1) {
+ LOG_DEBUG("SPSR_EL1 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_write_data_r0_64(dpm,
+ ARMV8_MSR_GP(SYSTEM_SPSR_EL1, 0), value_64);
break;
case ARMV8_SPSR_EL2:
- value = value_64;
- retval = dpm->instr_write_data_r0(dpm,
- ARMV8_MSR_GP(SYSTEM_SPSR_EL2, 0), value);
+ if (curel < SYSTEM_CUREL_EL2) {
+ LOG_DEBUG("SPSR_EL2 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_write_data_r0_64(dpm,
+ ARMV8_MSR_GP(SYSTEM_SPSR_EL2, 0), value_64);
break;
case ARMV8_SPSR_EL3:
- value = value_64;
- retval = dpm->instr_write_data_r0(dpm,
- ARMV8_MSR_GP(SYSTEM_SPSR_EL3, 0), value);
+ if (curel < SYSTEM_CUREL_EL3) {
+ LOG_DEBUG("SPSR_EL3 not accessible in EL%u", curel);
+ retval = ERROR_FAIL;
+ break;
+ }
+ retval = dpm->instr_write_data_r0_64(dpm,
+ ARMV8_MSR_GP(SYSTEM_SPSR_EL3, 0), value_64);
break;
default:
retval = ERROR_FAIL;
@@ -512,6 +593,9 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re
uint32_t value = 0;
int retval;
+ if (!regval)
+ return ERROR_FAIL;
+
switch (regnum) {
case ARMV8_R0 ... ARMV8_R14:
/* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */
@@ -559,7 +643,7 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re
ARMV4_5_MRC(15, 4, 0, 5, 2, 0),
&value);
break;
- case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */
+ case ARMV8_ESR_EL3: /* no equivalent in aarch32 */
retval = ERROR_FAIL;
break;
case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */
@@ -587,7 +671,7 @@ static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *re
break;
}
- if (retval == ERROR_OK && regval)
+ if (retval == ERROR_OK)
*regval = value;
return retval;
@@ -695,7 +779,7 @@ static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t va
ARMV4_5_MCR(15, 4, 0, 5, 2, 0),
value);
break;
- case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */
+ case ARMV8_ESR_EL3: /* no equivalent in aarch32 */
retval = ERROR_FAIL;
break;
case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */
@@ -1504,23 +1588,23 @@ static const struct {
{ ARMV8_ELR_EL1, "ELR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked",
NULL},
- { ARMV8_ESR_EL1, "ESR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
+ { ARMV8_ESR_EL1, "ESR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked",
NULL},
- { ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
+ { ARMV8_SPSR_EL1, "SPSR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked",
NULL},
{ ARMV8_ELR_EL2, "ELR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked",
NULL},
- { ARMV8_ESR_EL2, "ESR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
+ { ARMV8_ESR_EL2, "ESR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked",
NULL},
- { ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
+ { ARMV8_SPSR_EL2, "SPSR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked",
NULL},
{ ARMV8_ELR_EL3, "ELR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked",
NULL},
- { ARMV8_ESR_EL3, "ESR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
+ { ARMV8_ESR_EL3, "ESR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked",
NULL},
- { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked",
+ { ARMV8_SPSR_EL3, "SPSR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_UINT64, "banked", "net.sourceforge.openocd.banked",
NULL},
{ ARMV8_PAUTH_DMASK, "pauth_dmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL},
{ ARMV8_PAUTH_CMASK, "pauth_cmask", 64, ARM_MODE_ANY, REG_TYPE_UINT64, NULL, "org.gnu.gdb.aarch64.pauth", NULL},
diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c
index 8bb24f2..271bd91 100644
--- a/src/target/armv8_dpm.c
+++ b/src/target/armv8_dpm.c
@@ -677,7 +677,7 @@ static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
}
if (retval != ERROR_OK)
- LOG_ERROR("Failed to read %s register", r->name);
+ LOG_DEBUG("Failed to read %s register", r->name);
return retval;
}
@@ -719,7 +719,7 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
}
if (retval != ERROR_OK)
- LOG_ERROR("Failed to write %s register", r->name);
+ LOG_DEBUG("Failed to write %s register", r->name);
return retval;
}
diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c
index c225b1a..34c7cd4 100644
--- a/src/target/cortex_m.c
+++ b/src/target/cortex_m.c
@@ -931,8 +931,12 @@ static int cortex_m_poll_one(struct target *target)
if (target->state != TARGET_RESET) {
target->state = TARGET_RESET;
LOG_TARGET_INFO(target, "external reset detected");
+ /* In case of an unexpected S_RESET_ST set TARGET_RESET state
+ * and keep it until the next poll to allow its detection */
+ return ERROR_OK;
}
- return ERROR_OK;
+ /* S_RESET_ST was expected (in a reset command). Continue processing
+ * to quickly get out of TARGET_RESET state */
}
if (target->state == TARGET_RESET) {
@@ -2655,8 +2659,8 @@ int cortex_m_examine(struct target *target)
if (retval != ERROR_OK)
return retval;
- if (armv7m->trace_config.itm_deferred_config)
- armv7m_trace_itm_config(target);
+ /* Configure ITM */
+ armv7m_trace_itm_config(target);
/* NOTE: FPB and DWT are both optional. */
diff --git a/src/target/hla_target.c b/src/target/hla_target.c
index c1bda99..d6f2afb 100644
--- a/src/target/hla_target.c
+++ b/src/target/hla_target.c
@@ -36,7 +36,7 @@
#define ARMV7M_SCS_DCRSR DCB_DCRSR
#define ARMV7M_SCS_DCRDR DCB_DCRDR
-static inline struct hl_interface_s *target_to_adapter(struct target *target)
+static inline struct hl_interface *target_to_adapter(struct target *target)
{
return target->tap->priv;
}
@@ -44,14 +44,14 @@ static inline struct hl_interface_s *target_to_adapter(struct target *target)
static int adapter_load_core_reg_u32(struct target *target,
uint32_t regsel, uint32_t *value)
{
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
return adapter->layout->api->read_reg(adapter->handle, regsel, value);
}
static int adapter_store_core_reg_u32(struct target *target,
uint32_t regsel, uint32_t value)
{
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
return adapter->layout->api->write_reg(adapter->handle, regsel, value);
}
@@ -65,7 +65,7 @@ static int adapter_examine_debug_reason(struct target *target)
return ERROR_OK;
}
-static int hl_dcc_read(struct hl_interface_s *hl_if, uint8_t *value, uint8_t *ctrl)
+static int hl_dcc_read(struct hl_interface *hl_if, uint8_t *value, uint8_t *ctrl)
{
uint16_t dcrdr;
int retval = hl_if->layout->api->read_mem(hl_if->handle,
@@ -90,7 +90,7 @@ static int hl_dcc_read(struct hl_interface_s *hl_if, uint8_t *value, uint8_t *ct
static int hl_target_request_data(struct target *target,
uint32_t size, uint8_t *buffer)
{
- struct hl_interface_s *hl_if = target_to_adapter(target);
+ struct hl_interface *hl_if = target_to_adapter(target);
uint8_t data;
uint8_t ctrl;
uint32_t i;
@@ -113,7 +113,7 @@ static int hl_handle_target_request(void *priv)
if (!target_was_examined(target))
return ERROR_OK;
- struct hl_interface_s *hl_if = target_to_adapter(target);
+ struct hl_interface *hl_if = target_to_adapter(target);
if (!target->dbg_msg_enabled)
return ERROR_OK;
@@ -227,7 +227,7 @@ static int adapter_load_context(struct target *target)
static int adapter_debug_entry(struct target *target)
{
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
struct arm *arm = &armv7m->arm;
struct reg *r;
@@ -286,7 +286,7 @@ static int adapter_debug_entry(struct target *target)
static int adapter_poll(struct target *target)
{
enum target_state state;
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
enum target_state prev_target_state = target->state;
@@ -329,7 +329,7 @@ static int adapter_poll(struct target *target)
static int hl_assert_reset(struct target *target)
{
int res = ERROR_OK;
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
bool use_srst_fallback = true;
@@ -412,7 +412,7 @@ static int hl_deassert_reset(struct target *target)
static int adapter_halt(struct target *target)
{
int res;
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
LOG_DEBUG("%s", __func__);
@@ -439,7 +439,7 @@ static int adapter_resume(struct target *target, int current,
int debug_execution)
{
int res;
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
uint32_t resume_pc;
struct breakpoint *breakpoint = NULL;
@@ -529,7 +529,7 @@ static int adapter_step(struct target *target, int current,
target_addr_t address, int handle_breakpoints)
{
int res;
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
struct armv7m_common *armv7m = target_to_armv7m(target);
struct breakpoint *breakpoint = NULL;
struct reg *pc = armv7m->arm.pc;
@@ -593,7 +593,7 @@ static int adapter_read_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count,
uint8_t *buffer)
{
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
if (!count || !buffer)
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -608,7 +608,7 @@ static int adapter_write_memory(struct target *target, target_addr_t address,
uint32_t size, uint32_t count,
const uint8_t *buffer)
{
- struct hl_interface_s *adapter = target_to_adapter(target);
+ struct hl_interface *adapter = target_to_adapter(target);
if (!count || !buffer)
return ERROR_COMMAND_SYNTAX_ERROR;
diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am
index 7f25eca..aa82f58 100644
--- a/src/target/riscv/Makefile.am
+++ b/src/target/riscv/Makefile.am
@@ -11,11 +11,18 @@ noinst_LTLIBRARIES += %D%/libriscv.la
%D%/opcodes.h \
%D%/program.h \
%D%/riscv.h \
+ %D%/riscv-011.h \
+ %D%/riscv-011_reg.h \
+ %D%/riscv-013.h \
+ %D%/riscv-013_reg.h \
%D%/batch.c \
%D%/program.c \
%D%/riscv-011.c \
+ %D%/riscv-011_reg.c \
%D%/riscv-013.c \
+ %D%/riscv-013_reg.c \
%D%/riscv.c \
+ %D%/riscv_reg.c \
%D%/riscv_semihosting.c \
%D%/debug_defines.c \
%D%/debug_reg_printer.c
diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c
index 4115a37..bb1070a 100644
--- a/src/target/riscv/batch.c
+++ b/src/target/riscv/batch.c
@@ -29,7 +29,7 @@ struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans)
out->allocated_scans = scans;
out->last_scan = RISCV_SCAN_TYPE_INVALID;
out->was_run = false;
- out->used_delay = 0;
+ out->last_scan_delay = 0;
out->data_out = NULL;
out->data_in = NULL;
@@ -109,7 +109,7 @@ static bool riscv_batch_was_scan_busy(const struct riscv_batch *batch,
}
static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_idx,
- struct riscv_scan_delays delays)
+ const struct riscv_scan_delays *delays)
{
if (!batch->was_run)
return;
@@ -121,9 +121,9 @@ static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_
? batch->delay_classes[start_idx - 1]
: RISCV_DELAY_BASE;
const unsigned int new_delay = riscv_scan_get_delay(delays, delay_class);
- if (new_delay <= batch->used_delay)
+ if (new_delay <= batch->last_scan_delay)
return;
- const unsigned int idle_change = new_delay - batch->used_delay;
+ const unsigned int idle_change = new_delay - batch->last_scan_delay;
LOG_TARGET_DEBUG(batch->target, "Adding %u idle cycles before the batch.",
idle_change);
assert(idle_change <= INT_MAX);
@@ -131,19 +131,19 @@ static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_
}
static int get_delay(const struct riscv_batch *batch, size_t scan_idx,
- struct riscv_scan_delays delays)
+ const struct riscv_scan_delays *delays)
{
assert(batch);
assert(scan_idx < batch->used_scans);
const enum riscv_scan_delay_class delay_class =
batch->delay_classes[scan_idx];
- const unsigned int delay = riscv_scan_get_delay(delays, delay_class);
+ const unsigned int delay = riscv_scan_get_delay(delays, delay_class);
assert(delay <= INT_MAX);
return delay;
}
int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
- struct riscv_scan_delays delays, bool resets_delays,
+ const struct riscv_scan_delays *delays, bool resets_delays,
size_t reset_delays_after)
{
assert(batch->used_scans);
@@ -195,7 +195,7 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
}
batch->was_run = true;
- batch->used_delay = get_delay(batch, batch->used_scans - 1, delays);
+ batch->last_scan_delay = get_delay(batch, batch->used_scans - 1, delays);
return ERROR_OK;
}
diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h
index 03947aa..327406c 100644
--- a/src/target/riscv/batch.h
+++ b/src/target/riscv/batch.h
@@ -25,40 +25,66 @@ enum riscv_scan_delay_class {
/* Delay for System Bus read operation: */
RISCV_DELAY_SYSBUS_READ,
/* Delay for System Bus write operation: */
- RISCV_DELAY_SYSBUS_WRITE,
+ RISCV_DELAY_SYSBUS_WRITE
};
+static inline const char *
+riscv_scan_delay_class_name(enum riscv_scan_delay_class delay_class)
+{
+ switch (delay_class) {
+ case RISCV_DELAY_BASE:
+ return "DM access";
+ case RISCV_DELAY_ABSTRACT_COMMAND:
+ return "Abstract Command";
+ case RISCV_DELAY_SYSBUS_READ:
+ return "System Bus read";
+ case RISCV_DELAY_SYSBUS_WRITE:
+ return "System Bus write";
+ }
+ assert(0);
+ return NULL;
+}
+
+/* The scan delay values are passed to "jtag_add_runtest()", which accepts an
+ * "int". Therefore, the passed value should be no greater than "INT_MAX".
+ *
+ * Since the resulting delay value can be a sum of two individual delays,
+ * individual delays are limited to "INT_MAX / 2" to prevent overflow of the
+ * final sum.
+ */
+#define RISCV_SCAN_DELAY_MAX (INT_MAX / 2)
+
struct riscv_scan_delays {
- /* The purpose of these delays is to be passed to "jtag_add_runtest()",
- * which accepts an "int".
- * Therefore, they should be no greater then "INT_MAX".
- */
unsigned int base_delay;
unsigned int ac_delay;
unsigned int sb_read_delay;
unsigned int sb_write_delay;
};
-static inline unsigned int riscv_scan_get_delay(struct riscv_scan_delays delays,
+static inline unsigned int
+riscv_scan_get_delay(const struct riscv_scan_delays *delays,
enum riscv_scan_delay_class delay_class)
{
switch (delay_class) {
case RISCV_DELAY_BASE:
- return delays.base_delay;
+ return delays->base_delay;
case RISCV_DELAY_ABSTRACT_COMMAND:
- return delays.ac_delay;
+ return delays->base_delay + delays->ac_delay;
case RISCV_DELAY_SYSBUS_READ:
- return delays.sb_read_delay;
+ return delays->base_delay + delays->sb_read_delay;
case RISCV_DELAY_SYSBUS_WRITE:
- return delays.sb_write_delay;
+ return delays->base_delay + delays->sb_write_delay;
}
+ assert(0);
return 0;
}
static inline void riscv_scan_set_delay(struct riscv_scan_delays *delays,
enum riscv_scan_delay_class delay_class, unsigned int delay)
{
- assert(delay <= INT_MAX);
+ assert(delay <= RISCV_SCAN_DELAY_MAX);
+ LOG_DEBUG("%s delay is set to %u.",
+ riscv_scan_delay_class_name(delay_class), delay);
switch (delay_class) {
case RISCV_DELAY_BASE:
delays->base_delay = delay;
@@ -73,6 +99,25 @@ static inline void riscv_scan_set_delay(struct riscv_scan_delays *delays,
delays->sb_write_delay = delay;
return;
}
+ assert(0);
+}
+
+static inline int riscv_scan_increase_delay(struct riscv_scan_delays *delays,
+ enum riscv_scan_delay_class delay_class)
+{
+ const unsigned int delay = riscv_scan_get_delay(delays, delay_class);
+ const unsigned int delay_step = delay / 10 + 1;
+ if (delay > RISCV_SCAN_DELAY_MAX - delay_step) {
+ /* It's not clear if this issue actually occurs in real
+ * use-cases, so stick with a simple solution until the
+ * first bug report.
+ */
+ LOG_ERROR("Delay for %s (%d) is not increased anymore (maximum was reached).",
+ riscv_scan_delay_class_name(delay_class), delay);
+ return ERROR_FAIL;
+ }
+ riscv_scan_set_delay(delays, delay_class, delay + delay_step);
+ return ERROR_OK;
}
/* A batch of multiple JTAG scans, which are grouped together to avoid the
@@ -113,7 +158,7 @@ struct riscv_batch {
/* Number of RTI cycles used by the last scan on the last run.
* Only valid when `was_run` is set.
*/
- unsigned int used_delay;
+ unsigned int last_scan_delay;
};
/* Allocates (or frees) a new scan set. "scans" is the maximum number of JTAG
@@ -138,7 +183,7 @@ bool riscv_batch_full(struct riscv_batch *batch);
* OpenOCD that are based on batches.
*/
int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx,
- struct riscv_scan_delays delays, bool resets_delays,
+ const struct riscv_scan_delays *delays, bool resets_delays,
size_t reset_delays_after);
/* Get the number of scans successfully executed form this batch. */
diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h
index 92c8cc5..d606f73 100644
--- a/src/target/riscv/gdb_regs.h
+++ b/src/target/riscv/gdb_regs.h
@@ -3,6 +3,8 @@
#ifndef TARGET__RISCV__GDB_REGS_H
#define TARGET__RISCV__GDB_REGS_H
+#include "encoding.h"
+
/* 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 {
@@ -123,6 +125,4 @@ enum gdb_regno {
GDB_REGNO_COUNT
};
-const char *gdb_regno_name(const struct target *target, enum gdb_regno regno);
-
#endif
diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h
index 361191a..93dbdbf 100644
--- a/src/target/riscv/program.h
+++ b/src/target/riscv/program.h
@@ -41,7 +41,7 @@ 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
+ * calls to things like riscv013_reg_save which itself could require a
* program to execute. That's OK, just make sure this eventually terminates.
* */
int riscv_program_exec(struct riscv_program *p, struct target *t);
diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c
index df59a49..0715de5 100644
--- a/src/target/riscv/riscv-011.c
+++ b/src/target/riscv/riscv-011.c
@@ -13,6 +13,8 @@
#include "config.h"
#endif
+#include "riscv-011.h"
+
#include "target/target.h"
#include "target/algorithm.h"
#include "target/target_type.h"
@@ -22,6 +24,8 @@
#include "target/breakpoints.h"
#include "helper/time_support.h"
#include "riscv.h"
+#include "riscv_reg.h"
+#include "riscv-011_reg.h"
#include "asm.h"
#include "gdb_regs.h"
#include "field_helpers.h"
@@ -210,8 +214,6 @@ typedef struct {
static int poll_target(struct target *target, bool announce);
static int riscv011_poll(struct target *target);
-static int get_register(struct target *target, riscv_reg_t *value,
- enum gdb_regno regid);
/*** Utility functions. ***/
@@ -739,7 +741,7 @@ static int wait_for_debugint_clear(struct target *target, bool ignore_first)
if (!bits.interrupt)
return ERROR_OK;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out waiting for debug int to clear."
"Increase timeout with riscv set_command_timeout_sec.");
return ERROR_FAIL;
@@ -1023,7 +1025,7 @@ static int wait_for_state(struct target *target, enum target_state state)
return result;
if (target->state == state)
return ERROR_OK;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out waiting for state %d. "
"Increase timeout with riscv set_command_timeout_sec.", state);
return ERROR_FAIL;
@@ -1045,7 +1047,7 @@ static int read_remote_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 %s", exception,
- gdb_regno_name(target, GDB_REGNO_CSR0 + csr));
+ riscv_reg_gdb_regno_name(target, GDB_REGNO_CSR0 + csr));
*value = ~0;
return ERROR_FAIL;
}
@@ -1111,7 +1113,7 @@ static int execute_resume(struct target *target, bool step)
LOG_DEBUG("step=%d", step);
- if (riscv_flush_registers(target) != ERROR_OK)
+ if (riscv_reg_flush_all(target) != ERROR_OK)
return ERROR_FAIL;
maybe_write_tselect(target);
@@ -1184,7 +1186,7 @@ static int full_step(struct target *target, bool announce)
return result;
if (target->state != TARGET_DEBUG_RUNNING)
break;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out waiting for step to complete."
"Increase timeout with riscv set_command_timeout_sec");
return ERROR_FAIL;
@@ -1225,7 +1227,7 @@ static int update_mstatus_actual(struct target *target)
/* Force reading the register. In that process mstatus_actual will be
* updated. */
riscv_reg_t mstatus;
- return get_register(target, &mstatus, GDB_REGNO_MSTATUS);
+ return riscv011_get_register(target, &mstatus, GDB_REGNO_MSTATUS);
}
/*** OpenOCD target functions. ***/
@@ -1247,7 +1249,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 %s", exception, gdb_regno_name(target, regnum));
+ LOG_WARNING("Got exception 0x%x when reading %s", exception, riscv_reg_gdb_regno_name(target, regnum));
*value = ~0;
return ERROR_FAIL;
}
@@ -1322,14 +1324,14 @@ 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 %s", exception,
- gdb_regno_name(target, number));
+ riscv_reg_gdb_regno_name(target, number));
return ERROR_FAIL;
}
return ERROR_OK;
}
-static int get_register(struct target *target, riscv_reg_t *value,
+int riscv011_get_register(struct target *target, riscv_reg_t *value,
enum gdb_regno regid)
{
riscv011_info_t *info = get_info(target);
@@ -1377,7 +1379,7 @@ static int get_register(struct target *target, riscv_reg_t *value,
/* This function is intended to handle accesses to registers through register
* cache. */
-static int set_register(struct target *target, enum gdb_regno regid,
+int riscv011_set_register(struct target *target, enum gdb_regno regid,
riscv_reg_t value)
{
assert(target->reg_cache);
@@ -1595,7 +1597,7 @@ static int examine(struct target *target)
}
/* Update register list to match discovered XLEN/supported extensions. */
- riscv_init_registers(target);
+ riscv011_reg_init_all(target);
info->never_halted = true;
@@ -2342,10 +2344,10 @@ static int wait_for_authbusy(struct target *target)
uint32_t dminfo = dbus_read(target, DMINFO);
if (!get_field(dminfo, DMINFO_AUTHBUSY))
break;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_ERROR("Timed out after %ds waiting for authbusy to go low (dminfo=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec,
+ riscv_get_command_timeout_sec(),
dminfo);
return ERROR_FAIL;
}
@@ -2391,8 +2393,6 @@ static int init_target(struct command_context *cmd_ctx,
{
LOG_DEBUG("init");
RISCV_INFO(generic_info);
- generic_info->get_register = get_register;
- generic_info->set_register = set_register;
generic_info->read_memory = read_memory;
generic_info->authdata_read = &riscv011_authdata_read;
generic_info->authdata_write = &riscv011_authdata_write;
@@ -2404,7 +2404,7 @@ static int init_target(struct command_context *cmd_ctx,
/* Assume 32-bit until we discover the real value in examine(). */
generic_info->xlen = 32;
- riscv_init_registers(target);
+ riscv011_reg_init_all(target);
return ERROR_OK;
}
diff --git a/src/target/riscv/riscv-011.h b/src/target/riscv/riscv-011.h
new file mode 100644
index 0000000..8d1d06a
--- /dev/null
+++ b/src/target/riscv/riscv-011.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef OPENOCD_TARGET_RISCV_RISCV_011_H
+#define OPENOCD_TARGET_RISCV_RISCV_011_H
+
+#include "riscv.h"
+#include "gdb_regs.h"
+#include "target/target.h"
+
+int riscv011_get_register(struct target *target, riscv_reg_t *value,
+ enum gdb_regno regid);
+int riscv011_set_register(struct target *target, enum gdb_regno regid,
+ riscv_reg_t value);
+
+#endif /*OPENOCD_TARGET_RISCV_RISCV_011_H*/
diff --git a/src/target/riscv/riscv-011_reg.c b/src/target/riscv/riscv-011_reg.c
new file mode 100644
index 0000000..7f29064
--- /dev/null
+++ b/src/target/riscv/riscv-011_reg.c
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "riscv-011_reg.h"
+
+#include "riscv_reg_impl.h"
+#include "riscv-011.h"
+
+static int riscv011_reg_get(struct reg *reg)
+{
+ struct target * const target = riscv_reg_impl_get_target(reg);
+ riscv_reg_t value;
+ const int result = riscv011_get_register(target, &value, reg->number);
+ if (result != ERROR_OK)
+ return result;
+ buf_set_u64(reg->value, 0, reg->size, value);
+ return ERROR_OK;
+}
+
+static int riscv011_reg_set(struct reg *reg, uint8_t *buf)
+{
+ const riscv_reg_t value = buf_get_u64(buf, 0, reg->size);
+ struct target * const target = riscv_reg_impl_get_target(reg);
+ return riscv011_set_register(target, reg->number, value);
+}
+
+static const struct reg_arch_type *riscv011_gdb_regno_reg_type(uint32_t regno)
+{
+ static const struct reg_arch_type riscv011_reg_type = {
+ .get = riscv011_reg_get,
+ .set = riscv011_reg_set
+ };
+ return &riscv011_reg_type;
+}
+
+static int riscv011_init_reg(struct target *target, uint32_t regno)
+{
+ return riscv_reg_impl_init_one(target, regno, riscv011_gdb_regno_reg_type(regno));
+}
+
+int riscv011_reg_init_all(struct target *target)
+{
+ if (riscv_reg_impl_init_cache(target) != ERROR_OK)
+ return ERROR_FAIL;
+
+ init_shared_reg_info(target);
+
+ for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno)
+ if (riscv011_init_reg(target, regno) != ERROR_OK)
+ return ERROR_FAIL;
+
+ if (riscv_reg_impl_expose_csrs(target) != ERROR_OK)
+ return ERROR_FAIL;
+
+ riscv_reg_impl_hide_csrs(target);
+
+ return ERROR_OK;
+}
diff --git a/src/target/riscv/riscv-011_reg.h b/src/target/riscv/riscv-011_reg.h
new file mode 100644
index 0000000..ee00c9b
--- /dev/null
+++ b/src/target/riscv/riscv-011_reg.h
@@ -0,0 +1,19 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_011_H
+#define OPENOCD_TARGET_RISCV_RISCV_REG_011_H
+
+#include "target/target.h"
+
+/**
+ * This file describes additional register cache interface available to the
+ * RISC-V Debug Specification v0.11 targets.
+ */
+
+/**
+ * Initialize register cache. After this function all registers can be
+ * safely accessed via functions described here and in `riscv_reg.h`.
+ */
+int riscv011_reg_init_all(struct target *target);
+
+#endif /*OPENOCD_TARGET_RISCV_RISCV_REG_011_H*/
diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c
index 3b043da..7898cae 100644
--- a/src/target/riscv/riscv-013.c
+++ b/src/target/riscv/riscv-013.c
@@ -23,6 +23,9 @@
#include "helper/time_support.h"
#include "helper/list.h"
#include "riscv.h"
+#include "riscv-013.h"
+#include "riscv_reg.h"
+#include "riscv-013_reg.h"
#include "debug_defines.h"
#include "rtos/rtos.h"
#include "program.h"
@@ -37,10 +40,6 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
static int riscv013_clear_abstract_error(struct target *target);
/* Implementations of the functions in struct riscv_info. */
-static int riscv013_get_register(struct target *target,
- riscv_reg_t *value, enum gdb_regno rid);
-static int riscv013_set_register(struct target *target, enum gdb_regno regid,
- riscv_reg_t value);
static int dm013_select_hart(struct target *target, int hart_index);
static int riscv013_halt_prep(struct target *target);
static int riscv013_halt_go(struct target *target);
@@ -170,21 +169,12 @@ typedef struct {
* access. */
unsigned int dtmcs_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. */
- unsigned int dmi_busy_delay;
-
- /* Number of run-test/idle cycles to add between consecutive bus master
- * reads/writes respectively. */
- unsigned int bus_master_write_delay, bus_master_read_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. */
- unsigned int ac_busy_delay;
+ /* This structure is used to determine how many run-test/idle to use after
+ * an access of corresponding "riscv_scan_delay_class".
+ * Values are incremented every time an access results in a busy
+ * response.
+ */
+ struct riscv_scan_delays learned_delays;
bool abstract_read_csr_supported;
bool abstract_write_csr_supported;
@@ -479,15 +469,25 @@ static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr
return ERROR_OK;
}
-static void increase_dmi_busy_delay(struct target *target)
+static int 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_TARGET_DEBUG(target, "dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d",
- info->dtmcs_idle, info->dmi_busy_delay,
- info->ac_busy_delay);
+ RISCV013_INFO(info);
- dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */);
+ int res = dtmcontrol_scan(target, DTM_DTMCS_DMIRESET,
+ NULL /* discard result */);
+ if (res != ERROR_OK)
+ return res;
+
+ res = riscv_scan_increase_delay(&info->learned_delays,
+ RISCV_DELAY_BASE);
+ return res;
+}
+
+static void reset_learned_delays(struct target *target)
+{
+ RISCV013_INFO(info);
+ assert(info);
+ memset(&info->learned_delays, 0, sizeof(info->learned_delays));
}
static void decrement_reset_delays_counter(struct target *target, size_t finished_scans)
@@ -504,9 +504,7 @@ static void decrement_reset_delays_counter(struct target *target, size_t finishe
r->reset_delays_wait = -1;
LOG_TARGET_DEBUG(target,
"resetting learned delays (reset_delays_wait counter expired)");
- RISCV013_INFO(info);
- info->dmi_busy_delay = 0;
- info->ac_busy_delay = 0;
+ reset_learned_delays(target);
}
/**
* exec: If this is set, assume the scan results in an execution, so more
@@ -555,9 +553,9 @@ static dmi_status_t dmi_scan(struct target *target, uint32_t *address_in,
jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE);
}
- int idle_count = info->dmi_busy_delay;
- if (exec)
- idle_count += info->ac_busy_delay;
+ int idle_count = exec
+ ? riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_ABSTRACT_COMMAND)
+ : riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_BASE);
if (idle_count)
jtag_add_runtest(idle_count, TAP_IDLE);
@@ -636,7 +634,9 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in,
status = dmi_scan(target, NULL, NULL, op, address, data_out,
exec);
if (status == DMI_STATUS_BUSY) {
- increase_dmi_busy_delay(target);
+ int result = increase_dmi_busy_delay(target);
+ if (result != ERROR_OK)
+ return result;
if (dmi_busy_encountered)
*dmi_busy_encountered = true;
} else if (status == DMI_STATUS_SUCCESS) {
@@ -662,7 +662,9 @@ static int dmi_op_timeout(struct target *target, uint32_t *data_in,
status = dmi_scan(target, NULL, data_in, DMI_OP_NOP, address, 0,
false);
if (status == DMI_STATUS_BUSY) {
- increase_dmi_busy_delay(target);
+ int result = increase_dmi_busy_delay(target);
+ if (result != ERROR_OK)
+ return result;
if (dmi_busy_encountered)
*dmi_busy_encountered = true;
} else if (status == DMI_STATUS_SUCCESS) {
@@ -693,12 +695,12 @@ static int dmi_op(struct target *target, uint32_t *data_in,
uint32_t data_out, bool exec, bool ensure_success)
{
int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, op,
- address, data_out, riscv_command_timeout_sec, exec, ensure_success);
+ address, data_out, riscv_get_command_timeout_sec(), exec, ensure_success);
if (result == ERROR_TIMEOUT_REACHED) {
LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. The target is "
"either really slow or broken. You could increase the "
"timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec);
+ riscv_get_command_timeout_sec());
return ERROR_FAIL;
}
return result;
@@ -729,17 +731,6 @@ static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t a
return address + base;
}
-static int dm_op_timeout(struct target *target, uint32_t *data_in,
- bool *dmi_busy_encountered, int op, uint32_t address,
- uint32_t data_out, int timeout_sec, bool exec, bool ensure_success)
-{
- dm013_info_t *dm = get_dm(target);
- if (!dm)
- return ERROR_FAIL;
- return dmi_op_timeout(target, data_in, dmi_busy_encountered, op, address + dm->base,
- data_out, timeout_sec, exec, ensure_success);
-}
-
static int dm_op(struct target *target, uint32_t *data_in,
bool *dmi_busy_encountered, int op, uint32_t address,
uint32_t data_out, bool exec, bool ensure_success)
@@ -803,11 +794,10 @@ static bool check_dbgbase_exists(struct target *target)
return false;
}
-static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus,
- bool authenticated, unsigned timeout_sec)
+static int dmstatus_read(struct target *target, uint32_t *dmstatus,
+ bool authenticated)
{
- int result = dm_op_timeout(target, dmstatus, NULL, DMI_OP_READ,
- DM_DMSTATUS, 0, timeout_sec, false, true);
+ int result = dm_read(target, dmstatus, DM_DMSTATUS);
if (result != ERROR_OK)
return result;
int dmstatus_version = get_field(*dmstatus, DM_DMSTATUS_VERSION);
@@ -825,26 +815,11 @@ static int dmstatus_read_timeout(struct target *target, uint32_t *dmstatus,
return ERROR_OK;
}
-static int dmstatus_read(struct target *target, uint32_t *dmstatus,
- bool authenticated)
-{
- int result = dmstatus_read_timeout(target, dmstatus, authenticated,
- riscv_command_timeout_sec);
- if (result == ERROR_TIMEOUT_REACHED)
- LOG_TARGET_ERROR(target, "DMSTATUS read didn't complete in %d seconds. The target is "
- "either really slow or broken. You could increase the "
- "timeout with `riscv set_command_timeout_sec`.",
- riscv_command_timeout_sec);
- return result;
-}
-
-static void increase_ac_busy_delay(struct target *target)
+static int 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_TARGET_DEBUG(target, "dtmcs_idle=%d, dmi_busy_delay=%d, ac_busy_delay=%d",
- info->dtmcs_idle, info->dmi_busy_delay,
- info->ac_busy_delay);
+ return riscv_scan_increase_delay(&info->learned_delays,
+ RISCV_DELAY_ABSTRACT_COMMAND);
}
static uint32_t __attribute__((unused)) abstract_register_size(unsigned width)
@@ -890,12 +865,12 @@ static int wait_for_idle(struct target *target, uint32_t *abstractcs)
dm->abstract_cmd_maybe_busy = false;
return ERROR_OK;
}
- } while ((time(NULL) - start) < riscv_command_timeout_sec);
+ } while ((time(NULL) - start) < riscv_get_command_timeout_sec());
LOG_TARGET_ERROR(target,
"Timed out after %ds waiting for busy to go low (abstractcs=0x%" PRIx32 "). "
"Increase the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec,
+ riscv_get_command_timeout_sec(),
*abstractcs);
if (!dm->abstract_cmd_maybe_busy)
@@ -912,13 +887,13 @@ static int dm013_select_target(struct target *target)
return dm013_select_hart(target, info->index);
}
-#define EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE 2
+#define ABSTRACT_COMMAND_BATCH_SIZE 2
static size_t abstract_cmd_fill_batch(struct riscv_batch *batch,
uint32_t command)
{
assert(riscv_batch_available_scans(batch)
- >= EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE);
+ >= ABSTRACT_COMMAND_BATCH_SIZE);
riscv_batch_add_dm_write(batch, DM_COMMAND, command, /* read_back */ true,
RISCV_DELAY_ABSTRACT_COMMAND);
return riscv_batch_add_dm_read(batch, DM_ABSTRACTCS, RISCV_DELAY_BASE);
@@ -936,7 +911,9 @@ static int abstract_cmd_batch_check_and_clear_cmderr(struct target *target,
res = wait_for_idle(target, &abstractcs);
if (res != ERROR_OK)
goto clear_cmderr;
- increase_ac_busy_delay(target);
+ res = increase_ac_busy_delay(target);
+ if (res != ERROR_OK)
+ goto clear_cmderr;
}
*cmderr = get_field32(abstractcs, DM_ABSTRACTCS_CMDERR);
if (*cmderr == CMDERR_NONE)
@@ -976,7 +953,7 @@ static int execute_abstract_command(struct target *target, uint32_t command,
return ERROR_FAIL;
struct riscv_batch *batch = riscv_batch_alloc(target,
- EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE);
+ ABSTRACT_COMMAND_BATCH_SIZE);
const size_t abstractcs_read_key = abstract_cmd_fill_batch(batch, command);
/* Abstract commands are executed while running the batch. */
@@ -1104,7 +1081,7 @@ static uint32_t access_register_command(struct target *target, uint32_t number,
break;
default:
LOG_TARGET_ERROR(target, "%d-bit register %s not supported.",
- size, gdb_regno_name(target, number));
+ size, riscv_reg_gdb_regno_name(target, number));
assert(0);
}
@@ -1204,7 +1181,7 @@ static int register_write_abstract(struct target *target, enum gdb_regno number,
assert(size_bits % 32 == 0);
const unsigned int size_in_words = size_bits / 32;
const unsigned int batch_size = size_in_words
- + EXECUTE_ABSTRACT_COMMAND_BATCH_SIZE;
+ + ABSTRACT_COMMAND_BATCH_SIZE;
struct riscv_batch * const batch = riscv_batch_alloc(target, batch_size);
abstract_data_write_fill_batch(batch, value, /*index*/ 0, size_bits);
@@ -1290,7 +1267,7 @@ static int examine_progbuf(struct target *target)
return ERROR_OK;
}
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@@ -1365,12 +1342,12 @@ static int prep_for_register_access(struct target *target,
}
LOG_TARGET_DEBUG(target, "Preparing mstatus to access %s",
- gdb_regno_name(target, regno));
+ riscv_reg_gdb_regno_name(target, regno));
assert(target->state == TARGET_HALTED &&
"The target must be halted to modify and then restore mstatus");
- if (riscv_get_register(target, orig_mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
+ if (riscv_reg_get(target, orig_mstatus, GDB_REGNO_MSTATUS) != ERROR_OK)
return ERROR_FAIL;
riscv_reg_t new_mstatus = *orig_mstatus;
@@ -1381,11 +1358,11 @@ static int prep_for_register_access(struct target *target,
new_mstatus = set_field(new_mstatus, field_mask, 1);
- if (riscv_write_register(target, GDB_REGNO_MSTATUS, new_mstatus) != ERROR_OK)
+ if (riscv_reg_write(target, GDB_REGNO_MSTATUS, new_mstatus) != ERROR_OK)
return ERROR_FAIL;
LOG_TARGET_DEBUG(target, "Prepared to access %s (mstatus=0x%" PRIx64 ")",
- gdb_regno_name(target, regno), new_mstatus);
+ riscv_reg_gdb_regno_name(target, regno), new_mstatus);
return ERROR_OK;
}
@@ -1397,7 +1374,7 @@ static int cleanup_after_register_access(struct target *target,
return ERROR_OK;
LOG_TARGET_DEBUG(target, "Restoring mstatus to 0x%" PRIx64, mstatus);
- return riscv_write_register(target, GDB_REGNO_MSTATUS, mstatus);
+ return riscv_reg_write(target, GDB_REGNO_MSTATUS, mstatus);
}
typedef enum {
@@ -1616,7 +1593,7 @@ static int fpr_read_progbuf(struct target *target, uint64_t *value,
const unsigned int freg = number - GDB_REGNO_FPR0;
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@@ -1646,7 +1623,7 @@ static int csr_read_progbuf(struct target *target, uint64_t *value,
assert(target->state == TARGET_HALTED);
assert(number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095);
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@@ -1674,7 +1651,7 @@ static int register_read_progbuf(struct target *target, uint64_t *value,
return csr_read_progbuf(target, value, number);
LOG_TARGET_ERROR(target, "Unexpected read of %s via program buffer.",
- gdb_regno_name(target, number));
+ riscv_reg_gdb_regno_name(target, number));
return ERROR_FAIL;
}
@@ -1714,7 +1691,7 @@ static int fpr_write_progbuf(struct target *target, enum gdb_regno number,
assert(number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31);
const unsigned int freg = number - GDB_REGNO_FPR0;
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@@ -1744,11 +1721,11 @@ static int vtype_write_progbuf(struct target *target, riscv_reg_t value)
{
assert(target->state == TARGET_HALTED);
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@@ -1765,11 +1742,11 @@ static int vl_write_progbuf(struct target *target, riscv_reg_t value)
{
assert(target->state == TARGET_HALTED);
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@@ -1788,7 +1765,7 @@ static int csr_write_progbuf(struct target *target, enum gdb_regno number,
assert(target->state == TARGET_HALTED);
assert(number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095);
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
if (register_write_abstract(target, GDB_REGNO_S0, value) != ERROR_OK)
return ERROR_FAIL;
@@ -1820,7 +1797,7 @@ static int register_write_progbuf(struct target *target, enum gdb_regno number,
return csr_write_progbuf(target, number, value);
LOG_TARGET_ERROR(target, "Unexpected write to %s via program buffer.",
- gdb_regno_name(target, number));
+ riscv_reg_gdb_regno_name(target, number));
return ERROR_FAIL;
}
@@ -1832,7 +1809,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number,
riscv_reg_t value)
{
LOG_TARGET_DEBUG(target, "Writing 0x%" PRIx64 " to %s", value,
- gdb_regno_name(target, number));
+ riscv_reg_gdb_regno_name(target, number));
if (target->state != TARGET_HALTED)
return register_write_abstract(target, number, value);
@@ -1850,7 +1827,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number,
return ERROR_FAIL;
if (result == ERROR_OK)
- LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, gdb_regno_name(target, number),
+ LOG_TARGET_DEBUG(target, "%s <- 0x%" PRIx64, riscv_reg_gdb_regno_name(target, number),
value);
return result;
@@ -1860,7 +1837,7 @@ static int register_write_direct(struct target *target, enum gdb_regno number,
static int register_read_direct(struct target *target, riscv_reg_t *value,
enum gdb_regno number)
{
- LOG_TARGET_DEBUG(target, "Reading %s", gdb_regno_name(target, number));
+ LOG_TARGET_DEBUG(target, "Reading %s", riscv_reg_gdb_regno_name(target, number));
if (target->state != TARGET_HALTED)
return register_read_abstract(target, value, number);
@@ -1879,7 +1856,7 @@ static int register_read_direct(struct target *target, riscv_reg_t *value,
return ERROR_FAIL;
if (result == ERROR_OK)
- LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, gdb_regno_name(target, number),
+ LOG_TARGET_DEBUG(target, "%s = 0x%" PRIx64, riscv_reg_gdb_regno_name(target, number),
*value);
return result;
@@ -1896,10 +1873,10 @@ static int wait_for_authbusy(struct target *target, uint32_t *dmstatus)
*dmstatus = value;
if (!get_field(value, DM_DMSTATUS_AUTHBUSY))
break;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "Timed out after %ds waiting for authbusy to go low (dmstatus=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec,
+ riscv_get_command_timeout_sec(),
value);
return ERROR_FAIL;
}
@@ -1919,7 +1896,7 @@ static int set_dcsr_ebreak(struct target *target, bool step)
RISCV013_INFO(info);
riscv_reg_t original_dcsr, dcsr;
/* We want to twiddle some bits in the debug CSR so debugging works. */
- if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
+ if (riscv_reg_get(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;
original_dcsr = dcsr;
dcsr = set_field(dcsr, CSR_DCSR_STEP, step);
@@ -1929,7 +1906,7 @@ static int set_dcsr_ebreak(struct target *target, bool step)
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H'));
if (dcsr != original_dcsr &&
- riscv_set_register(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK)
+ riscv_reg_set(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK)
return ERROR_FAIL;
info->dcsr_ebreak_is_set = true;
return ERROR_OK;
@@ -2089,11 +2066,10 @@ static int reset_dm(struct target *target)
if (result != ERROR_OK)
return result;
- if (time(NULL) - start > riscv_reset_timeout_sec) {
- /* TODO: Introduce a separate timeout for this. */
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "DM didn't acknowledge reset in %d s. "
- "Increase the timeout with 'riscv set_reset_timeout_sec'.",
- riscv_reset_timeout_sec);
+ "Increase the timeout with 'riscv set_command_timeout_sec'.",
+ riscv_get_command_timeout_sec());
return ERROR_TIMEOUT_REACHED;
}
} while (get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE));
@@ -2112,11 +2088,10 @@ static int reset_dm(struct target *target)
if (result != ERROR_OK)
return result;
- if (time(NULL) - start > riscv_reset_timeout_sec) {
- /* TODO: Introduce a separate timeout for this. */
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "Debug Module did not become active in %d s. "
- "Increase the timeout with 'riscv set_reset_timeout_sec'.",
- riscv_reset_timeout_sec);
+ "Increase the timeout with 'riscv set_command_timeout_sec'.",
+ riscv_get_command_timeout_sec());
return ERROR_TIMEOUT_REACHED;
}
} while (!get_field32(dmcontrol, DM_DMCONTROL_DMACTIVE));
@@ -2404,7 +2379,7 @@ static int examine(struct target *target)
}
/* Now init registers based on what we discovered. */
- if (riscv_init_registers(target) != ERROR_OK)
+ if (riscv013_reg_init_all(target) != ERROR_OK)
return ERROR_FAIL;
if (set_dcsr_ebreak(target, false) != ERROR_OK)
@@ -2564,14 +2539,14 @@ static int try_set_vsew(struct target *target, unsigned int *debug_vsew)
/* Set standard element width to match XLEN, for vmv instruction to move
* the least significant bits into a GPR.
*/
- if (riscv_write_register(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK)
+ if (riscv_reg_write(target, GDB_REGNO_VTYPE, encoded_vsew << 3) != ERROR_OK)
return ERROR_FAIL;
if (encoded_vsew == 3 && r->vsew64_supported == YNM_MAYBE) {
/* Check that it's supported. */
riscv_reg_t vtype;
- if (riscv_get_register(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK)
+ if (riscv_reg_get(target, &vtype, GDB_REGNO_VTYPE) != ERROR_OK)
return ERROR_FAIL;
if (vtype >> (riscv_xlen(target) - 1)) {
r->vsew64_supported = YNM_NO;
@@ -2604,9 +2579,9 @@ static int prep_for_vector_access(struct target *target,
return ERROR_FAIL;
/* Save vtype and vl. */
- if (riscv_get_register(target, orig_vtype, GDB_REGNO_VTYPE) != ERROR_OK)
+ if (riscv_reg_get(target, orig_vtype, GDB_REGNO_VTYPE) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_get_register(target, orig_vl, GDB_REGNO_VL) != ERROR_OK)
+ if (riscv_reg_get(target, orig_vl, GDB_REGNO_VL) != ERROR_OK)
return ERROR_FAIL;
if (try_set_vsew(target, debug_vsew) != ERROR_OK)
@@ -2615,22 +2590,22 @@ static int prep_for_vector_access(struct target *target,
* instruction, for the vslide1down instruction.
* Set it so the entire V register is updated. */
*debug_vl = DIV_ROUND_UP(r->vlenb * 8, *debug_vsew);
- return riscv_write_register(target, GDB_REGNO_VL, *debug_vl);
+ return riscv_reg_write(target, GDB_REGNO_VL, *debug_vl);
}
static int cleanup_after_vector_access(struct target *target,
riscv_reg_t mstatus, riscv_reg_t vtype, riscv_reg_t vl)
{
/* Restore vtype and vl. */
- if (riscv_write_register(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK)
+ if (riscv_reg_write(target, GDB_REGNO_VTYPE, vtype) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_write_register(target, GDB_REGNO_VL, vl) != ERROR_OK)
+ if (riscv_reg_write(target, GDB_REGNO_VL, vl) != ERROR_OK)
return ERROR_FAIL;
return cleanup_after_register_access(target, mstatus, GDB_REGNO_VL);
}
-static int riscv013_get_register_buf(struct target *target,
- uint8_t *value, enum gdb_regno regno)
+int riscv013_get_register_buf(struct target *target, uint8_t *value,
+ enum gdb_regno regno)
{
assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31);
@@ -2644,7 +2619,7 @@ static int riscv013_get_register_buf(struct target *target,
&debug_vl, &debug_vsew) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
unsigned int vnum = regno - GDB_REGNO_V0;
@@ -2673,7 +2648,7 @@ static int riscv013_get_register_buf(struct target *target,
} else {
LOG_TARGET_ERROR(target,
"Failed to execute vmv/vslide1down while reading %s",
- gdb_regno_name(target, regno));
+ riscv_reg_gdb_regno_name(target, regno));
break;
}
}
@@ -2684,8 +2659,8 @@ static int riscv013_get_register_buf(struct target *target,
return result;
}
-static int riscv013_set_register_buf(struct target *target,
- enum gdb_regno regno, const uint8_t *value)
+int riscv013_set_register_buf(struct target *target, enum gdb_regno regno,
+ const uint8_t *value)
{
assert(regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31);
@@ -2699,7 +2674,7 @@ static int riscv013_set_register_buf(struct target *target,
&debug_vl, &debug_vsew) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
unsigned int vnum = regno - GDB_REGNO_V0;
@@ -2758,37 +2733,25 @@ static int sb_write_address(struct target *target, target_addr_t address,
(uint32_t)address, false, ensure_success);
}
-/* TODO: store delays in "struct riscv_scan_delays" and remove this function. */
-struct riscv_scan_delays get_scan_delays(struct target *target)
-{
- RISCV013_INFO(info);
- assert(info);
- struct riscv_scan_delays delays;
- riscv_scan_set_delay(&delays, RISCV_DELAY_BASE, info->dmi_busy_delay);
- riscv_scan_set_delay(&delays, RISCV_DELAY_ABSTRACT_COMMAND, info->dmi_busy_delay +
- info->ac_busy_delay);
- riscv_scan_set_delay(&delays, RISCV_DELAY_SYSBUS_READ, info->dmi_busy_delay +
- info->bus_master_read_delay);
- riscv_scan_set_delay(&delays, RISCV_DELAY_SYSBUS_WRITE, info->dmi_busy_delay +
- info->bus_master_write_delay);
- return delays;
-}
-
static int batch_run(struct target *target, struct riscv_batch *batch)
{
RISCV_INFO(r);
+ RISCV013_INFO(info);
select_dmi(target);
riscv_batch_add_nop(batch);
- const int result = riscv_batch_run_from(batch, 0,
- get_scan_delays(target),
+ const int result = riscv_batch_run_from(batch, 0, &info->learned_delays,
/*resets_delays*/ r->reset_delays_wait >= 0,
r->reset_delays_wait);
+ if (result != ERROR_OK)
+ return result;
/* TODO: To use `riscv_batch_finished_scans()` here, it is needed for
* all scans to not discard input, meaning
* "riscv_batch_add_dm_write(..., false)" should not be used. */
const size_t finished_scans = batch->used_scans;
decrement_reset_delays_counter(target, finished_scans);
- return result;
+ if (riscv_batch_was_batch_busy(batch))
+ return increase_dmi_busy_delay(target);
+ return ERROR_OK;
}
/* It is expected that during creation of the batch
@@ -2797,45 +2760,49 @@ static int batch_run(struct target *target, struct riscv_batch *batch)
static int batch_run_timeout(struct target *target, struct riscv_batch *batch)
{
RISCV013_INFO(info);
-
select_dmi(target);
riscv_batch_add_nop(batch);
size_t finished_scans = 0;
const time_t start = time(NULL);
- const unsigned int old_dmi_busy_delay = info->dmi_busy_delay;
+ const unsigned int old_base_delay = riscv_scan_get_delay(&info->learned_delays,
+ RISCV_DELAY_BASE);
int result;
do {
RISCV_INFO(r);
result = riscv_batch_run_from(batch, finished_scans,
- get_scan_delays(target),
+ &info->learned_delays,
/*resets_delays*/ r->reset_delays_wait >= 0,
r->reset_delays_wait);
+ if (result != ERROR_OK)
+ return result;
const size_t new_finished_scans = riscv_batch_finished_scans(batch);
assert(new_finished_scans >= finished_scans);
decrement_reset_delays_counter(target, new_finished_scans - finished_scans);
finished_scans = new_finished_scans;
- if (result != ERROR_OK)
- return result;
if (!riscv_batch_was_batch_busy(batch)) {
assert(finished_scans == batch->used_scans);
return ERROR_OK;
}
- increase_dmi_busy_delay(target);
- } while (time(NULL) - start < riscv_command_timeout_sec);
+ result = increase_dmi_busy_delay(target);
+ if (result != ERROR_OK)
+ return result;
+ } while (time(NULL) - start < riscv_get_command_timeout_sec());
assert(result == ERROR_OK);
assert(riscv_batch_was_batch_busy(batch));
/* Reset dmi_busy_delay, so the value doesn't get too big. */
- LOG_TARGET_DEBUG(target, "dmi_busy_delay is restored to %u.",
- old_dmi_busy_delay);
- info->dmi_busy_delay = old_dmi_busy_delay;
+ LOG_TARGET_DEBUG(target, "%s delay is restored to %u.",
+ riscv_scan_delay_class_name(RISCV_DELAY_BASE),
+ old_base_delay);
+ riscv_scan_set_delay(&info->learned_delays, RISCV_DELAY_BASE,
+ old_base_delay);
LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. "
"The target is either really slow or broken. You could increase "
"the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec);
+ riscv_get_command_timeout_sec());
return ERROR_TIMEOUT_REACHED;
}
@@ -2969,7 +2936,11 @@ static int sample_memory_bus_v1(struct target *target,
* with a larger DMI delay. */
unsigned int sbcs_read_op = riscv_batch_get_dmi_read_op(batch, sbcs_read_index);
if (sbcs_read_op == DTM_DMI_OP_BUSY) {
- increase_dmi_busy_delay(target);
+ result = increase_dmi_busy_delay(target);
+ if (result != ERROR_OK) {
+ riscv_batch_free(batch);
+ return result;
+ }
continue;
}
@@ -2977,9 +2948,12 @@ static int sample_memory_bus_v1(struct target *target,
if (get_field(sbcs_read, DM_SBCS_SBBUSYERROR)) {
/* Discard this batch when we encounter "busy error" state on the System Bus level.
* We'll try next time with a larger System Bus read delay. */
- info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1;
dm_write(target, DM_SBCS, sbcs_read | DM_SBCS_SBBUSYERROR | DM_SBCS_SBERROR);
+ int res = riscv_scan_increase_delay(&info->learned_delays,
+ RISCV_DELAY_SYSBUS_READ);
riscv_batch_free(batch);
+ if (res != ERROR_OK)
+ return res;
continue;
}
if (get_field(sbcs_read, DM_SBCS_SBERROR)) {
@@ -3098,10 +3072,6 @@ static int init_target(struct command_context *cmd_ctx,
LOG_TARGET_DEBUG(target, "Init.");
RISCV_INFO(generic_info);
- generic_info->get_register = &riscv013_get_register;
- generic_info->set_register = &riscv013_set_register;
- generic_info->get_register_buf = &riscv013_get_register_buf;
- generic_info->set_register_buf = &riscv013_set_register_buf;
generic_info->select_target = &dm013_select_target;
generic_info->get_hart_state = &riscv013_get_hart_state;
generic_info->resume_go = &riscv013_resume_go;
@@ -3140,11 +3110,7 @@ static int init_target(struct command_context *cmd_ctx,
riscv013_info_t *info = get_info(target);
info->progbufsize = -1;
-
- info->dmi_busy_delay = 0;
- info->bus_master_read_delay = 0;
- info->bus_master_write_delay = 0;
- info->ac_busy_delay = 0;
+ reset_learned_delays(target);
/* Assume all these abstract commands are supported until we learn
* otherwise.
@@ -3231,25 +3197,20 @@ static int deassert_reset(struct target *target)
return result;
uint32_t dmstatus;
- const int orig_dmi_busy_delay = info->dmi_busy_delay;
+ const unsigned int orig_base_delay = riscv_scan_get_delay(&info->learned_delays,
+ RISCV_DELAY_BASE);
time_t start = time(NULL);
LOG_TARGET_DEBUG(target, "Waiting for hart to come out of reset.");
do {
- result = dmstatus_read_timeout(target, &dmstatus, true,
- riscv_reset_timeout_sec);
- if (result == ERROR_TIMEOUT_REACHED)
- LOG_TARGET_ERROR(target, "Hart didn't complete a DMI read coming "
- "out of reset in %ds; Increase the timeout with riscv "
- "set_reset_timeout_sec.",
- riscv_reset_timeout_sec);
+ result = dmstatus_read(target, &dmstatus, true);
if (result != ERROR_OK)
return result;
- if (time(NULL) - start > riscv_reset_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "Hart didn't leave reset in %ds; "
"dmstatus=0x%x (allunavail=%s, allhavereset=%s); "
- "Increase the timeout with riscv set_reset_timeout_sec.",
- riscv_reset_timeout_sec, dmstatus,
+ "Increase the timeout with riscv set_command_timeout_sec.",
+ riscv_get_command_timeout_sec(), dmstatus,
get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) ? "true" : "false",
get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET) ? "true" : "false");
return ERROR_TIMEOUT_REACHED;
@@ -3264,7 +3225,8 @@ static int deassert_reset(struct target *target)
} while (get_field(dmstatus, DM_DMSTATUS_ALLUNAVAIL) &&
!get_field(dmstatus, DM_DMSTATUS_ALLHAVERESET));
- info->dmi_busy_delay = orig_dmi_busy_delay;
+ riscv_scan_set_delay(&info->learned_delays, RISCV_DELAY_BASE,
+ orig_base_delay);
if (target->reset_halt) {
target->state = TARGET_HALTED;
@@ -3434,10 +3396,10 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs)
return ERROR_FAIL;
if (!get_field(*sbcs, DM_SBCS_SBBUSY))
return ERROR_OK;
- if (time(NULL) - start > riscv_command_timeout_sec) {
+ if (time(NULL) - start > riscv_get_command_timeout_sec()) {
LOG_TARGET_ERROR(target, "Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). "
"Increase the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec, *sbcs);
+ riscv_get_command_timeout_sec(), *sbcs);
return ERROR_FAIL;
}
}
@@ -3579,6 +3541,9 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
target_addr_t next_address = address;
target_addr_t end_address = address + (increment ? count : 1) * size;
+ /* TODO: Reading all the elements in a single batch will boost the
+ * performance.
+ */
while (next_address < end_address) {
uint32_t sbcs_write = set_field(0, DM_SBCS_SBREADONADDR, 1);
sbcs_write |= sb_sbaccess(size);
@@ -3593,10 +3558,12 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
if (sb_write_address(target, next_address, true) != ERROR_OK)
return ERROR_FAIL;
- if (info->bus_master_read_delay) {
+ unsigned int bus_master_read_delay = riscv_scan_get_delay(&info->learned_delays,
+ RISCV_DELAY_SYSBUS_READ);
+ if (bus_master_read_delay) {
LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay",
- info->bus_master_read_delay);
- jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE);
+ bus_master_read_delay);
+ jtag_add_runtest(bus_master_read_delay, TAP_IDLE);
if (jtag_execute_queue() != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to scan idle sequence");
return ERROR_FAIL;
@@ -3607,75 +3574,44 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
* completed. */
static int sbdata[4] = {DM_SBDATA0, DM_SBDATA1, DM_SBDATA2, DM_SBDATA3};
+ /* TODO: The only purpose of "sbvalue" is to be passed to
+ * "log_memory_access()". If "log_memory_access()" were to
+ * accept "uint8_t *" instead of "uint32_t *", "sbvalue" would
+ * be unnecessary.
+ */
uint32_t sbvalue[4] = {0};
assert(size <= 16);
- target_addr_t next_read = address - 1;
- uint32_t buffer_offset = 0;
- int next_read_j = 0;
for (uint32_t i = (next_address - address) / size; i < count - 1; i++) {
- for (int j = (size - 1) / 4; j >= 0; j--) {
- unsigned attempt = 0;
- while (1) {
- if (attempt++ > 100) {
- LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory"
- " just past " TARGET_ADDR_FMT, next_read);
- return ERROR_FAIL;
- }
- keep_alive();
- dmi_status_t status = dmi_scan(target, NULL, &sbvalue[next_read_j],
- DMI_OP_READ, sbdata[j] + dm->base, 0, false);
- /* By reading from sbdata0, we have just initiated another system bus read.
- * If necessary add a delay so the read can finish. */
- if (j == 0 && info->bus_master_read_delay) {
- LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay",
- info->bus_master_read_delay);
- jtag_add_runtest(info->bus_master_read_delay, TAP_IDLE);
- if (jtag_execute_queue() != ERROR_OK) {
- LOG_TARGET_ERROR(target, "Failed to scan idle sequence");
- return ERROR_FAIL;
- }
- }
+ const uint32_t size_in_words = DIV_ROUND_UP(size, 4);
+ struct riscv_batch *batch = riscv_batch_alloc(target, size_in_words);
+ /* Read of sbdata0 must be performed as last because it
+ * starts the new bus data transfer
+ * (in case "sbcs.sbreadondata" was set above).
+ * We don't want to start the next bus read before we
+ * fetch all the data from the last bus read. */
+ for (uint32_t j = size_in_words - 1; j > 0; --j)
+ riscv_batch_add_dm_read(batch, sbdata[j], RISCV_DELAY_BASE);
+ riscv_batch_add_dm_read(batch, sbdata[0], RISCV_DELAY_SYSBUS_READ);
+
+ int res = batch_run_timeout(target, batch);
+ if (res != ERROR_OK) {
+ riscv_batch_free(batch);
+ return res;
+ }
- if (status == DMI_STATUS_BUSY)
- increase_dmi_busy_delay(target);
- else if (status == DMI_STATUS_SUCCESS)
- break;
- else
- return ERROR_FAIL;
- }
- if (next_read != address - 1) {
- buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[next_read_j]);
- if (next_read_j == 0) {
- log_memory_access(next_read, sbvalue, size, true);
- memset(sbvalue, 0, size);
- }
- }
- next_read_j = j;
- next_read = address + i * increment + next_read_j * 4;
- buffer_offset = i * size + next_read_j * 4;
+ const size_t last_key = batch->read_keys_used - 1;
+ for (size_t k = 0; k <= last_key; ++k) {
+ sbvalue[k] = riscv_batch_get_dmi_read_data(batch,
+ last_key - k);
+ buf_set_u32(buffer + i * size + k * 4, 0, 8 * size, sbvalue[k]);
}
+ riscv_batch_free(batch);
+ const target_addr_t read_addr = address + i * increment;
+ log_memory_access(read_addr, sbvalue, size, true);
}
uint32_t sbcs_read = 0;
if (count > 1) {
- unsigned attempt = 0;
- while (1) {
- if (attempt++ > 100) {
- LOG_TARGET_ERROR(target, "DMI keeps being busy in while reading memory"
- " just past " TARGET_ADDR_FMT, next_read);
- return ERROR_FAIL;
- }
- dmi_status_t status = dmi_scan(target, NULL, &sbvalue[0], DMI_OP_NOP, 0, 0, false);
- if (status == DMI_STATUS_BUSY)
- increase_dmi_busy_delay(target);
- else if (status == DMI_STATUS_SUCCESS)
- break;
- else
- return ERROR_FAIL;
- }
- buf_set_u32(buffer + buffer_offset, 0, 8 * MIN(size, 4), sbvalue[0]);
- log_memory_access(next_read, sbvalue, size, true);
-
/* "Writes to sbcs while sbbusy is high result in undefined behavior.
* A debugger must not write to sbcs until it reads sbbusy as 0." */
if (read_sbcs_nonbusy(target, &sbcs_read) != ERROR_OK)
@@ -3716,9 +3652,10 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address,
return ERROR_FAIL;
}
- info->bus_master_read_delay += info->bus_master_read_delay / 10 + 1;
- LOG_TARGET_DEBUG(target, "Increasing bus_master_read_delay to %d.",
- info->bus_master_read_delay);
+ int res = riscv_scan_increase_delay(&info->learned_delays,
+ RISCV_DELAY_SYSBUS_READ);
+ if (res != ERROR_OK)
+ return res;
continue;
}
@@ -4134,8 +4071,12 @@ static int read_memory_progbuf_inner_on_ac_busy(struct target *target,
uint32_t start_index, uint32_t *elements_read,
struct memory_access_info access)
{
- increase_ac_busy_delay(target);
- riscv013_clear_abstract_error(target);
+ int res = riscv013_clear_abstract_error(target);
+ if (res != ERROR_OK)
+ return res;
+ res = increase_ac_busy_delay(target);
+ if (res != ERROR_OK)
+ return res;
if (dm_write(target, DM_ABSTRACTAUTO, 0) != ERROR_OK)
return ERROR_FAIL;
@@ -4439,11 +4380,11 @@ static int read_memory_progbuf_inner_fill_progbuf(struct target *target,
{
const bool is_repeated_read = increment == 0;
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
- if (is_repeated_read && riscv_save_register(target, GDB_REGNO_A0) != ERROR_OK)
+ if (is_repeated_read && riscv013_reg_save(target, GDB_REGNO_A0) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@@ -4536,7 +4477,7 @@ static int read_memory_progbuf_inner(struct target *target,
static int read_memory_progbuf_inner_one(struct target *target,
struct memory_access_info access, bool mprven)
{
- if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@@ -4802,39 +4743,30 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address,
/* Execute the batch of writes */
result = batch_run(target, batch);
- riscv_batch_free(batch);
- if (result != ERROR_OK)
+ if (result != ERROR_OK) {
+ riscv_batch_free(batch);
return result;
+ }
- /* Read sbcs value.
- * At the same time, detect if DMI busy has occurred during the batch write. */
- bool dmi_busy_encountered;
- if (dm_op(target, &sbcs, &dmi_busy_encountered, DMI_OP_READ,
- DM_SBCS, 0, false, true) != ERROR_OK)
- return ERROR_FAIL;
+ bool dmi_busy_encountered = riscv_batch_was_batch_busy(batch);
+ riscv_batch_free(batch);
if (dmi_busy_encountered)
LOG_TARGET_DEBUG(target, "DMI busy encountered during system bus write.");
- /* Wait until sbbusy goes low */
- time_t start = time(NULL);
- while (get_field(sbcs, DM_SBCS_SBBUSY)) {
- if (time(NULL) - start > riscv_command_timeout_sec) {
- LOG_TARGET_ERROR(target, "Timed out after %ds waiting for sbbusy to go low (sbcs=0x%x). "
- "Increase the timeout with riscv set_command_timeout_sec.",
- riscv_command_timeout_sec, sbcs);
- return ERROR_FAIL;
- }
- if (dm_read(target, &sbcs, DM_SBCS) != ERROR_OK)
- return ERROR_FAIL;
- }
+ result = read_sbcs_nonbusy(target, &sbcs);
+ if (result != ERROR_OK)
+ return result;
if (get_field(sbcs, DM_SBCS_SBBUSYERROR)) {
/* We wrote while the target was busy. */
LOG_TARGET_DEBUG(target, "Sbbusyerror encountered during system bus write.");
/* Clear the sticky error flag. */
dm_write(target, DM_SBCS, sbcs | DM_SBCS_SBBUSYERROR);
- /* Slow down before trying again. */
- info->bus_master_write_delay += info->bus_master_write_delay / 10 + 1;
+ /* Slow down before trying again.
+ * FIXME: Possible overflow is ignored here.
+ */
+ riscv_scan_increase_delay(&info->learned_delays,
+ RISCV_DELAY_SYSBUS_WRITE);
}
if (get_field(sbcs, DM_SBCS_SBBUSYERROR) || dmi_busy_encountered) {
@@ -4945,8 +4877,12 @@ static int write_memory_progbuf_teardown(struct target *target)
static int write_memory_progbuf_handle_busy(struct target *target,
target_addr_t *address_p, uint32_t size, const uint8_t *buffer)
{
- riscv013_clear_abstract_error(target);
- increase_ac_busy_delay(target);
+ int res = riscv013_clear_abstract_error(target);
+ if (res != ERROR_OK)
+ return res;
+ res = increase_ac_busy_delay(target);
+ if (res != ERROR_OK)
+ return res;
if (write_memory_progbuf_teardown(target) != ERROR_OK)
return ERROR_FAIL;
@@ -5079,9 +5015,9 @@ static int riscv_program_store_mprv(struct riscv_program *p, enum gdb_regno d,
static int write_memory_progbuf_fill_progbuf(struct target *target,
uint32_t size, bool mprven)
{
- if (riscv_save_register(target, GDB_REGNO_S0) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_save_register(target, GDB_REGNO_S1) != ERROR_OK)
+ if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK)
return ERROR_FAIL;
struct riscv_program program;
@@ -5252,7 +5188,7 @@ struct target_type riscv013_target = {
};
/*** 0.13-specific implementations of various RISC-V helper functions. ***/
-static int riscv013_get_register(struct target *target,
+int riscv013_get_register(struct target *target,
riscv_reg_t *value, enum gdb_regno rid)
{
/* It would be beneficial to move this redirection to the
@@ -5261,14 +5197,14 @@ static int riscv013_get_register(struct target *target,
*/
if (rid == GDB_REGNO_PRIV) {
uint64_t dcsr;
- if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
+ if (riscv_reg_get(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
return ERROR_FAIL;
*value = set_field(0, VIRT_PRIV_V, get_field(dcsr, CSR_DCSR_V));
*value = set_field(*value, VIRT_PRIV_PRV, get_field(dcsr, CSR_DCSR_PRV));
return ERROR_OK;
}
- LOG_TARGET_DEBUG(target, "reading register %s", gdb_regno_name(target, rid));
+ LOG_TARGET_DEBUG(target, "reading register %s", riscv_reg_gdb_regno_name(target, rid));
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
@@ -5281,11 +5217,11 @@ static int riscv013_get_register(struct target *target,
return ERROR_OK;
}
-static int riscv013_set_register(struct target *target, enum gdb_regno rid,
+int riscv013_set_register(struct target *target, enum gdb_regno rid,
riscv_reg_t value)
{
LOG_TARGET_DEBUG(target, "writing 0x%" PRIx64 " to register %s",
- value, gdb_regno_name(target, rid));
+ value, riscv_reg_gdb_regno_name(target, rid));
if (dm013_select_target(target) != ERROR_OK)
return ERROR_FAIL;
@@ -5649,7 +5585,7 @@ static int riscv013_on_step_or_resume(struct target *target, bool step)
if (set_dcsr_ebreak(target, step) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_flush_registers(target) != ERROR_OK)
+ if (riscv_reg_flush_all(target) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
}
@@ -5663,7 +5599,7 @@ static int riscv013_step_or_resume_current_hart(struct target *target,
}
LOG_TARGET_DEBUG(target, "resuming (for step?=%d)", step);
- if (riscv_flush_registers(target) != ERROR_OK)
+ if (riscv_reg_flush_all(target) != ERROR_OK)
return ERROR_FAIL;
dm013_info_t *dm = get_dm(target);
diff --git a/src/target/riscv/riscv-013.h b/src/target/riscv/riscv-013.h
new file mode 100644
index 0000000..be508f7
--- /dev/null
+++ b/src/target/riscv/riscv-013.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef OPENOCD_TARGET_RISCV_RISCV_013_H
+#define OPENOCD_TARGET_RISCV_RISCV_013_H
+
+#include "riscv.h"
+
+/* TODO: These functions should be replaced here by access methods that can be
+ * reused by other modules (e.g. a function writing an abstract commands, a
+ * function filling/executing program buffer, etc.), while the specifics on how
+ * to use these general-purpose version-specific methods to get a register's
+ * value will be in `riscv-013_reg.c`.
+ */
+int riscv013_get_register(struct target *target,
+ riscv_reg_t *value, enum gdb_regno rid);
+int riscv013_get_register_buf(struct target *target, uint8_t *value,
+ enum gdb_regno regno);
+int riscv013_set_register(struct target *target, enum gdb_regno rid,
+ riscv_reg_t value);
+int riscv013_set_register_buf(struct target *target, enum gdb_regno regno,
+ const uint8_t *value);
+
+#endif /*OPENOCD_TARGET_RISCV_RISCV_013_H*/
diff --git a/src/target/riscv/riscv-013_reg.c b/src/target/riscv/riscv-013_reg.c
new file mode 100644
index 0000000..a71a01c
--- /dev/null
+++ b/src/target/riscv/riscv-013_reg.c
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "riscv-013_reg.h"
+
+#include "riscv_reg.h"
+#include "riscv_reg_impl.h"
+#include "riscv-013.h"
+#include <helper/time_support.h>
+
+static int riscv013_reg_get(struct reg *reg)
+{
+ struct target *target = riscv_reg_impl_get_target(reg);
+
+ /* TODO: Hack to deal with gdb that thinks these registers still exist. */
+ if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 &&
+ riscv_supports_extension(target, 'E')) {
+ buf_set_u64(reg->value, 0, reg->size, 0);
+ return ERROR_OK;
+ }
+
+ if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
+ if (riscv013_get_register_buf(target, reg->value, reg->number) != ERROR_OK)
+ return ERROR_FAIL;
+
+ reg->valid = riscv_reg_impl_gdb_regno_cacheable(reg->number, /* is write? */ false);
+ } else {
+ uint64_t value;
+ int result = riscv_reg_get(target, &value, reg->number);
+ if (result != ERROR_OK)
+ return result;
+ buf_set_u64(reg->value, 0, reg->size, value);
+ }
+ char *str = buf_to_hex_str(reg->value, reg->size);
+ LOG_TARGET_DEBUG(target, "Read 0x%s from %s (valid=%d).", str, reg->name,
+ reg->valid);
+ free(str);
+ return ERROR_OK;
+}
+
+static int riscv013_reg_set(struct reg *reg, uint8_t *buf)
+{
+ struct target *target = riscv_reg_impl_get_target(reg);
+ RISCV_INFO(r);
+
+ char *str = buf_to_hex_str(buf, reg->size);
+ LOG_TARGET_DEBUG(target, "Write 0x%s to %s (valid=%d).", str, reg->name,
+ reg->valid);
+ free(str);
+
+ /* TODO: Hack to deal with gdb that thinks these registers still exist. */
+ if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 &&
+ riscv_supports_extension(target, 'E') &&
+ buf_get_u64(buf, 0, reg->size) == 0)
+ return ERROR_OK;
+
+ if (reg->number == GDB_REGNO_TDATA1 ||
+ reg->number == GDB_REGNO_TDATA2) {
+ r->manual_hwbp_set = true;
+ /* When enumerating triggers, we clear any triggers with DMODE set,
+ * assuming they were left over from a previous debug session. So make
+ * sure that is done before a user might be setting their own triggers.
+ */
+ if (riscv_enumerate_triggers(target) != ERROR_OK)
+ return ERROR_FAIL;
+ }
+
+ if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
+ if (riscv013_set_register_buf(target, reg->number, buf) != ERROR_OK)
+ return ERROR_FAIL;
+
+ memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8));
+ reg->valid = riscv_reg_impl_gdb_regno_cacheable(reg->number, /* is write? */ true);
+ } else {
+ const riscv_reg_t value = buf_get_u64(buf, 0, reg->size);
+ if (riscv_reg_set(target, reg->number, value) != ERROR_OK)
+ return ERROR_FAIL;
+ }
+
+ return ERROR_OK;
+}
+
+static const struct reg_arch_type *riscv013_gdb_regno_reg_type(uint32_t regno)
+{
+ static const struct reg_arch_type riscv011_reg_type = {
+ .get = riscv013_reg_get,
+ .set = riscv013_reg_set
+ };
+ return &riscv011_reg_type;
+}
+
+static int riscv013_init_reg(struct target *target, uint32_t regno)
+{
+ return riscv_reg_impl_init_one(target, regno, riscv013_gdb_regno_reg_type(regno));
+}
+
+int riscv013_reg_init_all(struct target *target)
+{
+ if (riscv_reg_impl_init_cache(target) != ERROR_OK)
+ return ERROR_FAIL;
+
+ init_shared_reg_info(target);
+
+ riscv_reg_impl_init_vector_reg_type(target);
+
+ for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno)
+ if (riscv013_init_reg(target, regno) != ERROR_OK)
+ return ERROR_FAIL;
+
+ if (riscv_reg_impl_expose_csrs(target) != ERROR_OK)
+ return ERROR_FAIL;
+
+ riscv_reg_impl_hide_csrs(target);
+
+ return ERROR_OK;
+}
+
+/**
+ * This function is used to save the value of a register in cache. The register
+ * is marked as dirty, and writeback is delayed for as long as possible.
+ */
+int riscv013_reg_save(struct target *target, enum gdb_regno regid)
+{
+ if (target->state != TARGET_HALTED) {
+ LOG_TARGET_ERROR(target, "Can't save register %s on a hart that is not halted.",
+ riscv_reg_gdb_regno_name(target, regid));
+ return ERROR_FAIL;
+ }
+ assert(riscv_reg_impl_gdb_regno_cacheable(regid, /* is write? */ false) &&
+ "Only cacheable registers can be saved.");
+
+ RISCV_INFO(r);
+ riscv_reg_t value;
+ if (!target->reg_cache) {
+ assert(!target_was_examined(target));
+ /* To create register cache it is needed to examine the target first,
+ * therefore during examine, any changed register needs to be saved
+ * and restored manually.
+ */
+ return ERROR_OK;
+ }
+
+ struct reg *reg = riscv_reg_impl_cache_entry(target, regid);
+
+ LOG_TARGET_DEBUG(target, "Saving %s", reg->name);
+ if (riscv_reg_get(target, &value, regid) != ERROR_OK)
+ return ERROR_FAIL;
+
+ assert(reg->valid &&
+ "The register is cacheable, so the cache entry must be valid now.");
+ /* Mark the register dirty. We assume that this function is called
+ * because the caller is about to mess with the underlying value of the
+ * register. */
+ reg->dirty = true;
+
+ r->last_activity = timeval_ms();
+
+ return ERROR_OK;
+}
diff --git a/src/target/riscv/riscv-013_reg.h b/src/target/riscv/riscv-013_reg.h
new file mode 100644
index 0000000..2bdaaa0
--- /dev/null
+++ b/src/target/riscv/riscv-013_reg.h
@@ -0,0 +1,31 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_013_H
+#define OPENOCD_TARGET_RISCV_RISCV_REG_013_H
+
+#include "target/target.h"
+#include "gdb_regs.h"
+#include "riscv.h"
+
+/**
+ * This file describes additional register cache interface available to the
+ * RISC-V Debug Specification v0.13+ targets.
+ */
+
+/**
+ * Init initialize register cache. After this function all registers can be
+ * safely accessed via functions described here and in `riscv_reg.h`.
+ */
+int riscv013_reg_init_all(struct target *target);
+
+/**
+ * This function is used to save the value of a register in cache. The register
+ * is marked as dirty, and writeback is delayed for as long as possible.
+ * Generally used to save registers before program buffer execution.
+ *
+ * TODO: The interface should be restricted in such a way that only GPRs can be
+ * saved.
+ */
+int riscv013_reg_save(struct target *target, enum gdb_regno regid);
+
+#endif /*OPENOCD_TARGET_RISCV_RISCV_REG_013_H*/
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index b2612c2..a57c709 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -20,6 +20,7 @@
#include "helper/base64.h"
#include "helper/time_support.h"
#include "riscv.h"
+#include "riscv_reg.h"
#include "program.h"
#include "gdb_regs.h"
#include "rtos/rtos.h"
@@ -139,10 +140,15 @@ struct tdata1_cache {
};
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
-int riscv_command_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC;
+static int riscv_command_timeout_sec_value = DEFAULT_COMMAND_TIMEOUT_SEC;
-/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
-int riscv_reset_timeout_sec = DEFAULT_RESET_TIMEOUT_SEC;
+/* DEPRECATED Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
+static int riscv_reset_timeout_sec = DEFAULT_COMMAND_TIMEOUT_SEC;
+
+int riscv_get_command_timeout_sec(void)
+{
+ return MAX(riscv_command_timeout_sec_value, riscv_reset_timeout_sec);
+}
static bool riscv_enable_virt2phys = true;
@@ -481,38 +487,6 @@ static int riscv_init_target(struct command_context *cmd_ctx,
return ERROR_OK;
}
-static void free_reg_names(struct target *target);
-
-static void riscv_free_registers(struct target *target)
-{
- free_reg_names(target);
- /* Free the shared structure use for most registers. */
- if (!target->reg_cache)
- return;
- if (target->reg_cache->reg_list) {
- for (unsigned int i = GDB_REGNO_COUNT; i < target->reg_cache->num_regs; i++)
- free(target->reg_cache->reg_list[i].arch_info);
- for (unsigned int i = 0; i < target->reg_cache->num_regs; i++)
- free(target->reg_cache->reg_list[i].value);
- free(target->reg_cache->reg_list);
- }
- free(target->reg_cache);
- target->reg_cache = NULL;
-}
-
-static void free_custom_register_names(struct target *target)
-{
- RISCV_INFO(info);
-
- if (!info->custom_register_names.reg_names)
- return;
-
- for (unsigned int i = 0; i < info->custom_register_names.num_entries; i++)
- free(info->custom_register_names.reg_names[i]);
- free(info->custom_register_names.reg_names);
- info->custom_register_names.reg_names = NULL;
-}
-
static void free_wp_triggers_cache(struct target *target)
{
RISCV_INFO(r);
@@ -541,13 +515,13 @@ static void riscv_deinit_target(struct target *target)
if (!tt)
LOG_TARGET_ERROR(target, "Could not identify target type.");
- if (riscv_flush_registers(target) != ERROR_OK)
+ if (riscv_reg_flush_all(target) != ERROR_OK)
LOG_TARGET_ERROR(target, "Failed to flush registers. Ignoring this error.");
if (tt && info && info->version_specific)
tt->deinit_target(target);
- riscv_free_registers(target);
+ riscv_reg_free_all(target);
free_wp_triggers_cache(target);
if (!info)
@@ -648,25 +622,25 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat
{
riscv_reg_t tdata1_rb, tdata2_rb;
// Select which trigger to use
- if (riscv_set_register(target, GDB_REGNO_TSELECT, idx) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, idx) != ERROR_OK)
return ERROR_FAIL;
// Disable the trigger by writing 0 to it
- if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
return ERROR_FAIL;
// Set trigger data for tdata2 (and tdata3 if it was supported)
- if (riscv_set_register(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TDATA2, tdata2) != ERROR_OK)
return ERROR_FAIL;
// Set trigger data for tdata1
- if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1) != ERROR_OK)
return ERROR_FAIL;
// Read back tdata1, tdata2, (tdata3), and check if the configuration is supported
- if (riscv_get_register(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK)
+ if (riscv_reg_get(target, &tdata1_rb, GDB_REGNO_TDATA1) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_get_register(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK)
+ if (riscv_reg_get(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK)
return ERROR_FAIL;
bool tdata1_config_denied = (tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask);
bool tdata2_config_denied = tdata2 != tdata2_rb;
@@ -682,7 +656,7 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat
LOG_TARGET_DEBUG(target,
"wrote 0x%" PRIx64 " to tdata2 but read back 0x%" PRIx64,
tdata2, tdata2_rb);
- if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
return ERROR_FAIL;
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
@@ -712,7 +686,7 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger)
if (ret != ERROR_OK)
return ret;
- if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
+ if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
return ERROR_FAIL;
if (tdata1 & (bpcontrol_r | bpcontrol_w | bpcontrol_x)) {
/* Trigger is already in use, presumably by user code. */
@@ -1242,7 +1216,7 @@ static int add_trigger(struct target *target, struct trigger *trigger)
if (ret != ERROR_OK)
return ret;
- ret = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT);
+ ret = riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT);
if (ret != ERROR_OK)
return ret;
@@ -1260,7 +1234,7 @@ static int add_trigger(struct target *target, struct trigger *trigger)
break;
} while (0);
- if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK &&
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK &&
ret == ERROR_OK)
return ERROR_FAIL;
@@ -1444,15 +1418,15 @@ static int remove_trigger(struct target *target, int unique_id)
return ERROR_FAIL;
riscv_reg_t tselect;
- int result = riscv_get_register(target, &tselect, GDB_REGNO_TSELECT);
+ int result = riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT);
if (result != ERROR_OK)
return result;
bool done = false;
for (unsigned int i = 0; i < r->trigger_count; i++) {
if (r->trigger_unique_id[i] == unique_id) {
- riscv_set_register(target, GDB_REGNO_TSELECT, i);
- riscv_set_register(target, GDB_REGNO_TDATA1, 0);
+ riscv_reg_set(target, GDB_REGNO_TSELECT, i);
+ riscv_reg_set(target, GDB_REGNO_TDATA1, 0);
r->trigger_unique_id[i] = -1;
LOG_TARGET_DEBUG(target, "Stop using resource %d for bp %d",
i, unique_id);
@@ -1465,7 +1439,7 @@ static int remove_trigger(struct target *target, int unique_id)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
- riscv_set_register(target, GDB_REGNO_TSELECT, tselect);
+ riscv_reg_set(target, GDB_REGNO_TSELECT, tselect);
return ERROR_OK;
}
@@ -1566,7 +1540,7 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
RISCV_INFO(r);
riscv_reg_t tselect;
- if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
+ if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
return ERROR_FAIL;
*unique_id = RISCV_TRIGGER_HIT_NOT_FOUND;
@@ -1574,11 +1548,11 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
if (r->trigger_unique_id[i] == -1)
continue;
- if (riscv_set_register(target, GDB_REGNO_TSELECT, i) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, i) != ERROR_OK)
return ERROR_FAIL;
uint64_t tdata1;
- if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
+ if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
return ERROR_FAIL;
int type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target)));
@@ -1612,7 +1586,7 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
if (tdata1 & hit_mask) {
LOG_TARGET_DEBUG(target, "Trigger %u (unique_id=%" PRIi64 ") has hit bit set.",
i, r->trigger_unique_id[i]);
- if (riscv_set_register(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK)
return ERROR_FAIL;
*unique_id = r->trigger_unique_id[i];
@@ -1620,7 +1594,7 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_
}
}
- if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
return ERROR_FAIL;
return ERROR_OK;
@@ -2082,7 +2056,7 @@ static int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_w
}
riscv_reg_t dpc;
- if (riscv_get_register(target, &dpc, GDB_REGNO_DPC) != ERROR_OK)
+ if (riscv_reg_get(target, &dpc, GDB_REGNO_DPC) != ERROR_OK)
return ERROR_FAIL;
const uint8_t length = 4;
LOG_TARGET_DEBUG(target, "dpc is 0x%" PRIx64, dpc);
@@ -2109,7 +2083,7 @@ static int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_w
if (get_loadstore_membase_regno(target, instruction, &rs) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_get_register(target, &mem_addr, rs) != ERROR_OK)
+ if (riscv_reg_get(target, &mem_addr, rs) != ERROR_OK)
return ERROR_FAIL;
if (get_loadstore_memoffset(target, instruction, &memoffset) != ERROR_OK)
return ERROR_FAIL;
@@ -2239,44 +2213,6 @@ static int old_or_new_riscv_poll(struct target *target)
return riscv_openocd_poll(target);
}
-static struct reg *get_reg_cache_entry(const struct target *target,
- uint32_t number)
-{
- assert(target->reg_cache);
- assert(target->reg_cache->reg_list);
- assert(number < target->reg_cache->num_regs);
- return &target->reg_cache->reg_list[number];
-}
-
-int riscv_flush_registers(struct target *target)
-{
- RISCV_INFO(r);
-
- if (!target->reg_cache)
- return ERROR_OK;
-
- LOG_TARGET_DEBUG(target, "Flushing register cache");
-
- /* Writing non-GPR registers may require progbuf execution, and some GPRs
- * may become dirty in the process (e.g. S0, S1). For that reason, flush
- * registers in reverse order, so that GPRs are flushed last.
- */
- for (unsigned int number = target->reg_cache->num_regs; number-- > 0; ) {
- struct reg *reg = get_reg_cache_entry(target, number);
- if (reg->valid && reg->dirty) {
- riscv_reg_t value = buf_get_u64(reg->value, 0, reg->size);
-
- LOG_TARGET_DEBUG(target, "%s is dirty; write back 0x%" PRIx64,
- reg->name, value);
- if (r->set_register(target, number, value) != ERROR_OK)
- return ERROR_FAIL;
- reg->dirty = false;
- }
- }
- LOG_TARGET_DEBUG(target, "Flush of register cache completed");
- return ERROR_OK;
-}
-
static enum target_debug_reason
derive_debug_reason_without_hitbit(const struct target *target, riscv_reg_t dpc)
{
@@ -2352,7 +2288,7 @@ static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_r
LOG_TARGET_DEBUG(target,
"No trigger hit found, deriving debug reason without it.");
riscv_reg_t dpc;
- if (riscv_get_register(target, &dpc, GDB_REGNO_DPC) != ERROR_OK)
+ if (riscv_reg_get(target, &dpc, GDB_REGNO_DPC) != ERROR_OK)
return ERROR_FAIL;
/* Here we don't have the hit bit set (likely, HW does not support it).
* We are trying to guess the state. But here comes the problem:
@@ -2530,21 +2466,21 @@ static int disable_triggers(struct target *target, riscv_reg_t *state)
if (r->manual_hwbp_set) {
/* Look at every trigger that may have been set. */
riscv_reg_t tselect;
- if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
+ if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
return ERROR_FAIL;
for (unsigned int t = 0; t < r->trigger_count; t++) {
- if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, t) != ERROR_OK)
return ERROR_FAIL;
riscv_reg_t tdata1;
- if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
+ if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
return ERROR_FAIL;
if (tdata1 & CSR_TDATA1_DMODE(riscv_xlen(target))) {
state[t] = tdata1;
- if (riscv_set_register(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK)
return ERROR_FAIL;
}
}
- if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
return ERROR_FAIL;
} else {
@@ -2573,17 +2509,17 @@ static int enable_triggers(struct target *target, riscv_reg_t *state)
if (r->manual_hwbp_set) {
/* Look at every trigger that may have been set. */
riscv_reg_t tselect;
- if (riscv_get_register(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
+ if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK)
return ERROR_FAIL;
for (unsigned int t = 0; t < r->trigger_count; t++) {
if (state[t] != 0) {
- if (riscv_set_register(target, GDB_REGNO_TSELECT, t) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, t) != ERROR_OK)
return ERROR_FAIL;
- if (riscv_set_register(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK)
return ERROR_FAIL;
}
}
- if (riscv_set_register(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK)
return ERROR_FAIL;
} else {
@@ -2612,7 +2548,7 @@ static int resume_prep(struct target *target, int current,
assert(target->state == TARGET_HALTED);
RISCV_INFO(r);
- if (!current && riscv_set_register(target, GDB_REGNO_PC, address) != ERROR_OK)
+ if (!current && riscv_reg_set(target, GDB_REGNO_PC, address) != ERROR_OK)
return ERROR_FAIL;
if (handle_breakpoints) {
@@ -2753,14 +2689,14 @@ static int riscv_target_resume(struct target *target, int current,
static int riscv_effective_privilege_mode(struct target *target, int *v_mode, int *effective_mode)
{
riscv_reg_t priv;
- if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
+ if (riscv_reg_get(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read priv register.");
return ERROR_FAIL;
}
*v_mode = get_field(priv, VIRT_PRIV_V);
riscv_reg_t mstatus;
- if (riscv_get_register(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) {
+ if (riscv_reg_get(target, &mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read mstatus register.");
return ERROR_FAIL;
}
@@ -2784,7 +2720,7 @@ static int riscv_mmu(struct target *target, int *enabled)
/* Don't use MMU in explicit or effective M (machine) mode */
riscv_reg_t priv;
- if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
+ if (riscv_reg_get(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read priv register.");
return ERROR_FAIL;
}
@@ -2802,7 +2738,7 @@ static int riscv_mmu(struct target *target, int *enabled)
* effective privilege mode is U and hstatus.HU=0. */
if (effective_mode == PRV_U) {
riscv_reg_t hstatus;
- if (riscv_get_register(target, &hstatus, GDB_REGNO_HSTATUS) != ERROR_OK) {
+ if (riscv_reg_get(target, &hstatus, GDB_REGNO_HSTATUS) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read hstatus register.");
return ERROR_FAIL;
}
@@ -2815,7 +2751,7 @@ static int riscv_mmu(struct target *target, int *enabled)
}
riscv_reg_t vsatp;
- if (riscv_get_register(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) {
+ if (riscv_reg_get(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read vsatp register; priv=0x%" PRIx64,
priv);
return ERROR_FAIL;
@@ -2828,7 +2764,7 @@ static int riscv_mmu(struct target *target, int *enabled)
}
riscv_reg_t hgatp;
- if (riscv_get_register(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) {
+ if (riscv_reg_get(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read hgatp register; priv=0x%" PRIx64,
priv);
return ERROR_FAIL;
@@ -2850,7 +2786,7 @@ static int riscv_mmu(struct target *target, int *enabled)
}
riscv_reg_t satp;
- if (riscv_get_register(target, &satp, GDB_REGNO_SATP) != ERROR_OK) {
+ if (riscv_reg_get(target, &satp, GDB_REGNO_SATP) != ERROR_OK) {
LOG_TARGET_DEBUG(target, "Couldn't read SATP.");
/* If we can't read SATP, then there must not be an MMU. */
return ERROR_OK;
@@ -2961,7 +2897,7 @@ static int riscv_address_translate(struct target *target,
static int riscv_virt2phys_v(struct target *target, target_addr_t virtual, target_addr_t *physical)
{
riscv_reg_t vsatp;
- if (riscv_get_register(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) {
+ if (riscv_reg_get(target, &vsatp, GDB_REGNO_VSATP) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read vsatp register.");
return ERROR_FAIL;
}
@@ -2970,7 +2906,7 @@ static int riscv_virt2phys_v(struct target *target, target_addr_t virtual, targe
int vsatp_mode = get_field(vsatp, RISCV_SATP_MODE(xlen));
LOG_TARGET_DEBUG(target, "VS-stage translation mode: %d", vsatp_mode);
riscv_reg_t hgatp;
- if (riscv_get_register(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) {
+ if (riscv_reg_get(target, &hgatp, GDB_REGNO_HGATP) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read hgatp register.");
return ERROR_FAIL;
}
@@ -3080,7 +3016,7 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_
}
riscv_reg_t priv;
- if (riscv_get_register(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
+ if (riscv_reg_get(target, &priv, GDB_REGNO_PRIV) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read priv register.");
return ERROR_FAIL;
}
@@ -3089,7 +3025,7 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_
return riscv_virt2phys_v(target, virtual, physical);
riscv_reg_t satp_value;
- if (riscv_get_register(target, &satp_value, GDB_REGNO_SATP) != ERROR_OK) {
+ if (riscv_reg_get(target, &satp_value, GDB_REGNO_SATP) != ERROR_OK) {
LOG_TARGET_ERROR(target, "Failed to read SATP register.");
return ERROR_FAIL;
}
@@ -3366,10 +3302,10 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params,
for (unsigned i = 0; i < ARRAY_SIZE(regnums); i++) {
enum gdb_regno regno = regnums[i];
riscv_reg_t reg_value;
- if (riscv_get_register(target, &reg_value, regno) != ERROR_OK)
+ if (riscv_reg_get(target, &reg_value, regno) != ERROR_OK)
break;
- LOG_TARGET_ERROR(target, "%s = 0x%" PRIx64, gdb_regno_name(target, regno), reg_value);
+ LOG_TARGET_ERROR(target, "%s = 0x%" PRIx64, riscv_reg_gdb_regno_name(target, regno), reg_value);
}
return ERROR_TARGET_TIMEOUT;
}
@@ -3578,7 +3514,7 @@ static int riscv_poll_hart(struct target *target, enum riscv_next_action *next_a
if (state == RISCV_STATE_HALTED && timeval_ms() - r->last_activity > 100) {
/* If we've been idle for a while, flush the register cache. Just in case
* OpenOCD is going to be disconnected without shutting down cleanly. */
- if (riscv_flush_registers(target) != ERROR_OK)
+ if (riscv_reg_flush_all(target) != ERROR_OK)
return ERROR_FAIL;
}
@@ -3829,7 +3765,7 @@ static int riscv_openocd_step_impl(struct target *target, int current,
LOG_TARGET_DEBUG(target, "stepping hart");
if (!current) {
- if (riscv_set_register(target, GDB_REGNO_PC, address) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_PC, address) != ERROR_OK)
return ERROR_FAIL;
}
@@ -3837,7 +3773,7 @@ static int riscv_openocd_step_impl(struct target *target, int current,
/* the front-end may request us not to handle breakpoints */
if (handle_breakpoints) {
if (current) {
- if (riscv_get_register(target, &address, GDB_REGNO_PC) != ERROR_OK)
+ if (riscv_reg_get(target, &address, GDB_REGNO_PC) != ERROR_OK)
return ERROR_FAIL;
}
breakpoint = breakpoint_find(target, address);
@@ -3922,13 +3858,14 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec)
return ERROR_FAIL;
}
- riscv_command_timeout_sec = timeout;
+ riscv_command_timeout_sec_value = timeout;
return ERROR_OK;
}
COMMAND_HANDLER(riscv_set_reset_timeout_sec)
{
+ LOG_WARNING("The command 'riscv set_reset_timeout_sec' is deprecated! Please, use 'riscv set_command_timeout_sec'.");
if (CMD_ARGC != 1) {
LOG_ERROR("Command takes exactly 1 parameter.");
return ERROR_COMMAND_SYNTAX_ERROR;
@@ -5036,7 +4973,7 @@ COMMAND_HANDLER(riscv_exec_progbuf)
return ERROR_FAIL;
}
- if (riscv_flush_registers(target) != ERROR_OK)
+ if (riscv_reg_flush_all(target) != ERROR_OK)
return ERROR_FAIL;
int error = riscv_program_exec(&prog, target);
riscv_invalidate_register_cache(target);
@@ -5135,7 +5072,7 @@ static const struct command_registration riscv_exec_command_handlers[] = {
.handler = riscv_set_reset_timeout_sec,
.mode = COMMAND_ANY,
.usage = "[sec]",
- .help = "Set the wall-clock timeout (in seconds) after reset is deasserted"
+ .help = "DEPRECATED. Use 'riscv set_command_timeout_sec' instead."
},
{
.name = "set_mem_access",
@@ -5608,253 +5545,6 @@ static void riscv_invalidate_register_cache(struct target *target)
register_cache_invalidate(target->reg_cache);
}
-
-/**
- * If write is true:
- * return true iff we are guaranteed that the register will contain exactly
- * the value we just wrote when it's read.
- * If write is false:
- * return true iff we are guaranteed that the register will read the same
- * value in the future as the value we just read.
- */
-static bool gdb_regno_cacheable(enum gdb_regno regno, bool is_write)
-{
- if (regno == GDB_REGNO_ZERO)
- return !is_write;
-
- /* GPRs, FPRs, vector registers are just normal data stores. */
- if (regno <= GDB_REGNO_XPR31 ||
- (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) ||
- (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31))
- return true;
-
- /* Most CSRs won't change value on us, but we can't assume it about arbitrary
- * CSRs. */
- switch (regno) {
- case GDB_REGNO_DPC:
- case GDB_REGNO_VSTART:
- case GDB_REGNO_VXSAT:
- case GDB_REGNO_VXRM:
- case GDB_REGNO_VLENB:
- case GDB_REGNO_VL:
- case GDB_REGNO_VTYPE:
- case GDB_REGNO_MISA:
- case GDB_REGNO_DCSR:
- case GDB_REGNO_DSCRATCH0:
- case GDB_REGNO_MSTATUS:
- case GDB_REGNO_MEPC:
- case GDB_REGNO_MCAUSE:
- case GDB_REGNO_SATP:
- /*
- * WARL registers might not contain the value we just wrote, but
- * these ones won't spontaneously change their value either. *
- */
- return !is_write;
-
- case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */
- case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */
- case GDB_REGNO_TDATA2: /* Changes value when tselect is changed. */
- default:
- return false;
- }
-}
-
-/**
- * This function is used internally by functions that change register values.
- * If `write_through` is true, it is ensured that the value of the target's
- * register is set to be equal to the `value` argument. The cached value is
- * updated if the register is cacheable.
- */
-static int riscv_set_or_write_register(struct target *target,
- enum gdb_regno regid, riscv_reg_t value, bool write_through)
-{
- RISCV_INFO(r);
- assert(r);
- assert(r->set_register);
- if (r->dtm_version == DTM_DTMCS_VERSION_0_11)
- return r->set_register(target, regid, value);
-
- keep_alive();
-
- if (regid == GDB_REGNO_PC) {
- return riscv_set_or_write_register(target, GDB_REGNO_DPC, value, write_through);
- } else if (regid == GDB_REGNO_PRIV) {
- riscv_reg_t dcsr;
-
- if (riscv_get_register(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
- return ERROR_FAIL;
- dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV));
- dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V));
- return riscv_set_or_write_register(target, GDB_REGNO_DCSR, dcsr, write_through);
- }
-
- if (!target->reg_cache) {
- assert(!target_was_examined(target));
- LOG_TARGET_DEBUG(target,
- "No cache, writing to target: %s <- 0x%" PRIx64,
- gdb_regno_name(target, regid), value);
- return r->set_register(target, regid, value);
- }
-
- struct reg *reg = get_reg_cache_entry(target, regid);
-
- if (!reg->exist) {
- LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name);
- return ERROR_FAIL;
- }
-
- if (target->state != TARGET_HALTED) {
- LOG_TARGET_DEBUG(target,
- "Target not halted, writing to target: %s <- 0x%" PRIx64,
- reg->name, value);
- return r->set_register(target, regid, value);
- }
-
- const bool need_to_write = !reg->valid || reg->dirty ||
- value != buf_get_u64(reg->value, 0, reg->size);
- const bool cacheable = gdb_regno_cacheable(regid, need_to_write);
-
- if (!cacheable || (write_through && need_to_write)) {
- LOG_TARGET_DEBUG(target,
- "Writing to target: %s <- 0x%" PRIx64 " (cacheable=%s, valid=%s, dirty=%s)",
- reg->name, value, cacheable ? "true" : "false",
- reg->valid ? "true" : "false",
- reg->dirty ? "true" : "false");
- if (r->set_register(target, regid, value) != ERROR_OK)
- return ERROR_FAIL;
-
- reg->dirty = false;
- } else {
- reg->dirty = need_to_write;
- }
-
- buf_set_u64(reg->value, 0, reg->size, value);
- reg->valid = cacheable;
-
- LOG_TARGET_DEBUG(target,
- "Wrote 0x%" PRIx64 " to %s (cacheable=%s, valid=%s, dirty=%s)",
- value, reg->name, cacheable ? "true" : "false",
- reg->valid ? "true" : "false",
- reg->dirty ? "true" : "false");
- return ERROR_OK;
-}
-
-/**
- * This function is used to change the value of a register. The new value may
- * be cached, and may not be written until the hart is resumed.
- */
-int riscv_set_register(struct target *target, enum gdb_regno regid,
- riscv_reg_t value)
-{
- return riscv_set_or_write_register(target, regid, value,
- /* write_through */ false);
-}
-
-/**
- * This function is used to change the value of a register. The new value may
- * be cached, but it will be written to hart immediately.
- */
-int riscv_write_register(struct target *target, enum gdb_regno regid,
- riscv_reg_t value)
-{
- return riscv_set_or_write_register(target, regid, value,
- /* write_through */ true);
-}
-
-/**
- * This function is used to get the value of a register. If possible, the value
- * in cache will be updated.
- */
-int riscv_get_register(struct target *target, riscv_reg_t *value,
- enum gdb_regno regid)
-{
- RISCV_INFO(r);
- assert(r);
- assert(r->get_register);
- if (r->dtm_version == DTM_DTMCS_VERSION_0_11)
- return r->get_register(target, value, regid);
-
- keep_alive();
-
- if (regid == GDB_REGNO_PC)
- return riscv_get_register(target, value, GDB_REGNO_DPC);
-
- if (!target->reg_cache) {
- assert(!target_was_examined(target));
- LOG_TARGET_DEBUG(target, "No cache, reading %s from target",
- gdb_regno_name(target, regid));
- return r->get_register(target, value, regid);
- }
-
- struct reg *reg = get_reg_cache_entry(target, regid);
- if (!reg->exist) {
- LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name);
- return ERROR_FAIL;
- }
-
- if (reg->valid) {
- *value = buf_get_u64(reg->value, 0, reg->size);
- LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64 " (cached)", reg->name,
- *value);
- return ERROR_OK;
- }
-
- LOG_TARGET_DEBUG(target, "Reading %s from target", reg->name);
- if (r->get_register(target, value, regid) != ERROR_OK)
- return ERROR_FAIL;
-
- buf_set_u64(reg->value, 0, reg->size, *value);
- reg->valid = gdb_regno_cacheable(regid, /* is write? */ false) &&
- target->state == TARGET_HALTED;
- reg->dirty = false;
-
- LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64, reg->name, *value);
- return ERROR_OK;
-}
-
-/**
- * This function is used to save the value of a register in cache. The register
- * is marked as dirty, and writeback is delayed for as long as possible.
- */
-int riscv_save_register(struct target *target, enum gdb_regno regid)
-{
- if (target->state != TARGET_HALTED) {
- LOG_TARGET_ERROR(target, "Can't save register %s on a hart that is not halted.",
- gdb_regno_name(target, regid));
- return ERROR_FAIL;
- }
- assert(gdb_regno_cacheable(regid, /* is write? */ false) &&
- "Only cacheable registers can be saved.");
-
- RISCV_INFO(r);
- riscv_reg_t value;
- if (!target->reg_cache) {
- assert(!target_was_examined(target));
- /* To create register cache it is needed to examine the target first,
- * therefore during examine, any changed register needs to be saved
- * and restored manually.
- */
- return ERROR_OK;
- }
-
- struct reg *reg = get_reg_cache_entry(target, regid);
-
- LOG_TARGET_DEBUG(target, "Saving %s", reg->name);
- if (riscv_get_register(target, &value, regid) != ERROR_OK)
- return ERROR_FAIL;
-
- assert(reg->valid &&
- "The register is cacheable, so the cache entry must be valid now.");
- /* Mark the register dirty. We assume that this function is called
- * because the caller is about to mess with the underlying value of the
- * register. */
- reg->dirty = true;
-
- r->last_activity = timeval_ms();
-
- return ERROR_OK;
-}
-
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state)
{
RISCV_INFO(r);
@@ -5924,10 +5614,10 @@ int riscv_get_dmi_scan_length(struct target *target)
static int check_if_trigger_exists(struct target *target, unsigned int index)
{
/* If we can't write tselect, then this hart does not support triggers. */
- if (riscv_set_register(target, GDB_REGNO_TSELECT, index) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, index) != ERROR_OK)
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
riscv_reg_t tselect_rb;
- if (riscv_get_register(target, &tselect_rb, GDB_REGNO_TSELECT) != ERROR_OK)
+ if (riscv_reg_get(target, &tselect_rb, GDB_REGNO_TSELECT) != ERROR_OK)
return ERROR_FAIL;
/* Mask off the top bit, which is used as tdrmode in legacy RISC-V Debug Spec
* (old revisions of v0.11 spec). */
@@ -5947,7 +5637,7 @@ static int get_trigger_types(struct target *target, unsigned int *trigger_tinfo,
{
assert(trigger_tinfo);
riscv_reg_t tinfo;
- if (riscv_get_register(target, &tinfo, GDB_REGNO_TINFO) == ERROR_OK) {
+ if (riscv_reg_get(target, &tinfo, GDB_REGNO_TINFO) == ERROR_OK) {
/* tinfo.INFO == 1: trigger doesn’t exist
* tinfo == 0 or tinfo.INFO != 1 and tinfo LSB is set: invalid tinfo */
if (tinfo == 0 || tinfo & 0x1)
@@ -5990,7 +5680,7 @@ static int disable_trigger_if_dmode(struct target *target, riscv_reg_t tdata1)
if (!dmode_is_set)
/* Nothing to do */
return ERROR_OK;
- return riscv_set_register(target, GDB_REGNO_TDATA1, 0);
+ return riscv_reg_set(target, GDB_REGNO_TDATA1, 0);
}
/**
@@ -6013,7 +5703,7 @@ int riscv_enumerate_triggers(struct target *target)
}
riscv_reg_t orig_tselect;
- int result = riscv_get_register(target, &orig_tselect, GDB_REGNO_TSELECT);
+ int result = riscv_reg_get(target, &orig_tselect, GDB_REGNO_TSELECT);
/* If tselect is not readable, the trigger module is likely not
* implemented. */
if (result != ERROR_OK) {
@@ -6033,7 +5723,7 @@ int riscv_enumerate_triggers(struct target *target)
break;
riscv_reg_t tdata1;
- if (riscv_get_register(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
+ if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK)
return ERROR_FAIL;
result = get_trigger_types(target, &r->trigger_tinfo[t], tdata1);
@@ -6049,7 +5739,7 @@ int riscv_enumerate_triggers(struct target *target)
return ERROR_FAIL;
}
- if (riscv_set_register(target, GDB_REGNO_TSELECT, orig_tselect) != ERROR_OK)
+ if (riscv_reg_set(target, GDB_REGNO_TSELECT, orig_tselect) != ERROR_OK)
return ERROR_FAIL;
r->triggers_enumerated = true;
@@ -6059,1006 +5749,6 @@ int riscv_enumerate_triggers(struct target *target)
return ERROR_OK;
}
-static char *init_reg_name(const char *name)
-{
- const int size_buf = strlen(name) + 1;
-
- char * const buf = calloc(size_buf, sizeof(char));
- if (!buf) {
- LOG_ERROR("Failed to allocate memory for a register name.");
- return NULL;
- }
- strcpy(buf, name);
- return buf;
-}
-
-static char *init_reg_name_with_prefix(const char *name_prefix,
- unsigned int num)
-{
- const int size_buf = snprintf(NULL, 0, "%s%d", name_prefix, num) + 1;
-
- char * const buf = calloc(size_buf, sizeof(char));
- if (!buf) {
- LOG_ERROR("Failed to allocate memory for a register name.");
- return NULL;
- }
- int result = snprintf(buf, size_buf, "%s%d", name_prefix, num);
- assert(result > 0 && result <= (size_buf - 1));
- return buf;
-}
-
-static const char * const default_reg_names[GDB_REGNO_COUNT] = {
- [GDB_REGNO_ZERO] = "zero",
- [GDB_REGNO_RA] = "ra",
- [GDB_REGNO_SP] = "sp",
- [GDB_REGNO_GP] = "gp",
- [GDB_REGNO_TP] = "tp",
- [GDB_REGNO_T0] = "t0",
- [GDB_REGNO_T1] = "t1",
- [GDB_REGNO_T2] = "t2",
- [GDB_REGNO_FP] = "fp",
- [GDB_REGNO_S1] = "s1",
- [GDB_REGNO_A0] = "a0",
- [GDB_REGNO_A1] = "a1",
- [GDB_REGNO_A2] = "a2",
- [GDB_REGNO_A3] = "a3",
- [GDB_REGNO_A4] = "a4",
- [GDB_REGNO_A5] = "a5",
- [GDB_REGNO_A6] = "a6",
- [GDB_REGNO_A7] = "a7",
- [GDB_REGNO_S2] = "s2",
- [GDB_REGNO_S3] = "s3",
- [GDB_REGNO_S4] = "s4",
- [GDB_REGNO_S5] = "s5",
- [GDB_REGNO_S6] = "s6",
- [GDB_REGNO_S7] = "s7",
- [GDB_REGNO_S8] = "s8",
- [GDB_REGNO_S9] = "s9",
- [GDB_REGNO_S10] = "s10",
- [GDB_REGNO_S11] = "s11",
- [GDB_REGNO_T3] = "t3",
- [GDB_REGNO_T4] = "t4",
- [GDB_REGNO_T5] = "t5",
- [GDB_REGNO_T6] = "t6",
- [GDB_REGNO_PC] = "pc",
- [GDB_REGNO_CSR0] = "csr0",
- [GDB_REGNO_PRIV] = "priv",
- [GDB_REGNO_FT0] = "ft0",
- [GDB_REGNO_FT1] = "ft1",
- [GDB_REGNO_FT2] = "ft2",
- [GDB_REGNO_FT3] = "ft3",
- [GDB_REGNO_FT4] = "ft4",
- [GDB_REGNO_FT5] = "ft5",
- [GDB_REGNO_FT6] = "ft6",
- [GDB_REGNO_FT7] = "ft7",
- [GDB_REGNO_FS0] = "fs0",
- [GDB_REGNO_FS1] = "fs1",
- [GDB_REGNO_FA0] = "fa0",
- [GDB_REGNO_FA1] = "fa1",
- [GDB_REGNO_FA2] = "fa2",
- [GDB_REGNO_FA3] = "fa3",
- [GDB_REGNO_FA4] = "fa4",
- [GDB_REGNO_FA5] = "fa5",
- [GDB_REGNO_FA6] = "fa6",
- [GDB_REGNO_FA7] = "fa7",
- [GDB_REGNO_FS2] = "fs2",
- [GDB_REGNO_FS3] = "fs3",
- [GDB_REGNO_FS4] = "fs4",
- [GDB_REGNO_FS5] = "fs5",
- [GDB_REGNO_FS6] = "fs6",
- [GDB_REGNO_FS7] = "fs7",
- [GDB_REGNO_FS8] = "fs8",
- [GDB_REGNO_FS9] = "fs9",
- [GDB_REGNO_FS10] = "fs10",
- [GDB_REGNO_FS11] = "fs11",
- [GDB_REGNO_FT8] = "ft8",
- [GDB_REGNO_FT9] = "ft9",
- [GDB_REGNO_FT10] = "ft10",
- [GDB_REGNO_FT11] = "ft11",
-
- #define DECLARE_CSR(csr_name, number)[(number) + GDB_REGNO_CSR0] = #csr_name,
- #include "encoding.h"
- #undef DECLARE_CSR
-};
-
-static void free_reg_names(struct target *target)
-{
- RISCV_INFO(info);
-
- if (!info->reg_names)
- return;
-
- for (unsigned int i = 0; i < GDB_REGNO_COUNT; ++i)
- free(info->reg_names[i]);
- free(info->reg_names);
- info->reg_names = NULL;
-
- free_custom_register_names(target);
-}
-
-static void init_custom_csr_names(const struct target *target)
-{
- RISCV_INFO(info);
- range_list_t *entry;
-
- list_for_each_entry(entry, &info->expose_csr, list) {
- if (!entry->name)
- continue;
- assert(entry->low == entry->high);
- const unsigned int regno = entry->low + GDB_REGNO_CSR0;
- assert(regno <= GDB_REGNO_CSR4095);
- if (info->reg_names[regno])
- return;
- info->reg_names[regno] = init_reg_name(entry->name);
- }
-}
-
-const char *gdb_regno_name(const struct target *target, enum gdb_regno regno)
-{
- RISCV_INFO(info);
-
- if (regno >= GDB_REGNO_COUNT) {
- assert(info->custom_register_names.reg_names);
- assert(regno - GDB_REGNO_COUNT <= info->custom_register_names.num_entries);
- return info->custom_register_names.reg_names[regno - GDB_REGNO_COUNT];
- }
-
- if (!info->reg_names)
- info->reg_names = calloc(GDB_REGNO_COUNT, sizeof(char *));
-
- if (info->reg_names[regno])
- return info->reg_names[regno];
- if (default_reg_names[regno])
- return default_reg_names[regno];
- if (regno <= GDB_REGNO_XPR31) {
- info->reg_names[regno] = init_reg_name_with_prefix("x", regno - GDB_REGNO_ZERO);
- return info->reg_names[regno];
- }
- if (regno <= GDB_REGNO_V31 && regno >= GDB_REGNO_V0) {
- info->reg_names[regno] = init_reg_name_with_prefix("v", regno - GDB_REGNO_V0);
- return info->reg_names[regno];
- }
- if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
- init_custom_csr_names(target);
- info->reg_names[regno] = init_reg_name_with_prefix("csr", regno - GDB_REGNO_CSR0);
- return info->reg_names[regno];
- }
- assert(!"Encountered uninitialized entry in reg_names table");
-
- return NULL;
-}
-
-static struct target *get_target_from_reg(const struct reg *reg);
-
-/**
- * This function is the handler of user's request to read a register.
- */
-static int riscv013_reg_get(struct reg *reg)
-{
- struct target *target = get_target_from_reg(reg);
- RISCV_INFO(r);
- assert(r);
- assert(r->dtm_version == DTM_DTMCS_VERSION_1_0);
-
- /* TODO: Hack to deal with gdb that thinks these registers still exist. */
- if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 &&
- riscv_supports_extension(target, 'E')) {
- buf_set_u64(reg->value, 0, reg->size, 0);
- return ERROR_OK;
- }
-
- if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
- if (!r->get_register_buf) {
- LOG_TARGET_ERROR(target,
- "Reading register %s not supported on this target.",
- reg->name);
- return ERROR_FAIL;
- }
-
- if (r->get_register_buf(target, reg->value, reg->number) != ERROR_OK)
- return ERROR_FAIL;
-
- reg->valid = gdb_regno_cacheable(reg->number, /* is write? */ false);
- } else {
- 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);
- }
- char *str = buf_to_hex_str(reg->value, reg->size);
- LOG_TARGET_DEBUG(target, "Read 0x%s from %s (valid=%d).", str, reg->name,
- reg->valid);
- free(str);
- return ERROR_OK;
-}
-
-/**
- * This function is the handler of user's request to write a register.
- */
-static int riscv013_reg_set(struct reg *reg, uint8_t *buf)
-{
- struct target *target = get_target_from_reg(reg);
- RISCV_INFO(r);
- assert(r);
- assert(r->dtm_version == DTM_DTMCS_VERSION_1_0);
-
- char *str = buf_to_hex_str(buf, reg->size);
- LOG_TARGET_DEBUG(target, "Write 0x%s to %s (valid=%d).", str, reg->name,
- reg->valid);
- free(str);
-
- /* TODO: Hack to deal with gdb that thinks these registers still exist. */
- if (reg->number > GDB_REGNO_XPR15 && reg->number <= GDB_REGNO_XPR31 &&
- riscv_supports_extension(target, 'E') &&
- buf_get_u64(buf, 0, reg->size) == 0)
- return ERROR_OK;
-
- if (reg->number == GDB_REGNO_TDATA1 ||
- reg->number == GDB_REGNO_TDATA2) {
- r->manual_hwbp_set = true;
- /* When enumerating triggers, we clear any triggers with DMODE set,
- * assuming they were left over from a previous debug session. So make
- * sure that is done before a user might be setting their own triggers.
- */
- if (riscv_enumerate_triggers(target) != ERROR_OK)
- return ERROR_FAIL;
- }
-
- if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) {
- if (!r->set_register_buf) {
- LOG_TARGET_ERROR(target,
- "Writing register %s not supported on this target.",
- reg->name);
- return ERROR_FAIL;
- }
-
- if (r->set_register_buf(target, reg->number, buf) != ERROR_OK)
- return ERROR_FAIL;
-
- memcpy(reg->value, buf, DIV_ROUND_UP(reg->size, 8));
- reg->valid = gdb_regno_cacheable(reg->number, /* is write? */ true);
- } else {
- const riscv_reg_t value = buf_get_u64(buf, 0, reg->size);
- if (riscv_set_register(target, reg->number, value) != ERROR_OK)
- return ERROR_FAIL;
- }
-
- return ERROR_OK;
-}
-
-static int init_custom_register_names(struct list_head *expose_custom,
- struct reg_name_table *custom_register_names)
-{
- unsigned int custom_regs_num = 0;
- if (!list_empty(expose_custom)) {
- range_list_t *entry;
- list_for_each_entry(entry, expose_custom, list)
- custom_regs_num += entry->high - entry->low + 1;
- }
-
- if (!custom_regs_num)
- return ERROR_OK;
-
- custom_register_names->reg_names = calloc(custom_regs_num, sizeof(char *));
- if (!custom_register_names->reg_names) {
- LOG_ERROR("Failed to allocate memory for custom_register_names->reg_names");
- return ERROR_FAIL;
- }
- custom_register_names->num_entries = custom_regs_num;
- char **reg_names = custom_register_names->reg_names;
- range_list_t *range;
- unsigned int next_custom_reg_index = 0;
- list_for_each_entry(range, expose_custom, list) {
- for (unsigned int custom_number = range->low; custom_number <= range->high; ++custom_number) {
- if (range->name)
- reg_names[next_custom_reg_index] = init_reg_name(range->name);
- else
- reg_names[next_custom_reg_index] =
- init_reg_name_with_prefix("custom", custom_number);
-
- if (!reg_names[next_custom_reg_index])
- return ERROR_FAIL;
- ++next_custom_reg_index;
- }
- }
- return ERROR_OK;
-}
-
-static bool is_known_standard_csr(unsigned int csr_num)
-{
- static const bool is_csr_in_buf[GDB_REGNO_CSR4095 - GDB_REGNO_CSR0 + 1] = {
- #define DECLARE_CSR(csr_name, number)[number] = true,
- #include "encoding.h"
- #undef DECLARE_CSR
- };
- assert(csr_num < ARRAY_SIZE(is_csr_in_buf));
-
- return is_csr_in_buf[csr_num];
-}
-
-static bool reg_is_initialized(const struct reg *reg)
-{
- assert(reg);
- if (!reg->feature) {
- const struct reg default_reg = {0};
- assert(!memcmp(&default_reg, reg, sizeof(*reg)));
- return false;
- }
- assert(reg->arch_info);
- assert(((riscv_reg_info_t *)reg->arch_info)->target);
- assert((!reg->exist && !reg->value) || (reg->exist && reg->value));
- assert(reg->valid || !reg->dirty);
- return true;
-}
-
-static struct target *get_target_from_reg(const struct reg *reg)
-{
- assert(reg_is_initialized(reg));
- return ((const riscv_reg_info_t *)reg->arch_info)->target;
-}
-
-static int riscv011_reg_get(struct reg *reg)
-{
- struct target * const target = get_target_from_reg(reg);
- RISCV_INFO(r);
- assert(r);
- assert(r->dtm_version == DTM_DTMCS_VERSION_0_11);
- riscv_reg_t value;
- const int result = r->get_register(target, &value, reg->number);
- if (result != ERROR_OK)
- return result;
- buf_set_u64(reg->value, 0, reg->size, value);
- return ERROR_OK;
-}
-
-static int riscv011_reg_set(struct reg *reg, uint8_t *buf)
-{
- const riscv_reg_t value = buf_get_u64(buf, 0, reg->size);
- struct target * const target = get_target_from_reg(reg);
- RISCV_INFO(r);
- assert(r);
- assert(r->dtm_version == DTM_DTMCS_VERSION_0_11);
- if (reg->number == GDB_REGNO_TDATA1 || reg->number == GDB_REGNO_TDATA2) {
- r->manual_hwbp_set = true;
- /* When enumerating triggers, we clear any triggers with DMODE set,
- * assuming they were left over from a previous debug session. So make
- * sure that is done before a user might be setting their own triggers.
- */
- if (riscv_enumerate_triggers(target) != ERROR_OK)
- return ERROR_FAIL;
- }
- return r->set_register(target, reg->number, value);
-}
-
-static struct reg_arch_type *gdb_regno_reg_type(const struct target *target,
- uint32_t regno)
-{
- RISCV_INFO(info);
- assert(info);
- if (info->dtm_version == DTM_DTMCS_VERSION_0_11) {
- static struct reg_arch_type riscv011_reg_type = {
- .get = riscv011_reg_get,
- .set = riscv011_reg_set
- };
- return &riscv011_reg_type;
- }
-
- static struct reg_arch_type riscv013_reg_type = {
- .get = riscv013_reg_get,
- .set = riscv013_reg_set
- };
- return &riscv013_reg_type;
-}
-
-static struct reg_feature *gdb_regno_feature(uint32_t regno)
-{
- if (regno <= GDB_REGNO_XPR31 || regno == GDB_REGNO_PC) {
- static struct reg_feature feature_cpu = {
- .name = "org.gnu.gdb.riscv.cpu"
- };
- return &feature_cpu;
- }
- if ((regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) ||
- regno == GDB_REGNO_FFLAGS ||
- regno == GDB_REGNO_FRM ||
- regno == GDB_REGNO_FCSR) {
- static struct reg_feature feature_fpu = {
- .name = "org.gnu.gdb.riscv.fpu"
- };
- return &feature_fpu;
- }
- if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) {
- static struct reg_feature feature_vector = {
- .name = "org.gnu.gdb.riscv.vector"
- };
- return &feature_vector;
- }
- if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
- static struct reg_feature feature_csr = {
- .name = "org.gnu.gdb.riscv.csr"
- };
- return &feature_csr;
- }
- if (regno == GDB_REGNO_PRIV) {
- static struct reg_feature feature_virtual = {
- .name = "org.gnu.gdb.riscv.virtual"
- };
- return &feature_virtual;
- }
- assert(regno >= GDB_REGNO_COUNT);
- static struct reg_feature feature_custom = {
- .name = "org.gnu.gdb.riscv.custom"
- };
- return &feature_custom;
-}
-
-static bool gdb_regno_caller_save(uint32_t regno)
-{
- return regno <= GDB_REGNO_XPR31 ||
- regno == GDB_REGNO_PC ||
- (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31);
-}
-
-static struct reg_data_type *gdb_regno_reg_data_type(const struct target *target,
- uint32_t regno)
-{
- if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) {
- 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"
- };
- static struct reg_data_type_union_field single_double_fields[] = {
- {"float", &type_ieee_single, single_double_fields + 1},
- {"double", &type_ieee_double, NULL},
- };
- static struct reg_data_type_union single_double_union = {
- .fields = single_double_fields
- };
- static struct reg_data_type type_ieee_single_double = {
- .type = REG_TYPE_ARCH_DEFINED,
- .id = "FPU_FD",
- .type_class = REG_TYPE_CLASS_UNION,
- {.reg_type_union = &single_double_union}
- };
- return riscv_supports_extension(target, 'D') ?
- &type_ieee_single_double :
- &type_ieee_single;
- }
- if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) {
- RISCV_INFO(info);
- return &info->type_vector;
- }
- return NULL;
-}
-
-static const char *gdb_regno_group(uint32_t regno)
-{
- if (regno <= GDB_REGNO_XPR31 ||
- regno == GDB_REGNO_PC ||
- regno == GDB_REGNO_PRIV)
- return "general";
- if ((regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) ||
- regno == GDB_REGNO_FFLAGS ||
- regno == GDB_REGNO_FRM ||
- regno == GDB_REGNO_FCSR)
- return "float";
- if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095)
- return "csr";
- if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)
- return "vector";
- assert(regno >= GDB_REGNO_COUNT);
- return "custom";
-}
-
-uint32_t gdb_regno_size(const struct target *target, uint32_t regno)
-{
- if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31)
- return riscv_supports_extension(target, 'D') ? 64 : 32;
- if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)
- return riscv_vlenb(target) * 8;
- if (regno == GDB_REGNO_PRIV)
- return 8;
- if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
- const unsigned int csr_number = regno - GDB_REGNO_CSR0;
- switch (csr_number) {
- case CSR_DCSR:
- case CSR_MVENDORID:
- case CSR_MCOUNTINHIBIT:
-
- case CSR_FFLAGS:
- case CSR_FRM:
- case CSR_FCSR:
-
- case CSR_SCOUNTEREN:
- case CSR_MCOUNTEREN:
- return 32;
- }
- }
- return riscv_xlen(target);
-}
-
-static bool vlenb_exists(const struct target *target)
-{
- return riscv_vlenb(target) != 0;
-}
-
-static bool mtopi_exists(const struct target *target)
-{
- RISCV_INFO(info)
- /* TODO: The naming is quite unfortunate here. `mtopi_readable` refers
- * to how the fact that `mtopi` exists was deduced during examine.
- */
- return info->mtopi_readable;
-}
-
-static bool mtopei_exists(const struct target *target)
-{
- RISCV_INFO(info)
- /* TODO: The naming is quite unfortunate here. `mtopei_readable` refers
- * to how the fact that `mtopei` exists was deduced during examine.
- */
- return info->mtopei_readable;
-}
-
-static bool gdb_regno_exist(const struct target *target, uint32_t regno)
-{
- if (regno <= GDB_REGNO_XPR15 ||
- regno == GDB_REGNO_PC ||
- regno == GDB_REGNO_PRIV)
- return true;
- if (regno > GDB_REGNO_XPR15 && regno <= GDB_REGNO_XPR31)
- return !riscv_supports_extension(target, 'E');
- if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31)
- return riscv_supports_extension(target, 'F');
- if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)
- return vlenb_exists(target);
- if (regno >= GDB_REGNO_COUNT)
- return true;
- assert(regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095);
- const unsigned int csr_number = regno - GDB_REGNO_CSR0;
- switch (csr_number) {
- case CSR_FFLAGS:
- case CSR_FRM:
- case CSR_FCSR:
- return riscv_supports_extension(target, 'F');
- case CSR_SCOUNTEREN:
- case CSR_SSTATUS:
- case CSR_STVEC:
- case CSR_SIP:
- case CSR_SIE:
- case CSR_SSCRATCH:
- case CSR_SEPC:
- case CSR_SCAUSE:
- case CSR_STVAL:
- case CSR_SATP:
- return riscv_supports_extension(target, 'S');
- case CSR_MEDELEG:
- case CSR_MIDELEG:
- /* "In systems with only M-mode, or with both M-mode and
- * U-mode but without U-mode trap support, the medeleg and
- * mideleg registers should not exist." */
- return riscv_supports_extension(target, 'S') ||
- riscv_supports_extension(target, 'N');
-
- case CSR_PMPCFG1:
- case CSR_PMPCFG3:
- case CSR_CYCLEH:
- case CSR_TIMEH:
- case CSR_INSTRETH:
- case CSR_HPMCOUNTER3H:
- case CSR_HPMCOUNTER4H:
- case CSR_HPMCOUNTER5H:
- case CSR_HPMCOUNTER6H:
- case CSR_HPMCOUNTER7H:
- case CSR_HPMCOUNTER8H:
- case CSR_HPMCOUNTER9H:
- case CSR_HPMCOUNTER10H:
- case CSR_HPMCOUNTER11H:
- case CSR_HPMCOUNTER12H:
- case CSR_HPMCOUNTER13H:
- case CSR_HPMCOUNTER14H:
- case CSR_HPMCOUNTER15H:
- case CSR_HPMCOUNTER16H:
- case CSR_HPMCOUNTER17H:
- case CSR_HPMCOUNTER18H:
- case CSR_HPMCOUNTER19H:
- case CSR_HPMCOUNTER20H:
- case CSR_HPMCOUNTER21H:
- case CSR_HPMCOUNTER22H:
- case CSR_HPMCOUNTER23H:
- case CSR_HPMCOUNTER24H:
- case CSR_HPMCOUNTER25H:
- case CSR_HPMCOUNTER26H:
- case CSR_HPMCOUNTER27H:
- case CSR_HPMCOUNTER28H:
- case CSR_HPMCOUNTER29H:
- case CSR_HPMCOUNTER30H:
- case CSR_HPMCOUNTER31H:
- case CSR_MCYCLEH:
- case CSR_MINSTRETH:
- case CSR_MHPMCOUNTER4H:
- case CSR_MHPMCOUNTER5H:
- case CSR_MHPMCOUNTER6H:
- case CSR_MHPMCOUNTER7H:
- case CSR_MHPMCOUNTER8H:
- case CSR_MHPMCOUNTER9H:
- case CSR_MHPMCOUNTER10H:
- case CSR_MHPMCOUNTER11H:
- case CSR_MHPMCOUNTER12H:
- case CSR_MHPMCOUNTER13H:
- case CSR_MHPMCOUNTER14H:
- case CSR_MHPMCOUNTER15H:
- case CSR_MHPMCOUNTER16H:
- case CSR_MHPMCOUNTER17H:
- case CSR_MHPMCOUNTER18H:
- case CSR_MHPMCOUNTER19H:
- case CSR_MHPMCOUNTER20H:
- case CSR_MHPMCOUNTER21H:
- case CSR_MHPMCOUNTER22H:
- case CSR_MHPMCOUNTER23H:
- case CSR_MHPMCOUNTER24H:
- case CSR_MHPMCOUNTER25H:
- case CSR_MHPMCOUNTER26H:
- case CSR_MHPMCOUNTER27H:
- case CSR_MHPMCOUNTER28H:
- case CSR_MHPMCOUNTER29H:
- case CSR_MHPMCOUNTER30H:
- case CSR_MHPMCOUNTER31H:
- return riscv_xlen(target) == 32;
- case CSR_MCOUNTEREN:
- return riscv_supports_extension(target, 'U');
- /* Interrupts M-Mode CSRs. */
- case CSR_MISELECT:
- case CSR_MIREG:
- case CSR_MVIEN:
- case CSR_MVIP:
- case CSR_MIEH:
- case CSR_MIPH:
- return mtopi_exists(target);
- case CSR_MIDELEGH:
- case CSR_MVIENH:
- case CSR_MVIPH:
- return mtopi_exists(target) &&
- riscv_xlen(target) == 32 &&
- riscv_supports_extension(target, 'S');
- /* Interrupts S-Mode CSRs. */
- case CSR_SISELECT:
- case CSR_SIREG:
- case CSR_STOPI:
- return mtopi_exists(target) &&
- riscv_supports_extension(target, 'S');
- case CSR_STOPEI:
- return mtopei_exists(target) &&
- riscv_supports_extension(target, 'S');
- case CSR_SIEH:
- case CSR_SIPH:
- return mtopi_exists(target) &&
- riscv_xlen(target) == 32 &&
- riscv_supports_extension(target, 'S');
- /* Interrupts Hypervisor and VS CSRs. */
- case CSR_HVIEN:
- case CSR_HVICTL:
- case CSR_HVIPRIO1:
- case CSR_HVIPRIO2:
- case CSR_VSISELECT:
- case CSR_VSIREG:
- case CSR_VSTOPI:
- return mtopi_exists(target) &&
- riscv_supports_extension(target, 'H');
- case CSR_VSTOPEI:
- return mtopei_exists(target) &&
- riscv_supports_extension(target, 'H');
- case CSR_HIDELEGH:
- case CSR_HVIENH:
- case CSR_HVIPH:
- case CSR_HVIPRIO1H:
- case CSR_HVIPRIO2H:
- case CSR_VSIEH:
- case CSR_VSIPH:
- return mtopi_exists(target) &&
- riscv_xlen(target) == 32 &&
- riscv_supports_extension(target, 'H');
- }
- return is_known_standard_csr(csr_number);
-}
-
-static unsigned int gdb_regno_custom_number(const struct target *target, uint32_t regno)
-{
- if (regno < GDB_REGNO_COUNT)
- return 0;
-
- RISCV_INFO(info);
- assert(!list_empty(&info->expose_custom));
- range_list_t *range;
- unsigned int regno_start = GDB_REGNO_COUNT;
- unsigned int start = 0;
- unsigned int offset = 0;
- list_for_each_entry(range, &info->expose_custom, list) {
- start = range->low;
- assert(regno >= regno_start);
- offset = regno - regno_start;
- const unsigned int regs_in_range = range->high - range->low + 1;
- if (offset < regs_in_range)
- break;
- regno_start += regs_in_range;
- }
- return start + offset;
-}
-
-static int resize_reg(const struct target *target, uint32_t regno, bool exist,
- uint32_t size)
-{
- struct reg *reg = get_reg_cache_entry(target, regno);
- assert(reg_is_initialized(reg));
- free(reg->value);
- reg->size = size;
- reg->exist = exist;
- if (reg->exist) {
- reg->value = malloc(DIV_ROUND_UP(reg->size, 8));
- if (!reg->value) {
- LOG_ERROR("Failed to allocate memory.");
- return ERROR_FAIL;
- }
- } else {
- reg->value = NULL;
- }
- assert(reg_is_initialized(reg));
- return ERROR_OK;
-}
-
-static int set_reg_exist(const struct target *target, uint32_t regno, bool exist)
-{
- const struct reg *reg = get_reg_cache_entry(target, regno);
- assert(reg_is_initialized(reg));
- return resize_reg(target, regno, exist, reg->size);
-}
-
-static int init_reg(struct target *target, uint32_t regno)
-{
- struct reg * const reg = get_reg_cache_entry(target, regno);
- if (reg_is_initialized(reg))
- return ERROR_OK;
- reg->number = regno;
- reg->type = gdb_regno_reg_type(target, regno);
- reg->dirty = false;
- reg->valid = false;
- reg->hidden = false;
- reg->name = gdb_regno_name(target, regno);
- reg->feature = gdb_regno_feature(regno);
- reg->caller_save = gdb_regno_caller_save(regno);
- reg->reg_data_type = gdb_regno_reg_data_type(target, regno);
- reg->group = gdb_regno_group(regno);
- if (regno < GDB_REGNO_COUNT) {
- RISCV_INFO(info);
- reg->arch_info = &info->shared_reg_info;
- } else {
- reg->arch_info = calloc(1, sizeof(riscv_reg_info_t));
- if (!reg->arch_info) {
- LOG_ERROR("Out of memory.");
- return ERROR_FAIL;
- }
- riscv_reg_info_t * const reg_arch_info = reg->arch_info;
- reg_arch_info->target = target;
- reg_arch_info->custom_number = gdb_regno_custom_number(target, regno);
- }
- return resize_reg(target, regno, gdb_regno_exist(target, regno),
- gdb_regno_size(target, regno));
-}
-
-static int riscv_init_reg_cache(struct target *target)
-{
- RISCV_INFO(info);
-
- riscv_free_registers(target);
-
- target->reg_cache = calloc(1, sizeof(*target->reg_cache));
- if (!target->reg_cache) {
- LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache");
- return ERROR_FAIL;
- }
- target->reg_cache->name = "RISC-V Registers";
-
- if (init_custom_register_names(&info->expose_custom, &info->custom_register_names) != ERROR_OK) {
- LOG_TARGET_ERROR(target, "init_custom_register_names failed");
- return ERROR_FAIL;
- }
-
- target->reg_cache->num_regs = GDB_REGNO_COUNT + info->custom_register_names.num_entries;
- LOG_TARGET_DEBUG(target, "create register cache for %d registers",
- target->reg_cache->num_regs);
-
- target->reg_cache->reg_list =
- calloc(target->reg_cache->num_regs, sizeof(struct reg));
- if (!target->reg_cache->reg_list) {
- LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache->reg_list");
- return ERROR_FAIL;
- }
- return ERROR_OK;
-}
-
-static void init_shared_reg_info(struct target *target)
-{
- RISCV_INFO(info);
- info->shared_reg_info.target = target;
- info->shared_reg_info.custom_number = 0;
-}
-
-static void init_vector_reg_type(const struct target *target)
-{
- RISCV_INFO(info);
- static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" };
- static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" };
- static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" };
- static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" };
- static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" };
-
- /* This is roughly the XML we want:
- * <vector id="bytes" type="uint8" count="16"/>
- * <vector id="shorts" type="uint16" count="8"/>
- * <vector id="words" type="uint32" count="4"/>
- * <vector id="longs" type="uint64" count="2"/>
- * <vector id="quads" type="uint128" count="1"/>
- * <union id="riscv_vector_type">
- * <field name="b" type="bytes"/>
- * <field name="s" type="shorts"/>
- * <field name="w" type="words"/>
- * <field name="l" type="longs"/>
- * <field name="q" type="quads"/>
- * </union>
- */
-
- info->vector_uint8.type = &type_uint8;
- info->vector_uint8.count = riscv_vlenb(target);
- info->type_uint8_vector.type = REG_TYPE_ARCH_DEFINED;
- info->type_uint8_vector.id = "bytes";
- info->type_uint8_vector.type_class = REG_TYPE_CLASS_VECTOR;
- info->type_uint8_vector.reg_type_vector = &info->vector_uint8;
-
- info->vector_uint16.type = &type_uint16;
- info->vector_uint16.count = riscv_vlenb(target) / 2;
- info->type_uint16_vector.type = REG_TYPE_ARCH_DEFINED;
- info->type_uint16_vector.id = "shorts";
- info->type_uint16_vector.type_class = REG_TYPE_CLASS_VECTOR;
- info->type_uint16_vector.reg_type_vector = &info->vector_uint16;
-
- info->vector_uint32.type = &type_uint32;
- info->vector_uint32.count = riscv_vlenb(target) / 4;
- info->type_uint32_vector.type = REG_TYPE_ARCH_DEFINED;
- info->type_uint32_vector.id = "words";
- info->type_uint32_vector.type_class = REG_TYPE_CLASS_VECTOR;
- info->type_uint32_vector.reg_type_vector = &info->vector_uint32;
-
- info->vector_uint64.type = &type_uint64;
- info->vector_uint64.count = riscv_vlenb(target) / 8;
- info->type_uint64_vector.type = REG_TYPE_ARCH_DEFINED;
- info->type_uint64_vector.id = "longs";
- info->type_uint64_vector.type_class = REG_TYPE_CLASS_VECTOR;
- info->type_uint64_vector.reg_type_vector = &info->vector_uint64;
-
- info->vector_uint128.type = &type_uint128;
- info->vector_uint128.count = riscv_vlenb(target) / 16;
- info->type_uint128_vector.type = REG_TYPE_ARCH_DEFINED;
- info->type_uint128_vector.id = "quads";
- info->type_uint128_vector.type_class = REG_TYPE_CLASS_VECTOR;
- info->type_uint128_vector.reg_type_vector = &info->vector_uint128;
-
- info->vector_fields[0].name = "b";
- info->vector_fields[0].type = &info->type_uint8_vector;
- if (riscv_vlenb(target) >= 2) {
- info->vector_fields[0].next = info->vector_fields + 1;
- info->vector_fields[1].name = "s";
- info->vector_fields[1].type = &info->type_uint16_vector;
- } else {
- info->vector_fields[0].next = NULL;
- }
- if (riscv_vlenb(target) >= 4) {
- info->vector_fields[1].next = info->vector_fields + 2;
- info->vector_fields[2].name = "w";
- info->vector_fields[2].type = &info->type_uint32_vector;
- } else {
- info->vector_fields[1].next = NULL;
- }
- if (riscv_vlenb(target) >= 8) {
- info->vector_fields[2].next = info->vector_fields + 3;
- info->vector_fields[3].name = "l";
- info->vector_fields[3].type = &info->type_uint64_vector;
- } else {
- info->vector_fields[2].next = NULL;
- }
- if (riscv_vlenb(target) >= 16) {
- info->vector_fields[3].next = info->vector_fields + 4;
- info->vector_fields[4].name = "q";
- info->vector_fields[4].type = &info->type_uint128_vector;
- } else {
- info->vector_fields[3].next = NULL;
- }
- info->vector_fields[4].next = NULL;
-
- info->vector_union.fields = info->vector_fields;
-
- info->type_vector.type = REG_TYPE_ARCH_DEFINED;
- info->type_vector.id = "riscv_vector";
- info->type_vector.type_class = REG_TYPE_CLASS_UNION;
- info->type_vector.reg_type_union = &info->vector_union;
-}
-
-static int expose_csrs(const struct target *target)
-{
- RISCV_INFO(info);
- range_list_t *entry;
- list_for_each_entry(entry, &info->expose_csr, list) {
- assert(entry->low <= entry->high);
- assert(entry->high <= GDB_REGNO_CSR4095 - GDB_REGNO_CSR0);
- const enum gdb_regno last_regno = GDB_REGNO_CSR0 + entry->high;
- for (enum gdb_regno regno = GDB_REGNO_CSR0 + entry->low;
- regno <= last_regno; ++regno) {
- struct reg * const reg = get_reg_cache_entry(target, regno);
- const unsigned int csr_number = regno - GDB_REGNO_CSR0;
- if (reg->exist) {
- LOG_TARGET_WARNING(target,
- "Not exposing CSR %d: register already exists.",
- csr_number);
- continue;
- }
- if (set_reg_exist(target, regno, /*exist*/ true) != ERROR_OK)
- return ERROR_FAIL;
- LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)",
- csr_number, reg->name);
- }
- }
- return ERROR_OK;
-}
-
-static void hide_csrs(const struct target *target)
-{
- RISCV_INFO(info);
- range_list_t *entry;
- list_for_each_entry(entry, &info->hide_csr, list) {
- assert(entry->high <= GDB_REGNO_CSR4095 - GDB_REGNO_CSR0);
- const enum gdb_regno last_regno = GDB_REGNO_CSR0 + entry->high;
- for (enum gdb_regno regno = GDB_REGNO_CSR0 + entry->low;
- regno <= last_regno; ++regno) {
- struct reg * const reg = get_reg_cache_entry(target, regno);
- const unsigned int csr_number = regno - GDB_REGNO_CSR0;
- if (!reg->exist) {
- LOG_TARGET_DEBUG(target,
- "Not hiding CSR %d: register does not exist.",
- csr_number);
- continue;
- }
- LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s).", csr_number, reg->name);
- reg->hidden = true;
- }
- }
-}
-
-int riscv_init_registers(struct target *target)
-{
- if (riscv_init_reg_cache(target) != ERROR_OK)
- return ERROR_FAIL;
-
- init_shared_reg_info(target);
-
- init_vector_reg_type(target);
-
- for (uint32_t reg_num = 0; reg_num < target->reg_cache->num_regs; reg_num++)
- if (init_reg(target, reg_num) != ERROR_OK)
- return ERROR_FAIL;
-
-
- if (expose_csrs(target) != ERROR_OK)
- return ERROR_FAIL;
-
- hide_csrs(target);
-
- return ERROR_OK;
-}
-
void riscv_add_bscan_tunneled_scan(struct target *target, const struct scan_field *field,
riscv_bscan_tunneled_scan_context_t *ctxt)
{
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h
index d3703d1..5b75bf6 100644
--- a/src/target/riscv/riscv.h
+++ b/src/target/riscv/riscv.h
@@ -9,8 +9,9 @@ struct riscv_program;
#include "opcodes.h"
#include "gdb_regs.h"
#include "jtag/jtag.h"
-#include "target/register.h"
#include "target/semihosting_common.h"
+#include "target/target.h"
+#include "target/register.h"
#include <helper/command.h>
#include <helper/bits.h>
@@ -21,8 +22,7 @@ struct riscv_program;
#define RISCV_MAX_HWBPS 16
#define RISCV_MAX_DMS 100
-#define DEFAULT_COMMAND_TIMEOUT_SEC 2
-#define DEFAULT_RESET_TIMEOUT_SEC 30
+#define DEFAULT_COMMAND_TIMEOUT_SEC 5
#define RISCV_SATP_MODE(xlen) ((xlen) == 32 ? SATP32_MODE : SATP64_MODE)
#define RISCV_SATP_PPN(xlen) ((xlen) == 32 ? SATP32_PPN : SATP64_PPN)
@@ -83,9 +83,11 @@ enum riscv_hart_state {
RISCV_STATE_UNAVAILABLE
};
+/* RISC-V-specific data assigned to a register. */
typedef struct {
struct target *target;
- unsigned custom_number;
+ /* Abstract command's regno for a custom register. */
+ unsigned int custom_number;
} riscv_reg_info_t;
#define RISCV_SAMPLE_BUF_TIMESTAMP_BEFORE 0x80
@@ -190,14 +192,6 @@ struct riscv_info {
/* Helper functions that target the various RISC-V debug spec
* implementations. */
- int (*get_register)(struct target *target, riscv_reg_t *value,
- enum gdb_regno regno);
- int (*set_register)(struct target *target, enum gdb_regno regno,
- riscv_reg_t value);
- int (*get_register_buf)(struct target *target, uint8_t *buf,
- enum gdb_regno regno);
- int (*set_register_buf)(struct target *target, enum gdb_regno regno,
- const uint8_t *buf);
int (*select_target)(struct target *target);
int (*get_hart_state)(struct target *target, enum riscv_hart_state *state);
/* Resume this target, as well as every other prepped target that can be
@@ -345,10 +339,7 @@ typedef struct {
} virt2phys_info_t;
/* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/
-extern int riscv_command_timeout_sec;
-
-/* Wall-clock timeout after reset. Settable via RISC-V Target commands.*/
-extern int riscv_reset_timeout_sec;
+int riscv_get_command_timeout_sec(void);
extern bool riscv_enable_virtual;
@@ -404,25 +395,6 @@ unsigned int riscv_vlenb(const struct target *target);
/*** Support functions for the RISC-V 'RTOS', which provides multihart support
* without requiring multiple targets. */
-/**
- * Set the register value. For cacheable registers, only the cache is updated
- * (write-back mode).
- */
-int riscv_set_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
-/**
- * Set the register value and immediately write it to the target
- * (write-through mode).
- */
-int riscv_write_register(struct target *target, enum gdb_regno i, riscv_reg_t v);
-/** Get register, from the cache if it's in there. */
-int riscv_get_register(struct target *target, riscv_reg_t *value,
- enum gdb_regno r);
-/** Read the register into the cache, and mark it dirty so it will be restored
- * before resuming. */
-int riscv_save_register(struct target *target, enum gdb_regno regid);
-/** Write all dirty registers to the target. */
-int riscv_flush_registers(struct target *target);
-
/* Checks the state of the current hart -- "is_halted" checks the actual
* on-device register. */
int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state);
@@ -448,8 +420,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);
-
void riscv_semihosting_init(struct target *target);
enum semihosting_result riscv_semihosting(struct target *target, int *retval);
diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c
new file mode 100644
index 0000000..6cf67dd
--- /dev/null
+++ b/src/target/riscv/riscv_reg.c
@@ -0,0 +1,976 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gdb_regs.h"
+#include "riscv.h"
+#include "riscv_reg.h"
+#include "riscv_reg_impl.h"
+/**
+ * TODO: Currently `reg->get/set` is implemented in terms of
+ * `riscv_get/set_register`. However, the intention behind
+ * `riscv_get/set_register` is to work with the cache, therefore it accesses
+ * and modifyes register cache directly. The idea is to implement
+ * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and
+ * `reg->get/set`.
+ * Once this is done, the following includes should be removed.
+ */
+#include "debug_defines.h"
+#include "riscv-011.h"
+#include "riscv-013.h"
+#include "field_helpers.h"
+
+static const char * const default_reg_names[GDB_REGNO_COUNT] = {
+ [GDB_REGNO_ZERO] = "zero",
+ [GDB_REGNO_RA] = "ra",
+ [GDB_REGNO_SP] = "sp",
+ [GDB_REGNO_GP] = "gp",
+ [GDB_REGNO_TP] = "tp",
+ [GDB_REGNO_T0] = "t0",
+ [GDB_REGNO_T1] = "t1",
+ [GDB_REGNO_T2] = "t2",
+ [GDB_REGNO_FP] = "fp",
+ [GDB_REGNO_S1] = "s1",
+ [GDB_REGNO_A0] = "a0",
+ [GDB_REGNO_A1] = "a1",
+ [GDB_REGNO_A2] = "a2",
+ [GDB_REGNO_A3] = "a3",
+ [GDB_REGNO_A4] = "a4",
+ [GDB_REGNO_A5] = "a5",
+ [GDB_REGNO_A6] = "a6",
+ [GDB_REGNO_A7] = "a7",
+ [GDB_REGNO_S2] = "s2",
+ [GDB_REGNO_S3] = "s3",
+ [GDB_REGNO_S4] = "s4",
+ [GDB_REGNO_S5] = "s5",
+ [GDB_REGNO_S6] = "s6",
+ [GDB_REGNO_S7] = "s7",
+ [GDB_REGNO_S8] = "s8",
+ [GDB_REGNO_S9] = "s9",
+ [GDB_REGNO_S10] = "s10",
+ [GDB_REGNO_S11] = "s11",
+ [GDB_REGNO_T3] = "t3",
+ [GDB_REGNO_T4] = "t4",
+ [GDB_REGNO_T5] = "t5",
+ [GDB_REGNO_T6] = "t6",
+ [GDB_REGNO_PC] = "pc",
+ [GDB_REGNO_CSR0] = "csr0",
+ [GDB_REGNO_PRIV] = "priv",
+ [GDB_REGNO_FT0] = "ft0",
+ [GDB_REGNO_FT1] = "ft1",
+ [GDB_REGNO_FT2] = "ft2",
+ [GDB_REGNO_FT3] = "ft3",
+ [GDB_REGNO_FT4] = "ft4",
+ [GDB_REGNO_FT5] = "ft5",
+ [GDB_REGNO_FT6] = "ft6",
+ [GDB_REGNO_FT7] = "ft7",
+ [GDB_REGNO_FS0] = "fs0",
+ [GDB_REGNO_FS1] = "fs1",
+ [GDB_REGNO_FA0] = "fa0",
+ [GDB_REGNO_FA1] = "fa1",
+ [GDB_REGNO_FA2] = "fa2",
+ [GDB_REGNO_FA3] = "fa3",
+ [GDB_REGNO_FA4] = "fa4",
+ [GDB_REGNO_FA5] = "fa5",
+ [GDB_REGNO_FA6] = "fa6",
+ [GDB_REGNO_FA7] = "fa7",
+ [GDB_REGNO_FS2] = "fs2",
+ [GDB_REGNO_FS3] = "fs3",
+ [GDB_REGNO_FS4] = "fs4",
+ [GDB_REGNO_FS5] = "fs5",
+ [GDB_REGNO_FS6] = "fs6",
+ [GDB_REGNO_FS7] = "fs7",
+ [GDB_REGNO_FS8] = "fs8",
+ [GDB_REGNO_FS9] = "fs9",
+ [GDB_REGNO_FS10] = "fs10",
+ [GDB_REGNO_FS11] = "fs11",
+ [GDB_REGNO_FT8] = "ft8",
+ [GDB_REGNO_FT9] = "ft9",
+ [GDB_REGNO_FT10] = "ft10",
+ [GDB_REGNO_FT11] = "ft11",
+
+ #define DECLARE_CSR(csr_name, number)[(number) + GDB_REGNO_CSR0] = #csr_name,
+ #include "encoding.h"
+ #undef DECLARE_CSR
+};
+
+static void free_custom_register_names(struct target *target)
+{
+ RISCV_INFO(info);
+
+ if (!info->custom_register_names.reg_names)
+ return;
+
+ for (unsigned int i = 0; i < info->custom_register_names.num_entries; i++)
+ free(info->custom_register_names.reg_names[i]);
+ free(info->custom_register_names.reg_names);
+ info->custom_register_names.reg_names = NULL;
+}
+
+static void free_reg_names(struct target *target)
+{
+ RISCV_INFO(info);
+
+ if (!info->reg_names)
+ return;
+
+ for (unsigned int i = 0; i < GDB_REGNO_COUNT; ++i)
+ free(info->reg_names[i]);
+ free(info->reg_names);
+ info->reg_names = NULL;
+
+ free_custom_register_names(target);
+}
+
+static char *init_reg_name(const char *name)
+{
+ const int size_buf = strlen(name) + 1;
+
+ char * const buf = calloc(size_buf, sizeof(char));
+ if (!buf) {
+ LOG_ERROR("Failed to allocate memory for a register name.");
+ return NULL;
+ }
+ strcpy(buf, name);
+ return buf;
+}
+
+static void init_custom_csr_names(const struct target *target)
+{
+ RISCV_INFO(info);
+ range_list_t *entry;
+
+ list_for_each_entry(entry, &info->expose_csr, list) {
+ if (!entry->name)
+ continue;
+ assert(entry->low == entry->high);
+ const unsigned int regno = entry->low + GDB_REGNO_CSR0;
+ assert(regno <= GDB_REGNO_CSR4095);
+ if (info->reg_names[regno])
+ return;
+ info->reg_names[regno] = init_reg_name(entry->name);
+ }
+}
+
+static char *init_reg_name_with_prefix(const char *name_prefix,
+ unsigned int num)
+{
+ const int size_buf = snprintf(NULL, 0, "%s%d", name_prefix, num) + 1;
+
+ char * const buf = calloc(size_buf, sizeof(char));
+ if (!buf) {
+ LOG_ERROR("Failed to allocate memory for a register name.");
+ return NULL;
+ }
+ int result = snprintf(buf, size_buf, "%s%d", name_prefix, num);
+ assert(result > 0 && result <= (size_buf - 1));
+ return buf;
+}
+
+const char *riscv_reg_gdb_regno_name(const struct target *target, enum gdb_regno regno)
+{
+ RISCV_INFO(info);
+
+ if (regno >= GDB_REGNO_COUNT) {
+ assert(info->custom_register_names.reg_names);
+ assert(regno - GDB_REGNO_COUNT <= info->custom_register_names.num_entries);
+ return info->custom_register_names.reg_names[regno - GDB_REGNO_COUNT];
+ }
+
+ if (!info->reg_names)
+ info->reg_names = calloc(GDB_REGNO_COUNT, sizeof(char *));
+
+ if (info->reg_names[regno])
+ return info->reg_names[regno];
+ if (default_reg_names[regno])
+ return default_reg_names[regno];
+ if (regno <= GDB_REGNO_XPR31) {
+ info->reg_names[regno] = init_reg_name_with_prefix("x", regno - GDB_REGNO_ZERO);
+ return info->reg_names[regno];
+ }
+ if (regno <= GDB_REGNO_V31 && regno >= GDB_REGNO_V0) {
+ info->reg_names[regno] = init_reg_name_with_prefix("v", regno - GDB_REGNO_V0);
+ return info->reg_names[regno];
+ }
+ if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
+ init_custom_csr_names(target);
+ info->reg_names[regno] = init_reg_name_with_prefix("csr", regno - GDB_REGNO_CSR0);
+ return info->reg_names[regno];
+ }
+ assert(!"Encountered uninitialized entry in reg_names table");
+
+ return NULL;
+}
+
+struct target *riscv_reg_impl_get_target(const struct reg *reg)
+{
+ assert(riscv_reg_impl_is_initialized(reg));
+ return ((const riscv_reg_info_t *)reg->arch_info)->target;
+}
+
+static struct reg_feature *gdb_regno_feature(uint32_t regno)
+{
+ if (regno <= GDB_REGNO_XPR31 || regno == GDB_REGNO_PC) {
+ static struct reg_feature feature_cpu = {
+ .name = "org.gnu.gdb.riscv.cpu"
+ };
+ return &feature_cpu;
+ }
+ if ((regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) ||
+ regno == GDB_REGNO_FFLAGS ||
+ regno == GDB_REGNO_FRM ||
+ regno == GDB_REGNO_FCSR) {
+ static struct reg_feature feature_fpu = {
+ .name = "org.gnu.gdb.riscv.fpu"
+ };
+ return &feature_fpu;
+ }
+ if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) {
+ static struct reg_feature feature_vector = {
+ .name = "org.gnu.gdb.riscv.vector"
+ };
+ return &feature_vector;
+ }
+ if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
+ static struct reg_feature feature_csr = {
+ .name = "org.gnu.gdb.riscv.csr"
+ };
+ return &feature_csr;
+ }
+ if (regno == GDB_REGNO_PRIV) {
+ static struct reg_feature feature_virtual = {
+ .name = "org.gnu.gdb.riscv.virtual"
+ };
+ return &feature_virtual;
+ }
+ assert(regno >= GDB_REGNO_COUNT);
+ static struct reg_feature feature_custom = {
+ .name = "org.gnu.gdb.riscv.custom"
+ };
+ return &feature_custom;
+}
+
+static bool gdb_regno_caller_save(uint32_t regno)
+{
+ return regno <= GDB_REGNO_XPR31 ||
+ regno == GDB_REGNO_PC ||
+ (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31);
+}
+
+static struct reg_data_type *gdb_regno_reg_data_type(const struct target *target,
+ uint32_t regno)
+{
+ if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) {
+ 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"
+ };
+ static struct reg_data_type_union_field single_double_fields[] = {
+ {"float", &type_ieee_single, single_double_fields + 1},
+ {"double", &type_ieee_double, NULL},
+ };
+ static struct reg_data_type_union single_double_union = {
+ .fields = single_double_fields
+ };
+ static struct reg_data_type type_ieee_single_double = {
+ .type = REG_TYPE_ARCH_DEFINED,
+ .id = "FPU_FD",
+ .type_class = REG_TYPE_CLASS_UNION,
+ {.reg_type_union = &single_double_union}
+ };
+ return riscv_supports_extension(target, 'D') ?
+ &type_ieee_single_double :
+ &type_ieee_single;
+ }
+ if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31) {
+ RISCV_INFO(info);
+ return &info->type_vector;
+ }
+ return NULL;
+}
+
+static const char *gdb_regno_group(uint32_t regno)
+{
+ if (regno <= GDB_REGNO_XPR31 ||
+ regno == GDB_REGNO_PC ||
+ regno == GDB_REGNO_PRIV)
+ return "general";
+ if ((regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) ||
+ regno == GDB_REGNO_FFLAGS ||
+ regno == GDB_REGNO_FRM ||
+ regno == GDB_REGNO_FCSR)
+ return "float";
+ if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095)
+ return "csr";
+ if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)
+ return "vector";
+ assert(regno >= GDB_REGNO_COUNT);
+ return "custom";
+}
+
+uint32_t gdb_regno_size(const struct target *target, uint32_t regno)
+{
+ if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31)
+ return riscv_supports_extension(target, 'D') ? 64 : 32;
+ if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)
+ return riscv_vlenb(target) * 8;
+ if (regno == GDB_REGNO_PRIV)
+ return 8;
+ if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) {
+ const unsigned int csr_number = regno - GDB_REGNO_CSR0;
+ switch (csr_number) {
+ case CSR_DCSR:
+ case CSR_MVENDORID:
+ case CSR_MCOUNTINHIBIT:
+
+ case CSR_FFLAGS:
+ case CSR_FRM:
+ case CSR_FCSR:
+
+ case CSR_SCOUNTEREN:
+ case CSR_MCOUNTEREN:
+ return 32;
+ }
+ }
+ return riscv_xlen(target);
+}
+
+static bool vlenb_exists(const struct target *target)
+{
+ return riscv_vlenb(target) != 0;
+}
+
+static bool mtopi_exists(const struct target *target)
+{
+ RISCV_INFO(info)
+ /* TODO: The naming is quite unfortunate here. `mtopi_readable` refers
+ * to how the fact that `mtopi` exists was deduced during examine.
+ */
+ return info->mtopi_readable;
+}
+
+static bool mtopei_exists(const struct target *target)
+{
+ RISCV_INFO(info)
+ /* TODO: The naming is quite unfortunate here. `mtopei_readable` refers
+ * to how the fact that `mtopei` exists was deduced during examine.
+ */
+ return info->mtopei_readable;
+}
+
+static bool is_known_standard_csr(unsigned int csr_num)
+{
+ static const bool is_csr_in_buf[GDB_REGNO_CSR4095 - GDB_REGNO_CSR0 + 1] = {
+ #define DECLARE_CSR(csr_name, number)[number] = true,
+ #include "encoding.h"
+ #undef DECLARE_CSR
+ };
+ assert(csr_num < ARRAY_SIZE(is_csr_in_buf));
+
+ return is_csr_in_buf[csr_num];
+}
+
+static bool gdb_regno_exist(const struct target *target, uint32_t regno)
+{
+ if (regno <= GDB_REGNO_XPR15 ||
+ regno == GDB_REGNO_PC ||
+ regno == GDB_REGNO_PRIV)
+ return true;
+ if (regno > GDB_REGNO_XPR15 && regno <= GDB_REGNO_XPR31)
+ return !riscv_supports_extension(target, 'E');
+ if (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31)
+ return riscv_supports_extension(target, 'F');
+ if (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31)
+ return vlenb_exists(target);
+ if (regno >= GDB_REGNO_COUNT)
+ return true;
+ assert(regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095);
+ const unsigned int csr_number = regno - GDB_REGNO_CSR0;
+ switch (csr_number) {
+ case CSR_FFLAGS:
+ case CSR_FRM:
+ case CSR_FCSR:
+ return riscv_supports_extension(target, 'F');
+ case CSR_VSTART:
+ case CSR_VXSAT:
+ case CSR_VXRM:
+ case CSR_VL:
+ case CSR_VCSR:
+ case CSR_VTYPE:
+ case CSR_VLENB:
+ return vlenb_exists(target);
+ case CSR_SCOUNTEREN:
+ case CSR_SSTATUS:
+ case CSR_STVEC:
+ case CSR_SIP:
+ case CSR_SIE:
+ case CSR_SSCRATCH:
+ case CSR_SEPC:
+ case CSR_SCAUSE:
+ case CSR_STVAL:
+ case CSR_SATP:
+ return riscv_supports_extension(target, 'S');
+ case CSR_MEDELEG:
+ case CSR_MIDELEG:
+ /* "In systems with only M-mode, or with both M-mode and
+ * U-mode but without U-mode trap support, the medeleg and
+ * mideleg registers should not exist." */
+ return riscv_supports_extension(target, 'S') ||
+ riscv_supports_extension(target, 'N');
+
+ case CSR_PMPCFG1:
+ case CSR_PMPCFG3:
+ case CSR_CYCLEH:
+ case CSR_TIMEH:
+ case CSR_INSTRETH:
+ case CSR_HPMCOUNTER3H:
+ case CSR_HPMCOUNTER4H:
+ case CSR_HPMCOUNTER5H:
+ case CSR_HPMCOUNTER6H:
+ case CSR_HPMCOUNTER7H:
+ case CSR_HPMCOUNTER8H:
+ case CSR_HPMCOUNTER9H:
+ case CSR_HPMCOUNTER10H:
+ case CSR_HPMCOUNTER11H:
+ case CSR_HPMCOUNTER12H:
+ case CSR_HPMCOUNTER13H:
+ case CSR_HPMCOUNTER14H:
+ case CSR_HPMCOUNTER15H:
+ case CSR_HPMCOUNTER16H:
+ case CSR_HPMCOUNTER17H:
+ case CSR_HPMCOUNTER18H:
+ case CSR_HPMCOUNTER19H:
+ case CSR_HPMCOUNTER20H:
+ case CSR_HPMCOUNTER21H:
+ case CSR_HPMCOUNTER22H:
+ case CSR_HPMCOUNTER23H:
+ case CSR_HPMCOUNTER24H:
+ case CSR_HPMCOUNTER25H:
+ case CSR_HPMCOUNTER26H:
+ case CSR_HPMCOUNTER27H:
+ case CSR_HPMCOUNTER28H:
+ case CSR_HPMCOUNTER29H:
+ case CSR_HPMCOUNTER30H:
+ case CSR_HPMCOUNTER31H:
+ case CSR_MCYCLEH:
+ case CSR_MINSTRETH:
+ case CSR_MHPMCOUNTER4H:
+ case CSR_MHPMCOUNTER5H:
+ case CSR_MHPMCOUNTER6H:
+ case CSR_MHPMCOUNTER7H:
+ case CSR_MHPMCOUNTER8H:
+ case CSR_MHPMCOUNTER9H:
+ case CSR_MHPMCOUNTER10H:
+ case CSR_MHPMCOUNTER11H:
+ case CSR_MHPMCOUNTER12H:
+ case CSR_MHPMCOUNTER13H:
+ case CSR_MHPMCOUNTER14H:
+ case CSR_MHPMCOUNTER15H:
+ case CSR_MHPMCOUNTER16H:
+ case CSR_MHPMCOUNTER17H:
+ case CSR_MHPMCOUNTER18H:
+ case CSR_MHPMCOUNTER19H:
+ case CSR_MHPMCOUNTER20H:
+ case CSR_MHPMCOUNTER21H:
+ case CSR_MHPMCOUNTER22H:
+ case CSR_MHPMCOUNTER23H:
+ case CSR_MHPMCOUNTER24H:
+ case CSR_MHPMCOUNTER25H:
+ case CSR_MHPMCOUNTER26H:
+ case CSR_MHPMCOUNTER27H:
+ case CSR_MHPMCOUNTER28H:
+ case CSR_MHPMCOUNTER29H:
+ case CSR_MHPMCOUNTER30H:
+ case CSR_MHPMCOUNTER31H:
+ return riscv_xlen(target) == 32;
+ case CSR_MCOUNTEREN:
+ return riscv_supports_extension(target, 'U');
+ /* Interrupts M-Mode CSRs. */
+ case CSR_MISELECT:
+ case CSR_MIREG:
+ case CSR_MVIEN:
+ case CSR_MVIP:
+ case CSR_MIEH:
+ case CSR_MIPH:
+ return mtopi_exists(target);
+ case CSR_MIDELEGH:
+ case CSR_MVIENH:
+ case CSR_MVIPH:
+ return mtopi_exists(target) &&
+ riscv_xlen(target) == 32 &&
+ riscv_supports_extension(target, 'S');
+ /* Interrupts S-Mode CSRs. */
+ case CSR_SISELECT:
+ case CSR_SIREG:
+ case CSR_STOPI:
+ return mtopi_exists(target) &&
+ riscv_supports_extension(target, 'S');
+ case CSR_STOPEI:
+ return mtopei_exists(target) &&
+ riscv_supports_extension(target, 'S');
+ case CSR_SIEH:
+ case CSR_SIPH:
+ return mtopi_exists(target) &&
+ riscv_xlen(target) == 32 &&
+ riscv_supports_extension(target, 'S');
+ /* Interrupts Hypervisor and VS CSRs. */
+ case CSR_HVIEN:
+ case CSR_HVICTL:
+ case CSR_HVIPRIO1:
+ case CSR_HVIPRIO2:
+ case CSR_VSISELECT:
+ case CSR_VSIREG:
+ case CSR_VSTOPI:
+ return mtopi_exists(target) &&
+ riscv_supports_extension(target, 'H');
+ case CSR_VSTOPEI:
+ return mtopei_exists(target) &&
+ riscv_supports_extension(target, 'H');
+ case CSR_HIDELEGH:
+ case CSR_HVIENH:
+ case CSR_HVIPH:
+ case CSR_HVIPRIO1H:
+ case CSR_HVIPRIO2H:
+ case CSR_VSIEH:
+ case CSR_VSIPH:
+ return mtopi_exists(target) &&
+ riscv_xlen(target) == 32 &&
+ riscv_supports_extension(target, 'H');
+ }
+ return is_known_standard_csr(csr_number);
+}
+
+static unsigned int gdb_regno_custom_number(const struct target *target, uint32_t regno)
+{
+ if (regno < GDB_REGNO_COUNT)
+ return 0;
+
+ RISCV_INFO(info);
+ assert(!list_empty(&info->expose_custom));
+ range_list_t *range;
+ unsigned int regno_start = GDB_REGNO_COUNT;
+ unsigned int start = 0;
+ unsigned int offset = 0;
+ list_for_each_entry(range, &info->expose_custom, list) {
+ start = range->low;
+ assert(regno >= regno_start);
+ offset = regno - regno_start;
+ const unsigned int regs_in_range = range->high - range->low + 1;
+ if (offset < regs_in_range)
+ break;
+ regno_start += regs_in_range;
+ }
+ return start + offset;
+}
+
+struct reg *riscv_reg_impl_cache_entry(const struct target *target,
+ uint32_t number)
+{
+ assert(target->reg_cache);
+ assert(target->reg_cache->reg_list);
+ assert(number < target->reg_cache->num_regs);
+ return &target->reg_cache->reg_list[number];
+}
+
+static int resize_reg(const struct target *target, uint32_t regno, bool exist,
+ uint32_t size)
+{
+ struct reg *reg = riscv_reg_impl_cache_entry(target, regno);
+ assert(riscv_reg_impl_is_initialized(reg));
+ free(reg->value);
+ reg->size = size;
+ reg->exist = exist;
+ if (reg->exist) {
+ reg->value = malloc(DIV_ROUND_UP(reg->size, 8));
+ if (!reg->value) {
+ LOG_ERROR("Failed to allocate memory.");
+ return ERROR_FAIL;
+ }
+ } else {
+ reg->value = NULL;
+ }
+ assert(riscv_reg_impl_is_initialized(reg));
+ return ERROR_OK;
+}
+
+static int set_reg_exist(const struct target *target, uint32_t regno, bool exist)
+{
+ const struct reg *reg = riscv_reg_impl_cache_entry(target, regno);
+ assert(riscv_reg_impl_is_initialized(reg));
+ return resize_reg(target, regno, exist, reg->size);
+}
+
+int riscv_reg_impl_init_one(struct target *target, uint32_t regno, const struct reg_arch_type *reg_type)
+{
+ struct reg * const reg = riscv_reg_impl_cache_entry(target, regno);
+ if (riscv_reg_impl_is_initialized(reg))
+ return ERROR_OK;
+ reg->number = regno;
+ reg->type = reg_type;
+ reg->dirty = false;
+ reg->valid = false;
+ reg->hidden = false;
+ reg->name = riscv_reg_gdb_regno_name(target, regno);
+ reg->feature = gdb_regno_feature(regno);
+ reg->caller_save = gdb_regno_caller_save(regno);
+ reg->reg_data_type = gdb_regno_reg_data_type(target, regno);
+ reg->group = gdb_regno_group(regno);
+ if (regno < GDB_REGNO_COUNT) {
+ RISCV_INFO(info);
+ reg->arch_info = &info->shared_reg_info;
+ } else {
+ reg->arch_info = calloc(1, sizeof(riscv_reg_info_t));
+ if (!reg->arch_info) {
+ LOG_ERROR("Out of memory.");
+ return ERROR_FAIL;
+ }
+ riscv_reg_info_t * const reg_arch_info = reg->arch_info;
+ reg_arch_info->target = target;
+ reg_arch_info->custom_number = gdb_regno_custom_number(target, regno);
+ }
+ return resize_reg(target, regno, gdb_regno_exist(target, regno),
+ gdb_regno_size(target, regno));
+}
+
+static int init_custom_register_names(struct list_head *expose_custom,
+ struct reg_name_table *custom_register_names)
+{
+ unsigned int custom_regs_num = 0;
+ if (!list_empty(expose_custom)) {
+ range_list_t *entry;
+ list_for_each_entry(entry, expose_custom, list)
+ custom_regs_num += entry->high - entry->low + 1;
+ }
+
+ if (!custom_regs_num)
+ return ERROR_OK;
+
+ custom_register_names->reg_names = calloc(custom_regs_num, sizeof(char *));
+ if (!custom_register_names->reg_names) {
+ LOG_ERROR("Failed to allocate memory for custom_register_names->reg_names");
+ return ERROR_FAIL;
+ }
+ custom_register_names->num_entries = custom_regs_num;
+ char **reg_names = custom_register_names->reg_names;
+ range_list_t *range;
+ unsigned int next_custom_reg_index = 0;
+ list_for_each_entry(range, expose_custom, list) {
+ for (unsigned int custom_number = range->low; custom_number <= range->high; ++custom_number) {
+ if (range->name)
+ reg_names[next_custom_reg_index] = init_reg_name(range->name);
+ else
+ reg_names[next_custom_reg_index] =
+ init_reg_name_with_prefix("custom", custom_number);
+
+ if (!reg_names[next_custom_reg_index])
+ return ERROR_FAIL;
+ ++next_custom_reg_index;
+ }
+ }
+ return ERROR_OK;
+}
+
+int riscv_reg_impl_init_cache(struct target *target)
+{
+ RISCV_INFO(info);
+
+ riscv_reg_free_all(target);
+
+ target->reg_cache = calloc(1, sizeof(*target->reg_cache));
+ if (!target->reg_cache) {
+ LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache");
+ return ERROR_FAIL;
+ }
+ target->reg_cache->name = "RISC-V Registers";
+
+ if (init_custom_register_names(&info->expose_custom, &info->custom_register_names) != ERROR_OK) {
+ LOG_TARGET_ERROR(target, "init_custom_register_names failed");
+ return ERROR_FAIL;
+ }
+
+ target->reg_cache->num_regs = GDB_REGNO_COUNT + info->custom_register_names.num_entries;
+ LOG_TARGET_DEBUG(target, "create register cache for %d registers",
+ target->reg_cache->num_regs);
+
+ target->reg_cache->reg_list =
+ calloc(target->reg_cache->num_regs, sizeof(struct reg));
+ if (!target->reg_cache->reg_list) {
+ LOG_TARGET_ERROR(target, "Failed to allocate memory for target->reg_cache->reg_list");
+ return ERROR_FAIL;
+ }
+ return ERROR_OK;
+}
+
+int riscv_reg_impl_expose_csrs(const struct target *target)
+{
+ RISCV_INFO(info);
+ range_list_t *entry;
+ list_for_each_entry(entry, &info->expose_csr, list) {
+ assert(entry->low <= entry->high);
+ assert(entry->high <= GDB_REGNO_CSR4095 - GDB_REGNO_CSR0);
+ const enum gdb_regno last_regno = GDB_REGNO_CSR0 + entry->high;
+ for (enum gdb_regno regno = GDB_REGNO_CSR0 + entry->low;
+ regno <= last_regno; ++regno) {
+ struct reg * const reg = riscv_reg_impl_cache_entry(target, regno);
+ const unsigned int csr_number = regno - GDB_REGNO_CSR0;
+ if (reg->exist) {
+ LOG_TARGET_WARNING(target,
+ "Not exposing CSR %d: register already exists.",
+ csr_number);
+ continue;
+ }
+ if (set_reg_exist(target, regno, /*exist*/ true) != ERROR_OK)
+ return ERROR_FAIL;
+ LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)",
+ csr_number, reg->name);
+ }
+ }
+ return ERROR_OK;
+}
+
+void riscv_reg_impl_hide_csrs(const struct target *target)
+{
+ RISCV_INFO(info);
+ range_list_t *entry;
+ list_for_each_entry(entry, &info->hide_csr, list) {
+ assert(entry->high <= GDB_REGNO_CSR4095 - GDB_REGNO_CSR0);
+ const enum gdb_regno last_regno = GDB_REGNO_CSR0 + entry->high;
+ for (enum gdb_regno regno = GDB_REGNO_CSR0 + entry->low;
+ regno <= last_regno; ++regno) {
+ struct reg * const reg = riscv_reg_impl_cache_entry(target, regno);
+ const unsigned int csr_number = regno - GDB_REGNO_CSR0;
+ if (!reg->exist) {
+ LOG_TARGET_WARNING(target,
+ "Not hiding CSR %d: register does not exist.",
+ csr_number);
+ continue;
+ }
+ LOG_TARGET_DEBUG(target, "Hiding CSR %d (name=%s).", csr_number, reg->name);
+ reg->hidden = true;
+ }
+ }
+}
+
+void riscv_reg_free_all(struct target *target)
+{
+ free_reg_names(target);
+ /* Free the shared structure use for most registers. */
+ if (!target->reg_cache)
+ return;
+ if (target->reg_cache->reg_list) {
+ for (unsigned int i = GDB_REGNO_COUNT; i < target->reg_cache->num_regs; i++)
+ free(target->reg_cache->reg_list[i].arch_info);
+ for (unsigned int i = 0; i < target->reg_cache->num_regs; i++)
+ free(target->reg_cache->reg_list[i].value);
+ free(target->reg_cache->reg_list);
+ }
+ free(target->reg_cache);
+ target->reg_cache = NULL;
+}
+
+int riscv_reg_flush_all(struct target *target)
+{
+ if (!target->reg_cache)
+ return ERROR_OK;
+
+ LOG_TARGET_DEBUG(target, "Flushing register cache");
+
+ /* Writing non-GPR registers may require progbuf execution, and some GPRs
+ * may become dirty in the process (e.g. S0, S1). For that reason, flush
+ * registers in reverse order, so that GPRs are flushed last.
+ */
+ for (unsigned int number = target->reg_cache->num_regs; number-- > 0; ) {
+ struct reg *reg = riscv_reg_impl_cache_entry(target, number);
+ if (reg->valid && reg->dirty) {
+ riscv_reg_t value = buf_get_u64(reg->value, 0, reg->size);
+
+ LOG_TARGET_DEBUG(target, "%s is dirty; write back 0x%" PRIx64,
+ reg->name, value);
+ if (riscv_reg_write(target, number, value) != ERROR_OK)
+ return ERROR_FAIL;
+ }
+ }
+ LOG_TARGET_DEBUG(target, "Flush of register cache completed");
+ return ERROR_OK;
+}
+
+/**
+ * This function is used internally by functions that change register values.
+ * If `write_through` is true, it is ensured that the value of the target's
+ * register is set to be equal to the `value` argument. The cached value is
+ * updated if the register is cacheable.
+ * TODO: Currently `reg->get/set` is implemented in terms of
+ * `riscv_get/set_register`. However, the intention behind
+ * `riscv_get/set_register` is to work with the cache, therefore it accesses
+ * and modifyes register cache directly. The idea is to implement
+ * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and
+ * `reg->get/set`.
+ */
+static int riscv_set_or_write_register(struct target *target,
+ enum gdb_regno regid, riscv_reg_t value, bool write_through)
+{
+ RISCV_INFO(r);
+ assert(r);
+ if (r->dtm_version == DTM_DTMCS_VERSION_0_11)
+ return riscv011_set_register(target, regid, value);
+
+ keep_alive();
+
+ if (regid == GDB_REGNO_PC) {
+ return riscv_set_or_write_register(target, GDB_REGNO_DPC, value, write_through);
+ } else if (regid == GDB_REGNO_PRIV) {
+ riscv_reg_t dcsr;
+
+ if (riscv_reg_get(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK)
+ return ERROR_FAIL;
+ dcsr = set_field(dcsr, CSR_DCSR_PRV, get_field(value, VIRT_PRIV_PRV));
+ dcsr = set_field(dcsr, CSR_DCSR_V, get_field(value, VIRT_PRIV_V));
+ return riscv_set_or_write_register(target, GDB_REGNO_DCSR, dcsr, write_through);
+ }
+
+ if (!target->reg_cache) {
+ assert(!target_was_examined(target));
+ LOG_TARGET_DEBUG(target,
+ "No cache, writing to target: %s <- 0x%" PRIx64,
+ riscv_reg_gdb_regno_name(target, regid), value);
+ return riscv013_set_register(target, regid, value);
+ }
+
+ struct reg *reg = riscv_reg_impl_cache_entry(target, regid);
+
+ if (!reg->exist) {
+ LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name);
+ return ERROR_FAIL;
+ }
+
+ if (target->state != TARGET_HALTED) {
+ LOG_TARGET_DEBUG(target,
+ "Target not halted, writing to target: %s <- 0x%" PRIx64,
+ reg->name, value);
+ return riscv013_set_register(target, regid, value);
+ }
+
+ const bool need_to_write = !reg->valid || reg->dirty ||
+ value != buf_get_u64(reg->value, 0, reg->size);
+ const bool cacheable = riscv_reg_impl_gdb_regno_cacheable(regid, need_to_write);
+
+ if (!cacheable || (write_through && need_to_write)) {
+ LOG_TARGET_DEBUG(target,
+ "Writing to target: %s <- 0x%" PRIx64 " (cacheable=%s, valid=%s, dirty=%s)",
+ reg->name, value, cacheable ? "true" : "false",
+ reg->valid ? "true" : "false",
+ reg->dirty ? "true" : "false");
+ if (riscv013_set_register(target, regid, value) != ERROR_OK)
+ return ERROR_FAIL;
+
+ reg->dirty = false;
+ } else {
+ reg->dirty = need_to_write;
+ }
+
+ buf_set_u64(reg->value, 0, reg->size, value);
+ reg->valid = cacheable;
+
+ LOG_TARGET_DEBUG(target,
+ "Wrote 0x%" PRIx64 " to %s (cacheable=%s, valid=%s, dirty=%s)",
+ value, reg->name, cacheable ? "true" : "false",
+ reg->valid ? "true" : "false",
+ reg->dirty ? "true" : "false");
+ return ERROR_OK;
+}
+
+/**
+ * This function is used to change the value of a register. The new value may
+ * be cached, and may not be written until the hart is resumed.
+ * TODO: Currently `reg->get/set` is implemented in terms of
+ * `riscv_get/set_register`. However, the intention behind
+ * `riscv_get/set_register` is to work with the cache, therefore it accesses
+ * and modifyes register cache directly. The idea is to implement
+ * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and
+ * `reg->get/set`.
+ */
+int riscv_reg_set(struct target *target, enum gdb_regno regid,
+ riscv_reg_t value)
+{
+ return riscv_set_or_write_register(target, regid, value,
+ /* write_through */ false);
+}
+
+/**
+ * This function is used to change the value of a register. The new value may
+ * be cached, but it will be written to hart immediately.
+ * TODO: Currently `reg->get/set` is implemented in terms of
+ * `riscv_get/set_register`. However, the intention behind
+ * `riscv_get/set_register` is to work with the cache, therefore it accesses
+ * and modifyes register cache directly. The idea is to implement
+ * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and
+ * `reg->get/set`.
+ */
+int riscv_reg_write(struct target *target, enum gdb_regno regid,
+ riscv_reg_t value)
+{
+ return riscv_set_or_write_register(target, regid, value,
+ /* write_through */ true);
+}
+
+/**
+ * This function is used to get the value of a register. If possible, the value
+ * in cache will be updated.
+ * TODO: Currently `reg->get/set` is implemented in terms of
+ * `riscv_get/set_register`. However, the intention behind
+ * `riscv_get/set_register` is to work with the cache, therefore it accesses
+ * and modifyes register cache directly. The idea is to implement
+ * `riscv_get/set_register` in terms of `riscv_reg_impl_cache_entry` and
+ * `reg->get/set`.
+ */
+int riscv_reg_get(struct target *target, riscv_reg_t *value,
+ enum gdb_regno regid)
+{
+ RISCV_INFO(r);
+ assert(r);
+ if (r->dtm_version == DTM_DTMCS_VERSION_0_11)
+ return riscv013_get_register(target, value, regid);
+
+ keep_alive();
+
+ if (regid == GDB_REGNO_PC)
+ return riscv_reg_get(target, value, GDB_REGNO_DPC);
+
+ if (!target->reg_cache) {
+ assert(!target_was_examined(target));
+ LOG_TARGET_DEBUG(target, "No cache, reading %s from target",
+ riscv_reg_gdb_regno_name(target, regid));
+ return riscv013_get_register(target, value, regid);
+ }
+
+ struct reg *reg = riscv_reg_impl_cache_entry(target, regid);
+ if (!reg->exist) {
+ LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name);
+ return ERROR_FAIL;
+ }
+
+ if (reg->valid) {
+ *value = buf_get_u64(reg->value, 0, reg->size);
+ LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64 " (cached)", reg->name,
+ *value);
+ return ERROR_OK;
+ }
+
+ LOG_TARGET_DEBUG(target, "Reading %s from target", reg->name);
+ if (riscv013_get_register(target, value, regid) != ERROR_OK)
+ return ERROR_FAIL;
+
+ buf_set_u64(reg->value, 0, reg->size, *value);
+ reg->valid = riscv_reg_impl_gdb_regno_cacheable(regid, /* is write? */ false) &&
+ target->state == TARGET_HALTED;
+ reg->dirty = false;
+
+ LOG_TARGET_DEBUG(target, "Read %s: 0x%" PRIx64, reg->name, *value);
+ return ERROR_OK;
+}
diff --git a/src/target/riscv/riscv_reg.h b/src/target/riscv/riscv_reg.h
new file mode 100644
index 0000000..264addd
--- /dev/null
+++ b/src/target/riscv/riscv_reg.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_H
+#define OPENOCD_TARGET_RISCV_RISCV_REG_H
+
+#include "target/target.h"
+#include "target/register.h"
+
+/**
+ * This file describes the register cache interface available to the RISC-V
+ * target. Functions declared here should be safe to use once register cache is
+ * completely initialized and may be used with caution during register cache
+ * initialization.
+ */
+
+/** Return the name of the register by it's number in register cache. */
+const char *riscv_reg_gdb_regno_name(const struct target *target, enum gdb_regno regno);
+
+/** Free register cache and associated structures. */
+void riscv_reg_free_all(struct target *target);
+
+/** Write all dirty registers to the target. */
+int riscv_reg_flush_all(struct target *target);
+/**
+ * Set the register value. For cacheable registers, only the cache is updated
+ * (write-back mode).
+ */
+int riscv_reg_set(struct target *target, enum gdb_regno i, riscv_reg_t v);
+/**
+ * Set the register value and immediately write it to the target
+ * (write-through mode).
+ */
+int riscv_reg_write(struct target *target, enum gdb_regno i, riscv_reg_t v);
+/** Get register, from the cache if it's in there. */
+int riscv_reg_get(struct target *target, riscv_reg_t *value,
+ enum gdb_regno r);
+
+#endif /* OPENOCD_TARGET_RISCV_RISCV_REG_H */
diff --git a/src/target/riscv/riscv_reg_impl.h b/src/target/riscv/riscv_reg_impl.h
new file mode 100644
index 0000000..906a5b6
--- /dev/null
+++ b/src/target/riscv/riscv_reg_impl.h
@@ -0,0 +1,214 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_IMPL_H
+#define OPENOCD_TARGET_RISCV_RISCV_REG_IMPL_H
+
+#include "gdb_regs.h"
+#include "riscv.h"
+#include "target/target.h"
+#include "target/register.h"
+#include <assert.h>
+
+/**
+ * This file describes the helpers to use during register cache initialization
+ * of a RISC-V target. Each cache entry proceedes through the following stages:
+ * - not allocated before `riscv_reg_impl_init_cache()`
+ * - not initialized before the call to `riscv_reg_impl_init_one()` with appropriate regno.
+ * - initialized until `riscv_reg_free_all()` is called.
+ */
+static inline bool riscv_reg_impl_is_initialized(const struct reg *reg)
+{
+ assert(reg);
+ if (!reg->feature) {
+ const struct reg default_reg = {0};
+ assert(!memcmp(&default_reg, reg, sizeof(*reg)));
+ return false;
+ }
+ assert(reg->arch_info);
+ assert(((riscv_reg_info_t *)reg->arch_info)->target);
+ assert((!reg->exist && !reg->value) || (reg->exist && reg->value));
+ assert(reg->valid || !reg->dirty);
+ return true;
+}
+/**
+ * Initialize register cache. Note, that each specific register cache entry is
+ * not initialized by this function.
+ */
+int riscv_reg_impl_init_cache(struct target *target);
+
+/** Initialize register. */
+int riscv_reg_impl_init_one(struct target *target, uint32_t regno,
+ const struct reg_arch_type *reg_type);
+
+/** Return the entry in the register cache of the target. */
+struct reg *riscv_reg_impl_cache_entry(const struct target *target,
+ uint32_t number);
+
+/** Return the target that owns the cache entry. */
+struct target *riscv_reg_impl_get_target(const struct reg *reg);
+
+static inline void init_shared_reg_info(struct target *target)
+{
+ RISCV_INFO(info);
+ info->shared_reg_info.target = target;
+ info->shared_reg_info.custom_number = 0;
+}
+
+/** TODO: vector register type description can be moved into `riscv013_info_t`,
+ * since 0.11 targets do not support access to vector registers. */
+static inline void riscv_reg_impl_init_vector_reg_type(const struct target *target)
+{
+ RISCV_INFO(info);
+ static struct reg_data_type type_uint8 = { .type = REG_TYPE_UINT8, .id = "uint8" };
+ static struct reg_data_type type_uint16 = { .type = REG_TYPE_UINT16, .id = "uint16" };
+ static struct reg_data_type type_uint32 = { .type = REG_TYPE_UINT32, .id = "uint32" };
+ static struct reg_data_type type_uint64 = { .type = REG_TYPE_UINT64, .id = "uint64" };
+ static struct reg_data_type type_uint128 = { .type = REG_TYPE_UINT128, .id = "uint128" };
+
+ /* This is roughly the XML we want:
+ * <vector id="bytes" type="uint8" count="16"/>
+ * <vector id="shorts" type="uint16" count="8"/>
+ * <vector id="words" type="uint32" count="4"/>
+ * <vector id="longs" type="uint64" count="2"/>
+ * <vector id="quads" type="uint128" count="1"/>
+ * <union id="riscv_vector_type">
+ * <field name="b" type="bytes"/>
+ * <field name="s" type="shorts"/>
+ * <field name="w" type="words"/>
+ * <field name="l" type="longs"/>
+ * <field name="q" type="quads"/>
+ * </union>
+ */
+
+ info->vector_uint8.type = &type_uint8;
+ info->vector_uint8.count = riscv_vlenb(target);
+ info->type_uint8_vector.type = REG_TYPE_ARCH_DEFINED;
+ info->type_uint8_vector.id = "bytes";
+ info->type_uint8_vector.type_class = REG_TYPE_CLASS_VECTOR;
+ info->type_uint8_vector.reg_type_vector = &info->vector_uint8;
+
+ info->vector_uint16.type = &type_uint16;
+ info->vector_uint16.count = riscv_vlenb(target) / 2;
+ info->type_uint16_vector.type = REG_TYPE_ARCH_DEFINED;
+ info->type_uint16_vector.id = "shorts";
+ info->type_uint16_vector.type_class = REG_TYPE_CLASS_VECTOR;
+ info->type_uint16_vector.reg_type_vector = &info->vector_uint16;
+
+ info->vector_uint32.type = &type_uint32;
+ info->vector_uint32.count = riscv_vlenb(target) / 4;
+ info->type_uint32_vector.type = REG_TYPE_ARCH_DEFINED;
+ info->type_uint32_vector.id = "words";
+ info->type_uint32_vector.type_class = REG_TYPE_CLASS_VECTOR;
+ info->type_uint32_vector.reg_type_vector = &info->vector_uint32;
+
+ info->vector_uint64.type = &type_uint64;
+ info->vector_uint64.count = riscv_vlenb(target) / 8;
+ info->type_uint64_vector.type = REG_TYPE_ARCH_DEFINED;
+ info->type_uint64_vector.id = "longs";
+ info->type_uint64_vector.type_class = REG_TYPE_CLASS_VECTOR;
+ info->type_uint64_vector.reg_type_vector = &info->vector_uint64;
+
+ info->vector_uint128.type = &type_uint128;
+ info->vector_uint128.count = riscv_vlenb(target) / 16;
+ info->type_uint128_vector.type = REG_TYPE_ARCH_DEFINED;
+ info->type_uint128_vector.id = "quads";
+ info->type_uint128_vector.type_class = REG_TYPE_CLASS_VECTOR;
+ info->type_uint128_vector.reg_type_vector = &info->vector_uint128;
+
+ info->vector_fields[0].name = "b";
+ info->vector_fields[0].type = &info->type_uint8_vector;
+ if (riscv_vlenb(target) >= 2) {
+ info->vector_fields[0].next = info->vector_fields + 1;
+ info->vector_fields[1].name = "s";
+ info->vector_fields[1].type = &info->type_uint16_vector;
+ } else {
+ info->vector_fields[0].next = NULL;
+ }
+ if (riscv_vlenb(target) >= 4) {
+ info->vector_fields[1].next = info->vector_fields + 2;
+ info->vector_fields[2].name = "w";
+ info->vector_fields[2].type = &info->type_uint32_vector;
+ } else {
+ info->vector_fields[1].next = NULL;
+ }
+ if (riscv_vlenb(target) >= 8) {
+ info->vector_fields[2].next = info->vector_fields + 3;
+ info->vector_fields[3].name = "l";
+ info->vector_fields[3].type = &info->type_uint64_vector;
+ } else {
+ info->vector_fields[2].next = NULL;
+ }
+ if (riscv_vlenb(target) >= 16) {
+ info->vector_fields[3].next = info->vector_fields + 4;
+ info->vector_fields[4].name = "q";
+ info->vector_fields[4].type = &info->type_uint128_vector;
+ } else {
+ info->vector_fields[3].next = NULL;
+ }
+ info->vector_fields[4].next = NULL;
+
+ info->vector_union.fields = info->vector_fields;
+
+ info->type_vector.type = REG_TYPE_ARCH_DEFINED;
+ info->type_vector.id = "riscv_vector";
+ info->type_vector.type_class = REG_TYPE_CLASS_UNION;
+ info->type_vector.reg_type_union = &info->vector_union;
+}
+
+/** Expose additional CSRs, as specified by `riscv_info_t::expose_csr` list. */
+int riscv_reg_impl_expose_csrs(const struct target *target);
+
+/** Hide additional CSRs, as specified by `riscv_info_t::hide_csr` list. */
+void riscv_reg_impl_hide_csrs(const struct target *target);
+
+/**
+ * If write is true:
+ * return true iff we are guaranteed that the register will contain exactly
+ * the value we just wrote when it's read.
+ * If write is false:
+ * return true iff we are guaranteed that the register will read the same
+ * value in the future as the value we just read.
+ */
+static inline bool riscv_reg_impl_gdb_regno_cacheable(enum gdb_regno regno,
+ bool is_write)
+{
+ if (regno == GDB_REGNO_ZERO)
+ return !is_write;
+
+ /* GPRs, FPRs, vector registers are just normal data stores. */
+ if (regno <= GDB_REGNO_XPR31 ||
+ (regno >= GDB_REGNO_FPR0 && regno <= GDB_REGNO_FPR31) ||
+ (regno >= GDB_REGNO_V0 && regno <= GDB_REGNO_V31))
+ return true;
+
+ /* Most CSRs won't change value on us, but we can't assume it about arbitrary
+ * CSRs. */
+ switch (regno) {
+ case GDB_REGNO_DPC:
+ case GDB_REGNO_VSTART:
+ case GDB_REGNO_VXSAT:
+ case GDB_REGNO_VXRM:
+ case GDB_REGNO_VLENB:
+ case GDB_REGNO_VL:
+ case GDB_REGNO_VTYPE:
+ case GDB_REGNO_MISA:
+ case GDB_REGNO_DCSR:
+ case GDB_REGNO_DSCRATCH0:
+ case GDB_REGNO_MSTATUS:
+ case GDB_REGNO_MEPC:
+ case GDB_REGNO_MCAUSE:
+ case GDB_REGNO_SATP:
+ /*
+ * WARL registers might not contain the value we just wrote, but
+ * these ones won't spontaneously change their value either. *
+ */
+ return !is_write;
+
+ case GDB_REGNO_TSELECT: /* I think this should be above, but then it doesn't work. */
+ case GDB_REGNO_TDATA1: /* Changes value when tselect is changed. */
+ case GDB_REGNO_TDATA2: /* Changes value when tselect is changed. */
+ default:
+ return false;
+ }
+}
+#endif /* OPENOCD_TARGET_RISCV_RISCV_REG_IMPL_H */
diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c
index 9c708c8..0f4f6b5 100644
--- a/src/target/riscv/riscv_semihosting.c
+++ b/src/target/riscv/riscv_semihosting.c
@@ -32,6 +32,7 @@
#include "target/target.h"
#include "riscv.h"
+#include "riscv_reg.h"
static int riscv_semihosting_setup(struct target *target, int enable);
static int riscv_semihosting_post_result(struct target *target);
@@ -67,7 +68,7 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval)
}
riscv_reg_t pc;
- int result = riscv_get_register(target, &pc, GDB_REGNO_PC);
+ int result = riscv_reg_get(target, &pc, GDB_REGNO_PC);
if (result != ERROR_OK)
return SEMIHOSTING_ERROR;
@@ -107,13 +108,13 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval)
riscv_reg_t r0;
riscv_reg_t r1;
- result = riscv_get_register(target, &r0, GDB_REGNO_A0);
+ result = riscv_reg_get(target, &r0, GDB_REGNO_A0);
if (result != ERROR_OK) {
LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a0)");
return SEMIHOSTING_ERROR;
}
- result = riscv_get_register(target, &r1, GDB_REGNO_A1);
+ result = riscv_reg_get(target, &r1, GDB_REGNO_A1);
if (result != ERROR_OK) {
LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a1)");
return SEMIHOSTING_ERROR;
@@ -140,7 +141,7 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval)
}
/* Resume right after the EBREAK 4 bytes instruction. */
- *retval = riscv_set_register(target, GDB_REGNO_PC, pc + 4);
+ *retval = riscv_reg_set(target, GDB_REGNO_PC, pc + 4);
if (*retval != ERROR_OK)
return SEMIHOSTING_ERROR;
@@ -184,6 +185,6 @@ static int riscv_semihosting_post_result(struct target *target)
}
LOG_TARGET_DEBUG(target, "Result: 0x%" PRIx64, semihosting->result);
- riscv_set_register(target, GDB_REGNO_A0, semihosting->result);
+ riscv_reg_set(target, GDB_REGNO_A0, semihosting->result);
return 0;
}
diff --git a/src/target/target.c b/src/target/target.c
index 5187006..fd9c34f 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -4675,9 +4675,8 @@ void target_handle_event(struct target *target, enum target_event e)
if (retval != JIM_OK) {
Jim_MakeErrorMessage(teap->interp);
- LOG_USER("Error executing event %s on target %s:\n%s",
+ LOG_TARGET_ERROR(target, "Execution of event %s failed:\n%s",
target_event_name(e),
- target_name(target),
Jim_GetString(Jim_GetResult(teap->interp), NULL));
/* clean both error code and stacktrace before return */
Jim_Eval(teap->interp, "error \"\" \"\"");
@@ -5349,17 +5348,19 @@ COMMAND_HANDLER(handle_target_reset)
return ERROR_FAIL;
}
- if (target->defer_examine)
- target_reset_examined(target);
-
/* determine if we should halt or not. */
target->reset_halt = (a != 0);
/* When this happens - all workareas are invalid. */
target_free_all_working_areas_restore(target, 0);
/* do the assert */
- if (n->value == NVP_ASSERT)
- return target->type->assert_reset(target);
+ if (n->value == NVP_ASSERT) {
+ int retval = target->type->assert_reset(target);
+ if (target->defer_examine)
+ target_reset_examined(target);
+ return retval;
+ }
+
return target->type->deassert_reset(target);
}
diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c
index f7c82ef..702b8fc 100644
--- a/src/target/xtensa/xtensa.c
+++ b/src/target/xtensa/xtensa.c
@@ -331,7 +331,7 @@ union xtensa_reg_val_u {
uint8_t buf[4];
};
-static const struct xtensa_keyval_info_s xt_qerr[XT_QERR_NUM] = {
+static const struct xtensa_keyval_info xt_qerr[XT_QERR_NUM] = {
{ .chrval = "E00", .intval = ERROR_FAIL },
{ .chrval = "E01", .intval = ERROR_FAIL },
{ .chrval = "E02", .intval = ERROR_COMMAND_ARGUMENT_INVALID },
diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h
index a220021..1d56f83 100644
--- a/src/target/xtensa/xtensa.h
+++ b/src/target/xtensa/xtensa.h
@@ -97,7 +97,7 @@ enum xtensa_ar_scratch_set_e {
XT_AR_SCRATCH_NUM
};
-struct xtensa_keyval_info_s {
+struct xtensa_keyval_info {
char *chrval;
int intval;
};
@@ -283,7 +283,7 @@ struct xtensa {
bool halt_request;
uint32_t nx_stop_cause;
uint32_t nx_reg_idx[XT_NX_REG_IDX_NUM];
- struct xtensa_keyval_info_s scratch_ars[XT_AR_SCRATCH_NUM];
+ struct xtensa_keyval_info scratch_ars[XT_AR_SCRATCH_NUM];
bool regs_fetched; /* true after first register fetch completed successfully */
};
diff --git a/tcl/board/digilent_nexys2.cfg b/tcl/board/digilent_nexys2.cfg
new file mode 100644
index 0000000..c1c5b2a
--- /dev/null
+++ b/tcl/board/digilent_nexys2.cfg
@@ -0,0 +1,30 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# https://digilent.com/reference/programmable-logic/nexys-2/start
+#
+# The Digilent Nexy2 normally requires proprietary tools to program and will
+# enumerate as:
+# ID 1443:0005 1443 ONBOARD USB
+#
+# However, the ixo-usb-jtag project provides an alternative open firmware for
+# the on board programmer. When using this firmware the board will then
+# enumerate as:
+# ID 16c0:06ad ixo.de USB-JTAG-IF (With SerialNumber == hw_nexys)
+#
+# See the interface/usb-jtag.cfg for more information.
+
+source [find interface/usb-jtag.cfg]
+source [find cpld/xilinx-xcf-s.cfg]
+source [find fpga/xilinx-xc3s.cfg]
+
+# Usage:
+#
+# Load Bitstream into FPGA:
+# openocd -f board/digilent_nexys2.cfg -c "init;\
+# pld load 0 bitstream.bit;\
+# shutdown"
+
+# Read Unique Device Identifier (DNA):
+# openocd -f board/digilent_nexys2.cfg -c "init;\
+# xilinx_print_dna [xc3s_get_dna xc3s.tap];\
+# shutdown"
diff --git a/tcl/board/nxp/frdm-kv11z-jlink.cfg b/tcl/board/nxp/frdm-kv11z-jlink.cfg
new file mode 100644
index 0000000..725a37b
--- /dev/null
+++ b/tcl/board/nxp/frdm-kv11z-jlink.cfg
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Configuration file for NXP FRDM-KV11Z development boards.
+#
+# This configuration file is only for FRDM-KV11Z development boards with the
+# SEGGER J-Link OpenSDA firmware, see:
+# https://www.segger.com/products/debug-probes/j-link/models/other-j-links/opensda-sda-v2/
+
+source [find interface/jlink.cfg]
+
+# Set working area size to 16 KiB.
+set WORKAREASIZE 0x4000
+
+# Set the chip name.
+set CHIPNAME kv11z
+
+transport select swd
+
+source [find target/kx.cfg]
+
+reset_config srst_only
diff --git a/tcl/board/nxp/frdm-kv31f-jlink.cfg b/tcl/board/nxp/frdm-kv31f-jlink.cfg
new file mode 100644
index 0000000..e55a01c
--- /dev/null
+++ b/tcl/board/nxp/frdm-kv31f-jlink.cfg
@@ -0,0 +1,21 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Configuration file for NXP FRDM-KV31F development boards.
+#
+# This configuration file is only for FRDM-KV31F development boards with the
+# SEGGER J-Link OpenSDA firmware, see:
+# https://www.segger.com/products/debug-probes/j-link/models/other-j-links/opensda-sda-v2/
+
+source [find interface/jlink.cfg]
+
+# Set working area size to 32 KiB.
+set WORKAREASIZE 0x8000
+
+# Set the chip name.
+set CHIPNAME kv31f
+
+transport select swd
+
+source [find target/kx.cfg]
+
+reset_config srst_only
diff --git a/tcl/chip/st/spear/spear3xx_ddr.tcl b/tcl/chip/st/spear/spear3xx_ddr.tcl
index 5992567..0696221 100644
--- a/tcl/chip/st/spear/spear3xx_ddr.tcl
+++ b/tcl/chip/st/spear/spear3xx_ddr.tcl
@@ -10,7 +10,7 @@
proc sp3xx_ddr_init {ddr_type {ddr_chips 1}} {
if { $ddr_chips != 1 && $ddr_chips != 2 } {
- error "Only 1 or 2 DDR chips permitted. Wrong value "$ddr_chips
+ error "Only 1 or 2 DDR chips permitted. Wrong value $ddr_chips"
}
if { $ddr_type == "mt47h64m16_3_333_cl5_async" } {
@@ -21,7 +21,7 @@ proc sp3xx_ddr_init {ddr_type {ddr_chips 1}} {
# ????? $ddr_chips
# set ddr_size 0x?????
} else {
- error "sp3xx_ddr_init: unrecognized DDR type "$ddr_type
+ error "sp3xx_ddr_init: unrecognized DDR type $ddr_type"
}
# MPMC START
diff --git a/tcl/fpga/altera-arriaii.cfg b/tcl/fpga/altera-arriaii.cfg
index d59c182..9cf680d 100644
--- a/tcl/fpga/altera-arriaii.cfg
+++ b/tcl/fpga/altera-arriaii.cfg
@@ -21,11 +21,26 @@ if { [info exists CHIPNAME] } {
set _CHIPNAME arriaii
}
-jtag newtap $_CHIPNAME tap -irlen 10 \
- -expected-id 0x025120dd -expected-id 0x025040dd \
- -expected-id 0x025020dd -expected-id 0x024810dd \
- -expected-id 0x025130dd -expected-id 0x0240a0dd \
- -expected-id 0x025030dd -expected-id 0x024820dd \
- -expected-id 0x025140dd
+array set _ARRIA_2_DATA {
+ 0x025120dd {1227 1174 EP2AGX45}
+ 0x025020dd {1227 -1 EP2AGX65}
+ 0x025130dd {1467 -1 EP2AGX95}
+ 0x025030dd {1467 -1 EP2AGX125}
+ 0x025140dd {1971 -1 EP2AGX190}
+ 0x025040dd {1971 -1 EP2AGX260}
+ 0x024810dd {2274 -1 EP2AGZ225}
+ 0x0240a0dd {2682 -1 EP2AGZ300}
+ 0x024820dd {2682 -1 EP2AGZ350}
+}
+
+set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version}
+foreach id [array names _ARRIA_2_DATA] {
+ set cmd [concat "-expected-id" id]
+}
+eval $jtag_newtap_cmd
+
+source [find fpga/altera_common_init.cfg]
pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family arriaii
+jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_ARRIA_2_DATA}"
+
diff --git a/tcl/fpga/altera-cyclone10.cfg b/tcl/fpga/altera-cyclone10.cfg
index 3a1bc1f..0898c74 100644
--- a/tcl/fpga/altera-cyclone10.cfg
+++ b/tcl/fpga/altera-cyclone10.cfg
@@ -4,31 +4,33 @@
# see: https://www.intel.com/content/www/us/en/docs/programmable/683777/current/bst-operation-control.html
# and: https://www.intel.cn/content/dam/support/us/en/programmable/kdb/pdfs/literature/hb/cyclone-10/c10gx-51003.pdf
-# GX085: 0x02e120dd
-# GX105: 0x02e320dd
-# GX150: 0x02e720dd
-# GX220: 0x02ef20dd
-# 10cl006: 0x020f10dd
-# 10cl010: 0x020f10dd
-# 10cl016: 0x020f20dd
-# 10cl025: 0x020f30dd
-# 10cl040: 0x020f40dd
-# 10cl055: 0x020f50dd
-# 10cl080: 0x020f60dd
-# 10cl120: 0x020f70dd
-
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME cyclone10
}
-jtag newtap $_CHIPNAME tap -irlen 10 \
- -expected-id 0x02e720dd -expected-id 0x02e120dd \
- -expected-id 0x02ef20dd -expected-id 0x02e320dd \
- -expected-id 0x020f10dd -expected-id 0x020f20dd \
- -expected-id 0x020f30dd -expected-id 0x020f40dd \
- -expected-id 0x020f50dd -expected-id 0x020f60dd \
- -expected-id 0x020f70dd
+array set _CYCLONE_10_DATA {
+ 0x020f10dd { 603 226 10cl006_10cl010}
+ 0x020f20dd {1080 409 10cl016}
+ 0x020f30dd { 732 286 10cl025}
+ 0x020f40dd {1632 604 10cl040}
+ 0x020f50dd {1164 442 10cl055}
+ 0x020f60dd {1314 502 10cl080}
+ 0x020f70dd {1620 613 10cl120}
+ 0x02e120dd {1339 -1 GX085}
+ 0x02e320dd {1339 -1 GX105}
+ 0x02e720dd {1339 -1 GX150}
+ 0x02ef20dd {1339 -1 GX220}
+}
+
+set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version}
+foreach id [array names _CYCLONE_10_DATA] {
+ set cmd [concat "-expected-id" id]
+}
+eval $jtag_newtap_cmd
+
+source [find fpga/altera_common_init.cfg]
-pld device intel $_CHIPNAME.tap cyclone10
+pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cyclone10
+jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_CYCLONE_10_DATA}"
diff --git a/tcl/fpga/altera-cycloneiii.cfg b/tcl/fpga/altera-cycloneiii.cfg
index d9be645..b0da418 100644
--- a/tcl/fpga/altera-cycloneiii.cfg
+++ b/tcl/fpga/altera-cycloneiii.cfg
@@ -4,32 +4,33 @@
# see Cyclone III Device Handbook
# Table 12-2: Device IDCODE for Cyclone III Device Family
-#EP3C5 0x020f10dd
-#EP3C10 0x020f10dd
-#EP3C16 0x020f20dd
-#EP3C25 0x020f30dd
-#EP3C40 0x020f40dd
-#EP3C55 0x020f50dd
-#EP3C80 0x020f60dd
-#EP3C120 0x020f70dd
-#Cyclone III LS
-#EP3CLS70 0x027010dd
-#EP3CLS100 0x027000dd
-#EP3CLS150 0x027030dd
-#EP3CLS200 0x027020dd
-
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME cycloneiii
}
-jtag newtap $_CHIPNAME tap -irlen 10 \
- -expected-id 0x020f10dd -expected-id 0x020f20dd \
- -expected-id 0x020f30dd -expected-id 0x020f40dd \
- -expected-id 0x020f50dd -expected-id 0x020f60dd \
- -expected-id 0x020f70dd -expected-id 0x027010dd \
- -expected-id 0x027000dd -expected-id 0x027030dd \
- -expected-id 0x027020dd
+array set _CYCLONE_3_DATA {
+ 0x020f10dd { 603 226 EP3C5_EP3C10}
+ 0x020f20dd {1080 409 EP3C16}
+ 0x020f30dd { 732 286 EP3C25}
+ 0x020f40dd {1632 604 EP3C40}
+ 0x020f50dd {1164 442 EP3C55}
+ 0x020f60dd {1314 502 EP3C80}
+ 0x020f70dd {1620 613 EP3C120}
+ 0x027010dd {1314 226 EP3CLS70}
+ 0x027000dd {1314 226 EP3CLS100}
+ 0x027030dd {1314 409 EP3CLS150}
+ 0x027020dd {1314 409 EP3CLS200}
+}
+
+set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version}
+foreach id [array names _CYCLONE_3_DATA] {
+ set cmd [concat "-expected-id" id]
+}
+eval $jtag_newtap_cmd
+
+source [find fpga/altera_common_init.cfg]
pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiii
+jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_CYCLONE_3_DATA}"
diff --git a/tcl/fpga/altera-cycloneiv.cfg b/tcl/fpga/altera-cycloneiv.cfg
index 6a908e8..44eb89d 100644
--- a/tcl/fpga/altera-cycloneiv.cfg
+++ b/tcl/fpga/altera-cycloneiv.cfg
@@ -4,38 +4,37 @@
# see Cyclone IV Device Handbook
# Table 10-2: IDCODE Information for 32-Bit Cyclone IV Devices
-#EP4CE6 0x020f10dd
-#EP4CE10 0x020f10dd
-#EP4CE15 0x020f20dd
-#EP4CE22 0x020f30dd
-#EP4CE30 0x020f40dd
-#EP4CE40 0x020f40dd
-#EP4CE55 0x020f50dd
-#EP4CE75 0x020f60dd
-#EP4CE115 0x020f70dd
-#EP4CGX15 0x028010dd
-#EP4CGX22 0x028120dd
-#EP4CGX30 (3) 0x028020dd
-#EP4CGX30 (4) 0x028230dd
-#EP4CGX50 0x028130dd
-#EP4CGX75 0x028030dd
-#EP4CGX110 0x028140dd
-#EP4CGX150 0x028040dd
-
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME cycloneiv
}
-jtag newtap $_CHIPNAME tap -irlen 10 \
- -expected-id 0x020f10dd -expected-id 0x020f20dd \
- -expected-id 0x020f30dd -expected-id 0x020f40dd \
- -expected-id 0x020f50dd -expected-id 0x020f60dd \
- -expected-id 0x020f70dd -expected-id 0x028010dd \
- -expected-id 0x028120dd -expected-id 0x028020dd \
- -expected-id 0x028230dd -expected-id 0x028130dd \
- -expected-id 0x028030dd -expected-id 0x028140dd \
- -expected-id 0x028040dd
+array set _CYCLON_4_DATA {
+ 0x020f10dd { 603 226 EP4CE6_EP4CE10}
+ 0x020f20dd {1080 409 EP4CE15}
+ 0x020f30dd { 732 286 EP4CE22}
+ 0x020f40dd {1632 604 EP4CE30_EP4CE40}
+ 0x020f50dd {1164 442 EP4CE55}
+ 0x020f60dd {1314 502 EP4CE75}
+ 0x020f70dd {1620 613 EP4CE115}
+ 0x028010dd { 260 229 EP4CGX15}
+ 0x028120dd { 494 463 EP4CGX22}
+ 0x028020dd { 494 463 EP4CGX30}
+ 0x028230dd {1006 943 EP4CGX30}
+ 0x028130dd {1006 943 EP4CGX50}
+ 0x028030dd {1006 943 EP4CGX75}
+ 0x028140dd {1495 1438 EP4CGX110}
+ 0x028040dd {1495 1438 EP4CGX150}
+}
+
+set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version}
+foreach id [array names _CYCLON_4_DATA] {
+ set cmd [concat "-expected-id" id]
+}
+eval $jtag_newtap_cmd
+
+source [find fpga/altera_common_init.cfg]
pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cycloneiv
+jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_CYCLONE_4_DATA}"
diff --git a/tcl/fpga/altera-cyclonev.cfg b/tcl/fpga/altera-cyclonev.cfg
index 46532a5..8d19cd8 100644
--- a/tcl/fpga/altera-cyclonev.cfg
+++ b/tcl/fpga/altera-cyclonev.cfg
@@ -4,44 +4,36 @@
# see Cyclone V Device Handbook
# Table 9-1: IDCODE Information for Cyclone V Devices
-#5CEA2 0x02b150dd
-#5CEA4 0x02b050dd
-#5CEA5 0x02b220dd
-#5CEA7 0x02b130dd
-#5CEA9 0x02b140dd
-#5CGXC3 0x02b010dd
-#5CGXC4 0x02b120dd
-#5CGXC5 0x02b020dd
-#5CGXC7 0x02b030dd
-#5CGXC9 0x02b040dd
-#5CGTD5 0x02b020dd
-#5CGTD7 0x02b030dd
-#5CGTD9 0x02b040dd
-#5CSEA2 0x02d110dd
-#5CSEA4 0x02d010dd
-#5CSEA5 0x02d120dd
-#5CSEA6 0x02d020dd
-#5CSXC2 0x02d110dd
-#5CSXC4 0x02d010dd
-#5CSXC5 0x02d120dd
-#5CSXC6 0x02d020dd
-#5CSTD5 0x02d120dd
-#5CSTD6 0x02d020dd
-
-
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME cyclonev
}
-jtag newtap $_CHIPNAME tap -irlen 10 \
- -expected-id 0x02b150dd -expected-id 0x02b050dd \
- -expected-id 0x02b220dd -expected-id 0x02b130dd \
- -expected-id 0x02b140dd -expected-id 0x02b010dd \
- -expected-id 0x02b120dd -expected-id 0x02b020dd \
- -expected-id 0x02b030dd -expected-id 0x02b040dd \
- -expected-id 0x02d110dd -expected-id 0x02d010dd \
- -expected-id 0x02d120dd -expected-id 0x02d020dd
+array set _CYCLONE_5_DATA {
+ 0x02b150dd { 864 163 5CEA2}
+ 0x02d020dd {1485 19 5CSEA6_5CSXC6_5CSTD6}
+ 0x02b040dd {1728 -1 5CGXC9_5CGTD9}
+ 0x02b050dd { 864 163 5CEA4}
+ 0x02b030dd {1488 19 5CGXC7_5CGTD7}
+ 0x02d120dd {1485 -1 5CSEA5_5CSXC5_5CSTD5}
+ 0x02b220dd {1104 19 5CEA5}
+ 0x02b020dd {1104 19 5CGXC5_5CGTD5}
+ 0x02d010dd {1197 -1 5CSEA4_5CSXC4}
+ 0x02b120dd {1104 19 5CGXC4}
+ 0x02b140dd {1728 -1 5CEA9}
+ 0x02b010dd { 720 19 5CGXC3}
+ 0x02b130dd {1488 19 5CEA7}
+ 0x02d110dd {1197 -1 5CSEA2_5CSXC2}
+}
+
+set jtag_newtap_cmd {jtag newtap $_CHIPNAME tap -irlen 10 -ignore-version}
+foreach id [array names _CYCLONE_5_DATA] {
+ set cmd [concat "-expected-id" id]
+}
+eval $jtag_newtap_cmd
+
+source [find fpga/altera_common_init.cfg]
pld create $_CHIPNAME.pld intel -chain-position $_CHIPNAME.tap -family cyclonev
+jtag configure $_CHIPNAME.tap -event setup "set_bscan_checkpos_on_setup $_CHIPNAME {$_CYCLONE_5_DATA}"
diff --git a/tcl/fpga/altera_common_init.cfg b/tcl/fpga/altera_common_init.cfg
new file mode 100644
index 0000000..683a844
--- /dev/null
+++ b/tcl/fpga/altera_common_init.cfg
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+proc set_bscan_checkpos_on_setup {chipname data} {
+ set tapid_w_version [jtag cget $chipname.tap -idcode]
+ set version_mask 0x0fffffff
+ set tapid [format 0x%08x [expr {$tapid_w_version & $version_mask}]]
+ intel set_bscan $chipname.pld [lindex $data($tapid) 0]
+ intel set_check_pos $chipname.pld [lindex $data($tapid) 1]
+}
diff --git a/tcl/fpga/xilinx-dna.cfg b/tcl/fpga/xilinx-dna.cfg
index 56f8c14..6b16b78 100644
--- a/tcl/fpga/xilinx-dna.cfg
+++ b/tcl/fpga/xilinx-dna.cfg
@@ -1,7 +1,9 @@
# SPDX-License-Identifier: GPL-2.0-or-later
+# Spartan3: Table 9-5 in https://www.xilinx.com/support/documentation/user_guides/ug332.pdf
proc xilinx_dna_addr {chip} {
array set addrs {
+ Spartan3 0x31
Spartan6 0x30
Series7 0x17
}
@@ -43,3 +45,7 @@ proc xc7_get_dna {tap} {
proc xc6s_get_dna {tap} {
return [xilinx_get_dna $tap Spartan6]
}
+
+proc xc3s_get_dna {tap} {
+ return [xilinx_get_dna $tap Spartan3]
+}
diff --git a/tcl/fpga/xilinx-xc3s.cfg b/tcl/fpga/xilinx-xc3s.cfg
new file mode 100644
index 0000000..7c17206
--- /dev/null
+++ b/tcl/fpga/xilinx-xc3s.cfg
@@ -0,0 +1,43 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Xilinx Spartan3 generation
+# https://www.xilinx.com/support/documentation/user_guides/ug331.pdf
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME xc3s
+}
+
+# Table 12-4 in https://www.xilinx.com/support/documentation/user_guides/ug332.pdf
+# the 4 top bits (28:31) are the die stepping, ignore them.
+jtag newtap $_CHIPNAME tap -irlen 6 -ignore-version \
+ -expected-id 0x02210093 \
+ -expected-id 0x02218093 \
+ -expected-id 0x02220093 \
+ -expected-id 0x02228093 \
+ -expected-id 0x02230093 \
+ -expected-id 0x02610093 \
+ -expected-id 0x02618093 \
+ -expected-id 0x02620093 \
+ -expected-id 0x02628093 \
+ -expected-id 0x02630093 \
+ -expected-id 0x03840093 \
+ -expected-id 0x0384E093 \
+ -expected-id 0x01C10093 \
+ -expected-id 0x01C1A093 \
+ -expected-id 0x01C22093 \
+ -expected-id 0x01C2E093 \
+ -expected-id 0x01C3A093 \
+ -expected-id 0x0140C093 \
+ -expected-id 0x01414093 \
+ -expected-id 0x0141C093 \
+ -expected-id 0x01428093 \
+ -expected-id 0x01434093 \
+ -expected-id 0x01440093 \
+ -expected-id 0x01448093 \
+ -expected-id 0x01450093
+
+pld create $_CHIPNAME.pld virtex2 -chain-position $_CHIPNAME.tap
+
+source [find fpga/xilinx-dna.cfg]
diff --git a/tcl/interface/raspberrypi-gpio-connector.cfg b/tcl/interface/raspberrypi-gpio-connector.cfg
index eff73fc..af7266b 100644
--- a/tcl/interface/raspberrypi-gpio-connector.cfg
+++ b/tcl/interface/raspberrypi-gpio-connector.cfg
@@ -10,6 +10,12 @@
# Do not forget the GND connection, e.g. pin 20 of the GPIO header.
#
+if { [info exists GPIO_CHIP] } {
+ set _GPIO_CHIP $GPIO_CHIP
+} else {
+ set _GPIO_CHIP 0
+}
+
# GPIO 25 (pin 22) previously used for TMS/SWDIO is pulled-down by default.
# The JTAG/SWD specification requires pull-up at the target board
# for either signal. Connecting the signal pulled-up on the target
@@ -19,23 +25,23 @@ echo "Warn : TMS/SWDIO moved to GPIO 8 (pin 24). Check the wiring please!"
# Each of the JTAG lines need a gpio number set: tck tms tdi tdo
# Header pin numbers: 23 24 19 21
-adapter gpio tck -chip 0 11
-adapter gpio tms -chip 0 8
-adapter gpio tdi -chip 0 10
-adapter gpio tdo -chip 0 9
+adapter gpio tck -chip $_GPIO_CHIP 11
+adapter gpio tms -chip $_GPIO_CHIP 8
+adapter gpio tdi -chip $_GPIO_CHIP 10
+adapter gpio tdo -chip $_GPIO_CHIP 9
# Each of the SWD lines need a gpio number set: swclk swdio
# Header pin numbers: 23 24
-adapter gpio swclk -chip 0 11
-adapter gpio swdio -chip 0 8
+adapter gpio swclk -chip $_GPIO_CHIP 11
+adapter gpio swdio -chip $_GPIO_CHIP 8
# If you define trst or srst, use appropriate reset_config
# Header pin numbers: TRST - 26, SRST - 18
-# adapter gpio trst -chip 0 7
+# adapter gpio trst -chip $_GPIO_CHIP 7
# reset_config trst_only
-# adapter gpio srst -chip 0 24
+# adapter gpio srst -chip $_GPIO_CHIP 24
# reset_config srst_only srst_push_pull
# or if you have both connected,
diff --git a/tcl/interface/raspberrypi-native.cfg b/tcl/interface/raspberrypi-native.cfg
index 7224723..c80f90a 100644
--- a/tcl/interface/raspberrypi-native.cfg
+++ b/tcl/interface/raspberrypi-native.cfg
@@ -37,9 +37,9 @@ proc get_max_cpu_clock { default } {
return $clock
}
- echo "WARNING: Host CPU clock unknown."
- echo "WARNING: Using the highest possible value $default kHz as a safe default."
- echo "WARNING: Expect JTAG/SWD clock significantly slower than requested."
+ echo "Warn : Host CPU clock unknown."
+ echo "Warn : Using the highest possible value $default kHz as a safe default."
+ echo "Warn : Expect JTAG/SWD clock significantly slower than requested."
return $default
}
@@ -56,9 +56,13 @@ if {[string match *bcm2711* $compat]} {
} elseif {[string match *bcm2835* $compat] || [string match *bcm2708* $compat]} {
set clocks_per_timing_loop 6
set speed_offset 32
+} elseif {[string match *bcm2712* $compat]} {
+ echo "Error: Raspberrypi Pi 5 has moved GPIOs to PCIe connected RP1 chip."
+ echo "Error: Native GPIO handling is not supported, use 'raspberrypi5-gpiod.cfg'"
+ shutdown
} else {
set speed_offset 32
- echo "WARNING: Unknown type of the host SoC. Expect JTAG/SWD clock slower than requested."
+ echo "Warn : Unknown type of the host SoC. Expect JTAG/SWD clock slower than requested."
}
set clock [get_max_cpu_clock 2000000]
diff --git a/tcl/interface/raspberrypi5-gpiod.cfg b/tcl/interface/raspberrypi5-gpiod.cfg
new file mode 100644
index 0000000..f3fdde0
--- /dev/null
+++ b/tcl/interface/raspberrypi5-gpiod.cfg
@@ -0,0 +1,29 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+# Config for Raspberry Pi 5 used as a bitbang adapter.
+# https://www.raspberrypi.com/documentation/computers/raspberry-pi.html
+
+# Raspberry Pi 5 is not compatible with bcm2835gpio native GPIO driver.
+# The linuxgpiod driver without configurable adapter speed runs at approximately
+# 800 kHz (SWD writes) and 360 kHz (SWD reads)
+
+adapter driver linuxgpiod
+
+proc read_file { name } {
+ if {[catch {open $name r} fd]} {
+ return ""
+ }
+ set result [read $fd]
+ close $fd
+ return $result
+}
+
+set pcie_aspm [read_file /sys/module/pcie_aspm/parameters/policy]
+# escaping [ ] characters in string match pattern does not work in Jim-Tcl
+if {![string match "*<performance>*" [string map { "\[" < "\]" > } $pcie_aspm]]} {
+ echo "Warn : Switch PCIe power saving off or the first couple of pulses gets clocked as fast as 20 MHz"
+ echo "Warn : Issue 'echo performance | sudo tee /sys/module/pcie_aspm/parameters/policy'"
+}
+
+set GPIO_CHIP 4
+source [find interface/raspberrypi-gpio-connector.cfg]
diff --git a/tcl/memory.tcl b/tcl/memory.tcl
index b111749..8b93b51 100644
--- a/tcl/memory.tcl
+++ b/tcl/memory.tcl
@@ -66,10 +66,10 @@ proc iswithin { ADDRESS BASE LEN } {
proc address_info { ADDRESS } {
foreach WHERE { FLASH RAM MMREGS XMEM UNKNOWN } {
- if { info exists $WHERE } {
+ if { [info exists $WHERE] } {
set lmt [set N_[set WHERE]]
for { set region 0 } { $region < $lmt } { incr region } {
- if { iswithin $ADDRESS $WHERE($region,BASE) $WHERE($region,LEN) } {
+ if { [iswithin $ADDRESS $WHERE($region,BASE) $WHERE($region,LEN)] } {
return "$WHERE $region";
}
}
diff --git a/tcl/target/c100helper.tcl b/tcl/target/c100helper.tcl
index d1d3f25..ba0e4fe 100644
--- a/tcl/target/c100helper.tcl
+++ b/tcl/target/c100helper.tcl
@@ -176,7 +176,7 @@ proc setupAmbaClk {} {
mmw $CLKCORE_AHB_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0
# wait for PLL to lock
echo "Waiting for Amba PLL to lock"
- while {[expr {[mrw $CLKCORE_PLL_STATUS] & $AHBCLK_PLL_LOCK]} == 0} { sleep 1 }
+ while {[mrw $CLKCORE_PLL_STATUS] & $AHBCLK_PLL_LOCK == 0} { sleep 1 }
# remove the internal PLL bypass
mmw $CLKCORE_AHB_CLK_CNTRL 0x0 $AHB_PLL_BY_CTRL
# remove PLL from BYPASS mode using MUX
@@ -250,7 +250,7 @@ proc setupArmClk {} {
mmw $CLKCORE_ARM_CLK_CNTRL [expr {($x << 16) + ($w << 8) + $y}] 0x0
# wait for PLL to lock
echo "Waiting for Amba PLL to lock"
- while {[expr {[mrw $CLKCORE_PLL_STATUS] & $FCLK_PLL_LOCK]} == 0} { sleep 1 }
+ while {[mrw $CLKCORE_PLL_STATUS] & $FCLK_PLL_LOCK == 0} { sleep 1 }
# remove the internal PLL bypass
mmw $CLKCORE_ARM_CLK_CNTRL 0x0 $ARM_PLL_BY_CTRL
# remove PLL from BYPASS mode using MUX
diff --git a/tcl/target/nrf53.cfg b/tcl/target/nrf53.cfg
new file mode 100644
index 0000000..307df90
--- /dev/null
+++ b/tcl/target/nrf53.cfg
@@ -0,0 +1,146 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+#
+# Nordic nRF53 series: dual ARM Cortex-M33, multidrop SWD
+#
+
+source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME nrf53
+}
+
+# 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 {
+ set _CPUTAPID 0x6ba02477
+}
+
+# Configurable instance ID resides in application UICR TINSTANCE
+if { [info exists SWD_INSTANCE_ID] } {
+ set _SWD_INSTANCE_ID $SWD_INSTANCE_ID
+} else {
+ set _SWD_INSTANCE_ID 0
+}
+
+swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+if { [info exists SWD_MULTIDROP] } {
+ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -dp-id 0x0070289 -instance-id $_SWD_INSTANCE_ID
+} else {
+ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+}
+
+set _TARGETNAME_APP $_CHIPNAME.cpuapp
+target create $_TARGETNAME_APP cortex_m -dap $_CHIPNAME.dap
+
+$_TARGETNAME_APP configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
+
+# The network core is not accessible over HLA
+if { ![using_hla] } {
+ set _TARGETNAME_NET $_CHIPNAME.cpunet
+ target create $_TARGETNAME_NET cortex_m -dap $_CHIPNAME.dap -ap-num 1 -defer-examine
+
+ targets $_TARGETNAME_APP
+
+ $_TARGETNAME_NET configure -work-area-phys 0x21000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
+}
+
+# Keep adapter speed less or equal 2000 kHz or flash programming fails!
+adapter speed 1000
+
+source [find target/nrf_common.cfg]
+
+flash bank $_CHIPNAME.app.flash nrf5 0x00000000 0 0 0 $_TARGETNAME_APP
+flash bank $_CHIPNAME.app.uicr nrf5 0x00FF8000 0 0 0 $_TARGETNAME_APP
+
+if { ![using_hla] } {
+
+ flash bank $_CHIPNAME.net.flash nrf5 0x01000000 0 0 0 $_TARGETNAME_NET
+ flash bank $_CHIPNAME.net.uicr nrf5 0x01FF8000 0 0 0 $_TARGETNAME_NET
+
+ # System reset sets NETWORK.FORCEOFF which keeps the network core in reset
+ # Don't touch network core during reset
+ $_TARGETNAME_NET configure -event reset-assert {}
+ # and start it after application core reset is finished to make all flash accessible
+ $_TARGETNAME_APP configure -event reset-init "nrf53_cpunet_release $_CHIPNAME"
+
+ $_TARGETNAME_APP cortex_m reset_config sysresetreq
+ $_TARGETNAME_NET cortex_m reset_config sysresetreq
+
+ $_TARGETNAME_APP configure -event examine-fail { _nrf_check_ap_lock 2 3 }
+ $_TARGETNAME_NET configure -event examine-fail { _nrf_check_ap_lock 3 3 }
+
+ $_TARGETNAME_NET configure -event gdb-attach "_nrf53_cpunet_gdb_attach $_CHIPNAME"
+
+ proc _nrf53_cpunet_gdb_attach { _CHIPNAME } {
+ set _TARGETNAME_APP $_CHIPNAME.cpuapp
+ set _TARGETNAME_NET $_CHIPNAME.cpunet
+ set RESET_NETWORK_FORCEOFF 0x50005614
+
+ set is_off [$_TARGETNAME_APP read_memory $RESET_NETWORK_FORCEOFF 32 1]
+ if { $is_off } {
+ nrf53_cpunet_release $_CHIPNAME
+ $_TARGETNAME_NET arp_poll
+ $_TARGETNAME_NET arp_waitstate halted 100
+ } else {
+ if { ![$_TARGETNAME_NET was_examined] } {
+ $_TARGETNAME_NET arp_examine
+ $_TARGETNAME_NET arp_poll
+ }
+ set s [$_TARGETNAME_NET curstate]
+ if { ![string compare $s "halted"] } {
+ halt
+ }
+ }
+ }
+ lappend _telnet_autocomplete_skip _nrf53_cpunet_gdb_attach
+
+ # Release the network core
+ proc nrf53_cpunet_release { {_CHIPNAME nrf53} } {
+ set _TARGETNAME_APP $_CHIPNAME.cpuapp
+ set _TARGETNAME_NET $_CHIPNAME.cpunet
+ set RESET_NETWORK_FORCEOFF 0x50005614
+ set RESET_NETWORK_WORKAROUND 0x50005618
+ set CORTEX_M_DCB_DEMCR 0xE000EDFC
+
+ $_TARGETNAME_APP mww $RESET_NETWORK_WORKAROUND 1
+ $_TARGETNAME_APP mww $RESET_NETWORK_FORCEOFF 0
+ $_TARGETNAME_APP mww $RESET_NETWORK_FORCEOFF 1
+ set err [catch {$_TARGETNAME_NET arp_examine}]
+ if { $err } {
+ if { ![_nrf_check_ap_lock 3 3] } {
+ echo "Error: \[$_TARGETNAME_NET\] examination failed"
+ }
+ return
+ }
+ # set TRCENA | VC_HARDERR | VC_BUSERR | VC_CORERESET
+ $_TARGETNAME_NET mww $CORTEX_M_DCB_DEMCR 0x01000501
+ # Write DEMCR directly intead of permanetly setting by cortex_m vector_catch reset
+ # following cortex_m_endreset_event() restores the original DEMCR value
+ $_TARGETNAME_APP mww $RESET_NETWORK_FORCEOFF 0
+ $_TARGETNAME_APP mww $RESET_NETWORK_WORKAROUND 0
+ }
+
+ # Mass erase and unlock the device using proprietary nRF CTRL-AP (AP #2 or #3)
+ proc nrf53_cpuapp_recover {} {
+ _nrf_ctrl_ap_recover 2
+ }
+ add_help_text nrf53_cpuapp_recover "Mass erase flash and unlock nRF53 application CPU"
+
+ proc nrf53_recover {} {
+ _nrf_ctrl_ap_recover 3 1
+ }
+ add_help_text nrf53_recover "Mass erase all device flash and unlock nRF53"
+}
diff --git a/tcl/target/nrf91.cfg b/tcl/target/nrf91.cfg
new file mode 100644
index 0000000..e0ff4e5
--- /dev/null
+++ b/tcl/target/nrf91.cfg
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+#
+# Nordic nRF91 series: ARM Cortex-M33, SWD only
+#
+
+source [find target/swj-dp.tcl]
+source [find mem_helper.tcl]
+
+if { [info exists CHIPNAME] } {
+ set _CHIPNAME $CHIPNAME
+} else {
+ set _CHIPNAME nrf91
+}
+
+# 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 {
+ set _CPUTAPID 0x6ba02477
+}
+
+swj_newdap $_CHIPNAME cpu -expected-id $_CPUTAPID
+
+# Contrary to the product specification at least nRF9161 supports multidrop SWD.
+# The instance ID is fixed, no more than one nRF91 can be connected to one SWD bus.
+if { [info exists SWD_MULTIDROP] } {
+ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu -dp-id 0x0090289 -instance-id 0
+} else {
+ dap create $_CHIPNAME.dap -chain-position $_CHIPNAME.cpu
+}
+
+set _TARGETNAME $_CHIPNAME.cpu
+target create $_TARGETNAME cortex_m -dap $_CHIPNAME.dap
+
+# Keep adapter speed less or equal 2000 kHz or flash programming fails!
+adapter speed 1000
+
+$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
+
+source [find target/nrf_common.cfg]
+
+flash bank $_CHIPNAME.flash nrf5 0x00000000 0 0 0 $_TARGETNAME
+flash bank $_CHIPNAME.uicr nrf5 0x00FF8000 0 0 0 $_TARGETNAME
+
+if { ![using_hla] } {
+ $_TARGETNAME cortex_m reset_config sysresetreq
+
+ $_TARGETNAME configure -event examine-fail { _nrf_check_ap_lock 4 3 }
+}
+
+# Mass erase and unlock the device using proprietary nRF CTRL-AP (AP #4)
+proc nrf91_recover {} {
+ _nrf_ctrl_ap_recover 4
+}
+add_help_text nrf91_recover "Mass erase and unlock nRF91 device"
diff --git a/tcl/target/nrf_common.cfg b/tcl/target/nrf_common.cfg
new file mode 100644
index 0000000..2ae5011
--- /dev/null
+++ b/tcl/target/nrf_common.cfg
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+#
+# Nordic nRF52, nRF53 and nRF91 CTRL-AP handling
+#
+
+if { [using_hla] } {
+ echo ""
+ echo "nRF device has a CTRL-AP dedicated to recover the device from AP lock."
+ echo "A high level adapter (like a ST-Link) you are currently using cannot access"
+ echo "the CTRL-AP so 'nrfxx_recover' command will not work."
+ echo "Do not enable UICR APPROTECT."
+ echo ""
+} else {
+
+ # Test if debug/MEM-AP is locked by UICR APPROTECT
+ proc _nrf_check_ap_lock { ctrl_ap_num unlocked_value } {
+ set target [target current]
+ set dap [$target cget -dap]
+ set err [catch {set APPROTECTSTATUS [$dap apreg $ctrl_ap_num 0xc]}]
+ if {$err == 0 && $APPROTECTSTATUS < $unlocked_value} {
+ echo ""
+ echo "****** WARNING ******"
+ echo "\[$target\] device has AP lock engaged (see UICR APPROTECT register)."
+ echo "Debug access is denied."
+ echo "Use 'nrfxx_recover' to erase and unlock the device."
+ echo ""
+ poll off
+ return 1
+ }
+ return 0
+ }
+
+ # Mass erase and unlock the device using proprietary nRF CTRL-AP
+ proc _nrf_ctrl_ap_recover { ctrl_ap_num {is_cpunet 0} } {
+ set target [target current]
+ set dap [$target cget -dap]
+
+ set IDR [$dap apreg $ctrl_ap_num 0xfc]
+ if {$IDR != 0x12880000} {
+ echo "Error: Cannot access nRF CTRL-AP!"
+ return
+ }
+
+ poll off
+
+ # Reset and trigger ERASEALL task
+ $dap apreg $ctrl_ap_num 4 0
+ $dap apreg $ctrl_ap_num 4 1
+
+ for {set i 0} {1} {incr i} {
+ set ERASEALLSTATUS [$dap apreg $ctrl_ap_num 8]
+ if {$ERASEALLSTATUS == 0} {
+ echo "\[$target\] device has been successfully erased and unlocked."
+ break
+ }
+ if {$i == 0} {
+ echo "Waiting for chip erase..."
+ }
+ if {$i >= 150} {
+ echo "Error: \[$target\] recovery failed."
+ break
+ }
+ sleep 100
+ }
+
+ # Assert reset
+ $dap apreg $ctrl_ap_num 0 1
+
+ # Deassert reset
+ $dap apreg $ctrl_ap_num 0 0
+
+ # Reset ERASEALL task
+ $dap apreg $ctrl_ap_num 4 0
+
+ if { $is_cpunet } {
+ reset init
+ } else {
+ sleep 100
+ $target arp_examine
+ poll on
+ }
+ }
+
+ lappend _telnet_autocomplete_skip _nrf_check_ap_lock _nrf_ctrl_ap_recover
+}