riscv-openocd/tcl/target/gd32vf103.cfg

97 lines
3.6 KiB
INI
Raw Normal View History

Improve support for GD32VF103 MCU (#538) * riscv: work around buggy hart states during reset in some DMs As described in the comment this change adds, the GD32VF103 DM reports that the hart is in more than one state while it is resetting. Because of this, the current code acknowledges resets before they actually complete. This sometimes prevents havereset from getting cleared as intended, leading to a spurious "Hart 0 unexpectedly reset!" message the next time riscv_is_halted() gets called. To work around this, check for the absence of the unavailable state rather than the presence of the running or halted states. This behavior is also arguably more true to the spec than what exists now: Section 3.2 states that "The system may take an arbitrarily long time to come out of reset, as reported by allunavail, anyunavail." Change-Id: I34e90a16233125608bce8e4c2414dbead637600e Signed-off-by: Thomas Hebb <tommyhebb@gmail.com> * riscv: support custom reset-assert scripts The reset-assert event is used, if present, to override the default reset logic for ARM and MIPS cores. Do the same for RISC-V so that devices with buggy ndmreset functionality (like GD32VF103) or nonstandard reset sequences can specify the appropriate logic in Tcl. Change-Id: I5e12077d67509853edb8ef3ad3f037f293a5fbb6 Signed-off-by: Thomas Hebb <tommyhebb@gmail.com> * tcl/target: support GD32VF103 RISC-V MCU The GD32VF103 is a low-cost 32-bit RISC-V microcontroller with peripherals that are more-or-less compatible with the STM32F103 ARM microcontroller. It is available on several low-cost dev boards, such as the Sipeed Longan Nano, which is what I am testing on. Add initial support for this chip, including a workaround for a buggy ndmreset line (i.e. one that doesn't actually trigger a reset) in its integrated debug module. Use the existing GD32VF103 flash driver that was ported from the vendor's code in commit 48e40f351325 ("Add support for GD32VF103 flash"). Change-Id: Iadac47ceb5437b8e18f3d35901388f10fef9f876 Signed-off-by: Thomas Hebb <tommyhebb@gmail.com> * tcl/target/gd32vf103: add main flash alias The GD32VF103 creates an alias to either main flash or the bootloader at 0x0, depending on how it was booted. As such, we want to indicate to debuggers that the memory at 0x0 is flash and so cannot support software breakpoints. To do this, add an alias to the main flash in the config. This isn't strictly accurate in the case where we're running the bootloader, but it still suits our purpose of fixing breakpoint behavior. Change-Id: I9eb8462d354f096eee231c0e5e2bffa538a5903e Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
2020-10-01 13:06:11 -05:00
reset_config srst_nogate
set _CHIPNAME gd32vf103
# The vendor's configuration expects an ID of 0x1e200a6d, but this one is what
# I have on my board (Sipeed Longan Nano, GD32VF103CBT6).
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d
jtag newtap $_CHIPNAME bs -irlen 5 -expected-id 0x790007a3
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
$_TARGETNAME riscv set_enable_virt2phys off
proc default_mem_access {} {
riscv set_mem_access progbuf
}
default_mem_access
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 0x1000 -work-area-backup 1
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME gd32vf103 0x08000000 0 0 0 $_TARGETNAME
# Address 0 is only aliased to main flash when the chip is not running its
# built-in bootloader. When it is, it's instead aliased to a read only section
# of flash at 0x1fffb000. However, we can't detect or dynamically switch this,
# so just pretend it's always aliased to main flash. We need to tell OpenOCD
# about this alias because otherwise we'll try to use software breakpoints on
# code in flash, which don't work because flash mappings are read-only.
flash bank $_CHIPNAME.flashalias virtual 0x0 0 0 0 $_TARGETNAME $_FLASHNAME
# On this chip, ndmreset (the debug module bit that triggers a software reset)
# doesn't work. So for JTAG connections without an SRST, we need to trigger a
# reset manually. This is an undocumented reset sequence that's used by the
# JTAG flashing script in the vendor-supplied GD32VF103 PlatformIO plugin:
#
# https://github.com/sipeed/platform-gd32v/commit/f9cbb44819bc05dd2010cc815c32be0486800cc2
#
$_TARGETNAME configure -event reset-assert {
set dmcontrol 0x10
set dmcontrol_dmactive [expr 1 << 0]
set dmcontrol_haltreq [expr 1 << 31]
global _RESETMODE
global _TARGETNAME
# Halt the core so that we can write to memory. We do this first so
# that it doesn't clobber our dmcontrol configuration.
halt
# Set haltreq appropriately for the type of reset we're doing. This
# replicates what the generic RISC-V reset_assert() function would
# do if we weren't overriding it. The $_RESETMODE hack sucks, but
# it's the least invasive way to determine whether we need to halt,
# and psoc6.cfg already uses the same trick. (reset_deassert(), which
# does run, also does this, but at that point it may be too late: the
# reset has already been triggered, so there's a race between it and
# the haltreq write.)
#
# If we didn't override the generic handler, we'd actually still have
# to do this: the default handler sets ndmreset, which prevents memory
# access even though it doesn't actually trigger a reset on this chip.
# So we'd need to unset it here, which involves a write to dmcontrol,
# Since haltreq is write-only and there's no way to leave it unchanged,
# we'd have to figure out its proper value anyway.
set val $dmcontrol_dmactive
if {$_RESETMODE ne "run"} {
set val [expr $val | $dmcontrol_haltreq]
}
$_TARGETNAME riscv dmi_write $dmcontrol $val
# Unlock 0xe0042008 so that the next write triggers a reset
$_TARGETNAME mww 0xe004200c 0x4b5a6978
# We need to trigger the reset using abstract memory access, since
# progbuf access tries to read a status code out of a core register
# after the write happens, which fails when the core is in reset.
riscv set_mem_access abstract
# Go!
$_TARGETNAME mww 0xe0042008 0x1
# Put the memory access mode back to what it was.
default_mem_access
}
# Capture the mode of a given reset so that we can use it later in the
# reset-assert handler.
proc init_reset { mode } {
global _RESETMODE
set _RESETMODE $mode
if {[using_jtag]} {
jtag arp_init-reset
}
}