frontend/bist: add dynamic random data and addressing
This commit is contained in:
parent
b13962c7bd
commit
209dc0d781
|
@ -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 += [
|
||||
|
|
Loading…
Reference in New Issue