def __init__(self): self.write_port = LiteDRAMNativeWritePort( address_width=32, data_width=data_width) if pattern is not None: self.submodules.generator = _LiteDRAMPatternGenerator( self.write_port, pattern) else: self.submodules.generator = _LiteDRAMBISTGenerator( self.write_port) self.mem = DRAMMemory(data_width, len(mem_expected))
def __init__(self, mode="bist", sdram_module="MT48LC16M16", sdram_data_width=32, bist_base=0x0000000, bist_end=0x0100000, bist_length=1024, bist_random=False, bist_alternating=False, num_generators=1, num_checkers=1, access_pattern=None, **kwargs): assert mode in ["bist", "pattern"] assert not (mode == "pattern" and access_pattern is None) # SimSoC ----------------------------------------------------------------------------------- SimSoC.__init__(self, with_sdram=True, sdram_module=sdram_module, sdram_data_width=sdram_data_width, **kwargs) # BIST/Pattern Generator / Checker --------------------------------------------------------- if mode == "pattern": make_generator = lambda: _LiteDRAMPatternGenerator( self.sdram.crossbar.get_port(), init=access_pattern) make_checker = lambda: _LiteDRAMPatternChecker( self.sdram.crossbar.get_port(), init=access_pattern) if mode == "bist": make_generator = lambda: _LiteDRAMBISTGenerator(self.sdram.crossbar .get_port()) make_checker = lambda: _LiteDRAMBISTChecker(self.sdram.crossbar. get_port()) generators = [make_generator() for _ in range(num_generators)] checkers = [make_checker() for _ in range(num_checkers)] self.submodules += generators + checkers if mode == "pattern": def bist_config(module): return [] if not bist_alternating: address_set = set() for addr, _ in access_pattern: assert addr not in address_set, \ "Duplicate address 0x%08x in access_pattern, write will overwrite previous value!" % addr address_set.add(addr) if mode == "bist": # Make sure that we perform at least one access bist_length = max(bist_length, self.sdram.controller.interface.data_width // 8) def bist_config(module): return [ module.base.eq(bist_base), module.end.eq(bist_end), module.length.eq(bist_length), module.random_addr.eq(bist_random), ] assert not (bist_random and not bist_alternating), \ "Write to random address may overwrite previously written data before reading!" # Check address correctness assert bist_end > bist_base assert bist_end <= 2**(len( generators[0].end)) - 1, "End address outside of range" bist_addr_range = bist_end - bist_base assert bist_addr_range > 0 and bist_addr_range & (bist_addr_range - 1) == 0, \ "Length of the address range must be a power of 2" def combined_read(modules, signal, operator): sig = Signal() self.comb += sig.eq( reduce(operator, (getattr(m, signal) for m in modules))) return sig def combined_write(modules, signal): sig = Signal() self.comb += [getattr(m, signal).eq(sig) for m in modules] return sig # Sequencer -------------------------------------------------------------------------------- class LiteDRAMCoreControl(Module, AutoCSR): def __init__(self): self.init_done = CSRStorage() self.init_error = CSRStorage() self.submodules.ddrctrl = ddrctrl = LiteDRAMCoreControl() self.add_csr("ddrctrl") display = Signal() finish = Signal() self.submodules.fsm = fsm = FSM(reset_state="WAIT-INIT") fsm.act( "WAIT-INIT", If( self.ddrctrl.init_done. storage, # Written by CPU when initialization is done NextState("BIST-GENERATOR"))) if bist_alternating: # Force generators to wait for checkers and vice versa. Connect them in pairs, with each # unpaired connected to the first of the others. bist_connections = [] for generator, checker in zip_longest(generators, checkers): g = generator or generators[0] c = checker or checkers[0] bist_connections += [ g.run_cascade_in.eq(c.run_cascade_out), c.run_cascade_in.eq(g.run_cascade_out), ] fsm.act( "BIST-GENERATOR", combined_write(generators + checkers, "start").eq(1), *bist_connections, *map(bist_config, generators + checkers), If(combined_read(checkers, "done", and_), NextState("DISPLAY"))) else: fsm.act( "BIST-GENERATOR", combined_write(generators, "start").eq(1), *map(bist_config, generators), If(combined_read(generators, "done", and_), NextState("BIST-CHECKER"))) fsm.act( "BIST-CHECKER", combined_write(checkers, "start").eq(1), *map(bist_config, checkers), If(combined_read(checkers, "done", and_), NextState("DISPLAY"))) fsm.act("DISPLAY", display.eq(1), NextState("FINISH")) fsm.act("FINISH", finish.eq(1)) # Simulation Results ----------------------------------------------------------------------- def max_signal(signals): signals = iter(signals) s = next(signals) out = Signal(len(s)) self.comb += out.eq(s) for curr in signals: prev = out out = Signal(max(len(prev), len(curr))) self.comb += If(prev > curr, out.eq(prev)).Else(out.eq(curr)) return out generator_ticks = max_signal((g.ticks for g in generators)) checker_errors = max_signal((c.errors for c in checkers)) checker_ticks = max_signal((c.ticks for c in checkers)) self.sync += [ If( display, Display("BIST-GENERATOR ticks: %08d", generator_ticks), Display("BIST-CHECKER errors: %08d", checker_errors), Display("BIST-CHECKER ticks: %08d", checker_ticks), ) ] # Simulation End --------------------------------------------------------------------------- end_timer = WaitTimer(2**16) self.submodules += end_timer self.comb += end_timer.wait.eq(finish) self.sync += If(end_timer.done, Finish())