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 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 += [