diff options
author | Paul Fertser <fercerpav@gmail.com> | 2013-06-22 01:16:41 +0400 |
---|---|---|
committer | Spencer Oliver <spen@spen-soft.co.uk> | 2013-10-29 22:50:33 +0000 |
commit | b16a7f9f6e3c7c417fa3d0d0bf042f032ee446f6 (patch) | |
tree | fbd87a74b47509f33d7e453938456d99b830935a /tcl/tools | |
parent | d4e195ad1b544b0396cab4c70437371958769196 (diff) |
tcl: add memory testing functions for board diagnostics
This is a tcl implementation of public domain tests by Michael Barr,
http://www.barrgroup.com/Embedded-Systems/How-To/Memory-Test-Suite-C
The initial porting is done by Shane Volpe and posted to the mailing
list:
http://www.mail-archive.com/openocd-development@lists.berlios.de/msg16676.html
This patch includes some cosmetic amendments plus hardcodes 32bit word
size (as the code depends on memread32/memwrite32 anyway) which fixes
original code's issue of testing only the first quarter of the
specified nBytes.
Change-Id: I5f3a66f1f16fc4082c7a5a6aba338430646ed21c
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/1455
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
Reviewed-by: Mathias Küster <kesmtp@freenet.de>
Diffstat (limited to 'tcl/tools')
-rw-r--r-- | tcl/tools/memtest.tcl | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/tcl/tools/memtest.tcl b/tcl/tools/memtest.tcl new file mode 100644 index 00000000..02f94d30 --- /dev/null +++ b/tcl/tools/memtest.tcl @@ -0,0 +1,189 @@ +# Algorithms by Michael Barr, released into public domain +# Ported to OpenOCD by Shane Volpe, additional fixes by Paul Fertser + +set CPU_MAX_ADDRESS 0xFFFFFFFF +source [find bitsbytes.tcl] +source [find memory.tcl] + +proc runAllMemTests { baseAddress nBytes } { + memTestDataBus $baseAddress + memTestAddressBus $baseAddress $nBytes + memTestDevice $baseAddress $nBytes +} + +#*********************************************************************************** +# * +# * Function: memTestDataBus() +# * +# * Description: Test the data bus wiring in a memory region by +# * performing a walking 1's test at a fixed address +# * within that region. The address (and hence the +# * memory region) is selected by the caller. +# * Ported from: +# * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C +# * Notes: +# * +# * Returns: Empty string if the test succeeds. +# * A non-zero result is the first pattern that failed. +# * +#*********************************************************************************** +proc memTestDataBus { address } { + echo "Running memTestDataBus" + + for {set i 0} {$i < 32} {incr i} { + # Shift bit + set pattern [expr {1 << $i}] + + # Write pattern to memory + memwrite32 $address $pattern + + # Read pattern from memory + set data [memread32 $address] + + if {$data != $pattern} { + echo "FAILED DATABUS: Address: $address, Pattern: $pattern, Returned: $data" + return $pattern + } + } +} + +#*********************************************************************************** +# * +# * Function: memTestAddressBus() +# * +# * Description: Perform a walking 1's test on the relevant bits +# * of the address and check for aliasing. This test +# * will find single-bit address failures such as stuck +# * -high, stuck-low, and shorted pins. The base address +# * and size of the region are selected by the caller. +# * Ported from: +# * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C +# * +# * Notes: For best results, the selected base address should +# * have enough LSB 0's to guarantee single address bit +# * changes. For example, to test a 64-Kbyte region, +# * select a base address on a 64-Kbyte boundary. Also, +# * select the region size as a power-of-two--if at all +# * possible. +# * +# * Returns: Empty string if the test succeeds. +# * A non-zero result is the first address at which an +# * aliasing problem was uncovered. By examining the +# * contents of memory, it may be possible to gather +# * additional information about the problem. +# * +#*********************************************************************************** +proc memTestAddressBus { baseAddress nBytes } { + set addressMask [expr $nBytes - 1] + set pattern 0xAAAAAAAA + set antipattern 0x55555555 + + echo "Running memTestAddressBus" + + echo "addressMask: [convertToHex $addressMask]" + + echo "memTestAddressBus: Writing the default pattern at each of the power-of-two offsets..." + for {set offset 32} {[expr $offset & $addressMask] != 0} {set offset [expr $offset << 1] } { + set addr [expr $baseAddress + $offset] + memwrite32 $addr $pattern + } + + echo "memTestAddressBus: Checking for address bits stuck high..." + memwrite32 $baseAddress $antipattern + + for {set offset 32} {[expr $offset & $addressMask] != 0} {set offset [expr $offset << 1]} { + set addr [expr $baseAddress + $offset] + set data [memread32 $addr] + + if {$data != $pattern} { + echo "FAILED DATA_ADDR_BUS_SHIGH: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]" + return $pattern + } + } + + echo "memTestAddressBus: Checking for address bits stuck low or shorted..." + memwrite32 $baseAddress $pattern + for {set testOffset 32} {[expr $testOffset & $addressMask] != 0} {set testOffset [expr $testOffset << 1] } { + set addr [expr $baseAddress + $testOffset] + memwrite32 $addr $antipattern + + set data [memread32 $baseAddress] + if {$data != $pattern} { + echo "FAILED DATA_ADDR_BUS_SLOW: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]" + return $pattern + } + + for {set offset 32} {[expr $offset & $addressMask] != 0} {set offset [expr $offset << 1]} { + set addr [expr $baseAddress + $offset] + set data [memread32 $baseAddress] + + if {(($data != $pattern) && ($offset != $testOffset))} { + echo "FAILED DATA_ADDR_BUS_SLOW2: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset], testOffset [convertToHex $testOffset]" + return $pattern + } + } + set addr [expr $baseAddress + $testOffset] + memwrite32 $addr $pattern + } +} + +#*********************************************************************************** +# * +# * Function: memTestDevice() +# * +# * Description: Test the integrity of a physical memory device by +# * performing an increment/decrement test over the +# * entire region. In the process every storage bit +# * in the device is tested as zero and as one. The +# * base address and the size of the region are +# * selected by the caller. +# * Ported from: +# * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C +# * Notes: +# * +# * Returns: Empty string if the test succeeds. +# * A non-zero result is the first address at which an +# * incorrect value was read back. By examining the +# * contents of memory, it may be possible to gather +# * additional information about the problem. +# * +#*********************************************************************************** +proc memTestDevice { baseAddress nBytes } { + echo "Running memTestDevice" + + echo "memTestDevice: Filling memory with a known pattern..." + for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { + memwrite32 [expr $baseAddress + $offset] $pattern + } + + echo "memTestDevice: Checking each location and inverting it for the second pass..." + for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { + set addr [expr $baseAddress + $offset] + set data [memread32 $addr] + + if {$data != $pattern} { + echo "FAILED memTestDevice_pattern: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset]" + return $pattern + } + + set antiPattern [expr ~$pattern] + memwrite32 [expr $baseAddress + $offset] $antiPattern + } + + echo "memTestDevice: Checking each location for the inverted pattern and zeroing it..." + for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} { + set antiPattern [expr ~$pattern & ((1<<32) - 1)] + set addr [expr $baseAddress + $offset] + set data [memread32 $addr] + set dataHex [convertToHex $data] + set antiPatternHex [convertToHex $antiPattern] + if {[expr $dataHex != $antiPatternHex]} { + echo "FAILED memTestDevice_antipattern: Address: [convertToHex $addr], antiPattern: $antiPatternHex, Returned: $dataHex, offset: $offset" + return $pattern + } + } +} + +proc convertToHex { value } { + format 0x%08x $value +} |