memtest.tcl 7.3 KB

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