1 # SPDX-License-Identifier: GPL-2.0-or-later
3 # Algorithms by Michael Barr, released into public domain
4 # Ported to OpenOCD by Shane Volpe, additional fixes by Paul Fertser
6 set CPU_MAX_ADDRESS 0xFFFFFFFF
7 source [find bitsbytes.tcl]
8 source [find memory.tcl]
10 proc runAllMemTests { baseAddress nBytes } {
11 memTestDataBus $baseAddress
12 memTestAddressBus $baseAddress $nBytes
13 memTestDevice $baseAddress $nBytes
16 #***********************************************************************************
18 # * Function: memTestDataBus()
20 # * Description: Test the data bus wiring in a memory region by
21 # * performing a walking 1's test at a fixed address
22 # * within that region. The address (and hence the
23 # * memory region) is selected by the caller.
25 # * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C
28 # * Returns: Empty string if the test succeeds.
29 # * A non-zero result is the first pattern that failed.
31 #***********************************************************************************
32 proc memTestDataBus { address } {
33 echo "Running memTestDataBus"
35 for {set i 0} {$i < 32} {incr i} {
37 set pattern [expr {1 << $i}]
39 # Write pattern to memory
40 memwrite32 $address $pattern
42 # Read pattern from memory
43 set data [memread32 $address]
45 if {$data != $pattern} {
46 echo "FAILED DATABUS: Address: $address, Pattern: $pattern, Returned: $data"
52 #***********************************************************************************
54 # * Function: memTestAddressBus()
56 # * Description: Perform a walking 1's test on the relevant bits
57 # * of the address and check for aliasing. This test
58 # * will find single-bit address failures such as stuck
59 # * -high, stuck-low, and shorted pins. The base address
60 # * and size of the region are selected by the caller.
62 # * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C
64 # * Notes: For best results, the selected base address should
65 # * have enough LSB 0's to guarantee single address bit
66 # * changes. For example, to test a 64-Kbyte region,
67 # * select a base address on a 64-Kbyte boundary. Also,
68 # * select the region size as a power-of-two--if at all
71 # * Returns: Empty string if the test succeeds.
72 # * A non-zero result is the first address at which an
73 # * aliasing problem was uncovered. By examining the
74 # * contents of memory, it may be possible to gather
75 # * additional information about the problem.
77 #***********************************************************************************
78 proc memTestAddressBus { baseAddress nBytes } {
79 set addressMask [expr {$nBytes - 1}]
80 set pattern 0xAAAAAAAA
81 set antipattern 0x55555555
83 echo "Running memTestAddressBus"
85 echo "addressMask: [convertToHex $addressMask]"
87 echo "memTestAddressBus: Writing the default pattern at each of the power-of-two offsets..."
88 for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}] } {
89 set addr [expr {$baseAddress + $offset}]
90 memwrite32 $addr $pattern
93 echo "memTestAddressBus: Checking for address bits stuck high..."
94 memwrite32 $baseAddress $antipattern
96 for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} {
97 set addr [expr {$baseAddress + $offset}]
98 set data [memread32 $addr]
100 if {$data != $pattern} {
101 echo "FAILED DATA_ADDR_BUS_SHIGH: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]"
106 echo "memTestAddressBus: Checking for address bits stuck low or shorted..."
107 memwrite32 $baseAddress $pattern
108 for {set testOffset 32} {[expr {$testOffset & $addressMask}] != 0} {set testOffset [expr {$testOffset << 1}] } {
109 set addr [expr {$baseAddress + $testOffset}]
110 memwrite32 $addr $antipattern
112 set data [memread32 $baseAddress]
113 if {$data != $pattern} {
114 echo "FAILED DATA_ADDR_BUS_SLOW: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]"
118 for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} {
119 set addr [expr {$baseAddress + $offset}]
120 set data [memread32 $baseAddress]
122 if {(($data != $pattern) && ($offset != $testOffset))} {
123 echo "FAILED DATA_ADDR_BUS_SLOW2: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset], testOffset [convertToHex $testOffset]"
127 set addr [expr {$baseAddress + $testOffset}]
128 memwrite32 $addr $pattern
132 #***********************************************************************************
134 # * Function: memTestDevice()
136 # * Description: Test the integrity of a physical memory device by
137 # * performing an increment/decrement test over the
138 # * entire region. In the process every storage bit
139 # * in the device is tested as zero and as one. The
140 # * base address and the size of the region are
141 # * selected by the caller.
143 # * http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C
146 # * Returns: Empty string if the test succeeds.
147 # * A non-zero result is the first address at which an
148 # * incorrect value was read back. By examining the
149 # * contents of memory, it may be possible to gather
150 # * additional information about the problem.
152 #***********************************************************************************
153 proc memTestDevice { baseAddress nBytes } {
154 echo "Running memTestDevice"
156 echo "memTestDevice: Filling memory with a known pattern..."
157 for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} {
158 memwrite32 [expr {$baseAddress + $offset}] $pattern
161 echo "memTestDevice: Checking each location and inverting it for the second pass..."
162 for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} {
163 set addr [expr {$baseAddress + $offset}]
164 set data [memread32 $addr]
166 if {$data != $pattern} {
167 echo "FAILED memTestDevice_pattern: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset]"
171 set antiPattern [expr {~$pattern}]
172 memwrite32 [expr {$baseAddress + $offset}] $antiPattern
175 echo "memTestDevice: Checking each location for the inverted pattern and zeroing it..."
176 for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} {
177 set antiPattern [expr {~$pattern & ((1<<32) - 1)}]
178 set addr [expr {$baseAddress + $offset}]
179 set data [memread32 $addr]
180 set dataHex [convertToHex $data]
181 set antiPatternHex [convertToHex $antiPattern]
182 if {$dataHex != $antiPatternHex} {
183 echo "FAILED memTestDevice_antipattern: Address: [convertToHex $addr], antiPattern: $antiPatternHex, Returned: $dataHex, offset: $offset"
189 proc convertToHex { value } {