Files
openocd/tcl/target/gigadevice/gd32vf103.cfg
Marc Schink f36ab02a80 tcl/target: Move GigaDevice configs into vendor directory
Move the configuration files into a dedicated vendor folder as required
by the developer guidelines.

Change-Id: I9ed39e32b6281a9cb8510914690f3f7751b795c8
Signed-off-by: Marc Schink <dev@zapb.de>
Reviewed-on: https://review.openocd.org/c/openocd/+/9271
Tested-by: jenkins
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
2026-01-25 09:26:39 +00:00

138 lines
4.4 KiB
INI

# SPDX-License-Identifier: GPL-2.0-or-later
#
# GigaDevice GD32VF103 target
#
# https://www.gigadevice.com/products/microcontrollers/gd32/risc-v/
#
source [find mem_helper.tcl]
transport select jtag
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME gd32vf103
}
# The smallest RAM size 6kB (GD32VF103C4/T4/R4)
if { [info exists WORKAREASIZE] } {
set _WORKAREASIZE $WORKAREASIZE
} else {
set _WORKAREASIZE 0x1800
}
# Example OpenOCD configurations from GigaDevice/Nuclei expect a cpu IDCODE of
# 0x1e200a6d instead. It's unclear if any units with that IDCODE exist in the
# wild. Please report a bug if you have such a unit.
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
# Disable virtual address translation since we don't have an MMU. Nothing will
# break without this line, but OpenOCD will do a few unnecessary register reads
# to figure it out on its own.
$_TARGETNAME riscv virt2phys_mode off
proc default_mem_access {} {
riscv set_mem_access progbuf
}
default_mem_access
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME stm32f1x 0x08000000 0 0 0 $_TARGETNAME
# DBGMCU_CR register cannot be set in examine-end event as the running RISC-V CPU
# does not allow the debugger to access memory.
# Stop watchdogs at least before flash programming.
$_TARGETNAME configure -event reset-init {
# DBGMCU_CR |= DBG_WWDG_STOP | DBG_IWDG_STOP
mmw 0xE0042004 0x00000300 0
}
set dmcontrol 0x10
set dmcontrol_dmactive [expr {1 << 0}]
set dmcontrol_clrresethaltreq [expr {1 << 2}]
set dmcontrol_setresethaltreq [expr {1 << 3}]
set dmcontrol_ackhavereset [expr {1 << 28}]
set dmstatus 0x11
set dmstatus_allunavail [expr {1 << 12}]
set dmstatus_allhavereset [expr {1 << 19}]
$_TARGETNAME configure -event reset-start {
if {$halt} {
set ctrl [expr {$::dmcontrol_dmactive | $::dmcontrol_setresethaltreq}]
} else {
set ctrl [expr {$::dmcontrol_dmactive | $::dmcontrol_clrresethaltreq}]
}
riscv dmi_write $::dmcontrol $ctrl
}
# 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 reset_config_options [reset_config]
# If hardware NRST signal is connected and configured, reset has been
# triggered. Avoid second reset and return early
if {[string match {srst_only *} $reset_config_options]
|| [string match {srst_and_trst *} $reset_config_options]} {
return
}
# Halt the core so that we can write to memory. We do this first so
# that it doesn't clobber our dmcontrol configuration.
halt
echo "gd32vf103 reset workaround halt=$halt"
# Unlock 0xe0042008 so that the next write triggers a reset
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!
mww 0xe0042008 0x1
# Put the memory access mode back to what it was.
default_mem_access
}
# On GD32VF103 the specification's requirement that each hart is in "exactly
# one of four states" is violated and, during reset, report harts as both
# unavailable and halted/running. To work around this, after the havereset is
# lowered in the main deassert_reset procedure, we wait for the absence of the
# unavailable state.
$_TARGETNAME configure -event reset-deassert-post {
set timeout_ms 100
set start [clock milliseconds]
while {1} {
set status [riscv dmi_read $::dmstatus]
if {!($status & $::dmstatus_allunavail)} {
break
}
if {[clock milliseconds] - $start > $timeout_ms} {
error {Timed out waiting for the hart to become available after a reset}
}
}
set ctrl [expr {$::dmcontrol_dmactive | $::dmcontrol_clrresethaltreq}]
if {$status & $::dmstatus_allhavereset} {
set ctrl [expr {$ctrl | $::dmcontrol_ackhavereset}]
}
riscv dmi_write $::dmcontrol $ctrl
}