frontend/bist: add dynamic random data and addressing

This commit is contained in:
Florent Kermarrec 2018-08-17 13:49:27 +02:00
parent b13962c7bd
commit 209dc0d781
1 changed files with 119 additions and 32 deletions

View File

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