From: Jędrzej Boczar Date: Wed, 24 Jun 2020 10:21:34 +0000 (+0200) Subject: bios: move memtest from liblitedram to libbase X-Git-Tag: 24jan2021_ls180~148^2 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=3b084b284a11e39a08b0e8140c8fab756b30f2c8;p=litex.git bios: move memtest from liblitedram to libbase --- diff --git a/litex/soc/software/bios/cmds/cmd_litedram.c b/litex/soc/software/bios/cmds/cmd_litedram.c index 4c14d98b..d07cf750 100644 --- a/litex/soc/software/bios/cmds/cmd_litedram.c +++ b/litex/soc/software/bios/cmds/cmd_litedram.c @@ -216,16 +216,6 @@ define_command(sdrwloff, sdrwloff, "Disable write leveling", LITEDRAM_CMDS); define_command(sdrlevel, sdrlevel, "Perform read/write leveling", LITEDRAM_CMDS); #endif -/** - * Command "memtest" - * - * Run a memory test - * - */ -#ifdef CSR_SDRAM_BASE -define_command(memtest, memtest, "Run a memory test", LITEDRAM_CMDS); -#endif - /** * Command "spdread" * diff --git a/litex/soc/software/bios/cmds/cmd_mem.c b/litex/soc/software/bios/cmds/cmd_mem.c index 01c607e1..ad163816 100644 --- a/litex/soc/software/bios/cmds/cmd_mem.c +++ b/litex/soc/software/bios/cmds/cmd_mem.c @@ -2,6 +2,7 @@ #include #include +#include #include @@ -137,3 +138,175 @@ static void mc(int nb_params, char **params) } define_command(mc, mc, "Copy address space", MEM_CMDS); + +/** + * Command "memtest" + * + * Run a memory test + * + */ +static void memtest_handler(int nb_params, char **params) +{ + char *c; + unsigned int *addr; + unsigned long maxsize = ~0uL; + + if (nb_params < 1) { + printf("memtest []"); + return; + } + + addr = (unsigned int *)strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect address"); + return; + } + + if (nb_params >= 2) { + maxsize = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect max size"); + return; + } + + } + + memtest(addr, maxsize); +} +define_command(memtest, memtest_handler, "Run a memory test", MEM_CMDS); + +/** + * Command "memspeed" + * + * Run a memory speed test + * + */ +static void memspeed_handler(int nb_params, char **params) +{ + char *c; + unsigned int *addr; + unsigned long size; + bool read_only = false; + + if (nb_params < 1) { + printf("memspeed []"); + return; + } + + addr = (unsigned int *)strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect address"); + return; + } + + size = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect size"); + return; + } + + if (nb_params >= 3) { + read_only = (bool) strtoul(params[2], &c, 0); + if (*c != 0) { + printf("Incorrect readonly value"); + return; + } + } + + memspeed(addr, size, read_only); +} +define_command(memspeed, memspeed_handler, "Run a memory speed test", MEM_CMDS); + +#ifdef CSR_DEBUG_PRINTER +/** + * Command "csrprint" + * + * Print CSR values + * + */ +static void csrprint(int nb_params, char **params) +{ + print_csrs(); +} +define_command(csrprint, csrprint, "Print CSR values", MEM_CMDS); +#endif + + +#ifdef CSR_WB_SOFTCONTROL_BASE +static void wbr(int nb_params, char **params) +{ + char *c; + unsigned int *addr; + unsigned int length; + unsigned int i; + + if (nb_params < 1) { + printf("mr
[length]"); + return; + } + addr = (unsigned int *)strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect address"); + return; + } + if (nb_params == 1) { + length = 4; + } else { + length = strtoul(params[1], &c, 0); + if(*c != 0) { + printf("\nIncorrect length"); + return; + } + } + + for (i = 0; i < length; ++i) { + wb_softcontrol_adr_write((unsigned long)(addr + i)); + wb_softcontrol_read_write(1); + printf("0x%08x: 0x%08x\n", (unsigned long)(addr + i), wb_softcontrol_data_read()); + } +} +define_command(wbr, wbr, "Read using softcontrol wishbone controller", MEM_CMDS); + +static void wbw(int nb_params, char **params) +{ + char *c; + unsigned int *addr; + unsigned int value; + unsigned int count; + unsigned int i; + + if (nb_params < 2) { + printf("mw
[count]"); + return; + } + + addr = (unsigned int *)strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect address"); + return; + } + + value = strtoul(params[1], &c, 0); + if(*c != 0) { + printf("Incorrect value"); + return; + } + + if (nb_params == 2) { + count = 1; + } else { + count = strtoul(params[2], &c, 0); + if(*c != 0) { + printf("Incorrect count"); + return; + } + } + + wb_softcontrol_data_write(value); + for (i = 0; i < count; i++) { + wb_softcontrol_adr_write((unsigned long)(addr + i)); + wb_softcontrol_write_write(1); + } +} +define_command(wbw, wbw, "Write using softcontrol wishbone controller", MEM_CMDS); +#endif diff --git a/litex/soc/software/include/base/lfsr.h b/litex/soc/software/include/base/lfsr.h new file mode 100644 index 00000000..50dfccfc --- /dev/null +++ b/litex/soc/software/include/base/lfsr.h @@ -0,0 +1,109 @@ +#include + +/* + * Copyright (C) 2020, Anton Blanchard , IBM + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Galois LFSR + * + * Polynomials verified with https://bitbucket.org/gallen/mlpolygen/ + */ +static inline unsigned long lfsr(unsigned long bits, unsigned long prev) +{ + static const unsigned long lfsr_taps[] = { + 0x0, + 0x0, + 0x3, + 0x6, + 0xc, + 0x14, + 0x30, + 0x60, + 0xb8, + 0x110, + 0x240, + 0x500, + 0x829, + 0x100d, + 0x2015, + 0x6000, + 0xd008, + 0x12000, + 0x20400, + 0x40023, + 0x90000, + 0x140000, + 0x300000, + 0x420000, + 0xe10000, + 0x1200000, + 0x2000023, + 0x4000013, + 0x9000000, + 0x14000000, + 0x20000029, + 0x48000000, + 0x80200003, +#if __WORDSIZE == 64 + 0x100080000, + 0x204000003, + 0x500000000, + 0x801000000, + 0x100000001f, + 0x2000000031, + 0x4400000000, + 0xa000140000, + 0x12000000000, + 0x300000c0000, + 0x63000000000, + 0xc0000030000, + 0x1b0000000000, + 0x300003000000, + 0x420000000000, + 0xc00000180000, + 0x1008000000000, + 0x3000000c00000, + 0x6000c00000000, + 0x9000000000000, + 0x18003000000000, + 0x30000000030000, + 0x40000040000000, + 0xc0000600000000, + 0x102000000000000, + 0x200004000000000, + 0x600003000000000, + 0xc00000000000000, + 0x1800300000000000, + 0x3000000000000030, + 0x6000000000000000, + 0x800000000000000d +#endif + }; + unsigned long lsb = prev & 1; + + prev >>= 1; + prev ^= (-lsb) & lfsr_taps[bits]; + + return prev; +} diff --git a/litex/soc/software/include/base/memtest.h b/litex/soc/software/include/base/memtest.h new file mode 100644 index 00000000..11196083 --- /dev/null +++ b/litex/soc/software/include/base/memtest.h @@ -0,0 +1,13 @@ +#ifndef __MEMTEST_H +#define __MEMTEST_H + +#include + +int memtest(unsigned int *addr, unsigned long maxsize); +void memspeed(unsigned int *addr, unsigned long size, bool read_only); + +int memtest_addr(unsigned int *addr, unsigned long size, int random); +int memtest_data(unsigned int *addr, unsigned long size, int random); +int memtest_bus(unsigned int *addr, unsigned long size); + +#endif /* __MEMTEST_H */ diff --git a/litex/soc/software/libbase/Makefile b/litex/soc/software/libbase/Makefile index 1094ac57..9aebad8e 100755 --- a/litex/soc/software/libbase/Makefile +++ b/litex/soc/software/libbase/Makefile @@ -17,7 +17,8 @@ OBJECTS = exception.o \ strcasecmp.o \ i2c.o \ div64.o \ - progress.o + progress.o \ + memtest.o all: crt0.o libbase.a libbase-nofloat.a diff --git a/litex/soc/software/libbase/memtest.c b/litex/soc/software/libbase/memtest.c new file mode 100644 index 00000000..d3193dab --- /dev/null +++ b/litex/soc/software/libbase/memtest.c @@ -0,0 +1,228 @@ +#include "memtest.h" + +#include +#include + +#include +#include +#include + +// #define MEMTEST_BUS_DEBUG +// #define MEMTEST_DATA_DEBUG +// #define MEMTEST_ADDR_DEBUG + +#ifndef MEMTEST_BUS_SIZE +#define MEMTEST_BUS_SIZE (512) +#endif + +#ifndef MEMTEST_DATA_SIZE +#define MEMTEST_DATA_SIZE (2*1024*1024) +#endif +#define MEMTEST_DATA_RANDOM 1 + +#ifndef MEMTEST_ADDR_SIZE +#define MEMTEST_ADDR_SIZE (32*1024) +#endif +#define MEMTEST_ADDR_RANDOM 0 + +#define ONEZERO 0xAAAAAAAA +#define ZEROONE 0x55555555 + +static unsigned int seed_to_data_32(unsigned int seed, int random) +{ + return random ? lfsr(32, seed) : seed + 1; +} + +static unsigned short seed_to_data_16(unsigned short seed, int random) +{ + return random ? lfsr(16, seed) : seed + 1; +} + +int memtest_bus(unsigned int *addr, unsigned long size) +{ + volatile unsigned int *array = addr; + int i, errors; + unsigned int rdata; + + errors = 0; + + for(i = 0; i < size/4;i++) { + array[i] = ONEZERO; + } + flush_cpu_dcache(); +#ifdef CONFIG_L2_SIZE + flush_l2_cache(); +#endif + for(i = 0; i < size/4; i++) { + rdata = array[i]; + if(rdata != ONEZERO) { + errors++; +#ifdef MEMTEST_BUS_DEBUG + printf("[bus: 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ONEZERO); +#endif + } + } + + for(i = 0; i < size/4; i++) { + array[i] = ZEROONE; + } + flush_cpu_dcache(); +#ifdef CONFIG_L2_SIZE + flush_l2_cache(); +#endif + for(i = 0; i < size/4; i++) { + rdata = array[i]; + if(rdata != ZEROONE) { + errors++; +#ifdef MEMTEST_BUS_DEBUG + printf("[bus 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, ZEROONE); +#endif + } + } + + return errors; +} + +int memtest_data(unsigned int *addr, unsigned long size, int random) +{ + volatile unsigned int *array = addr; + int i, errors; + unsigned int seed_32; + unsigned int rdata; + + errors = 0; + seed_32 = 1; + + for(i = 0; i < size/4; i++) { + seed_32 = seed_to_data_32(seed_32, random); + array[i] = seed_32; + } + + seed_32 = 1; + flush_cpu_dcache(); +#ifdef CONFIG_L2_SIZE + flush_l2_cache(); +#endif + for(i = 0; i < size/4; i++) { + seed_32 = seed_to_data_32(seed_32, random); + rdata = array[i]; + if(rdata != seed_32) { + errors++; +#ifdef MEMTEST_DATA_DEBUG + printf("[data 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, seed_32); +#endif + } + } + + return errors; +} + +int memtest_addr(unsigned int *addr, unsigned long size, int random) +{ + volatile unsigned int *array = addr; + int i, errors; + unsigned short seed_16; + unsigned short rdata; + + errors = 0; + seed_16 = 1; + + for(i = 0; i < size/4; i++) { + seed_16 = seed_to_data_16(seed_16, random); + array[(unsigned int) seed_16] = i; + } + + seed_16 = 1; + flush_cpu_dcache(); +#ifdef CONFIG_L2_SIZE + flush_l2_cache(); +#endif + for(i = 0; i < size/4; i++) { + seed_16 = seed_to_data_16(seed_16, random); + rdata = array[(unsigned int) seed_16]; + if(rdata != i) { + errors++; +#ifdef MEMTEST_ADDR_DEBUG + printf("[addr 0x%0x]: 0x%08x vs 0x%08x\n", i, rdata, i); +#endif + } + } + + return errors; +} + +void memspeed(unsigned int *addr, unsigned long size, bool read_only) +{ + volatile unsigned int *array = addr; + int i; + unsigned int start, end; + unsigned long write_speed = 0; + unsigned long read_speed; + __attribute__((unused)) unsigned long data; + const unsigned int sz = sizeof(unsigned long); + + /* init timer */ + timer0_en_write(0); + timer0_reload_write(0); + timer0_load_write(0xffffffff); + timer0_en_write(1); + + /* write speed */ + if (!read_only) { + timer0_update_value_write(1); + start = timer0_value_read(); + for(i = 0; i < size/sz; i++) { + array[i] = i; + } + timer0_update_value_write(1); + end = timer0_value_read(); + write_speed = (8*size*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end); + } + + /* flush CPU and L2 caches */ + flush_cpu_dcache(); +#ifdef CONFIG_L2_SIZE + flush_l2_cache(); +#endif + + /* read speed */ + timer0_en_write(1); + timer0_update_value_write(1); + start = timer0_value_read(); + for(i = 0; i < size/sz; i++) { + data = array[i]; + } + timer0_update_value_write(1); + end = timer0_value_read(); + read_speed = (8*size*(CONFIG_CLOCK_FREQUENCY/1000000))/(start - end); + + printf("Memspeed Writes: %ldMbps Reads: %ldMbps\n", write_speed, read_speed); +} + +int memtest(unsigned int *addr, unsigned long maxsize) +{ + int bus_errors, data_errors, addr_errors; + unsigned long bus_size = MEMTEST_BUS_SIZE < maxsize ? MEMTEST_BUS_SIZE : maxsize; + unsigned long data_size = MEMTEST_DATA_SIZE < maxsize ? MEMTEST_DATA_SIZE : maxsize; + unsigned long addr_size = MEMTEST_ADDR_SIZE < maxsize ? MEMTEST_ADDR_SIZE : maxsize; + + bus_errors = memtest_bus(addr, bus_size); + if(bus_errors != 0) + printf("Memtest bus failed: %d/%d errors\n", bus_errors, bus_size/4); + + data_errors = memtest_data(addr, data_size, MEMTEST_DATA_RANDOM); + if(data_errors != 0) + printf("Memtest data failed: %d/%d errors\n", data_errors, data_size/4); + + addr_errors = memtest_addr(addr, addr_size, MEMTEST_ADDR_RANDOM); + if(addr_errors != 0) + printf("Memtest addr failed: %d/%d errors\n", addr_errors, addr_size/4); + + if(bus_errors + data_errors + addr_errors != 0) + return 0; + else { + printf("Memtest OK\n"); + memspeed(addr, data_size, false); + return 1; + } +} diff --git a/litex/soc/software/liblitedram/lfsr.h b/litex/soc/software/liblitedram/lfsr.h deleted file mode 100644 index 50dfccfc..00000000 --- a/litex/soc/software/liblitedram/lfsr.h +++ /dev/null @@ -1,109 +0,0 @@ -#include - -/* - * Copyright (C) 2020, Anton Blanchard , IBM - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * Galois LFSR - * - * Polynomials verified with https://bitbucket.org/gallen/mlpolygen/ - */ -static inline unsigned long lfsr(unsigned long bits, unsigned long prev) -{ - static const unsigned long lfsr_taps[] = { - 0x0, - 0x0, - 0x3, - 0x6, - 0xc, - 0x14, - 0x30, - 0x60, - 0xb8, - 0x110, - 0x240, - 0x500, - 0x829, - 0x100d, - 0x2015, - 0x6000, - 0xd008, - 0x12000, - 0x20400, - 0x40023, - 0x90000, - 0x140000, - 0x300000, - 0x420000, - 0xe10000, - 0x1200000, - 0x2000023, - 0x4000013, - 0x9000000, - 0x14000000, - 0x20000029, - 0x48000000, - 0x80200003, -#if __WORDSIZE == 64 - 0x100080000, - 0x204000003, - 0x500000000, - 0x801000000, - 0x100000001f, - 0x2000000031, - 0x4400000000, - 0xa000140000, - 0x12000000000, - 0x300000c0000, - 0x63000000000, - 0xc0000030000, - 0x1b0000000000, - 0x300003000000, - 0x420000000000, - 0xc00000180000, - 0x1008000000000, - 0x3000000c00000, - 0x6000c00000000, - 0x9000000000000, - 0x18003000000000, - 0x30000000030000, - 0x40000040000000, - 0xc0000600000000, - 0x102000000000000, - 0x200004000000000, - 0x600003000000000, - 0xc00000000000000, - 0x1800300000000000, - 0x3000000000000030, - 0x6000000000000000, - 0x800000000000000d -#endif - }; - unsigned long lsb = prev & 1; - - prev >>= 1; - prev ^= (-lsb) & lfsr_taps[bits]; - - return prev; -} diff --git a/litex/soc/software/liblitedram/sdram.c b/litex/soc/software/liblitedram/sdram.c index 3d35d1b4..64ed5f1e 100644 --- a/litex/soc/software/liblitedram/sdram.c +++ b/litex/soc/software/liblitedram/sdram.c @@ -12,6 +12,8 @@ #include #include +#include +#include #ifdef CSR_SDRAM_BASE #include @@ -20,12 +22,14 @@ #include #include "sdram.h" -#include "lfsr.h" // FIXME(hack): If we don't have main ram, just target the sram instead. #ifndef MAIN_RAM_BASE #define MAIN_RAM_BASE SRAM_BASE #endif +#ifndef MAIN_RAM_SIZE +#define MAIN_RAM_SIZE SRAM_SIZE +#endif __attribute__((unused)) static void cdelay(int i) { @@ -725,227 +729,8 @@ static void read_level(int module) #endif /* CSR_SDRAM_BASE */ -static unsigned int seed_to_data_32(unsigned int seed, int random) -{ - if (random) - return lfsr(32, seed); - else - return seed + 1; -} - -static unsigned short seed_to_data_16(unsigned short seed, int random) -{ - if (random) - return lfsr(16, seed); - else - return seed + 1; -} - -#define ONEZERO 0xAAAAAAAA -#define ZEROONE 0x55555555 - -#ifndef MEMTEST_BUS_SIZE -#define MEMTEST_BUS_SIZE (512) -#endif - -//#define MEMTEST_BUS_DEBUG - -static int memtest_bus(void) -{ - volatile unsigned int *array = (unsigned int *)MAIN_RAM_BASE; - int i, errors; - unsigned int rdata; - - errors = 0; - - for(i=0;i