Progress getting OpenOCD usable with RevB

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}
  }
}
1 Like