aboutsummaryrefslogtreecommitdiff
path: root/tcl/tools
diff options
context:
space:
mode:
authorPaul Fertser <fercerpav@gmail.com>2013-06-22 01:16:41 +0400
committerSpencer Oliver <spen@spen-soft.co.uk>2013-10-29 22:50:33 +0000
commitb16a7f9f6e3c7c417fa3d0d0bf042f032ee446f6 (patch)
treefbd87a74b47509f33d7e453938456d99b830935a /tcl/tools
parentd4e195ad1b544b0396cab4c70437371958769196 (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.tcl189
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
+}