diff --git a/litedram/frontend/bist.py b/litedram/frontend/bist.py index 059353b..b674148 100644 --- a/litedram/frontend/bist.py +++ b/litedram/frontend/bist.py @@ -45,7 +45,7 @@ class LFSR(Module): self.sync += [ state.eq(Cat(*curval[:n_state])), - self.o.eq(Cat(*curval)) + self.o.eq(Cat(*curval)), ] @@ -66,6 +66,9 @@ class Counter(Module): def __init__(self, n_out): self.o = Signal(n_out) + + # # # + self.sync += self.o.eq(self.o + 1) @@ -80,32 +83,36 @@ class _LiteDRAMBISTGenerator(Module): # # # self.submodules.dma = dma = LiteDRAMDMAWriter(dram_port) + gen_cls = LFSR if random else Counter + self.submodules.gen = gen = gen_cls(dram_port.dw) - if random: - self.submodules.gen = gen = LFSR(dram_port.dw) - else: - self.submodules.gen = gen = Counter(dram_port.dw) + cmd_counter = Signal(dram_port.aw) - self.running = running = Signal() - not_finished = Signal() - counter = Signal(dram_port.aw) - self.comb += not_finished.eq(running & (counter != (self.length - 1))) - self.sync += [ + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + + fsm.act("IDLE", If(self.start, - running.eq(1), - counter.eq(0) - ).Elif(gen.ce, - counter.eq(counter + 1) - ) - ] - + NextValue(cmd_counter, 0), + NextState("RUN"), + ), + ) + fsm.act("RUN", + dma.sink.valid.eq(1), + If(dma.sink.ready, + gen.ce.eq(1), + NextValue(cmd_counter, cmd_counter + 1), + If(cmd_counter == (self.length-1), + NextState("DONE"), + ), + ), + ) + fsm.act("DONE", + self.done.eq(1), + ) self.comb += [ - dma.sink.valid.eq(not_finished), - dma.sink.address.eq(self.base + counter), + dma.sink.address.eq(self.base + cmd_counter), dma.sink.data.eq(gen.o), - gen.ce.eq(not_finished & dma.sink.ready), - - self.done.eq(~not_finished & running) ] @@ -144,28 +151,31 @@ class LiteDRAMBISTGenerator(Module, AutoCSR): reset_sync = BusSynchronizer(1, "sys", cd) start_sync = PulseSynchronizer("sys", cd) - done_sync = BusSynchronizer(1, cd, "sys") - self.submodules += reset_sync, start_sync, done_sync - - base_sync = BusSynchronizer(dram_port.aw, "sys", cd) - length_sync = BusSynchronizer(dram_port.aw, "sys", cd) - self.submodules += base_sync, length_sync - + self.submodules += reset_sync, start_sync self.comb += [ reset_sync.i.eq(self.reset.re), core.reset.eq(reset_sync.o), start_sync.i.eq(self.start.re), core.start.eq(start_sync.o), + ] + done_sync = BusSynchronizer(1, cd, "sys") + self.submodules += done_sync + self.comb += [ done_sync.i.eq(core.done), self.done.status.eq(done_sync.o), + ] + base_sync = BusSynchronizer(dram_port.aw, "sys", cd) + length_sync = BusSynchronizer(dram_port.aw, "sys", cd) + self.submodules += base_sync, length_sync + self.comb += [ base_sync.i.eq(self.base.storage), core.base.eq(base_sync.o), length_sync.i.eq(self.length.storage), - core.length.eq(length_sync.o) + core.length.eq(length_sync.o), ] @@ -173,77 +183,80 @@ class _LiteDRAMBISTChecker(Module, AutoCSR): def __init__(self, dram_port, random): self.start = Signal() + self.done = Signal() self.base = Signal(dram_port.aw) self.length = Signal(dram_port.aw) - self.error_count = Signal(32) + self.err_count = Signal(32) - self.running = running = Signal() - self.done = Signal() + # # # self.submodules.dma = dma = LiteDRAMDMAReader(dram_port) + gen_cls = LFSR if random else Counter + self.submodules.gen = gen = gen_cls(dram_port.dw) - # Address generation - self._address_counter = address_counter = Signal(dram_port.aw) - address_not_finished = Signal() - address_counter_ce = Signal() - self.comb += [ - address_not_finished.eq(running & (address_counter != (self.length - 1))), - address_counter_ce.eq(address_not_finished & dma.sink.ready), + # address + self._cmd_counter = cmd_counter = Signal(dram_port.aw) + cmd_fsm = FSM(reset_state="IDLE") + self.submodules += cmd_fsm - dma.sink.valid.eq(address_not_finished), - dma.sink.address.eq(self.base + address_counter), - ] - self.sync += [ - If(address_counter_ce, - address_counter.eq(address_counter + 1) + cmd_fsm.act("IDLE", + If(self.start, + NextValue(cmd_counter, 0), + NextState("RUN"), ), - ] + ) + cmd_fsm.act("RUN", + dma.sink.valid.eq(1), + If(dma.sink.ready, + NextValue(cmd_counter, cmd_counter + 1), + If(cmd_counter == (self.length-1), + NextState("DONE") + ), + ), + ) + cmd_fsm.act("DONE") + self.comb += dma.sink.address.eq(self.base + cmd_counter) - # Data receiving + # data self._data_counter = data_counter = Signal(dram_port.aw) - data_not_finished = Signal() - data_counter_ce = Signal() - self.comb += [ - data_not_finished.eq(running & (data_counter != address_counter)), - data_counter_ce.eq(data_not_finished & dma.source.valid), - - dma.source.ready.eq(data_counter_ce), - ] - self.sync += [ - If(data_counter_ce, data_counter.eq(data_counter + 1)), - ] - - # Data checking - if random: - self.submodules.gen = gen = LFSR(dram_port.dw) - else: - self.submodules.gen = gen = Counter(dram_port.dw) - self.comb += [ - gen.ce.eq(data_counter_ce), - ] - - self.expected = expected = Signal(dram_port.dw) - self.comb += [ - expected.eq(gen.o), - ] - self.actual = actual = Signal(dram_port.dw) - self.comb += [ - actual.eq(dma.source.data), - ] + data_fsm = FSM(reset_state="IDLE") + self.submodules += data_fsm self.error = error = Signal() + self.actual = actual = Signal(dram_port.aw) + self.expect = expect = Signal(dram_port.aw) self.comb += [ - error.eq(data_counter_ce & (expected != actual)), - ] - self.sync += [ - If(error, self.error_count.eq(self.error_count + 1)), + actual.eq(dma.source.data), + expect.eq(gen.o), + error.eq(dma.source.valid & (expect != actual)), ] - # States - self.sync += If(self.start, running.eq(1)) - self.comb += self.done.eq(~data_not_finished & ~address_not_finished & running) + data_fsm.act("IDLE", + If(self.start, + NextValue(data_counter, 0), + NextValue(self.err_count, 0), + NextState("RUN"), + ), + ) + data_fsm.act("RUN", + dma.source.ready.eq(1), + If(dma.source.valid, + gen.ce.eq(1), + NextValue(data_counter, data_counter + 1), + If(error, + NextValue(self.err_count, self.err_count + 1), + ), + If(data_counter == (self.length-1), + NextState("DONE"), + ), + ), + ) + data_fsm.act("DONE") + + self.comb += self.done.eq( + cmd_fsm.ongoing("DONE") & data_fsm.ongoing("DONE")) class LiteDRAMBISTChecker(Module, AutoCSR): @@ -264,7 +277,7 @@ class LiteDRAMBISTChecker(Module, AutoCSR): done : out The module has completed checking - error_count : out + err_count : out Number of DRAM words which don't match. """ @@ -274,11 +287,9 @@ class LiteDRAMBISTChecker(Module, AutoCSR): self.base = CSRStorage(dram_port.aw) self.length = CSRStorage(dram_port.aw) - self.halt_on_error = CSRStorage() self.done = CSRStatus() - - self.error_count = CSRStatus(32) + self.err_count = CSRStatus(32) # # # @@ -317,9 +328,9 @@ class LiteDRAMBISTChecker(Module, AutoCSR): core.length.eq(length_sync.o), ] - error_count_sync = BusSynchronizer(32, cd, "sys") - self.submodules += error_count_sync + err_count_sync = BusSynchronizer(32, cd, "sys") + self.submodules += err_count_sync self.comb += [ - error_count_sync.i.eq(core.error_count), - self.error_count.status.eq(error_count_sync.o), + err_count_sync.i.eq(core.err_count), + self.err_count.status.eq(err_count_sync.o), ] diff --git a/test/bist_tb.py b/test/bist_tb.py index 6fedf6f..6f65aa0 100755 --- a/test/bist_tb.py +++ b/test/bist_tb.py @@ -20,16 +20,6 @@ class TB(Module): self.submodules.checker = LiteDRAMBISTChecker(self.read_port, random=True) -finished = [] - -def cycle_assert(dut): - while not finished: - addr = yield dut.checker.core._address_counter - data = yield dut.checker.core._data_counter - assert addr >= data, "addr {} >= data {}".format(addr, data) - yield - - def main_generator(dut, mem): # Populate memory with random data random.seed(0) @@ -55,7 +45,7 @@ def main_generator(dut, mem): # read with no errors yield from reset_bist_module(dut.checker) - errors = yield dut.checker.error_count.status + errors = yield dut.checker.err_count.status assert errors == 0, errors yield dut.checker.base.storage.eq(16) @@ -69,7 +59,7 @@ def main_generator(dut, mem): yield done = yield dut.checker.done.status assert done, done - errors = yield dut.checker.error_count.status + errors = yield dut.checker.err_count.status assert errors == 0, errors yield @@ -77,7 +67,7 @@ def main_generator(dut, mem): # read with one error yield from reset_bist_module(dut.checker) - errors = yield dut.checker.error_count.status + errors = yield dut.checker.err_count.status assert errors == 0, errors print("mem.mem[20]", hex(mem.mem[20])) @@ -95,7 +85,7 @@ def main_generator(dut, mem): yield done = yield dut.checker.done.status assert done, done - errors = yield dut.checker.error_count.status + errors = yield dut.checker.err_count.status assert errors == 1, errors yield @@ -103,7 +93,7 @@ def main_generator(dut, mem): # read with two errors yield from reset_bist_module(dut.checker) - errors = yield dut.checker.error_count.status + errors = yield dut.checker.err_count.status assert errors == 0, errors print("mem.mem[21]", hex(mem.mem[21])) @@ -121,7 +111,7 @@ def main_generator(dut, mem): yield done = yield dut.checker.done.status assert done, done - errors = yield dut.checker.error_count.status + errors = yield dut.checker.err_count.status assert errors == 2, errors yield @@ -129,7 +119,7 @@ def main_generator(dut, mem): # read with two errors but halting on the first one yield from reset_bist_module(dut.checker) - errors = yield dut.checker.error_count.status + errors = yield dut.checker.err_count.status assert errors == 0, errors yield dut.checker.base.storage.eq(16) @@ -144,12 +134,12 @@ def main_generator(dut, mem): err_addr = yield dut.checker.core._data_counter + dut.checker.core.base assert err_addr == 20, err_addr - err_expect = yield dut.checker.core.expected + err_expect = yield dut.checker.core.expect assert err_expect == 0xffff000f, hex(err_expect) err_actual = yield dut.checker.core.actual assert err_actual == 0x200, err_actual yield - errors = yield dut.checker.core.error_count + errors = yield dut.checker.core.err_count assert errors == 1, errors while((yield dut.checker.core.error) == 0): @@ -157,31 +147,25 @@ def main_generator(dut, mem): err_addr = yield dut.checker.core._data_counter + dut.checker.core.base assert err_addr == 21, err_addr - err_expect = yield dut.checker.core.expected + err_expect = yield dut.checker.core.expect assert err_expect == 0xfff1ff1f, hex(err_expect) err_actual = yield dut.checker.core.actual assert err_actual == 0x210, hex(err_actual) yield - errors = yield dut.checker.core.error_count + errors = yield dut.checker.core.err_count assert errors == 2, errors while((yield dut.checker.done.status) == 0): yield + done = yield dut.checker.done.status assert done, done - running = yield dut.checker.core.running - assert running, running - for i in range(16): - yield - - errors = yield dut.checker.error_count.status + errors = yield dut.checker.err_count.status assert errors == 2, errors yield yield - finished.append(True) - if __name__ == "__main__": tb = TB() @@ -191,7 +175,6 @@ if __name__ == "__main__": main_generator(tb, mem), mem.write_generator(tb.write_port), mem.read_generator(tb.read_port), - cycle_assert(tb), ], } clocks = {"sys": 10} diff --git a/test/common.py b/test/common.py index 204114f..5c12f26 100644 --- a/test/common.py +++ b/test/common.py @@ -19,9 +19,6 @@ def reset_bist_module(module): yield # Check some initial conditions are correct after reset. - running = yield module.core.running - assert running == 0, running - done = yield module.done.status assert not done, done