Skip to content

Instantly share code, notes, and snippets.

@elfmimi
Last active May 18, 2023 22:56
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save elfmimi/1deb9c94b0f0900ae8a9df740b62bcd6 to your computer and use it in GitHub Desktop.
Save elfmimi/1deb9c94b0f0900ae8a9df740b62bcd6 to your computer and use it in GitHub Desktop.
OpenOCD script for GD32VF103 with improved reset procedure
# 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 { }
@joba-1
Copy link

joba-1 commented Oct 9, 2020

Hi elfmimi!
This, Is, Awesome!
Finally, no button press or power cycle for jtag flash/debug of Longan Nano
Thank you

It was a bit of a struggle though to integrate it in PlatformIO. So in case someone else needs this:

  • replace ~/.platformio/packages/tool-openocd-gd32v/share/openocd/scripts/target/gd32vf103.cfg with this version
  • in ~/.platformio/platforms/gd32v/builder/main.py change the whole line containig 'program {$SOURCE}' with ' "-c", "program {$SOURCE} verify reset exit"'

I'm sure there is a way to do this without fear of platformio overwriting it, but I havent figured it out...

@elfmimi
Copy link
Author

elfmimi commented Oct 11, 2020

@joba-1 thank you for your star.

@joba-1
Copy link

joba-1 commented Oct 11, 2020

You're welcome - it helped me a ton.

Meanwhile I figured out how to integrate it well with PlatformIO (see my fork, if interested)

@kristofmulier
Copy link

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

@nica-f
Copy link

nica-f commented Apr 7, 2023

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

@elfmimi
Copy link
Author

elfmimi commented Apr 11, 2023

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.

@aplund
Copy link

aplund commented May 18, 2023

The flash driver is now integrated with the "stm32f1x" driver. Substituting the gd32vf103 in the flash bank command seems to work.

@elfmimi
Copy link
Author

elfmimi commented May 18, 2023

@aplund thanks for the info!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment