bios/sdram: Use an LFSR to speed up pseudo-random number generation
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 6 May 2020 19:54:27 +0000 (21:54 +0200)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 6 May 2020 19:56:10 +0000 (21:56 +0200)
This speeds up the memory test by an order of magnitude, esp. on
cores without a hardware multiplier by getting rid of the
multiplication in the loop.

The LFSR implementation comes from microwatt's simple_random test
project.

Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
litex/soc/software/bios/lfsr.h [new file with mode: 0644]
litex/soc/software/bios/sdram.c

diff --git a/litex/soc/software/bios/lfsr.h b/litex/soc/software/bios/lfsr.h
new file mode 100644 (file)
index 0000000..50dfccf
--- /dev/null
@@ -0,0 +1,109 @@
+#include <limits.h>
+
+/*
+ * Copyright (C) 2020, Anton Blanchard <anton@linux.ibm.com>, 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;
+}
index 9056a2ff1cce185e719f279382258154fc90c0b5..517a223a144a5c94f4852873af7e88d5b7fa57e7 100644 (file)
@@ -21,6 +21,7 @@
 #include <system.h>
 
 #include "sdram.h"
+#include "lfsr.h"
 
 // FIXME(hack): If we don't have main ram, just target the sram instead.
 #ifndef MAIN_RAM_BASE
@@ -514,7 +515,7 @@ static int read_level_scan(int module, int bitslip)
        prv = 42;
        for(p=0;p<SDRAM_PHY_PHASES;p++)
                for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
-                       prv = 1664525*prv + 1013904223;
+                       return lfsr(32, seed);
                        prs[p][i] = prv;
                }
 
@@ -594,7 +595,7 @@ static void read_level(int module)
        prv = 42;
        for(p=0;p<SDRAM_PHY_PHASES;p++)
                for(i=0;i<DFII_PIX_DATA_BYTES;i++) {
-                       prv = 1664525*prv + 1013904223;
+                       return lfsr(32, seed);
                        prs[p][i] = prv;
                }
 
@@ -712,7 +713,7 @@ static void read_level(int module)
 static unsigned int seed_to_data_32(unsigned int seed, int random)
 {
        if (random)
-               return 1664525*seed + 1013904223;
+               return lfsr(32, seed);
        else
                return seed + 1;
 }
@@ -720,7 +721,7 @@ static unsigned int seed_to_data_32(unsigned int seed, int random)
 static unsigned short seed_to_data_16(unsigned short seed, int random)
 {
        if (random)
-               return 25173*seed + 13849;
+               return lfsr(16, seed);
        else
                return seed + 1;
 }
@@ -794,14 +795,14 @@ static int memtest_data(void)
        unsigned int rdata;
 
        errors = 0;
-       seed_32 = 0;
+       seed_32 = 1;
 
        for(i=0;i<MEMTEST_DATA_SIZE/4;i++) {
                seed_32 = seed_to_data_32(seed_32, MEMTEST_DATA_RANDOM);
                array[i] = seed_32;
        }
 
-       seed_32 = 0;
+       seed_32 = 1;
        flush_cpu_dcache();
 #ifdef CONFIG_L2_SIZE
        flush_l2_cache();
@@ -834,14 +835,14 @@ static int memtest_addr(void)
        unsigned short rdata;
 
        errors = 0;
-       seed_16 = 0;
+       seed_16 = 1;
 
        for(i=0;i<MEMTEST_ADDR_SIZE/4;i++) {
                seed_16 = seed_to_data_16(seed_16, MEMTEST_ADDR_RANDOM);
                array[(unsigned int) seed_16] = i;
        }
 
-       seed_16 = 0;
+       seed_16 = 1;
        flush_cpu_dcache();
 #ifdef CONFIG_L2_SIZE
        flush_l2_cache();