Skip to content

Instantly share code, notes, and snippets.

@elfmimi
Last active May 18, 2023 22:56
Show Gist options
  • Select an option

  • Save elfmimi/1deb9c94b0f0900ae8a9df740b62bcd6 to your computer and use it in GitHub Desktop.

Select an option

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

joba-1 commented Oct 9, 2020

Copy link
Copy Markdown

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

elfmimi commented Oct 11, 2020

Copy link
Copy Markdown
Author

@joba-1 thank you for your star.

@joba-1

joba-1 commented Oct 11, 2020

Copy link
Copy Markdown

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
Copy Markdown

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

nica-f commented Apr 7, 2023

Copy link
Copy Markdown

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

elfmimi commented Apr 11, 2023

Copy link
Copy Markdown
Author

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

aplund commented May 18, 2023

Copy link
Copy Markdown

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

@elfmimi

elfmimi commented May 18, 2023

Copy link
Copy Markdown
Author

@aplund thanks for the info!

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