diff --git a/litedram/frontend/bist.py b/litedram/frontend/bist.py index 8568e73..19623ca 100644 --- a/litedram/frontend/bist.py +++ b/litedram/frontend/bist.py @@ -4,14 +4,15 @@ from functools import reduce from operator import xor from migen import * -from migen.genlib.cdc import PulseSynchronizer, BusSynchronizer +from migen.genlib.cdc import MultiReg +from migen.genlib.cdc import PulseSynchronizer +from migen.genlib.cdc import BusSynchronizer from litex.soc.interconnect.csr import * from litedram.frontend.dma import LiteDRAMDMAWriter, LiteDRAMDMAReader -@CEInserter() class LFSR(Module): """Linear-Feedback Shift Register to generate a pseudo-random sequence. @@ -26,10 +27,10 @@ class LFSR(Module): Attributes ---------- - o : in + o : out Output data """ - def __init__(self, n_out, n_state=31, taps=[27, 30]): + def __init__(self, n_out, n_state, taps): self.o = Signal(n_out) # # # @@ -48,7 +49,6 @@ class LFSR(Module): ] -@CEInserter() class Counter(Module): """Simple incremental counter. @@ -59,7 +59,7 @@ class Counter(Module): Attributes ---------- - o : in + o : out Output data """ def __init__(self, n_out): @@ -70,23 +70,69 @@ class Counter(Module): self.sync += self.o.eq(self.o + 1) +@CEInserter() +class Generator(Module): + """Address/Data Generator. + + Parameters + ---------- + n_out : int + Width of the output data signal. + + Attributes + ---------- + random_enable : in + Enable Random (LFSR) + + o : out + Output data + """ + def __init__(self, n_out, n_state, taps): + self.random_enable = Signal() + self.o = Signal(n_out) + + # # # + + lfsr = LFSR(n_out, n_state, taps) + count = Counter(n_out) + self.submodules += lfsr, count + + self.comb += \ + If(self.random_enable, + self.o.eq(lfsr.o) + ).Else( + self.o.eq(count.o) + ) + + @ResetInserter() class _LiteDRAMBISTGenerator(Module): - def __init__(self, dram_port, random): + def __init__(self, dram_port): ashift = log2_int(dram_port.dw//8) awidth = dram_port.aw + ashift self.start = Signal() self.done = Signal() self.base = Signal(awidth) self.length = Signal(awidth) + self.random_data_enable = Signal() + self.random_addr_enable = Signal() self.ticks = Signal(32) # # # - gen_cls = LFSR if random else Counter - gen = gen_cls(min(dram_port.dw, 32)) # FIXME: remove lfsr limitation + # data / address generators + data_gen = Generator(31, n_state=31, taps=[27, 30]) # PRBS31 + addr_gen = Generator(23, n_state=23, taps=[17, 22]) # PRBS23 + assert (23 + ashift) < awidth # addressing large enough for random + self.submodules += data_gen, addr_gen + self.comb += [ + data_gen.random_enable.eq(self.random_data_enable), + addr_gen.random_enable.eq(self.random_addr_enable) + ] + + # dma dma = LiteDRAMDMAWriter(dram_port) - self.submodules += dma, gen + self.submodules += dma cmd_counter = Signal(dram_port.aw, reset_less=True) @@ -102,7 +148,8 @@ class _LiteDRAMBISTGenerator(Module): fsm.act("RUN", dma.sink.valid.eq(1), If(dma.sink.ready, - gen.ce.eq(1), + data_gen.ce.eq(1), + addr_gen.ce.eq(1), NextValue(cmd_counter, cmd_counter + 1), If(cmd_counter == (self.length[ashift:] - 1), NextState("DONE") @@ -114,8 +161,8 @@ class _LiteDRAMBISTGenerator(Module): self.done.eq(1) ) self.comb += [ - dma.sink.address.eq(self.base[ashift:] + cmd_counter), - dma.sink.data.eq(gen.o) + dma.sink.address.eq(self.base[ashift:] + addr_gen.o), + dma.sink.data.eq(data_gen.o) ] @@ -126,21 +173,29 @@ class LiteDRAMBISTGenerator(Module, AutoCSR): ---------- reset : in Reset the module. + start : in Start the generation. - base : in - DRAM address to start from. - length : in - Number of DRAM words to write. - done : out The module has completed writing the pattern. + base : in + DRAM address to start from. + + length : in + Number of DRAM words to write. + + random_data_enable : in + Enable random data (LFSR) + + random_addr_enable : in + Enable random addressing (LFSR) + ticks : out Duration of the generation. """ - def __init__(self, dram_port, random=True): + def __init__(self, dram_port): ashift = log2_int(dram_port.dw//8) awidth = dram_port.aw + ashift self.reset = CSR() @@ -148,13 +203,15 @@ class LiteDRAMBISTGenerator(Module, AutoCSR): self.done = CSRStatus() self.base = CSRStorage(awidth) self.length = CSRStorage(awidth) + self.random_data_enable = CSRStorage() + self.random_addr_enable = CSRStorage() self.ticks = CSRStatus(32) # # # cd = dram_port.cd - core = _LiteDRAMBISTGenerator(dram_port, random) + core = _LiteDRAMBISTGenerator(dram_port) core = ClockDomainsRenamer(cd)(core) self.submodules += core @@ -187,6 +244,11 @@ class LiteDRAMBISTGenerator(Module, AutoCSR): core.length.eq(length_sync.o) ] + self.specials += [ + MultiReg(self.random_data_enable.storage, core.random_data_enable, cd), + MultiReg(self.random_addr_enable.storage, core.random_addr_enable, cd), + ] + ticks_sync = BusSynchronizer(32, cd, "sys") self.submodules += ticks_sync self.comb += [ @@ -197,22 +259,33 @@ class LiteDRAMBISTGenerator(Module, AutoCSR): @ResetInserter() class _LiteDRAMBISTChecker(Module, AutoCSR): - def __init__(self, dram_port, random): + def __init__(self, dram_port): ashift = log2_int(dram_port.dw//8) awidth = dram_port.aw + ashift self.start = Signal() self.done = Signal() self.base = Signal(awidth) self.length = Signal(awidth) + self.random_data_enable = Signal() + self.random_addr_enable = Signal() self.ticks = Signal(32) self.errors = Signal(32) # # # - gen_cls = LFSR if random else Counter - gen = gen_cls(min(dram_port.dw, 32)) # FIXME: remove lfsr limitation + # data / address generators + data_gen = Generator(31, n_state=31, taps=[27, 30]) # PRBS31 + addr_gen = Generator(23, n_state=23, taps=[17, 22]) # PRBS23 + assert (23 + ashift) < awidth # addressing large enough for random + self.submodules += data_gen, addr_gen + self.comb += [ + data_gen.random_enable.eq(self.random_data_enable), + addr_gen.random_enable.eq(self.random_addr_enable) + ] + + # dma dma = LiteDRAMDMAReader(dram_port) - self.submodules += dma, gen + self.submodules += dma # address cmd_counter = Signal(dram_port.aw, reset_less=True) @@ -228,6 +301,7 @@ class _LiteDRAMBISTChecker(Module, AutoCSR): cmd_fsm.act("RUN", dma.sink.valid.eq(1), If(dma.sink.ready, + addr_gen.ce.eq(1), NextValue(cmd_counter, cmd_counter + 1), If(cmd_counter == (self.length[ashift:] - 1), NextState("DONE") @@ -235,7 +309,7 @@ class _LiteDRAMBISTChecker(Module, AutoCSR): ) ) cmd_fsm.act("DONE") - self.comb += dma.sink.address.eq(self.base[ashift:] + cmd_counter) + self.comb += dma.sink.address.eq(self.base[ashift:] + addr_gen.o) # data data_counter = Signal(dram_port.aw, reset_less=True) @@ -253,9 +327,9 @@ class _LiteDRAMBISTChecker(Module, AutoCSR): data_fsm.act("RUN", dma.source.ready.eq(1), If(dma.source.valid, - gen.ce.eq(1), + data_gen.ce.eq(1), NextValue(data_counter, data_counter + 1), - If(dma.source.data != gen.o, + If(dma.source.data != data_gen.o, NextValue(self.errors, self.errors + 1) ), If(data_counter == (self.length[ashift:] - 1), @@ -279,13 +353,19 @@ class LiteDRAMBISTChecker(Module, AutoCSR): start : in Start the checking + done : out + The module has completed checking + base : in DRAM address to start from. length : in Number of DRAM words to check. - done : out - The module has completed checking + random_data_enable : in + Enable random data (LFSR) + + random_addr_enable : in + Enable random addressing (LFSR) ticks: out Duration of the check. @@ -293,14 +373,16 @@ class LiteDRAMBISTChecker(Module, AutoCSR): errors : out Number of DRAM words which don't match. """ - def __init__(self, dram_port, random=True): + def __init__(self, dram_port): ashift = log2_int(dram_port.dw//8) awidth = dram_port.aw + ashift self.reset = CSR() self.start = CSR() + self.done = CSRStatus() self.base = CSRStorage(awidth) self.length = CSRStorage(awidth) - self.done = CSRStatus() + self.random_data_enable = CSRStorage() + self.random_addr_enable = CSRStorage() self.ticks = CSRStatus(32) self.errors = CSRStatus(32) @@ -308,7 +390,7 @@ class LiteDRAMBISTChecker(Module, AutoCSR): cd = dram_port.cd - core = _LiteDRAMBISTChecker(dram_port, random) + core = _LiteDRAMBISTChecker(dram_port) core = ClockDomainsRenamer(cd)(core) self.submodules += core @@ -341,6 +423,11 @@ class LiteDRAMBISTChecker(Module, AutoCSR): core.length.eq(length_sync.o) ] + self.specials += [ + MultiReg(self.random_data_enable.storage, core.random_data_enable, cd), + MultiReg(self.random_addr_enable.storage, core.random_addr_enable, cd), + ] + ticks_sync = BusSynchronizer(32, cd, "sys") self.submodules += ticks_sync self.comb += [