Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 11 additions & 79 deletions tcl/target/gd32vf103.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
# https://www.gigadevice.com/products/microcontrollers/gd32/risc-v/
#

adapter speed 1000
source [find mem_helper.tcl]

transport select jtag

reset_config srst_nogate
if { [info exists CHIPNAME] } {
set _CHIPNAME $CHIPNAME
} else {
set _CHIPNAME gd32vf103
}

# The smallest RAM size 6kB (GD32VF103C4/T4/R4)
if { [info exists WORKAREASIZE] } {
Expand All @@ -20,15 +23,10 @@ if { [info exists WORKAREASIZE] } {
set _WORKAREASIZE 0x1800
}

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
Expand All @@ -41,78 +39,12 @@ $_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE
set _FLASHNAME $_CHIPNAME.flash
flash bank $_FLASHNAME stm32f1x 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
}
# 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
}

# On this chip, ndmreset (the debug module bit that triggers a software reset)
Expand Down