diff --git a/litex/soc/software/include/base/memtest.h b/litex/soc/software/include/base/memtest.h index 864a7fdf6..8ea4c3528 100644 --- a/litex/soc/software/include/base/memtest.h +++ b/litex/soc/software/include/base/memtest.h @@ -3,10 +3,22 @@ #include +// Called when an error is encountered. Can return non-zero to stop the memtest. +// `arg` can be used to pass arbitrary data to the callback via `memtest_config.arg`. +typedef int (*on_error_callback)(unsigned int addr, unsigned int rdata, unsigned int refdata, void *arg); + +// Optional memtest configuration. If NULL, then we default to progress=1, read_only=0. +struct memtest_config { + int show_progress; + int read_only; + on_error_callback on_error; + void *arg; +}; + int memtest_access(unsigned int *addr); int memtest_bus(unsigned int *addr, unsigned long size); int memtest_addr(unsigned int *addr, unsigned long size, int random); -int memtest_data(unsigned int *addr, unsigned long size, int random); +int memtest_data(unsigned int *addr, unsigned long size, int random, struct memtest_config *config); void memspeed(unsigned int *addr, unsigned long size, bool read_only); int memtest(unsigned int *addr, unsigned long maxsize); diff --git a/litex/soc/software/libbase/memtest.c b/litex/soc/software/libbase/memtest.c index bbd1f2a23..139752276 100644 --- a/litex/soc/software/libbase/memtest.c +++ b/litex/soc/software/libbase/memtest.c @@ -172,25 +172,29 @@ static void print_progress(const char * header, unsigned int offset, unsigned in printf(" \r"); } -int memtest_data(unsigned int *addr, unsigned long size, int random) +int memtest_data(unsigned int *addr, unsigned long size, int random, struct memtest_config *config) { volatile unsigned int *array = addr; int i, errors; + int progress; unsigned int seed_32; unsigned int rdata; + progress = config == NULL ? 1 : config->show_progress; errors = 0; seed_32 = 1; - /* Write datas */ - for(i=0; iread_only) { + /* Write datas */ + for(i=0; ion_error != NULL) { + // call the handler, if non-zero status is returned finish now + if (config->on_error((unsigned int) (addr + i), rdata, seed_32, config->arg) != 0) + return errors; + } #ifdef MEMTEST_DATA_DEBUG printf("memtest_data error @ %p: 0x%08x vs 0x%08x\n", addr + i, rdata, seed_32); #endif } - if (i%0x8000 == 0) + if (i%0x8000 == 0 && progress) print_progress(" Read:", (unsigned long)addr, 4*i); } - print_progress(" Read:", (unsigned long)addr, 4*i); - printf("\n"); + if (progress) { + print_progress(" Read:", (unsigned long)addr, 4*i); + printf("\n"); + } return errors; } @@ -292,7 +303,7 @@ int memtest(unsigned int *addr, unsigned long maxsize) bus_errors = memtest_bus(addr, bus_size); addr_errors = memtest_addr(addr, addr_size, MEMTEST_ADDR_RANDOM); - data_errors = memtest_data(addr, data_size, MEMTEST_DATA_RANDOM); + data_errors = memtest_data(addr, data_size, MEMTEST_DATA_RANDOM, NULL); if(bus_errors + addr_errors + data_errors != 0) { printf(" bus errors: %d/%ld\n", bus_errors, 2*bus_size/4);