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" diff --git a/litex/soc/software/liblitedram/bist.c b/litex/soc/software/liblitedram/bist.c index 044563792..53eb278e0 100644 --- a/litex/soc/software/liblitedram/bist.c +++ b/litex/soc/software/liblitedram/bist.c @@ -5,31 +5,22 @@ #if defined(CSR_SDRAM_GENERATOR_BASE) && defined(CSR_SDRAM_CHECKER_BASE) #include #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 +57,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 +123,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=%" PRIu32 " and random=%" PRIu32 "\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 +139,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("%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), + total_errors); + total_length += wr_length; total_errors += rd_errors; @@ -174,8 +155,55 @@ void sdram_bist(uint32_t burst_length, uint32_t random) rd_ticks = 0; rd_errors = 0; } - i++; } } +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 2f0ea1a37..ab4c676ec 100644 --- a/litex/soc/software/liblitedram/bist.h +++ b/litex/soc/software/liblitedram/bist.h @@ -4,7 +4,9 @@ #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); +int sdram_hw_test(uint64_t origin, uint64_t size, uint64_t burst_length); #endif /* __SDRAM_BIST_H */ diff --git a/litex/tools/litex_sim.py b/litex/tools/litex_sim.py index c35fbcc72..6ae44f515 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,