Last active
May 18, 2023 22:56
-
-
Save elfmimi/1deb9c94b0f0900ae8a9df740b62bcd6 to your computer and use it in GitHub Desktop.
OpenOCD script for GD32VF103 with improved reset procedure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# OpenOCD script for GD32VF103 with improved reset procedure | |
# Invoke it like this. | |
# for Digilent HS2 | |
# openocd -f interface/ftdi/digilent-hs2.cfg -c "ftdi_device_desc {Digilent USB Device}" -f gd32vf103.cfg -c "program binary.elf verify reset exit" | |
# openocd -f interface/ftdi/digilent-hs2.cfg -c "ftdi_device_desc {Digilent USB Device}" -f gd32vf103.cfg -c "program binary.bin 0x08000000 verify reset exit" | |
# openocd -f interface/ftdi/digilent-hs2.cfg -c "ftdi_device_desc {Digilent USB Device}" -f gd32vf103.cfg -c "init; reset run; exit" | |
# for SiPEED USB-JTAG/TTL ( RV-Debugger ) | |
# openocd -f interface/ftdi/minimodule.cfg -c "ftdi_device_desc {Dual RS232}" -f gd32vf103.cfg -c "init; reset run; exit" | |
# for SiPEED RV-Debugger Lite | |
# openocd -f interface/ftdi/minimodule.cfg -c "ftdi_device_desc {Sipeed-Debug}" -f gd32vf103.cfg -c "init; reset run; exit" | |
# for SiPEED RV-Debugger Plus ( BL702 ) | |
# openocd -f interface/ftdi/minimodule.cfg -c "ftdi_device_desc {JTAG Debugger}" -f gd32vf103.cfg -c "init; reset run; exit" | |
if [string equal [adapter_name] ftdi] { | |
# Digilent HS2 can go upto 60MHz clock rate with this command enabled: "ftdi_tdo_sample_edge falling" | |
# ftdi_tdo_sample_edge falling | |
adapter_khz 20000 | |
} else { | |
adapter_khz 4000 | |
} | |
transport select jtag | |
set _CHIPNAME riscv | |
# True value of GD32VF103 core's IDCODE is 0x1000563d. But it could be masqueraded in some cases. | |
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x1000563d -expected-id 0x1e200a6d | |
jtag newtap gd32v tap -irlen 5 -expected-id 0x790007a3 | |
set _TARGETNAME $_CHIPNAME.cpu | |
target create $_TARGETNAME riscv -chain-position $_TARGETNAME | |
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size 10000 -work-area-backup 1 | |
$_TARGETNAME riscv set_reset_timeout_sec 1 | |
set _FLASHNAME $_CHIPNAME.flash | |
if {[catch {flash bank $_FLASHNAME gd32vf103 0x08000000 0 0 0 $_TARGETNAME}] != 0} { | |
echo "** Maybe flash driver for gd32vf103 is not implemented in this version of OpenOCD **" | |
echo "** You may still be able to debug target application already in the flash memory. **" | |
} | |
# riscv expose_csrs 3040-3071 | |
proc SystemReset {} { | |
global _TARGETNAME | |
if {[catch {init}] != 0} { | |
echo "** OpenOCD init failed **" | |
shutdown error | |
} | |
if ![string equal halted [$_TARGETNAME curstate]] { | |
halt | |
} | |
# See gd32vf103_eclic.c for eclic_system_reset() . | |
# void eclic_system_reset(void) { | |
# REG32(REG_DBGMCU2EN) = 0x4b5a6978; | |
# REG32(REG_DBGMCU2) = 0x1; | |
# } | |
mww 0xe004200c 0x4b5a6978 | |
mww 0xe0042008 0x01 | |
# resume | |
# set dmcontrol [dmi_read 0x10] | |
# dmi_write 0x10 [expr ${dmcontrol} | 0x40000000] | |
# sleep 100 | |
# set dmstatus [dmi_read 0x11] | |
# echo [format "dmstatus %08X" ${dmstatus}] | |
shutdown | |
} | |
proc dmi_read {reg} { | |
global _TARGETNAME | |
# You don't need this treatment if you are using latest openocd | |
set value [capture {$_TARGETNAME riscv dmi_read ${reg}}] | |
string trimright ${value} \n | |
} | |
proc dmi_write {reg value} { | |
global _TARGETNAME | |
$_TARGETNAME riscv dmi_write ${reg} ${value} | |
} | |
proc dmi_write_register {regno data0} { | |
dmi_write 0x04 ${data0} | |
set command [expr 0x00230000 | ${regno}] | |
dmi_write 0x17 ${command} | |
set abstractcs [dmi_read 0x16] | |
# echo [format "abstractcs %08X" ${abstractcs}] | |
if {(${abstractcs} & 0x0700) == 0} { | |
# echo [format "register write OK: %04X %08X" ${regno} ${data0}] | |
} else { | |
echo [format "register write NG: %04X %08X" ${regno} ${data0}] | |
shutdown | |
} | |
} | |
proc dmi_read_register {regno} { | |
set command [expr 0x00220000 | ${regno}] | |
dmi_write 0x17 ${command} | |
set abstractcs [dmi_read 0x16] | |
# echo [format "abstractcs %08X" ${abstractcs}] | |
if {(${abstractcs} & 0x0700) == 0} { | |
set data0 [dmi_read 0x04] | |
# echo [format "register read OK: %04X %08X" ${regno} ${data0}] | |
} else { | |
echo [format "register read NG: %04X" ${regno}] | |
#shutdown | |
exit | |
} | |
return ${data0} | |
} | |
proc clear_interrupt_level_by_dmi {} { | |
# progbuf0 = auipc a0, 0x0 (0x00000517) | |
dmi_write 0x20 0x00000517 | |
# progbuf1 = ebreak (0x00100073) | |
dmi_write 0x21 0x00100073 | |
# command = postexec | |
dmi_write 0x17 0x00040000 | |
set abstractcs [dmi_read 0x16] | |
if {(${abstractcs} & 0x0700) == 0} { | |
# echo [format "Debug : exec auipc OK"] | |
} else { | |
echo [format "Debug : exec auipc NG"] | |
echo [format "Debug : abstractcs %08X" ${abstractcs}] | |
exit | |
} | |
# a0 has been loaded with address of progbuf0 | |
set a0 [dmi_read_register 0x100A] | |
# mepc = &progbuf1 | |
dmi_write_register 0x0341 [expr ${a0} + 4] | |
# progbuf0 = mret (0x30200073) | |
dmi_write 0x20 0x30200073 | |
# command = postexec | |
dmi_write 0x17 0x00040000 | |
set abstractcs [dmi_read 0x16] | |
if {(${abstractcs} & 0x0700) == 0} { | |
# echo [format "Debug : exec mret OK"] | |
} else { | |
echo [format "Debug : exec mret NG"] | |
echo [format "Debug : abstractcs %08X" ${abstractcs}] | |
exit | |
} | |
} | |
proc reset_by_dmi {args} { | |
global _TARGETNAME | |
set curstate [$_TARGETNAME curstate] | |
# echo [format "curstate = %s" ${curstate}] | |
if ![string equal ${curstate} halted] { | |
halt | |
} | |
# Reset all peripherals | |
# RCU_APB1RST | |
mww 0x40021010 0xFFFFFFFF | |
mww 0x40021010 0x00000000 | |
# RCU_APB2RST | |
mww 0x4002100C 0xFFFFFFFF | |
mww 0x4002100C 0x00000000 | |
# RCU_AHBRST (USBFSRST) | |
mww 0x40021028 0xFFFFFFFF | |
mww 0x40021028 0x00000000 | |
# RCU_CFG0 | |
# echo [format "RCU_CFG0 %08X" [mrw 0x40021004]] | |
mwb 0x40021004 0x00 | |
# echo [format "RCU_CFG0 %08X" [mrw 0x40021004]] | |
# What should we do with EXTI and ECLIC ? | |
set dmstatus [dmi_read 0x11] | |
set impebreak [expr (${dmstatus} & 0x00400000) >> 22] | |
# echo [format "dmstatus(DMI(0x11)) = %08X" ${dmstatus}] | |
set abstractcs [dmi_read 0x16] | |
set datacount [expr (${abstractcs} & 0x0000000F)] | |
set progbufsize [expr (${abstractcs} & 0x1F000000) >> 24] | |
# echo [format "Info : datacount=%d progbufsize=%d impebreak=%d" ${datacount} ${progbufsize} ${impebreak}] | |
if {(${progbufsize} < 2) && !${impebreak}} { | |
exit | |
} | |
# echo [format "abstractcs(DMI(0x16)) = %08X" ${abstractcs}] | |
# echo [format "mstatus(0x300) = %08X" [dmi_read_register 0x0300]] | |
# echo [format "mie(0x304) = %08X" [dmi_read_register 0x0304]] | |
# echo [format "mepc(0x341) = %08X" [dmi_read_register 0x0341]] | |
# echo [format "mcause(0x342) = %08X" [dmi_read_register 0x342]] | |
set mintstatus [dmi_read_register 0x0346] | |
# echo [format "Debug : mintstatus(0x346)=%08X" ${mintstatus}] | |
# echo [format "msubm(0x7c4) = %08X" [dmi_read_register 0x07c4]] | |
# echo [format "dcsr = %08X" [dmi_read_register 0x07B0]] | |
# echo [format "dpc = %08X" [dmi_read_register 0x07B1]] | |
# mstatus | |
dmi_write_register 0x0300 0x00001800 | |
# msubm | |
dmi_write_register 0x07C4 0x00000000 | |
if {(${mintstatus} & 0xFF000000) != 0} { | |
# echo [format "a0(0x100A) = %08X" [dmi_read_register 0x100A]] | |
clear_interrupt_level_by_dmi | |
# echo [format "a0(0x100A) = %08X" [dmi_read_register 0x100A]] | |
# echo [format "Debug : mintstatus(0x346)=%08X" [dmi_read_register 0x0346]] | |
} | |
#echo [format "mepc(0x341) = %08X" [dmi_read_register 0x0341]] | |
# dcsr | |
dmi_write_register 0x07B0 0x00000003 | |
# dpc | |
dmi_write_register 0x07B1 0x08000000 | |
# mcountinhibit | |
dmi_write_register 0x0320 0x00000000 | |
foreach arg $args { | |
if [string equal [string tolower $arg] run] { | |
set run 1 | |
} | |
if [string equal [string tolower $arg] halt] { | |
set halt 1 | |
} | |
if [string equal [string tolower $arg] init] { | |
set halt 1 | |
} | |
} | |
if [info exists run] { | |
resume | |
} elseif [info exists halt] { | |
} elseif [string equal ${curstate} running] { | |
resume | |
} | |
} | |
rename init original_init | |
proc init {} { | |
rename init {} | |
rename original_init init | |
init | |
# rename reset original_reset | |
rename reset {} | |
proc reset {args} { | |
reset_by_dmi $args | |
} | |
} | |
# this will suppress value of the last expression getting printed | |
if 0 { } |
This OpenOCD config is indeed very helpful! I hope this gets upstreamed to OpenOCD some day? In the meantime I fixed some warnings:
--- gd32vf103.cfg-o 2023-04-07 21:05:06.571257340 +0200
+++ gd32vf103.cfg 2023-04-07 21:02:55.623886608 +0200
@@ -85,7 +85,7 @@
proc dmi_write_register {regno data0} {
dmi_write 0x04 ${data0}
- set command [expr 0x00230000 | ${regno}]
+ set command [expr { 0x00230000 | ${regno} }]
dmi_write 0x17 ${command}
set abstractcs [dmi_read 0x16]
# echo [format "abstractcs %08X" ${abstractcs}]
@@ -98,7 +98,7 @@
}
proc dmi_read_register {regno} {
- set command [expr 0x00220000 | ${regno}]
+ set command [expr { 0x00220000 | ${regno} }]
dmi_write 0x17 ${command}
set abstractcs [dmi_read 0x16]
# echo [format "abstractcs %08X" ${abstractcs}]
@@ -176,11 +176,11 @@
# What should we do with EXTI and ECLIC ?
set dmstatus [dmi_read 0x11]
- set impebreak [expr (${dmstatus} & 0x00400000) >> 22]
+ set impebreak [expr { (${dmstatus} & 0x00400000) >> 22 }]
# echo [format "dmstatus(DMI(0x11)) = %08X" ${dmstatus}]
set abstractcs [dmi_read 0x16]
- set datacount [expr (${abstractcs} & 0x0000000F)]
- set progbufsize [expr (${abstractcs} & 0x1F000000) >> 24]
+ set datacount [expr { (${abstractcs} & 0x0000000F) }]
+ set progbufsize [expr { (${abstractcs} & 0x1F000000) >> 24 }]
# echo [format "Info : datacount=%d progbufsize=%d impebreak=%d" ${datacount} ${progbufsize} ${impebreak}]
if {(${progbufsize} < 2) && !${impebreak}} {
exit
Hey! @nica-f What part did you find useful? Because you say your openocd emits warnings I suppose you are using relatively new version. I believe main line openocd has received improvements it deserves and it should behave just fine if not perfect.
The flash driver is now integrated with the "stm32f1x" driver. Substituting the gd32vf103 in the flash bank command seems to work.
@aplund thanks for the info!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @elfmimi,
Thanks a lot for this script!
You seem to know a lot about OpenOCD and this RISC-V processor. I just sent you an e-mail. Hope to hear from you soon ^_^
Kind regards,
Kristof Mulier