Example #1
0
    def __init__(self,
                 clocks,
                 log_level,
                 auto_precharge=False,
                 with_refresh=True,
                 trace_reset=0,
                 disable_delay=False,
                 masked_write=True,
                 double_rate_phy=False,
                 finish_after_memtest=False,
                 **kwargs):
        platform = Platform()
        sys_clk_freq = clocks["sys"]["freq_hz"]

        # SoCCore ----------------------------------------------------------------------------------
        super().__init__(platform,
                         clk_freq=sys_clk_freq,
                         ident="LiteX Simulation",
                         ident_version=True,
                         cpu_variant="minimal",
                         **kwargs)

        # CRG --------------------------------------------------------------------------------------
        self.submodules.crg = _CRG(platform, clocks.names())

        # Debugging --------------------------------------------------------------------------------
        platform.add_debug(self, reset=trace_reset)

        # LPDDR4 -----------------------------------------------------------------------------------
        sdram_module = litedram_modules.MT53E256M16D1(sys_clk_freq, "1:8")
        pads = platform.request("lpddr4")
        sim_phy_cls = DoubleRateLPDDR4SimPHY if double_rate_phy else LPDDR4SimPHY
        self.submodules.ddrphy = sim_phy_cls(
            sys_clk_freq=sys_clk_freq,
            aligned_reset_zero=True,
            masked_write=masked_write,
        )
        # fake delays (make no nsense in simulation, but sdram.c expects them)
        self.ddrphy._rdly_dq_rst = CSR()
        self.ddrphy._rdly_dq_inc = CSR()
        self.add_csr("ddrphy")

        for p in [
                "clk_p", "clk_n", "cke", "odt", "reset_n", "cs", "ca", "dq",
                "dqs", "dmi"
        ]:
            self.comb += getattr(pads, p).eq(getattr(self.ddrphy.pads, p))

        controller_settings = ControllerSettings()
        controller_settings.auto_precharge = auto_precharge
        controller_settings.with_refresh = with_refresh

        self.add_sdram("sdram",
                       phy=self.ddrphy,
                       module=sdram_module,
                       origin=self.mem_map["main_ram"],
                       size=kwargs.get("max_sdram_size", 0x40000000),
                       l2_cache_size=kwargs.get("l2_size", 8192),
                       l2_cache_min_data_width=kwargs.get(
                           "min_l2_data_width", 128),
                       l2_cache_reverse=False,
                       controller_settings=controller_settings)
        # Reduce memtest size for simulation speedup
        self.add_constant("MEMTEST_DATA_SIZE", 8 * 1024)
        self.add_constant("MEMTEST_ADDR_SIZE", 8 * 1024)

        # LPDDR4 Sim -------------------------------------------------------------------------------
        self.submodules.lpddr4sim = LPDDR4Sim(
            pads=self.ddrphy.pads,
            cl=self.sdram.controller.settings.phy.cl,
            cwl=self.sdram.controller.settings.phy.cwl,
            sys_clk_freq=sys_clk_freq,
            log_level=log_level,
            disable_delay=disable_delay,
        )
        self.add_csr("lpddr4sim")

        self.add_constant("CONFIG_SIM_DISABLE_BIOS_PROMPT")
        if disable_delay:
            self.add_constant("CONFIG_DISABLE_DELAYS")
        if finish_after_memtest:
            self.submodules.ddrctrl = LiteDRAMCoreControl()
            self.add_csr("ddrctrl")
            self.sync += If(self.ddrctrl.init_done.storage, Finish())

        # Reuse DFITimingsChecker from phy/model.py
        nphases = self.sdram.controller.settings.phy.nphases
        timings = {"tCK": (1e9 / sys_clk_freq) / nphases}
        for name in _speedgrade_timings + _technology_timings:
            timings[name] = sdram_module.get(name)

        self.submodules.dfi_timings_checker = DFITimingsChecker(
            dfi=self.ddrphy.dfi,
            nbanks=2**self.sdram.controller.settings.geom.bankbits,
            nphases=nphases,
            timings=timings,
            refresh_mode=sdram_module.timing_settings.fine_refresh_mode,
            memtype=self.sdram.controller.settings.phy.memtype,
            verbose=False,
        )

        # Debug info -------------------------------------------------------------------------------
        def dump(obj):
            print()
            print(" " + obj.__class__.__name__)
            print(" " + "-" * len(obj.__class__.__name__))
            d = obj if isinstance(obj, dict) else vars(obj)
            for var, val in d.items():
                if var == "self":
                    continue
                if isinstance(val, Signal):
                    val = "Signal(reset={})".format(val.reset.value)
                print("  {}: {}".format(var, val))

        print("=" * 80)
        dump(clocks)
        dump(self.ddrphy.settings)
        dump(sdram_module.geom_settings)
        dump(sdram_module.timing_settings)
        print()
        print("=" * 80)
