Hi @tincman, granted this is an old conversation but I believe it is still a relevant topic. Just put together a bunch of overrides for the start-up process, proper delays, handling of failures during scan and examine, and made a couple suggestions for high level loading procedures for ram and rom destinations.
#------------- your_interface_file.cfg -------------------------
#
# INTERFACE
#
adapter driver ...
#-------------------------------------------
adapter speed 2000
gdb_port disabled ;# 3333
tcl_port disabled ;# 6666
telnet_port disabled ;# 4444
#------------- fe310-g002.cfg -------------------------
#
# TARGET
#
transport select jtag
#
# SiFive FE310-G002 is "riscv" with cpuid "0x20000913"
#
jtag newtap riscv cpu -irlen 5 -expected-id 0x20000913
target create riscv.cpu.0 riscv -chain-position riscv.cpu
riscv.cpu.0 configure -event examine-start {
echo "examine start"
# prevent the dreaded 'Error: unable to halt hart 0' message
if {[catch {riscv.cpu.0 arp_examine} err] != 0} {
fe310_reset
riscv.cpu.0 arp_examine
}
}
proc fe310_reset { } {
echo "proc fe310_reset"
# pulse the reset line just in case h/w was locked
#!!!CRITICAL -- to avoid dreaded 'Error: unable to halt hart 0' message during init ...
echo "fe310_reset: pulsing reset line"
#------------------------
reset_config trst_only trst_open_drain separate
jtag_ntrst_assert_width 0
jtag_ntrst_delay 0
adapter assert trst ;# ftdi_set_signal nTRST 0 ;# assert RST
adapter deassert trst ;# ftdi_set_signal nTRST 1 ;# deassert RST
reset_config none
#------------------------
jtag arp_init-reset ;# this thing takes a long time to come back
echo "fe310_reset: wait for target get into reset state (prevent impatient scan retries)"
sleep 1500 ;# FE310 target AON reset block delay, default 2^8 cycles of core clock
}
proc jtag_init { } { ;# overrides openocd/src/jtag/startup.tcl
echo "proc jtag_init"
if {[catch {jtag arp_init} err] != 0} {
fe310_reset
}
}
proc init_reset { mode } { ;# overrides openocd/src/jtag/startup.tcl
echo "proc init_reset"
if {[catch {jtag arp_init} err] != 0} {
fe310_reset
}
}
riscv.cpu.0 configure -work-area-phys 0x80000000 -work-area-size 0x10000 -work-area-backup 0
riscv set_reset_timeout_sec 1
riscv set_enable_virt2phys off
riscv set_enable_virtual off
flash bank spi0 fespi 0x20000000 0 0 0 riscv.cpu.0 0x10014000
#--------------------------------------------------------------
#
# APPLICATION(S)
#
#
# fe310_ram_load <pgm-name-prefix> [<addr> [no_run]]
#
# Preverifies the target memory to make sure writing is even necessary.
# Allows for loading only when other than default address specified,
# such as when preparing overlay code or non-executable data.
#
# Typical usage:
# openocd -f fe310-g002.cfg -c "adapter speed 2000" -c init -c "fe310_ram_load my_prog"\
# -c shutdown -c exit
# where my_prog-ram.bin has been linked for ram target addresses in the linker .lds script.
proc fe310_ram_load { program {addr "0x80000000"} {no_run ""} } {
halt 100 ;# includes wait_halt 100
# in case of verify_image pass, message returned is ''
# in case of verify_image fail, message returned is 'contents differ', diff lines, abrupt exit
#
set rc [catch {verify_image ${program}-ram.bin ${addr} bin} err] ;# trap exit on verify fail
if {[expr $rc == 0]} {
echo "ram already up to date - nothing to do"
} else {
echo [load_image ${program}-ram.bin ${addr} bin]
echo [verify_image ${program}-ram.bin ${addr} bin]
}
if {[expr [string length $no_run] == 0]} {
resume ${addr}
}
}
#
# fe310_rom_load <pgm-name-prefix> [<addr> [no_run]]
#
# Preverifies the target memory to make sure writing is even necessary.
# When writing is necessary, prechecks the target memory to make sure
# erasing is even necessary.
# Determines smallest portion of target memory to work with, for
# best programming speed and target memory endurance (lifetime).
# Allows for loading only when other than default address specified,
# such as when preparing overlay code or non-executable data.
#
# assumes only one target, at position tap position 0, for now.
#
# Typical usage:
# openocd -f fe310-g002.cfg -c "adapter speed 2000" -c init -c "fe310_rom_load my_prog"\
# -c shutdown -c exit
# where my_prog-rom.bin has been linked for rom target addresses in the linker .lds script.
#
# --------------------------------------------------------------------
# Fixes the following bugs and issues:
#
# [flash erase_check num]
# Does not work, and takes a very long time, because of
# message 'Running slow fallback erase check - add working memory'
# All sectors are being tested, not just the ones which will be programmed.
# See src/flash/nor/core.c:344 default_flash_mem_blank_check(),
# src/flash/nor/core.c:391 default_flash_blank_check(),
# src/flash/nor/fespi.c:1077 fespi_flash = { .erase_check=default_flash_blank_check; },
# Suggest adding member 'int is_needed;' to struct flash_sector (nor/core.h:41)
# to make default implementations of blank_check more intelligent.
#
# [flash write_image erase unlock filename offset type]
# Does not work, because of
# messages 'Warn : Failed to write memory via program buffer.'
# and 'Warn : Failed to write memory via abstract access.'
# and also very long running time due to above problem when 'erase' specified.
#
# [program filename preverify verify offset]
# Does not work, because of
# messages 'Warn : Failed to write memory via program buffer.'
# and 'Warn : Failed to write memory via abstract access.'
#
# [flash verify_image filename offset type]
# seems to work okay.
# --------------------------------------------------------------------
#
proc fe310_rom_load { program {addr "0x20000000"} {no_run ""} } {
halt 100 ;# includes wait_halt 100
# sector size also defined in ...src/flash/nor/core.h:45 (uint32_t) size
set secsz [expr 0x1000] ;# 4K sectors issi is25lp128d, typ. most NOR flash
set len [file size ${program}-rom.bin]
set endsec [expr (${len}/${secsz})+((${len}-(${len}/${secsz})*${secsz})>0)-1]
#-----
# equivalent implementation in /bin/bash script, for use in, e.g., mk files, is shown below:
#$(eval SECSZ=$(shell echo "ibase=16; 1000" | bc))
#$(eval LEN=$(shell <${PROGRAM}-rom.bin wc -c))
#$(eval ENDSEC=$(shell echo "(${LEN}/${SECSZ})+((${LEN}-(${LEN}/${SECSZ})*${SECSZ})>0)-1" | bc))
#-----
set erased_value 255 ;# also defined in ...src/flash/nor/core.h:104 (uint8_t) erased_value
set is_erased 1
for {set i 0} { ($i <= $endsec) && $is_erased } {incr i} {
riscv.cpu.0 mem2array buf 8 [expr ${addr} + ${secsz} * $i] ${secsz}
foreach idx [array names buf] {
if {$buf($idx) != ${erased_value}} {
set is_erased 0
}
}
}
# in case of verify_bank pass, message returned is 'contents match'
# in case of verify_bank fail, message returned is 'contents differ', diff lines, abrupt exit
#
set rc [catch {flash verify_bank 0 ${program}-rom.bin} err] ;# trap exit on verify fail
if {[expr $rc == 0]} {
echo "flash device already up to date - nothing to do"
} else {
echo [flash protect 0 0 ${endsec} off]
if {! $is_erased} {
echo [flash erase_sector 0 0 ${endsec}]
}
echo [flash write_bank 0 ${program}-rom.bin]
echo [flash verify_bank 0 ${program}-rom.bin]
echo [flash protect 0 0 ${endsec} on]
}
if {[expr [string length $no_run] == 0]} {
resume ${addr}
}
}