c7fa591f3cee2dec7bcfc81f61bf7b1139bc64b2
[fw/openocd] / tcl / tools / memtest.tcl
1 # Algorithms by Michael Barr, released into public domain
2 # Ported to OpenOCD by Shane Volpe, additional fixes by Paul Fertser
3
4 set CPU_MAX_ADDRESS 0xFFFFFFFF
5 source [find bitsbytes.tcl]
6 source [find memory.tcl]
7
8 proc runAllMemTests { baseAddress nBytes } {
9     memTestDataBus $baseAddress
10     memTestAddressBus $baseAddress $nBytes
11     memTestDevice $baseAddress $nBytes
12 }
13
14 #***********************************************************************************
15 # *
16 # * Function:    memTestDataBus()
17 # *
18 # * Description: Test the data bus wiring in a memory region by
19 # *              performing a walking 1's test at a fixed address
20 # *              within that region.  The address (and hence the
21 # *              memory region) is selected by the caller.
22 # *              Ported from:
23 # *              http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C
24 # * Notes:
25 # *
26 # * Returns:     Empty string if the test succeeds.
27 # *              A non-zero result is the first pattern that failed.
28 # *
29 #***********************************************************************************
30 proc memTestDataBus { address } {
31     echo "Running memTestDataBus"
32
33     for {set i 0} {$i < 32} {incr i} {
34         # Shift bit
35         set pattern [expr {1 << $i}]
36
37         # Write pattern to memory
38         memwrite32 $address $pattern
39
40         # Read pattern from memory
41         set data [memread32 $address]
42
43         if {$data != $pattern} {
44             echo "FAILED DATABUS: Address: $address, Pattern: $pattern, Returned: $data"
45             return $pattern
46         }
47     }
48 }
49
50 #***********************************************************************************
51 # *
52 # * Function:    memTestAddressBus()
53 # *
54 # * Description: Perform a walking 1's test on the relevant bits
55 # *              of the address and check for aliasing.  This test
56 # *              will find single-bit address failures such as stuck
57 # *              -high, stuck-low, and shorted pins.  The base address
58 # *              and size of the region are selected by the caller.
59 # *              Ported from:
60 # *              http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C
61 # *
62 # * Notes:       For best results, the selected base address should
63 # *              have enough LSB 0's to guarantee single address bit
64 # *              changes.  For example, to test a 64-Kbyte region,
65 # *              select a base address on a 64-Kbyte boundary.  Also,
66 # *              select the region size as a power-of-two--if at all
67 # *              possible.
68 # *
69 # * Returns:     Empty string if the test succeeds.
70 # *              A non-zero result is the first address at which an
71 # *              aliasing problem was uncovered.  By examining the
72 # *              contents of memory, it may be possible to gather
73 # *              additional information about the problem.
74 # *
75 #***********************************************************************************
76 proc memTestAddressBus { baseAddress nBytes } {
77     set addressMask [expr {$nBytes - 1}]
78     set pattern 0xAAAAAAAA
79     set antipattern 0x55555555
80
81     echo "Running memTestAddressBus"
82
83     echo "addressMask: [convertToHex $addressMask]"
84
85     echo "memTestAddressBus: Writing the default pattern at each of the power-of-two offsets..."
86     for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}] } {
87         set addr [expr {$baseAddress + $offset}]
88         memwrite32 $addr $pattern
89     }
90
91     echo "memTestAddressBus: Checking for address bits stuck high..."
92     memwrite32 $baseAddress $antipattern
93
94     for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} {
95         set addr [expr {$baseAddress + $offset}]
96         set data [memread32 $addr]
97
98         if {$data != $pattern} {
99             echo "FAILED DATA_ADDR_BUS_SHIGH: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]"
100             return $pattern
101         }
102     }
103
104     echo "memTestAddressBus: Checking for address bits stuck low or shorted..."
105     memwrite32 $baseAddress $pattern
106     for {set testOffset 32} {[expr {$testOffset & $addressMask}] != 0} {set testOffset [expr {$testOffset << 1}] } {
107         set addr [expr {$baseAddress + $testOffset}]
108         memwrite32 $addr $antipattern
109
110         set data [memread32 $baseAddress]
111         if {$data != $pattern} {
112             echo "FAILED DATA_ADDR_BUS_SLOW: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data]"
113             return $pattern
114         }
115
116         for {set offset 32} {[expr {$offset & $addressMask}] != 0} {set offset [expr {$offset << 1}]} {
117             set addr [expr {$baseAddress + $offset}]
118             set data [memread32 $baseAddress]
119
120             if {(($data != $pattern) && ($offset != $testOffset))} {
121                 echo "FAILED DATA_ADDR_BUS_SLOW2: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset], testOffset [convertToHex $testOffset]"
122                 return $pattern
123             }
124         }
125         set addr [expr {$baseAddress + $testOffset}]
126         memwrite32 $addr $pattern
127     }
128 }
129
130 #***********************************************************************************
131 # *
132 # * Function:    memTestDevice()
133 # *
134 # * Description: Test the integrity of a physical memory device by
135 # *              performing an increment/decrement test over the
136 # *              entire region.  In the process every storage bit
137 # *              in the device is tested as zero and as one.  The
138 # *              base address and the size of the region are
139 # *              selected by the caller.
140 # *              Ported from:
141 # *              http://www.netrino.com/Embedded-Systems/How-To/Memory-Test-Suite-C
142 # * Notes:
143 # *
144 # * Returns:     Empty string if the test succeeds.
145 # *              A non-zero result is the first address at which an
146 # *              incorrect value was read back.  By examining the
147 # *              contents of memory, it may be possible to gather
148 # *              additional information about the problem.
149 # *
150 #***********************************************************************************
151 proc memTestDevice { baseAddress nBytes } {
152     echo "Running memTestDevice"
153
154     echo "memTestDevice: Filling memory with a known pattern..."
155     for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} {
156         memwrite32 [expr {$baseAddress + $offset}] $pattern
157     }
158
159     echo "memTestDevice: Checking each location and inverting it for the second pass..."
160     for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} {
161         set addr [expr {$baseAddress + $offset}]
162         set data [memread32 $addr]
163
164         if {$data != $pattern} {
165             echo "FAILED memTestDevice_pattern: Address: [convertToHex $addr], Pattern: [convertToHex $pattern], Returned: [convertToHex $data], offset: [convertToHex $offset]"
166             return $pattern
167         }
168
169         set antiPattern [expr {~$pattern}]
170         memwrite32 [expr {$baseAddress + $offset}] $antiPattern
171     }
172
173     echo "memTestDevice: Checking each location for the inverted pattern and zeroing it..."
174     for {set pattern 1; set offset 0} {$offset < $nBytes} {incr pattern; incr offset 32} {
175         set antiPattern [expr {~$pattern & ((1<<32) - 1)}]
176         set addr [expr {$baseAddress + $offset}]
177         set data [memread32 $addr]
178         set dataHex [convertToHex $data]
179         set antiPatternHex [convertToHex $antiPattern]
180         if {$dataHex != $antiPatternHex} {
181             echo "FAILED memTestDevice_antipattern: Address: [convertToHex $addr], antiPattern: $antiPatternHex, Returned: $dataHex, offset: $offset"
182             return $pattern
183         }
184     }
185 }
186
187 proc convertToHex { value } {
188     format 0x%08x $value
189 }