Example #2
0
    def __init__(self,
                 toolchain="vivado",
                 sys_clk_freq=int(100e6),
                 args=None,
                 ip_address="192.168.100.50",
                 mac_address=0x10e2d5000001,
                 udp_port=1234,
                 **kwargs):
        if not args.sim:
            platform = arty.Platform(toolchain=toolchain)
        else:
            platform = SimPlatform("SIM", _io)

        # SoCCore ----------------------------------------------------------------------------------
        SoCCore.__init__(self,
                         platform,
                         sys_clk_freq,
                         ident="LiteX SoC on Arty A7",
                         ident_version=True,
                         **kwargs)

        # CRG --------------------------------------------------------------------------------------
        if not args.sim:
            self.submodules.crg = _CRG(platform, sys_clk_freq, args)
        else:
            self.submodules.crg = CRG(platform.request("sys_clk"))

        # DDR3 SDRAM -------------------------------------------------------------------------------
        if not args.sim:
            self.submodules.ddrphy = s7ddrphy.A7DDRPHY(
                platform.request("ddram"),
                memtype="DDR3",
                nphases=4,
                sys_clk_freq=sys_clk_freq)
        else:
            from litedram.gen import get_dram_ios
            core_config = dict()
            core_config["sdram_module_nb"] = 2  # Number of byte groups
            core_config["sdram_rank_nb"] = 1  # Number of ranks
            core_config['sdram_module'] = getattr(litedram_modules,
                                                  'MT41K128M16')
            core_config["memtype"] = "DDR3"  # DRAM type

            platform.add_extension(get_dram_ios(core_config))
            sdram_module = core_config["sdram_module"](
                sys_clk_freq,
                rate={
                    "DDR2": "1:2",
                    "DDR3": "1:4",
                    "DDR4": "1:4"
                }[core_config["memtype"]])

            from litex.tools.litex_sim import get_sdram_phy_settings
            sdram_clk_freq = int(100e6)  # FIXME: use 100MHz timings
            phy_settings = get_sdram_phy_settings(
                memtype=sdram_module.memtype,
                data_width=core_config["sdram_module_nb"] * 8,
                clk_freq=sdram_clk_freq)

            self.submodules.ddrphy = SDRAMPHYModel(
                module=sdram_module,
                settings=phy_settings,
                clk_freq=sdram_clk_freq,
                verbosity=3,
            )

        class ControllerDynamicSettings(Module, AutoCSR, AutoDoc):
            """Allows to change LiteDRAMController behaviour at runtime"""
            def __init__(self):
                self.refresh = CSRStorage(
                    reset=1,
                    description="Enable/disable Refresh commands sending")

        self.submodules.controller_settings = ControllerDynamicSettings()
        self.add_csr("controller_settings")
        controller_settings = ControllerSettings()
        controller_settings.with_auto_precharge = True
        controller_settings.with_refresh = self.controller_settings.refresh.storage

        self.add_csr("ddrphy")
        self.add_sdram(
            "sdram",
            phy=self.ddrphy,
            module=MT41K128M16(sys_clk_freq, "1:4"),
            origin=self.mem_map["main_ram"],
            size=kwargs.get("max_sdram_size", 0x40000000),
            l2_cache_size=0,
            l2_cache_min_data_width=0,  #128
            l2_cache_reverse=True,
            controller_settings=controller_settings)

        # Ethernet / Etherbone ---------------------------------------------------------------------
        if not args.sim:
            # Ethernet PHY (arty)
            self.submodules.ethphy = LiteEthPHYMII(
                clock_pads=self.platform.request("eth_clocks"),
                pads=self.platform.request("eth"))
            self.add_csr("ethphy")

            self.add_etherbone(phy=self.ethphy,
                               ip_address=ip_address,
                               mac_address=mac_address,
                               udp_port=udp_port)
        else:
            # Ethernet PHY (simulation)
            self.submodules.ethphy = LiteEthPHYModel(
                self.platform.request("eth", 0))  # FIXME
            self.add_csr("ethphy")

            # Ethernet Core
            ethcore = LiteEthUDPIPCore(self.ethphy,
                                       ip_address=ip_address,
                                       mac_address=mac_address,
                                       clk_freq=sys_clk_freq)
            self.submodules.ethcore = ethcore
            # Etherbone
            self.submodules.etherbone = LiteEthEtherbone(self.ethcore.udp,
                                                         udp_port,
                                                         mode="master")
            self.add_wb_master(self.etherbone.wishbone.bus)

        # Leds -------------------------------------------------------------------------------------
        self.submodules.leds = LedChaser(pads=platform.request_all("user_led"),
                                         sys_clk_freq=sys_clk_freq)
        self.add_csr("leds")

        if args.sim:
            self.comb += platform.trace.eq(1)

        # Rowhammer --------------------------------------------------------------------------------
        self.submodules.rowhammer_dma = LiteDRAMDMAReader(
            self.sdram.crossbar.get_port())
        self.submodules.rowhammer = RowHammerDMA(self.rowhammer_dma)
        self.add_csr("rowhammer")

        def add_xram(self, name, origin, mem, mode='rw'):
            from litex.soc.interconnect import wishbone
            from litex.soc.integration.soc import SoCRegion
            ram = wishbone.SRAM(mem,
                                bus=wishbone.Interface(data_width=mem.width),
                                read_only='w' not in mode)
            ram_bus = wishbone.Interface(data_width=self.bus.data_width)
            self.submodules += wishbone.Converter(ram_bus, ram.bus)
            region = SoCRegion(origin=origin,
                               size=mem.width // 8 * mem.depth,
                               mode=mode)
            self.bus.add_slave(name, ram_bus, region)
            self.check_if_exists(name)
            self.logger.info("RAM {} {} {}.".format(
                colorer(name), colorer("added", color="green"),
                self.bus.regions[name]))
            setattr(self.submodules, name, ram)

        # Bist -------------------------------------------------------------------------------------
        if not args.no_memory_bist:
            # ------------------------------ writer ------------------------------------
            dram_wr_port = self.sdram.crossbar.get_port()
            self.submodules.writer = Writer(dram_wr_port)
            self.add_csr('writer')

            # TODO: Rename as 'pattern_wr_w?'
            add_xram(self,
                     name='pattern_w0',
                     mem=self.writer.memory_w0,
                     origin=0x20000000)
            add_xram(self,
                     name='pattern_w1',
                     mem=self.writer.memory_w1,
                     origin=0x21000000)
            add_xram(self,
                     name='pattern_w2',
                     mem=self.writer.memory_w2,
                     origin=0x22000000)
            add_xram(self,
                     name='pattern_w3',
                     mem=self.writer.memory_w3,
                     origin=0x23000000)
            add_xram(self,
                     name='pattern_adr',
                     mem=self.writer.memory_adr,
                     origin=0x24000000)

            # ----------------------------- reader -------------------------------------
            dram_rd_port = self.sdram.crossbar.get_port()
            self.submodules.reader = Reader(dram_rd_port)
            self.add_csr('reader')

            add_xram(self,
                     name='pattern_rd_w0',
                     mem=self.reader.memory_w0,
                     origin=0x30000000)
            add_xram(self,
                     name='pattern_rd_w1',
                     mem=self.reader.memory_w1,
                     origin=0x31000000)
            add_xram(self,
                     name='pattern_rd_w2',
                     mem=self.reader.memory_w2,
                     origin=0x32000000)
            add_xram(self,
                     name='pattern_rd_w3',
                     mem=self.reader.memory_w3,
                     origin=0x33000000)
            add_xram(self,
                     name='pattern_rd_adr',
                     mem=self.reader.memory_adr,
                     origin=0x34000000)

        # Payload executor -------------------------------------------------------------------------
        if not args.no_payload_executor:
            # TODO: disconnect bus during payload execution

            phy_settings = self.sdram.controller.settings.phy
            scratchpad_width = phy_settings.dfi_databits * phy_settings.nphases
            scratchpad_size = 2**10

            payload_mem = Memory(32, 2**10)
            scratchpad_mem = Memory(scratchpad_width,
                                    scratchpad_size // (scratchpad_width // 8))
            self.specials += payload_mem, scratchpad_mem

            add_xram(self, name='payload', mem=payload_mem, origin=0x35000000)
            add_xram(self,
                     name='scratchpad',
                     mem=scratchpad_mem,
                     origin=0x36000000,
                     mode='r')

            self.submodules.payload_executor = PayloadExecutor(
                mem_payload=payload_mem,
                mem_scratchpad=scratchpad_mem,
                dfi=self.sdram.dfii.ext_dfi,
                dfi_sel=self.sdram.dfii.ext_dfi_sel,
                nranks=self.sdram.controller.settings.phy.nranks,
                bankbits=self.sdram.controller.settings.geom.bankbits,
                rowbits=self.sdram.controller.settings.geom.rowbits,
                colbits=self.sdram.controller.settings.geom.colbits,
                rdphase=self.sdram.controller.settings.phy.rdphase,
            )
            self.payload_executor.add_csrs()
            self.add_csr('payload_executor')
Example #3
0
    def __init__(self,
                 *,
                 args,
                 sys_clk_freq,
                 sdram_module_cls,
                 sdram_module_speedgrade=None,
                 sdram_module_spd_file=None,
                 ip_address="192.168.100.50",
                 mac_address=0x10e2d5000001,
                 udp_port=1234,
                 **kwargs):
        self.args = args
        self.sys_clk_freq = sys_clk_freq
        self.ip_address = ip_address
        self.mac_address = mac_address
        self.udp_port = udp_port

        # Platform ---------------------------------------------------------------------------------
        if not args.sim:
            self.platform = self.get_platform()
        else:
            self.platform = SimPlatform()

        githash = git.Repo(
            '.', search_parent_directories=True).git.rev_parse("HEAD")

        # SoCCore ----------------------------------------------------------------------------------
        SoCCore.__init__(
            self,
            self.platform,
            sys_clk_freq,
            ident="LiteX Row Hammer Tester SoC on {}, git: {}".format(
                self.platform.device, githash),
            ident_version=True,
            integrated_rom_mode='rw' if args.rw_bios_mem else 'r',
            **kwargs)

        # CRG --------------------------------------------------------------------------------------
        if not args.sim:
            self.submodules.crg = self.get_crg()
        else:
            self.submodules.crg = CRG(self.platform.request('sys_clk'))
            # Add dynamic simulation trace control, start enabled
            self.platform.add_debug(self, reset=1)

        # Leds -------------------------------------------------------------------------------------
        self.submodules.leds = LedChaser(
            pads=self.platform.request_all("user_led"),
            sys_clk_freq=sys_clk_freq)
        self.add_csr("leds")

        # SDRAM PHY --------------------------------------------------------------------------------
        if sdram_module_spd_file is not None:
            self.logger.info('Using DRAM module {} data: {}'.format(
                colorer('SPD'), sdram_module_spd_file))
            with open(sdram_module_spd_file, 'rb') as f:
                spd_data = f.read()
            module = SDRAMModule.from_spd_data(spd_data, self.sys_clk_freq)
        else:
            ratio = self.get_sdram_ratio()
            self.logger.info('Using DRAM module {} ratio {}'.format(
                colorer(sdram_module_cls.__name__), colorer(ratio)))
            module = sdram_module_cls(self.sys_clk_freq,
                                      ratio,
                                      speedgrade=sdram_module_speedgrade)

        if args.sim:
            # Use the hardware platform to retrieve values for simulation
            hw_pads = self.get_platform().request('ddram')
            core_config = dict(
                sdram_module_nb=len(hw_pads.dq) // 8,  # number of byte groups
                sdram_rank_nb=len(hw_pads.cs_n),  # number of ranks
                sdram_module=module,
                memtype=module.memtype,
            )
            # Add IO pins
            self.platform.add_extension(get_dram_ios(core_config))

            phy_settings = get_sdram_phy_settings(
                memtype=module.memtype,
                data_width=core_config["sdram_module_nb"] * 8,
                clk_freq=sys_clk_freq)

            self.submodules.ddrphy = SDRAMPHYModel(
                module=module,
                settings=phy_settings,
                clk_freq=sys_clk_freq,
                verbosity=3,
            )
        else:  # hardware
            self.submodules.ddrphy = self.get_ddrphy()
        self.add_csr("ddrphy")

        # SDRAM Controller--------------------------------------------------------------------------
        class ControllerDynamicSettings(Module, AutoCSR, AutoDoc, ModuleDoc):
            """Allows to change LiteDRAMController behaviour at runtime"""
            def __init__(self):
                self.refresh = CSRStorage(
                    reset=1,
                    description="Enable/disable Refresh commands sending")

        self.submodules.controller_settings = ControllerDynamicSettings()
        self.add_csr("controller_settings")
        controller_settings = ControllerSettings()
        controller_settings.with_auto_precharge = True
        controller_settings.with_refresh = self.controller_settings.refresh.storage
        controller_settings.refresh_cls = SyncableRefresher

        assert self.ddrphy.settings.memtype == module.memtype, \
            'Wrong DRAM module type: {} vs {}'.format(self.ddrphy.settings.memtype, module.memtype)
        self.add_sdram("sdram",
                       phy=self.ddrphy,
                       module=module,
                       origin=self.mem_map["main_ram"],
                       size=kwargs.get("max_sdram_size", 0x40000000),
                       l2_cache_size=0,
                       controller_settings=controller_settings)

        # CPU will report that leveling finished by writing to ddrctrl CSRs
        self.submodules.ddrctrl = LiteDRAMCoreControl()
        self.add_csr("ddrctrl")

        # Ethernet / Etherbone ---------------------------------------------------------------------
        if not args.sim:
            self.add_host_bridge()
        else:  # simulation
            self.submodules.ethphy = LiteEthPHYModel(
                self.platform.request("eth"))
            self.add_csr("ethphy")

            # Ethernet Core
            ethcore = LiteEthUDPIPCore(self.ethphy,
                                       ip_address=self.ip_address,
                                       mac_address=self.mac_address,
                                       clk_freq=self.sys_clk_freq)
            self.submodules.ethcore = ethcore
            # Etherbone
            self.submodules.etherbone = LiteEthEtherbone(self.ethcore.udp,
                                                         self.udp_port,
                                                         mode="master")
            self.add_wb_master(self.etherbone.wishbone.bus)

        # Rowhammer --------------------------------------------------------------------------------
        self.submodules.rowhammer_dma = LiteDRAMDMAReader(
            self.sdram.crossbar.get_port())
        self.submodules.rowhammer = RowHammerDMA(self.rowhammer_dma)
        self.add_csr("rowhammer")

        # Bist -------------------------------------------------------------------------------------
        if not args.no_memory_bist:
            pattern_data_size = int(args.pattern_data_size, 0)
            phy_settings = self.sdram.controller.settings.phy
            pattern_data_width = phy_settings.dfi_databits * phy_settings.nphases
            pattern_length = pattern_data_size // (pattern_data_width // 8)

            assert pattern_data_size % (pattern_data_width//8) == 0, \
                'Pattern data memory size must be multiple of {} bytes'.format(pattern_data_width//8)

            self.submodules.pattern_mem = PatternMemory(
                data_width=pattern_data_width, mem_depth=pattern_length)
            self.add_memory(self.pattern_mem.data,
                            name='pattern_data',
                            origin=0x20000000)
            self.add_memory(self.pattern_mem.addr,
                            name='pattern_addr',
                            origin=0x21000000)
            self.logger.info(
                '{}: Length: {}, Data Width: {}-bit, Address width: {}-bit'.
                format(colorer('BIST pattern'), colorer(pattern_length),
                       colorer(pattern_data_width), colorer(32)))

            assert controller_settings.address_mapping == 'ROW_BANK_COL'
            row_offset = controller_settings.geom.bankbits + controller_settings.geom.colbits
            inversion_kwargs = dict(
                rowbits=int(self.args.bist_inversion_rowbits, 0),
                row_shift=row_offset -
                self.sdram.controller.interface.address_align,
            )

            # Writer
            dram_wr_port = self.sdram.crossbar.get_port()
            self.submodules.writer = Writer(dram_wr_port, self.pattern_mem,
                                            **inversion_kwargs)
            self.writer.add_csrs()
            self.add_csr('writer')

            # Reader
            dram_rd_port = self.sdram.crossbar.get_port()
            self.submodules.reader = Reader(dram_rd_port, self.pattern_mem,
                                            **inversion_kwargs)
            self.reader.add_csrs()
            self.add_csr('reader')

            assert pattern_data_width == dram_wr_port.data_width
            assert pattern_data_width == dram_rd_port.data_width

        # Payload executor -------------------------------------------------------------------------
        if not args.no_payload_executor:
            # TODO: disconnect bus during payload execution
            phy_settings = self.sdram.controller.settings.phy

            scratchpad_width = phy_settings.dfi_databits * phy_settings.nphases
            payload_size = int(args.payload_size, 0)
            scratchpad_size = int(args.scratchpad_size, 0)
            assert payload_size % 4 == 0, 'Payload memory size must be multiple of 4 bytes'
            assert scratchpad_size % (scratchpad_width//8) == 0, \
                'Scratchpad memory size must be multiple of {} bytes'.format(scratchpad_width//8)

            scratchpad_depth = scratchpad_size // (scratchpad_width // 8)
            payload_mem = Memory(32, payload_size // 4)
            scratchpad_mem = Memory(scratchpad_width, scratchpad_depth)
            self.specials += payload_mem, scratchpad_mem

            self.add_memory(payload_mem, name='payload', origin=0x30000000)
            self.add_memory(scratchpad_mem,
                            name='scratchpad',
                            origin=0x31000000,
                            mode='r')
            self.logger.info('{}: Length: {}, Data Width: {}-bit'.format(
                colorer('Instruction payload'), colorer(payload_size // 4),
                colorer(32)))
            self.logger.info('{}: Length: {}, Data Width: {}-bit'.format(
                colorer('Scratchpad memory'), colorer(scratchpad_depth),
                colorer(scratchpad_width)))

            self.submodules.dfi_switch = DFISwitch(
                with_refresh=self.sdram.controller.settings.with_refresh,
                dfii=self.sdram.dfii,
                refresher_reset=self.sdram.controller.refresher.reset,
            )
            self.dfi_switch.add_csrs()
            self.add_csr('dfi_switch')

            self.submodules.payload_executor = PayloadExecutor(
                mem_payload=payload_mem,
                mem_scratchpad=scratchpad_mem,
                dfi_switch=self.dfi_switch,
                nranks=self.sdram.controller.settings.phy.nranks,
                bankbits=self.sdram.controller.settings.geom.bankbits,
                rowbits=self.sdram.controller.settings.geom.rowbits,
                colbits=self.sdram.controller.settings.geom.colbits,
                rdphase=self.sdram.controller.settings.phy.rdphase,
            )
            self.payload_executor.add_csrs()
            self.add_csr('payload_executor')
Example #4
0
    def __init__(self,
                 toolchain="vivado",
                 sys_clk_freq=int(100e6),
                 args=None,
                 ip_address="192.168.100.50",
                 mac_address=0x10e2d5000001,
                 udp_port=1234,
                 **kwargs):
        if not args.sim:
            platform = arty.Platform(toolchain=toolchain)
        else:
            platform = Platform()

        # SoCCore ----------------------------------------------------------------------------------
        SoCCore.__init__(self,
                         platform,
                         sys_clk_freq,
                         ident="LiteX SoC on Arty A7",
                         ident_version=True,
                         **kwargs)

        # CRG --------------------------------------------------------------------------------------
        if not args.sim:
            self.submodules.crg = _CRG(platform, sys_clk_freq, args)
        else:
            self.submodules.crg = CRG(platform.request("sys_clk"))

        # DDR3 SDRAM -------------------------------------------------------------------------------
        if not args.sim:
            self.submodules.ddrphy = s7ddrphy.A7DDRPHY(
                platform.request("ddram"),
                memtype="DDR3",
                nphases=4,
                sys_clk_freq=sys_clk_freq)
        else:
            from litedram.gen import get_dram_ios
            core_config = dict()
            core_config["sdram_module_nb"] = 2  # Number of byte groups
            core_config["sdram_rank_nb"] = 1  # Number of ranks
            core_config['sdram_module'] = getattr(litedram_modules,
                                                  'MT41K128M16')
            core_config["memtype"] = "DDR3"  # DRAM type

            platform.add_extension(get_dram_ios(core_config))
            sdram_module = core_config["sdram_module"](
                sys_clk_freq,
                rate={
                    "DDR2": "1:2",
                    "DDR3": "1:4",
                    "DDR4": "1:4"
                }[core_config["memtype"]])

            from litex.tools.litex_sim import get_sdram_phy_settings
            sdram_clk_freq = int(100e6)  # FIXME: use 100MHz timings
            phy_settings = get_sdram_phy_settings(
                memtype=sdram_module.memtype,
                data_width=core_config["sdram_module_nb"] * 8,
                clk_freq=sdram_clk_freq)

            self.submodules.ddrphy = SDRAMPHYModel(
                module=sdram_module,
                settings=phy_settings,
                clk_freq=sdram_clk_freq,
                verbosity=3,
            )

        class ControllerDynamicSettings(Module, AutoCSR, AutoDoc):
            """Allows to change LiteDRAMController behaviour at runtime"""
            def __init__(self):
                self.refresh = CSRStorage(
                    reset=1,
                    description="Enable/disable Refresh commands sending")

        self.submodules.controller_settings = ControllerDynamicSettings()
        self.add_csr("controller_settings")
        controller_settings = ControllerSettings()
        controller_settings.with_auto_precharge = True
        controller_settings.with_refresh = self.controller_settings.refresh.storage

        self.add_csr("ddrphy")
        self.add_sdram(
            "sdram",
            phy=self.ddrphy,
            module=MT41K128M16(sys_clk_freq, "1:4"),
            origin=self.mem_map["main_ram"],
            size=kwargs.get("max_sdram_size", 0x40000000),
            l2_cache_size=0,
            l2_cache_min_data_width=0,  #128
            l2_cache_reverse=True,
            controller_settings=controller_settings)

        # Ethernet / Etherbone ---------------------------------------------------------------------
        if not args.sim:
            # Ethernet PHY (arty)
            self.submodules.ethphy = LiteEthPHYMII(
                clock_pads=self.platform.request("eth_clocks"),
                pads=self.platform.request("eth"))
            self.add_csr("ethphy")

            self.add_etherbone(phy=self.ethphy,
                               ip_address=ip_address,
                               mac_address=mac_address,
                               udp_port=udp_port)
        else:
            # Ethernet PHY (simulation)
            self.submodules.ethphy = LiteEthPHYModel(
                self.platform.request("eth", 0))  # FIXME
            self.add_csr("ethphy")

            # Ethernet Core
            ethcore = LiteEthUDPIPCore(self.ethphy,
                                       ip_address=ip_address,
                                       mac_address=mac_address,
                                       clk_freq=sys_clk_freq)
            self.submodules.ethcore = ethcore
            # Etherbone
            self.submodules.etherbone = LiteEthEtherbone(self.ethcore.udp,
                                                         udp_port,
                                                         mode="master")
            self.add_wb_master(self.etherbone.wishbone.bus)

        # Leds -------------------------------------------------------------------------------------
        self.submodules.leds = LedChaser(pads=platform.request_all("user_led"),
                                         sys_clk_freq=sys_clk_freq)
        self.add_csr("leds")

        # Analyzer ---------------------------------------------------------------------------------
        # analyzer_signals = [
        #    self.bus.masters['master0'].stb,
        #    self.bus.masters['master0'].cyc,
        #    self.bus.masters['master0'].adr,
        #    self.bus.masters['master0'].we,
        #    self.bus.masters['master0'].ack,
        #    self.bus.masters['master0'].sel,
        #    self.bus.masters['master0'].dat_w,
        #    self.bus.masters['master0'].dat_r,
        # ]
        # from litescope import LiteScopeAnalyzer
        # self.submodules.analyzer = LiteScopeAnalyzer(analyzer_signals,
        #    depth        = 512,
        #    clock_domain = "sys",
        #    csr_csv      = "analyzer.csv")
        # self.add_csr("analyzer")

        if args.sim:
            self.comb += platform.trace.eq(1)

        # Rowhammer --------------------------------------------------------------------------------
        from litedram.frontend.dma import LiteDRAMDMAReader, LiteDRAMDMAWriter

        self.submodules.rowhammer_dma = LiteDRAMDMAReader(
            self.sdram.crossbar.get_port())
        self.submodules.rowhammer = RowHammerDMA(self.rowhammer_dma)
        self.add_csr("rowhammer")

        # Bist -------------------------------------------------------------------------------------
        if not args.no_memory_bist:
            from litedram.frontend.bist import LiteDRAMBISTGenerator, LiteDRAMBISTChecker

            def add_xram(self, name, origin, mem):
                from litex.soc.interconnect import wishbone
                from litex.soc.integration.soc import SoCRegion
                ram_bus = wishbone.Interface(data_width=self.bus.data_width)
                ram = wishbone.SRAM(mem, bus=ram_bus)
                self.bus.add_slave(
                    name, ram.bus,
                    SoCRegion(origin=origin,
                              size=mem.width * mem.depth,
                              mode='rw'))
                self.check_if_exists(name)
                self.logger.info("RAM {} {} {}.".format(
                    colorer(name), colorer("added", color="green"),
                    self.bus.regions[name]))
                setattr(self.submodules, name, ram)
                return

            # ------------------------------ writer ------------------------------------
            memory_w0 = Memory(32, 1024)
            memory_w1 = Memory(32, 1024)
            memory_w2 = Memory(32, 1024)
            memory_w3 = Memory(32, 1024)
            memory_adr = Memory(32, 1024)

            add_xram(self, name='pattern_w0', mem=memory_w0, origin=0x20000000)
            add_xram(self, name='pattern_w1', mem=memory_w1, origin=0x21000000)
            add_xram(self, name='pattern_w2', mem=memory_w2, origin=0x22000000)
            add_xram(self, name='pattern_w3', mem=memory_w3, origin=0x23000000)
            add_xram(self,
                     name='pattern_adr',
                     mem=memory_adr,
                     origin=0x24000000)

            class Writer(Module, AutoCSR):
                def __init__(self, dram_port, w0_port, w1_port, w2_port,
                             w3_port, adr_port):
                    self.reset = CSRStorage()
                    self.start = CSRStorage()
                    self.done = CSRStatus()

                    self.count = CSRStorage(size=(32 * 1))

                    self.mem_base = CSRStorage(size=32)
                    self.mem_mask = CSRStorage(size=32)
                    self.data_mask = CSRStorage(size=32)  # patterns

                    dma = LiteDRAMDMAWriter(dram_port, fifo_depth=1)
                    self.submodules += dma

                    cmd_counter = Signal(32)

                    self.comb += [
                        w0_port.adr.eq(cmd_counter & self.data_mask.storage),
                        w1_port.adr.eq(cmd_counter & self.data_mask.storage),
                        w2_port.adr.eq(cmd_counter & self.data_mask.storage),
                        w3_port.adr.eq(cmd_counter & self.data_mask.storage),
                        adr_port.adr.eq(cmd_counter & self.data_mask.storage),
                    ]

                    self.comb += [
                        dma.sink.address.eq(self.mem_base.storage +
                                            adr_port.dat_r +
                                            (cmd_counter
                                             & self.mem_mask.storage)),
                        dma.sink.data.eq(
                            Cat(w0_port.dat_r, w1_port.dat_r, w2_port.dat_r,
                                w3_port.dat_r)),
                    ]

                    fsm = FSM(reset_state="IDLE")
                    self.submodules += fsm
                    fsm.act(
                        "IDLE",
                        If(
                            self.start.storage,
                            NextValue(cmd_counter, 0),
                            NextState("WAIT"),
                        ))
                    fsm.act(
                        "WAIT",
                        If(cmd_counter >= self.count.storage,
                           NextState("DONE")).Else(NextState("RUN")))
                    fsm.act(
                        "RUN", dma.sink.valid.eq(1),
                        If(dma.sink.ready,
                           NextValue(cmd_counter, cmd_counter + 1),
                           NextState("WAIT")))
                    fsm.act("DONE", self.done.status.eq(1),
                            If(self.reset.storage, NextState("IDLE")))

            dram_port = self.sdram.crossbar.get_port()
            w0_port = memory_w0.get_port()
            w1_port = memory_w1.get_port()
            w2_port = memory_w2.get_port()
            w3_port = memory_w3.get_port()
            adr_port = memory_adr.get_port()
            self.specials += w0_port, w1_port, w2_port, w3_port, adr_port
            self.submodules.writer = Writer(dram_port, w0_port, w1_port,
                                            w2_port, w3_port, adr_port)
            self.add_csr('writer')

            # ----------------------------- reader -------------------------------------
            memory_rd_w0 = Memory(32, 1024)
            memory_rd_w1 = Memory(32, 1024)
            memory_rd_w2 = Memory(32, 1024)
            memory_rd_w3 = Memory(32, 1024)
            memory_rd_adr = Memory(32, 1024)

            add_xram(self,
                     name='pattern_rd_w0',
                     mem=memory_rd_w0,
                     origin=0x30000000)
            add_xram(self,
                     name='pattern_rd_w1',
                     mem=memory_rd_w1,
                     origin=0x31000000)
            add_xram(self,
                     name='pattern_rd_w2',
                     mem=memory_rd_w2,
                     origin=0x32000000)
            add_xram(self,
                     name='pattern_rd_w3',
                     mem=memory_rd_w3,
                     origin=0x33000000)
            add_xram(self,
                     name='pattern_rd_adr',
                     mem=memory_rd_adr,
                     origin=0x34000000)

            class Reader(Module, AutoCSR):
                def __init__(self, dram_port, w0_port, w1_port, w2_port,
                             w3_port, adr_port):
                    self.reset = CSRStorage()
                    self.start = CSRStorage()
                    self.done = CSRStatus()

                    self.count = CSRStorage(size=32)
                    self.pointer = CSRStatus(size=32)

                    self.mem_base = CSRStorage(size=32)
                    self.mem_mask = CSRStorage(size=32)
                    self.data_mask = CSRStorage(size=32)  # patterns

                    dma = LiteDRAMDMAReader(dram_port,
                                            fifo_depth=1,
                                            fifo_buffered=False)
                    self.submodules += dma

                    cmd_counter = Signal(32)

                    self.comb += [
                        w0_port.adr.eq(cmd_counter & self.data_mask.storage),
                        w1_port.adr.eq(cmd_counter & self.data_mask.storage),
                        w2_port.adr.eq(cmd_counter & self.data_mask.storage),
                        w3_port.adr.eq(cmd_counter & self.data_mask.storage),
                        adr_port.adr.eq(cmd_counter & self.data_mask.storage),
                    ]

                    data_pattern = Signal(32 * 4)
                    self.comb += [
                        dma.sink.address.eq(self.mem_base.storage +
                                            adr_port.dat_r +
                                            (cmd_counter
                                             & self.mem_mask.storage)),
                        data_pattern.eq(
                            Cat(w0_port.dat_r, w1_port.dat_r, w2_port.dat_r,
                                w3_port.dat_r)),
                    ]

                    fsm = FSM(reset_state="IDLE")
                    self.submodules += fsm
                    fsm.act(
                        "IDLE",
                        If(
                            self.start.storage,
                            NextValue(cmd_counter, 0),
                            NextValue(self.pointer.status, 0xdeadbeef),
                            NextState("WAIT"),
                        ))
                    fsm.act(
                        "WAIT",
                        If(cmd_counter >= self.count.storage,
                           NextState("DONE")).Else(NextState("WR_ADR")))
                    fsm.act("WR_ADR", dma.sink.valid.eq(1),
                            If(dma.sink.ready, NextState("RD_DATA")))
                    fsm.act(
                        "RD_DATA", dma.source.ready.eq(1),
                        If(
                            dma.source.valid,
                            NextValue(cmd_counter, cmd_counter + 1),
                            If(dma.source.data != data_pattern,
                               NextValue(self.pointer.status, cmd_counter)),
                            NextState("WAIT")))
                    fsm.act("DONE", self.done.status.eq(1),
                            If(self.reset.storage, NextState("IDLE")))

            dram_rd_port = self.sdram.crossbar.get_port()
            w0_port = memory_rd_w0.get_port()
            w1_port = memory_rd_w1.get_port()
            w2_port = memory_rd_w2.get_port()
            w3_port = memory_rd_w3.get_port()
            adr_port = memory_rd_adr.get_port()
            self.specials += w0_port, w1_port, w2_port, w3_port, adr_port
            self.submodules.reader = Reader(dram_rd_port, w0_port, w1_port,
                                            w2_port, w3_port, adr_port)
            self.add_csr('reader')