144 lines
3.4 KiB
INI
144 lines
3.4 KiB
INI
#
|
|
# For each named Cortex-M3 vector_catch flag VECTOR ...
|
|
# bus_err state_err
|
|
# chk_err nocp_err
|
|
# mm_err reset
|
|
#
|
|
# BUT NYET hard_err, int_err (their test cases don't yet work) ...
|
|
#
|
|
# Do the following:
|
|
#
|
|
# - Test #1: verify that OpenOCD ignores exceptions by default
|
|
# + l_VECTOR (loads testcase to RAM)
|
|
# + fault triggers loop-to-self exception "handler"
|
|
# + "halt"
|
|
# + observe fault "handling" -- loop-to-self from load_and_run (below)
|
|
#
|
|
# - Test #2: verify that "vector_catch" makes OpenOCD stops ignoring them
|
|
# + cortex_m vector_catch none
|
|
# + cortex_m vector_catch VECTOR
|
|
# + l_VECTOR (loads testcase to RAM)
|
|
# + fault triggers vector catch hardware
|
|
# + observe OpenOCD entering debug state with no assistance
|
|
#
|
|
# NOTE "reset" includes the NVIC, so that test case gets its reset vector
|
|
# from the flash, not from the vector table set up here. Which means that
|
|
# for that vector_catch option, the Test #1 (above) "observe" step won't
|
|
# use the SRAM address.
|
|
#
|
|
|
|
# we can fully automate test #2
|
|
proc vector_test {tag} {
|
|
halt
|
|
# REVISIT -- annoying, we'd like to scrap vector_catch output
|
|
cortex_m vector_catch none
|
|
cortex_m vector_catch $tag
|
|
eval "l_$tag"
|
|
}
|
|
|
|
#
|
|
# Load and start one vector_catch test case.
|
|
#
|
|
# name -- tag for the vector_catch flag being tested
|
|
# halfwords -- array of instructions (some wide, some narrow)
|
|
# n_instr -- how many instructions are in $halfwords
|
|
#
|
|
proc load_and_run { name halfwords n_instr } {
|
|
reset halt
|
|
|
|
# Load code at beginning of SRAM.
|
|
echo "# code to trigger $name vector"
|
|
set addr 0x20000000
|
|
|
|
# write_memory should be faster, though we'd need to
|
|
# compute the resulting $addr ourselves
|
|
foreach opcode $halfwords {
|
|
mwh $addr $opcode
|
|
incr addr 2
|
|
}
|
|
|
|
# create default loop-to-self at $addr ... it serves as
|
|
# (a) "main loop" on error
|
|
# (b) handler for all exceptions that get triggered
|
|
mwh $addr 0xe7fe
|
|
|
|
# disassemble, as sanity check and what's-happening trace
|
|
arm disassemble 0x20000000 [expr 1 + $n_instr ]
|
|
|
|
# Assume that block of code is at most 16 halfwords long.
|
|
# Create a basic table of loop-to-self exception handlers.
|
|
mww 0x20000020 $addr 16
|
|
# Store its address in VTOR
|
|
mww 0xe000ed08 0x20000020
|
|
# Use SHCSR to ensure nothing escalates to a HardFault
|
|
mww 0xe000ed24 0x00070000
|
|
|
|
# now start, trigering the $name vector catch logic
|
|
resume 0x20000000
|
|
}
|
|
|
|
#proc l_hard_err {} {
|
|
# IMPLEMENT ME
|
|
# FORCED -- escalate something to HardFault
|
|
#}
|
|
|
|
#proc l_int_err {} {
|
|
# IMPLEMENT ME
|
|
# STKERR -- exception stack BusFault
|
|
#}
|
|
|
|
# BusFault, escalates to HardFault
|
|
proc l_bus_err {} {
|
|
# PRECISERR -- assume less than 512 MBytes of SRAM
|
|
load_and_run bus_err {
|
|
0xf06f 0x4040
|
|
0x7800
|
|
} 2
|
|
}
|
|
|
|
# UsageFault, escalates to HardFault
|
|
proc l_state_err {} {
|
|
# UNDEFINSTR -- issue architecturally undefined instruction
|
|
load_and_run state_err {
|
|
0xde00
|
|
} 1
|
|
}
|
|
|
|
# UsageFault, escalates to HardFault
|
|
proc l_chk_err {} {
|
|
# UNALIGNED -- LDM through unaligned pointer
|
|
load_and_run chk_err {
|
|
0xf04f 0x0001
|
|
0xe890 0x0006
|
|
} 2
|
|
}
|
|
|
|
# UsageFault, escalates to HardFault
|
|
proc l_nocp_err {} {
|
|
# NOCP -- issue cp14 DCC instruction
|
|
load_and_run nocp_err {
|
|
0xee10 0x0e15
|
|
} 1
|
|
}
|
|
|
|
# MemManage, escalates to HardFault
|
|
proc l_mm_err {} {
|
|
# IACCVIOL -- instruction fetch from an XN region
|
|
load_and_run mm_err {
|
|
0xf04f 0x4060
|
|
0x4687
|
|
} 2
|
|
}
|
|
|
|
proc l_reset {} {
|
|
# issue SYSRESETREQ via AIRCR
|
|
load_and_run reset {
|
|
0xf04f 0x0104
|
|
0xf2c0 0x51fa
|
|
0xf44f 0x406d
|
|
0xf100 0x000c
|
|
0xf2ce 0x0000
|
|
0x6001
|
|
} 6
|
|
}
|