From eb688d3af7d611bfb4457bbb2c283f98a71781c6 Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:44:33 +0100 Subject: [PATCH 1/5] tools/litex_sim: allow to enable BIST modules Signed-off-by: Michal Sieron --- litex/tools/litex_sim.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index 15eabe030..a7cd81605 100755 --- a/litex/tools/litex_sim.py +++ b/litex/tools/litex_sim.py @@ -149,6 +149,7 @@ class SimSoC(SoCCore): sdram_data_width = 32, sdram_spd_data = None, sdram_verbosity = 0, + with_bist = False, with_i2c = False, with_sdcard = False, with_spi_flash = False, @@ -195,7 +196,8 @@ class SimSoC(SoCCore): module = sdram_module, l2_cache_size = kwargs.get("l2_size", 8192), l2_cache_min_data_width = kwargs.get("min_l2_data_width", 128), - l2_cache_reverse = False + l2_cache_reverse = False, + with_bist = with_bist ) if sdram_init != []: # Skip SDRAM test to avoid corrupting pre-initialized contents. @@ -373,6 +375,7 @@ def sim_args(parser): parser.add_argument("--sdram-init", default=None, help="SDRAM init file (.bin or .json).") parser.add_argument("--sdram-from-spd-dump", default=None, help="Generate SDRAM module based on data from SPD EEPROM dump.") parser.add_argument("--sdram-verbosity", default=0, help="Set SDRAM checker verbosity.") + parser.add_argument("--with-bist", action="store_true", help="Enable SDRAM BIST modules.") # Ethernet /Etherbone. parser.add_argument("--with-ethernet", action="store_true", help="Enable Ethernet support.") @@ -476,6 +479,7 @@ def main(): # SoC ------------------------------------------------------------------------------------------ soc = SimSoC( with_sdram = args.with_sdram, + with_bist = args.with_bist, with_ethernet = args.with_ethernet, ethernet_phy_model = args.ethernet_phy_model, with_etherbone = args.with_etherbone, From e7e1b16027d07f3372961a95f093f902c212c57d Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:44:33 +0100 Subject: [PATCH 2/5] liblitedram/bist: small refactor of bist functions `SDRAM_TEST_DATA_BYTES` definition was incorrect as it treated size specified in CSR subregisters as if it was a byte count. Correct way to calculate that is to use definitions from `sdram_phy.h`. ``` #define SDRAM_TEST_DATA_BYTES (SDRAM_PHY_DFI_DATABITS / 8 * SDRAM_PHY_PHASES) ``` Also: - extracted code to `sdram_bist_[write|read]` functions - made global variables static - fixed formatting Signed-off-by: Michal Sieron --- litex/soc/software/liblitedram/bist.c | 129 +++++++++++--------------- litex/soc/software/liblitedram/bist.h | 2 +- 2 files changed, 55 insertions(+), 76 deletions(-) diff --git a/litex/soc/software/liblitedram/bist.c b/litex/soc/software/liblitedram/bist.c index 044563792..7b9ef5ca4 100644 --- a/litex/soc/software/liblitedram/bist.c +++ b/litex/soc/software/liblitedram/bist.c @@ -5,31 +5,21 @@ #if defined(CSR_SDRAM_GENERATOR_BASE) && defined(CSR_SDRAM_CHECKER_BASE) #include #include -#include #include #include #include #include +#include #define SDRAM_TEST_BASE 0x00000000 -#define SDRAM_TEST_DATA_BYTES (CSR_SDRAM_DFII_PI0_RDDATA_SIZE*4) +#define SDRAM_TEST_DATA_BYTES (SDRAM_PHY_DFI_DATABITS / 8 * SDRAM_PHY_PHASES) -uint32_t wr_ticks; -uint32_t wr_length; -uint32_t rd_ticks; -uint32_t rd_length; -uint32_t rd_errors; - -__attribute__((unused)) static void cdelay(int i) -{ -#ifndef CONFIG_BIOS_NO_DELAYS - while(i > 0) { - __asm__ volatile(CONFIG_CPU_NOP); - i--; - } -#endif -} +static uint32_t wr_ticks = 0; +static uint32_t wr_length = 0; +static uint32_t rd_ticks = 0; +static uint32_t rd_length = 0; +static uint32_t rd_errors = 0; static uint32_t pseudo_random_bases[128] = { 0x000e4018,0x0003338d,0x00233429,0x001f589d, @@ -66,65 +56,59 @@ static uint32_t pseudo_random_bases[128] = { 0x00027e36,0x000e51ae,0x002e7627,0x00275c9f, }; -void sdram_bist_loop(uint32_t loop, uint32_t burst_length, uint32_t random) { +static void sdram_bist_write(uint32_t base, uint32_t length) { + /* Prepare write */ + sdram_generator_reset_write(1); + sdram_generator_random_write(1); /* Random data */ + sdram_generator_base_write(base); + sdram_generator_end_write(base + length); + sdram_generator_length_write(length); + + /* Start write */ + sdram_generator_start_write(1); + + /* Wait write */ + while(sdram_generator_done_read() == 0); +} + +static void sdram_bist_read(uint32_t base, uint32_t length) { + /* Prepare read */ + sdram_checker_reset_write(1); + sdram_checker_random_write(1); /* Random data */ + sdram_checker_base_write(base); + sdram_checker_end_write(base + length); + sdram_checker_length_write(length); + + /* Start read */ + + sdram_checker_start_write(1); + /* Wait read */ + while(sdram_checker_done_read() == 0); +} + +static void sdram_bist_loop(uint32_t loop, uint32_t burst_length, uint32_t random) { int i; uint32_t base; uint32_t length; - length = burst_length*SDRAM_TEST_DATA_BYTES; + length = burst_length * SDRAM_TEST_DATA_BYTES; rd_errors = 0; - for(i=0; i<128; i++) { + for (i = 0; i < 128; i++) { if (random) base = SDRAM_TEST_BASE + pseudo_random_bases[(i+loop)%128]*SDRAM_TEST_DATA_BYTES; else base = SDRAM_TEST_BASE + ((i+loop)%128)*SDRAM_TEST_DATA_BYTES; - if (i == 0) { - /* Prepare first write */ - sdram_generator_reset_write(1); - sdram_generator_reset_write(0); - sdram_generator_random_write(1); /* Random data */ - sdram_generator_base_write(base); - sdram_generator_end_write(base + length); - sdram_generator_length_write(length); - cdelay(100); - } - /* Start write */ - sdram_generator_start_write(1); - /* Prepare next read */ - sdram_checker_reset_write(1); - sdram_checker_reset_write(0); - sdram_checker_random_write(1); /* Random data */ - sdram_checker_base_write(base); - sdram_checker_end_write(base + length); - sdram_checker_length_write(length); - cdelay(100); - /* Wait write */ - while(sdram_generator_done_read() == 0); + + sdram_bist_write(base, length); /* Get write results */ wr_length += length; wr_ticks += sdram_generator_ticks_read(); - /* Start read */ - sdram_checker_start_write(1); - if (i != 127) { - if (random) - base = SDRAM_TEST_BASE + pseudo_random_bases[(i+1+loop)%128]*SDRAM_TEST_DATA_BYTES; - else - base = SDRAM_TEST_BASE + ((i+1+loop)%128)*SDRAM_TEST_DATA_BYTES; - /* Prepare next write */ - sdram_generator_reset_write(1); - sdram_generator_reset_write(0); - sdram_generator_random_write(1); /* Random data */ - sdram_generator_base_write(base); - sdram_generator_end_write(base + length); - sdram_generator_length_write(length); - cdelay(100); - } - /* Wait read */ - while(sdram_checker_done_read() == 0); + + sdram_bist_read(base, length); /* Get read results */ + rd_length += length; rd_ticks += sdram_checker_ticks_read(); rd_errors += sdram_checker_errors_read(); - rd_length += length; } } @@ -138,19 +122,14 @@ static uint32_t compute_speed_mibs(uint32_t length, uint32_t ticks) { void sdram_bist(uint32_t burst_length, uint32_t random) { uint32_t i; - uint32_t total_length; + uint64_t total_length; uint32_t total_errors; - printf("Starting SDRAM BIST with burst_length=%d and random=%d\n", burst_length, random); + printf("Starting SDRAM BIST with burst_length=%lu and random=%lu\n", burst_length, random); - i = 0; total_length = 0; total_errors = 0; - for(;;) { - /* Exit on key pressed */ - if (readchar_nonblock()) - break; - + for (i = 0; !readchar_nonblock(); i++) { /* Exit on key pressed */ /* Bist loop */ sdram_bist_loop(i, burst_length, random); @@ -159,11 +138,12 @@ void sdram_bist(uint32_t burst_length, uint32_t random) printf("WR-SPEED(MiB/s) RD-SPEED(MiB/s) TESTED(MiB) ERRORS\n"); } if (i%100 == 100-1) { - printf("%15u %15u %12u %12u\n", - compute_speed_mibs(wr_length, wr_ticks), - compute_speed_mibs(rd_length, rd_ticks), - total_length/(1024*1024), - total_errors); + printf("%15lu %15lu %12llu %12lu\n", + compute_speed_mibs(wr_length, wr_ticks), + compute_speed_mibs(rd_length, rd_ticks), + total_length/(1024*1024), + total_errors); + total_length += wr_length; total_errors += rd_errors; @@ -174,7 +154,6 @@ void sdram_bist(uint32_t burst_length, uint32_t random) rd_ticks = 0; rd_errors = 0; } - i++; } } diff --git a/litex/soc/software/liblitedram/bist.h b/litex/soc/software/liblitedram/bist.h index 2f0ea1a37..d697658c3 100644 --- a/litex/soc/software/liblitedram/bist.h +++ b/litex/soc/software/liblitedram/bist.h @@ -4,7 +4,7 @@ #ifndef __SDRAM_BIST_H #define __SDRAM_BIST_H -void sdram_bist_loop(uint32_t loop, uint32_t burst_length, uint32_t random); +#include void sdram_bist(uint32_t burst_length, uint32_t random); #endif /* __SDRAM_BIST_H */ From dbf030e4cf8d4ec69027ceb0f3cd0e11ac7e8508 Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:44:33 +0100 Subject: [PATCH 3/5] liblitedram/bist: add sdram_hw_test function It allows to perform a memtest (similar to `sdram_test`), but using DMAs and bypassing system bus. This way, one can test ranges such above 4 GiB, which was the limit with `sdram_test` due to address_width being limited to 32 bits. Signed-off-by: Michal Sieron --- litex/soc/software/liblitedram/bist.c | 49 +++++++++++++++++++++++++++ litex/soc/software/liblitedram/bist.h | 2 ++ 2 files changed, 51 insertions(+) diff --git a/litex/soc/software/liblitedram/bist.c b/litex/soc/software/liblitedram/bist.c index 7b9ef5ca4..3206e5eb8 100644 --- a/litex/soc/software/liblitedram/bist.c +++ b/litex/soc/software/liblitedram/bist.c @@ -10,6 +10,7 @@ #include #include +#include #include #define SDRAM_TEST_BASE 0x00000000 @@ -157,4 +158,52 @@ void sdram_bist(uint32_t burst_length, uint32_t random) } } +int sdram_hw_test(uint64_t origin, uint64_t size, uint64_t burst_length) { + uint64_t burst_size = SDRAM_TEST_DATA_BYTES * burst_length; + uint64_t old_burst_size = burst_size; + int errors = 0; + + uint64_t supported_memory = sdram_get_supported_memory(); + + if (origin >= supported_memory) { + printf("Selected origin out of memory bounds! Supported memory: "); + print_size(supported_memory); + printf("\n"); + return 0; + } + + if (origin + size > supported_memory) { + printf("Test would go out of memory bounds. Clipping size to memory end: "); + print_size(supported_memory); + printf("\n"); + size = supported_memory - origin; + } + + for (uint64_t address = origin; address < origin + size; address += burst_size) { + if (address + burst_size > size) { + old_burst_size = burst_size; + burst_size = size - address; + } + + if (burst_size < SDRAM_TEST_DATA_BYTES || old_burst_size < burst_size) + break; + + sdram_bist_write(address, burst_size); + + sdram_bist_read(address, burst_size); + errors += sdram_checker_errors_read(); + + print_progress(" SDRAM HW test:", origin, address - origin + burst_size); + } + + if (burst_size < SDRAM_TEST_DATA_BYTES || old_burst_size < burst_size) { + printf("\nTest would go out of memory bounds. Finished early at the end: "); + print_size(supported_memory); + } + + printf("\n"); + + return errors; +} + #endif diff --git a/litex/soc/software/liblitedram/bist.h b/litex/soc/software/liblitedram/bist.h index d697658c3..ab4c676ec 100644 --- a/litex/soc/software/liblitedram/bist.h +++ b/litex/soc/software/liblitedram/bist.h @@ -5,6 +5,8 @@ #define __SDRAM_BIST_H #include + void sdram_bist(uint32_t burst_length, uint32_t random); +int sdram_hw_test(uint64_t origin, uint64_t size, uint64_t burst_length); #endif /* __SDRAM_BIST_H */ From cc27e3d6c710d17219b40850c1bddc58880dc94e Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Mon, 9 Jan 2023 16:44:33 +0100 Subject: [PATCH 4/5] cmds/cmd_litedram: add sdram_hw_test command Signed-off-by: Michal Sieron --- litex/soc/software/bios/cmds/cmd_litedram.c | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/litex/soc/software/bios/cmds/cmd_litedram.c b/litex/soc/software/bios/cmds/cmd_litedram.c index 498e4963f..4420bacea 100644 --- a/litex/soc/software/bios/cmds/cmd_litedram.c +++ b/litex/soc/software/bios/cmds/cmd_litedram.c @@ -89,6 +89,46 @@ static void sdram_bist_handler(int nb_params, char **params) define_command(sdram_bist, sdram_bist_handler, "Run SDRAM Build-In Self-Test", LITEDRAM_CMDS); #endif +/** + * Command "sdram_hw_test" + * + * Run SDRAM HW-accelerated memtest + * + */ +#if defined(CSR_SDRAM_GENERATOR_BASE) && defined(CSR_SDRAM_CHECKER_BASE) +static void sdram_hw_test_handler(int nb_params, char **params) +{ + char *c; + uint64_t origin; + uint64_t size; + uint64_t burst_length = 1; + if (nb_params < 2) { + printf("sdram_hw_test []"); + return; + } + origin = strtoull(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect origin"); + return; + } + size = strtoull(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect size"); + return; + } + if (nb_params > 2) { + burst_length = strtoull(params[2], &c, 0); + if (*c != 0) { + printf("Incorrect burst length"); + return; + } + } + int errors = sdram_hw_test(origin, size, burst_length); + printf("%d errors found\n", errors); +} +define_command(sdram_hw_test, sdram_hw_test_handler, "Run SDRAM HW-accelerated memtest", LITEDRAM_CMDS); +#endif + #ifdef CSR_DDRPHY_RDPHASE_ADDR /** * Command "sdram_force_rdphase" From fd59e8d55bed79350995707f360be0f4152f51f3 Mon Sep 17 00:00:00 2001 From: Michal Sieron Date: Thu, 19 Jan 2023 17:45:36 +0100 Subject: [PATCH 5/5] liblitedram/bist: fix printf format warnings Use format constants for fixed width integer types to make it work on both 32-bit and 64-bit CPUs without warnings. Signed-off-by: Michal Sieron --- litex/soc/software/liblitedram/bist.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/litex/soc/software/liblitedram/bist.c b/litex/soc/software/liblitedram/bist.c index 3206e5eb8..53eb278e0 100644 --- a/litex/soc/software/liblitedram/bist.c +++ b/litex/soc/software/liblitedram/bist.c @@ -126,7 +126,7 @@ void sdram_bist(uint32_t burst_length, uint32_t random) uint64_t total_length; uint32_t total_errors; - printf("Starting SDRAM BIST with burst_length=%lu and random=%lu\n", burst_length, random); + printf("Starting SDRAM BIST with burst_length=%" PRIu32 " and random=%" PRIu32 "\n", burst_length, random); total_length = 0; total_errors = 0; @@ -139,7 +139,7 @@ void sdram_bist(uint32_t burst_length, uint32_t random) printf("WR-SPEED(MiB/s) RD-SPEED(MiB/s) TESTED(MiB) ERRORS\n"); } if (i%100 == 100-1) { - printf("%15lu %15lu %12llu %12lu\n", + printf("%15" PRIu32 " %15" PRIu32 "%12" PRIu64 "%12" PRIu32 "\n", compute_speed_mibs(wr_length, wr_ticks), compute_speed_mibs(rd_length, rd_ticks), total_length/(1024*1024),