From 0ded19d04a10d9c39626431202b5c9c335da9529 Mon Sep 17 00:00:00 2001 From: Toby Jaffey Date: Thu, 11 Dec 2025 17:46:20 +0000 Subject: [PATCH] Basic memory test --- apps/memtest/Makefile | 13 +++ apps/memtest/barr_memtest.c | 221 ++++++++++++++++++++++++++++++++++++ apps/memtest/barr_memtest.h | 41 +++++++ apps/memtest/memtest.c | 11 ++ 4 files changed, 286 insertions(+) create mode 100644 apps/memtest/Makefile create mode 100644 apps/memtest/barr_memtest.c create mode 100644 apps/memtest/barr_memtest.h create mode 100644 apps/memtest/memtest.c diff --git a/apps/memtest/Makefile b/apps/memtest/Makefile new file mode 100644 index 0000000..f5cce9c --- /dev/null +++ b/apps/memtest/Makefile @@ -0,0 +1,13 @@ +TOPDIR=../../ +PROJECT:=$(shell basename ${PWD}) + +HEAP_SIZE=$(shell echo "1024 * 1024 * 32" | bc) +OPT=-Os +CFLAGS=-DHEAP_SIZE=${HEAP_SIZE} +SRCS=${PROJECT}.c ${TOPDIR}/apps/crt0.S barr_memtest.c + +HOST_EXTRA=-e ${HEAP_SIZE} -i 4294967295 +all: all_common +test: test_common +clean: clean_common +include ${TOPDIR}/apps/makefile.common diff --git a/apps/memtest/barr_memtest.c b/apps/memtest/barr_memtest.c new file mode 100644 index 0000000..3161c0e --- /dev/null +++ b/apps/memtest/barr_memtest.c @@ -0,0 +1,221 @@ +/********************************************************************** + * + * Filename: memtest.c + * + * Description: General-purpose memory testing functions. + * + * Notes: This software can be easily ported to systems with + * different data bus widths by redefining 'datum'. + * + * + * Copyright (c) 1998 by Michael Barr. This software is placed into + * the public domain and may be used for any purpose. However, this + * notice must not be changed or removed and no warranty is either + * expressed or implied by its publication or distribution. + **********************************************************************/ + + +#include "barr_memtest.h" + + +/********************************************************************** + * + * 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. + * + * Notes: + * + * Returns: 0 if the test succeeds. + * A non-zero result is the first pattern that failed. + * + **********************************************************************/ +datum +memTestDataBus(volatile datum * address) +{ + datum pattern; + + + /* + * Perform a walking 1's test at the given address. + */ + for (pattern = 1; pattern != 0; pattern <<= 1) + { + /* + * Write the test pattern. + */ + *address = pattern; + + /* + * Read it back (immediately is okay for this test). + */ + if (*address != pattern) + { + return (pattern); + } + } + + return (0); + +} /* memTestDataBus() */ + + +/********************************************************************** + * + * Function: memTestAddressBus() + * + * Description: Test the address bus wiring in a memory region by + * performing a walking 1's test on the relevant bits + * of the address and checking 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. + * + * 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: NULL 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. + * + **********************************************************************/ +datum * +memTestAddressBus(volatile datum * baseAddress, unsigned long nBytes) +{ + unsigned long addressMask = (nBytes/sizeof(datum) - 1); + unsigned long offset; + unsigned long testOffset; + + datum pattern = (datum) 0xAAAAAAAA; + datum antipattern = (datum) 0x55555555; + + + /* + * Write the default pattern at each of the power-of-two offsets. + */ + for (offset = 1; (offset & addressMask) != 0; offset <<= 1) + { + baseAddress[offset] = pattern; + } + + /* + * Check for address bits stuck high. + */ + testOffset = 0; + baseAddress[testOffset] = antipattern; + + for (offset = 1; (offset & addressMask) != 0; offset <<= 1) + { + if (baseAddress[offset] != pattern) + { + return ((datum *) &baseAddress[offset]); + } + } + + baseAddress[testOffset] = pattern; + + /* + * Check for address bits stuck low or shorted. + */ + for (testOffset = 1; (testOffset & addressMask) != 0; testOffset <<= 1) + { + baseAddress[testOffset] = antipattern; + + if (baseAddress[0] != pattern) + { + return ((datum *) &baseAddress[testOffset]); + } + + for (offset = 1; (offset & addressMask) != 0; offset <<= 1) + { + if ((baseAddress[offset] != pattern) && (offset != testOffset)) + { + return ((datum *) &baseAddress[testOffset]); + } + } + + baseAddress[testOffset] = pattern; + } + + return (NULL); + +} /* memTestAddressBus() */ + + +/********************************************************************** + * + * 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 a zero and a one. The + * base address and the size of the region are + * selected by the caller. + * + * Notes: + * + * Returns: NULL 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. + * + **********************************************************************/ +datum * +memTestDevice(volatile datum * baseAddress, unsigned long nBytes) +{ + unsigned long offset; + unsigned long nWords = nBytes / sizeof(datum); + + datum pattern; + datum antipattern; + + + /* + * Fill memory with a known pattern. + */ + for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) + { + baseAddress[offset] = pattern; + } + + /* + * Check each location and invert it for the second pass. + */ + for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) + { + if (baseAddress[offset] != pattern) + { + return ((datum *) &baseAddress[offset]); + } + + antipattern = ~pattern; + baseAddress[offset] = antipattern; + } + + /* + * Check each location for the inverted pattern and zero it. + */ + for (pattern = 1, offset = 0; offset < nWords; pattern++, offset++) + { + antipattern = ~pattern; + if (baseAddress[offset] != antipattern) + { + return ((datum *) &baseAddress[offset]); + } + } + + return (NULL); + +} /* memTestDevice() */ diff --git a/apps/memtest/barr_memtest.h b/apps/memtest/barr_memtest.h new file mode 100644 index 0000000..decda61 --- /dev/null +++ b/apps/memtest/barr_memtest.h @@ -0,0 +1,41 @@ +/********************************************************************** + * + * Filename: memtest.h + * + * Description: Memory-testing module API. + * + * Notes: The memory tests can be easily ported to systems with + * different data bus widths by redefining 'datum' type. + * + * + * Copyright (c) 2000 by Michael Barr. This software is placed into + * the public domain and may be used for any purpose. However, this + * notice must not be changed or removed and no warranty is either + * expressed or implied by its publication or distribution. + **********************************************************************/ + +#ifndef _memtest_h +#define _memtest_h + + +/* + * Define NULL pointer value. + */ +#ifndef NULL +#define NULL (void *) 0 +#endif + +/* + * Set the data bus width. + */ +typedef unsigned long datum; + +/* + * Function prototypes. + */ +datum memTestDataBus(volatile datum * address); +datum * memTestAddressBus(volatile datum * baseAddress, unsigned long nBytes); +datum * memTestDevice(volatile datum * baseAddress, unsigned long nBytes); + + +#endif /* _memtest_h */ diff --git a/apps/memtest/memtest.c b/apps/memtest/memtest.c new file mode 100644 index 0000000..391fbda --- /dev/null +++ b/apps/memtest/memtest.c @@ -0,0 +1,11 @@ +#include "uvm32_target.h" +#include "barr_memtest.h" + +void main(void) { + datum * base = (datum *)UVM32_EXTRAM_BASE; + if ((memTestDataBus(base) != 0) || (memTestAddressBus(base, HEAP_SIZE) != NULL) || (memTestDevice(base, HEAP_SIZE) != NULL)) { + println("Memory error!"); + } else { + println("Memory ok"); + } +}