From: Jean THOMAS Date: Mon, 8 Jun 2020 09:16:56 +0000 (+0200) Subject: Clean unused code X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=8f9f888206dca342be20e25098d7476404fe6a64;p=gram.git Clean unused code --- diff --git a/gram/frontend/axi.py b/gram/frontend/axi.py deleted file mode 100644 index c2b868b..0000000 --- a/gram/frontend/axi.py +++ /dev/null @@ -1,196 +0,0 @@ -# This file is Copyright (c) 2018-2019 Florent Kermarrec -# License: BSD - -""" -AXI frontend for LiteDRAM - -Converts AXI ports to Native ports. - -Features: -- Write/Read arbitration. -- Write/Read data buffers (configurable depth). -- Burst support (FIXED/INCR/WRAP). -- ID support (configurable width). - -Limitations: -- Response always okay. -- No reordering. -""" - -from migen import * -from migen.genlib.record import * -from migen.genlib.roundrobin import * - -from litex.soc.interconnect import stream -from litex.soc.interconnect.axi import * - -# LiteDRAMAXIPort ---------------------------------------------------------------------------------- - -class LiteDRAMAXIPort(AXIInterface): - pass - -# LiteDRAMAXI2NativeW ------------------------------------------------------------------------------ - -class LiteDRAMAXI2NativeW(Module): - def __init__(self, axi, port, buffer_depth, base_address): - assert axi.address_width >= log2_int(base_address) - assert axi.data_width == port.data_width - self.cmd_request = Signal() - self.cmd_grant = Signal() - - # # # - - ashift = log2_int(port.data_width//8) - - # Burst to Beat ---------------------------------------------------------------------------- - aw_buffer = stream.Buffer(ax_description(axi.address_width, axi.id_width)) - self.submodules += aw_buffer - self.comb += axi.aw.connect(aw_buffer.sink) - aw = stream.Endpoint(ax_description(axi.address_width, axi.id_width)) - aw_burst2beat = AXIBurst2Beat(aw_buffer.source, aw) - self.submodules.aw_burst2beat = aw_burst2beat - - # Write Buffer ----------------------------------------------------------------------------- - w_buffer = stream.SyncFIFO(w_description(axi.data_width, axi.id_width), - buffer_depth, buffered=True) - self.submodules.w_buffer = w_buffer - - # Write ID Buffer & Response --------------------------------------------------------------- - id_buffer = stream.SyncFIFO([("id", axi.id_width)], buffer_depth) - resp_buffer = stream.SyncFIFO([("id", axi.id_width), ("resp", 2)], buffer_depth) - self.submodules += id_buffer, resp_buffer - self.comb += [ - id_buffer.sink.valid.eq(aw.valid & aw.first & aw.ready), - id_buffer.sink.id.eq(aw.id), - If(w_buffer.source.valid & - w_buffer.source.last & - w_buffer.source.ready, - resp_buffer.sink.valid.eq(1), - resp_buffer.sink.resp.eq(RESP_OKAY), - resp_buffer.sink.id.eq(id_buffer.source.id), - id_buffer.source.ready.eq(1) - ), - resp_buffer.source.connect(axi.b) - ] - - # Command ---------------------------------------------------------------------------------- - # Accept and send command to the controller only if: - # - Address & Data request are *both* valid. - # - Data buffer is not full. - self.comb += [ - self.cmd_request.eq(aw.valid & axi.w.valid & w_buffer.sink.ready), - If(self.cmd_request & self.cmd_grant, - port.cmd.valid.eq(1), - port.cmd.we.eq(1), - port.cmd.addr.eq((aw.addr - base_address) >> ashift), - aw.ready.eq(port.cmd.ready), - axi.w.connect(w_buffer.sink, omit={"valid", "ready"}), - If(port.cmd.ready, - w_buffer.sink.valid.eq(1), - axi.w.ready.eq(1) - ) - ) - ] - - # Write Data ------------------------------------------------------------------------------- - self.comb += [ - w_buffer.source.connect(port.wdata, omit={"strb", "id"}), - port.wdata.we.eq(w_buffer.source.strb) - ] - -# LiteDRAMAXI2NativeR ------------------------------------------------------------------------------ - -class LiteDRAMAXI2NativeR(Module): - def __init__(self, axi, port, buffer_depth, base_address): - assert axi.address_width >= log2_int(base_address) - assert axi.data_width == port.data_width - self.cmd_request = Signal() - self.cmd_grant = Signal() - - # # # - - can_read = Signal() - - ashift = log2_int(port.data_width//8) - - # Burst to Beat ---------------------------------------------------------------------------- - ar_buffer = stream.Buffer(ax_description(axi.address_width, axi.id_width)) - self.submodules += ar_buffer - self.comb += axi.ar.connect(ar_buffer.sink) - ar = stream.Endpoint(ax_description(axi.address_width, axi.id_width)) - ar_burst2beat = AXIBurst2Beat(ar_buffer.source, ar) - self.submodules.ar_burst2beat = ar_burst2beat - - # Read buffer ------------------------------------------------------------------------------ - r_buffer = stream.SyncFIFO(r_description(axi.data_width, axi.id_width), buffer_depth, buffered=True) - self.submodules.r_buffer = r_buffer - - # Read Buffer reservation ------------------------------------------------------------------ - # - Incremented when data is planned to be queued - # - Decremented when data is dequeued - r_buffer_queue = Signal() - r_buffer_dequeue = Signal() - r_buffer_level = Signal(max=buffer_depth + 1) - self.comb += [ - r_buffer_queue.eq(port.cmd.valid & port.cmd.ready & ~port.cmd.we), - r_buffer_dequeue.eq(r_buffer.source.valid & r_buffer.source.ready) - ] - self.sync += [ - If(r_buffer_queue, - If(~r_buffer_dequeue, r_buffer_level.eq(r_buffer_level + 1)) - ).Elif(r_buffer_dequeue, - r_buffer_level.eq(r_buffer_level - 1) - ) - ] - self.comb += can_read.eq(r_buffer_level != buffer_depth) - - # Read ID Buffer --------------------------------------------------------------------------- - id_buffer = stream.SyncFIFO([("id", axi.id_width)], buffer_depth) - self.submodules += id_buffer - self.comb += [ - id_buffer.sink.valid.eq(ar.valid & ar.ready), - id_buffer.sink.last.eq(ar.last), - id_buffer.sink.id.eq(ar.id), - axi.r.last.eq(id_buffer.source.last), - axi.r.id.eq(id_buffer.source.id), - id_buffer.source.ready.eq(axi.r.valid & axi.r.ready) - ] - - # Command ---------------------------------------------------------------------------------- - self.comb += [ - self.cmd_request.eq(ar.valid & can_read), - If(self.cmd_grant, - port.cmd.valid.eq(ar.valid & can_read), - ar.ready.eq(port.cmd.ready & can_read), - port.cmd.we.eq(0), - port.cmd.addr.eq((ar.addr - base_address) >> ashift) - ) - ] - - # Read data -------------------------------------------------------------------------------- - self.comb += [ - port.rdata.connect(r_buffer.sink, omit={"bank"}), - r_buffer.source.connect(axi.r, omit={"id", "last"}), - axi.r.resp.eq(RESP_OKAY) - ] - -# LiteDRAMAXI2Native ------------------------------------------------------------------------------- - -class LiteDRAMAXI2Native(Module): - def __init__(self, axi, port, w_buffer_depth=16, r_buffer_depth=16, base_address=0x00000000): - - # # # - - # Write path ------------------------------------------------------------------------------- - self.submodules.write = LiteDRAMAXI2NativeW(axi, port, w_buffer_depth, base_address) - - # Read path -------------------------------------------------------------------------------- - self.submodules.read = LiteDRAMAXI2NativeR(axi, port, r_buffer_depth, base_address) - - # Write / Read arbitration ----------------------------------------------------------------- - arbiter = RoundRobin(2) - self.submodules += arbiter - self.comb += arbiter.stb.eq(~port.cmd.valid | port.cmd.ready) - for i, master in enumerate([self.write, self.read]): - self.comb += arbiter.request[i].eq(master.cmd_request) - self.comb += master.cmd_grant.eq(arbiter.grant == i) diff --git a/gram/phy/model.py b/gram/phy/model.py deleted file mode 100644 index 4a63a2c..0000000 --- a/gram/phy/model.py +++ /dev/null @@ -1,607 +0,0 @@ -# This file is Copyright (c) 2015-2020 Florent Kermarrec -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -# SDRAM simulation PHY at DFI level tested with SDR/DDR/DDR2/LPDDR/DDR3 -# TODO: -# - add multirank support. - -from nmigen import * - -from gram.common import burst_lengths -from gram.phy.dfi import * -from gram.modules import _speedgrade_timings, _technology_timings - -from functools import reduce -from operator import or_ - -import struct - - -SDRAM_VERBOSE_OFF = 0 -SDRAM_VERBOSE_STD = 1 -SDRAM_VERBOSE_DBG = 2 - -# Bank Model --------------------------------------------------------------------------------------- - -class BankModel(Module): - def __init__(self, data_width, nrows, ncols, burst_length, nphases, we_granularity, init): - self.activate = Signal() - self.activate_row = Signal(max=nrows) - self.precharge = Signal() - - self.write = Signal() - self.write_col = Signal(max=ncols) - self.write_data = Signal(data_width) - self.write_mask = Signal(data_width//8) - - self.read = Signal() - self.read_col = Signal(max=ncols) - self.read_data = Signal(data_width) - - # # # - - active = Signal() - row = Signal(max=nrows) - - self.sync += \ - If(self.precharge, - active.eq(0), - ).Elif(self.activate, - active.eq(1), - row.eq(self.activate_row) - ) - - bank_mem_len = nrows*ncols//(burst_length*nphases) - mem = Memory(data_width, bank_mem_len, init=init) - write_port = mem.get_port(write_capable=True, we_granularity=we_granularity) - read_port = mem.get_port(async_read=True) - self.specials += mem, read_port, write_port - - wraddr = Signal(max=bank_mem_len) - rdaddr = Signal(max=bank_mem_len) - - self.comb += [ - wraddr.eq((row*ncols | self.write_col)[log2_int(burst_length*nphases):]), - rdaddr.eq((row*ncols | self.read_col)[log2_int(burst_length*nphases):]), - ] - - self.comb += [ - If(active, - write_port.adr.eq(wraddr), - write_port.dat_w.eq(self.write_data), - If(we_granularity, - write_port.we.eq(Repl(self.write, data_width//8) & ~self.write_mask), - ).Else( - write_port.we.eq(self.write), - ), - If(self.read, - read_port.adr.eq(rdaddr), - self.read_data.eq(read_port.dat_r) - ) - ) - ] - -# DFI Phase Model ---------------------------------------------------------------------------------- - -class DFIPhaseModel(Module): - def __init__(self, dfi, n): - phase = getattr(dfi, "p"+str(n)) - - self.bank = phase.bank - self.address = phase.address - - self.wrdata = phase.wrdata - self.wrdata_mask = phase.wrdata_mask - - self.rddata = phase.rddata - self.rddata_valid = phase.rddata_valid - - self.activate = Signal() - self.precharge = Signal() - self.write = Signal() - self.read = Signal() - - # # # - - self.comb += [ - If(~phase.cs_n & ~phase.ras_n & phase.cas_n, - self.activate.eq(phase.we_n), - self.precharge.eq(~phase.we_n) - ), - If(~phase.cs_n & phase.ras_n & ~phase.cas_n, - self.write.eq(~phase.we_n), - self.read.eq(phase.we_n) - ) - ] - -# DFI Timings Checker ------------------------------------------------------------------------------ - -class SDRAMCMD: - def __init__(self, name: str, enc: int, idx: int): - self.name = name - self.enc = enc - self.idx = idx - - -class TimingRule: - def __init__(self, prev: str, curr: str, delay: int): - self.name = prev + "->" + curr - self.prev = prev - self.curr = curr - self.delay = delay - - -class DFITimingsChecker(Module): - CMDS = [ - # Name, cs & ras & cas & we value - ("PRE", "0010"), # Precharge - ("REF", "0001"), # Self refresh - ("ACT", "0011"), # Activate - ("RD", "0101"), # Read - ("WR", "0100"), # Write - ("ZQCS", "0110"), # ZQCS - ] - - RULES = [ - # tRP - ("PRE", "ACT", "tRP"), - ("PRE", "REF", "tRP"), - # tRCD - ("ACT", "WR", "tRCD"), - ("ACT", "RD", "tRCD"), - # tRAS - ("ACT", "PRE", "tRAS"), - # tRFC - ("REF", "PRE", "tRFC"), - ("REF", "ACT", "tRFC"), - # tCCD - ("WR", "RD", "tCCD"), - ("WR", "WR", "tCCD"), - ("RD", "RD", "tCCD"), - ("RD", "WR", "tCCD"), - # tRC - ("ACT", "ACT", "tRC"), - # tWR - ("WR", "PRE", "tWR"), - # tWTR - ("WR", "RD", "tWTR"), - # tZQCS - ("ZQCS", "ACT", "tZQCS"), - ] - - def add_cmds(self): - self.cmds = {} - for idx, (name, pattern) in enumerate(self.CMDS): - self.cmds[name] = SDRAMCMD(name, int(pattern, 2), idx) - - def add_rule(self, prev, curr, delay): - if not isinstance(delay, int): - delay = self.timings[delay] - self.rules.append(TimingRule(prev, curr, delay)) - - def add_rules(self): - self.rules = [] - for rule in self.RULES: - self.add_rule(*rule) - - # Convert ns to ps - def ns_to_ps(self, val): - return int(val * 1e3) - - def ck_ns_to_ps(self, val, tck): - c, t = val - c = 0 if c is None else c * tck - t = 0 if t is None else t - return self.ns_to_ps(max(c, t)) - - def prepare_timings(self, timings, refresh_mode, memtype): - CK_NS = ["tRFC", "tWTR", "tFAW", "tCCD", "tRRD", "tZQCS"] - REF = ["tREFI", "tRFC"] - self.timings = timings - new_timings = {} - - tck = self.timings["tCK"] - - for key, val in self.timings.items(): - if refresh_mode is not None and key in REF: - val = val[refresh_mode] - - if val is None: - val = 0 - elif key in CK_NS: - val = self.ck_ns_to_ps(val, tck) - else: - val = self.ns_to_ps(val) - - new_timings[key] = val - - new_timings["tRC"] = new_timings["tRAS"] + new_timings["tRP"] - - # Adjust timings relative to write burst - tWR & tWTR - wrburst = burst_lengths[memtype] if memtype == "SDR" else burst_lengths[memtype] // 2 - wrburst = (new_timings["tCK"] * (wrburst - 1)) - new_timings["tWR"] = new_timings["tWR"] + wrburst - new_timings["tWTR"] = new_timings["tWTR"] + wrburst - - self.timings = new_timings - - def __init__(self, dfi, nbanks, nphases, timings, refresh_mode, memtype, verbose=False): - self.prepare_timings(timings, refresh_mode, memtype) - self.add_cmds() - self.add_rules() - - cnt = Signal(64) - self.sync += cnt.eq(cnt + nphases) - - phases = [getattr(dfi, "p" + str(n)) for n in range(nphases)] - - last_cmd_ps = [[Signal.like(cnt) for _ in range(len(self.cmds))] for _ in range(nbanks)] - last_cmd = [Signal(4) for i in range(nbanks)] - - act_ps = Array([Signal().like(cnt) for i in range(4)]) - act_curr = Signal(max=4) - - ref_issued = Signal(nphases) - - for np, phase in enumerate(phases): - ps = Signal().like(cnt) - self.comb += ps.eq((cnt + np)*self.timings["tCK"]) - state = Signal(4) - self.comb += state.eq(Cat(phase.we_n, phase.cas_n, phase.ras_n, phase.cs_n)) - all_banks = Signal() - - self.comb += all_banks.eq( - (self.cmds["REF"].enc == state) | - ((self.cmds["PRE"].enc == state) & phase.address[10]) - ) - - # tREFI - self.comb += ref_issued[np].eq(self.cmds["REF"].enc == state) - - # Print debug information - if verbose: - for _, cmd in self.cmds.items(): - self.sync += [ - If(state == cmd.enc, - If(all_banks, - Display("[%016dps] P%0d " + cmd.name, ps, np) - ).Else( - Display("[%016dps] P%0d B%0d " + cmd.name, ps, np, phase.bank) - ) - ) - ] - - # Bank command monitoring - for i in range(nbanks): - for _, curr in self.cmds.items(): - cmd_recv = Signal() - self.comb += cmd_recv.eq(((phase.bank == i) | all_banks) & (state == curr.enc)) - - # Checking rules from self.rules - for _, prev in self.cmds.items(): - for rule in self.rules: - if rule.prev == prev.name and rule.curr == curr.name: - self.sync += [ - If(cmd_recv & (last_cmd[i] == prev.enc) & - (ps < (last_cmd_ps[i][prev.idx] + rule.delay)), - Display("[%016dps] {} violation on bank %0d".format(rule.name), ps, i) - ) - ] - - # Save command timestamp in an array - self.sync += If(cmd_recv, last_cmd_ps[i][curr.idx].eq(ps), last_cmd[i].eq(state)) - - # tRRD & tFAW - if curr.name == "ACT": - act_next = Signal().like(act_curr) - self.comb += act_next.eq(act_curr+1) - - # act_curr points to newest ACT timestamp - self.sync += [ - If(cmd_recv & (ps < (act_ps[act_curr] + self.timings["tRRD"])), - Display("[%016dps] tRRD violation on bank %0d", ps, i) - ) - ] - - # act_next points to the oldest ACT timestamp - self.sync += [ - If(cmd_recv & (ps < (act_ps[act_next] + self.timings["tFAW"])), - Display("[%016dps] tFAW violation on bank %0d", ps, i) - ) - ] - - # Save ACT timestamp in a circular buffer - self.sync += If(cmd_recv, act_ps[act_next].eq(ps), act_curr.eq(act_next)) - - # tREFI - ref_ps = Signal().like(cnt) - ref_ps_mod = Signal().like(cnt) - ref_ps_diff = Signal(min=-2**63, max=2**63) - curr_diff = Signal().like(ref_ps_diff) - - self.comb += curr_diff.eq(ps - (ref_ps + self.timings["tREFI"])) - - # Work in 64ms periods - self.sync += [ - If(ref_ps_mod < int(64e9), - ref_ps_mod.eq(ref_ps_mod + nphases * self.timings["tCK"]) - ).Else( - ref_ps_mod.eq(0) - ) - ] - - # Update timestamp and difference - self.sync += If(ref_issued != 0, ref_ps.eq(ps), ref_ps_diff.eq(ref_ps_diff - curr_diff)) - - self.sync += [ - If((ref_ps_mod == 0) & (ref_ps_diff > 0), - Display("[%016dps] tREFI violation (64ms period): %0d", ps, ref_ps_diff) - ) - ] - - # Report any refresh periods longer than tREFI - if verbose: - ref_done = Signal() - self.sync += [ - If(ref_issued != 0, - ref_done.eq(1), - If(~ref_done, - Display("[%016dps] Late refresh", ps) - ) - ) - ] - - self.sync += [ - If((curr_diff > 0) & ref_done & (ref_issued == 0), - Display("[%016dps] tREFI violation", ps), - ref_done.eq(0) - ) - ] - - # There is a maximum delay between refreshes on >=DDR - ref_limit = {"1x": 9, "2x": 17, "4x": 36} - if memtype != "SDR": - refresh_mode = "1x" if refresh_mode is None else refresh_mode - ref_done = Signal() - self.sync += If(ref_issued != 0, ref_done.eq(1)) - self.sync += [ - If((ref_issued == 0) & ref_done & - (ref_ps > (ps + ref_limit[refresh_mode] * self.timings['tREFI'])), - Display("[%016dps] tREFI violation (too many postponed refreshes)", ps), - ref_done.eq(0) - ) - ] - -# SDRAM PHY Model ---------------------------------------------------------------------------------- - -class SDRAMPHYModel(Module): - def __prepare_bank_init_data(self, init, nbanks, nrows, ncols, data_width, address_mapping): - mem_size = (self.settings.databits//8)*(nrows*ncols*nbanks) - bank_size = mem_size // nbanks - column_size = bank_size // nrows - model_bank_size = bank_size // (data_width//8) - model_column_size = model_bank_size // nrows - model_data_ratio = data_width // 32 - data_width_bytes = data_width // 8 - bank_init = [[] for i in range(nbanks)] - - # Pad init if too short - if len(init)%data_width_bytes != 0: - init.extend([0]*(data_width_bytes-len(init)%data_width_bytes)) - - - # Convert init data width from 32-bit to data_width if needed - if model_data_ratio > 1: - new_init = [0]*(len(init)//model_data_ratio) - for i in range(0, len(init), model_data_ratio): - ints = init[i:i+model_data_ratio] - strs = "".join("{:08x}".format(x) for x in reversed(ints)) - new_init[i//model_data_ratio] = int(strs, 16) - init = new_init - elif model_data_ratio == 0: - assert data_width_bytes in [1, 2] - model_data_ratio = 4 // data_width_bytes - struct_unpack_patterns = {1: "4B", 2: "2H"} - new_init = [0]*int(len(init)*model_data_ratio) - for i in range(len(init)): - new_init[model_data_ratio*i:model_data_ratio*(i+1)] = struct.unpack( - struct_unpack_patterns[data_width_bytes], - struct.pack("I", init[i]) - )[0:model_data_ratio] - init = new_init - - if address_mapping == "ROW_BANK_COL": - for row in range(nrows): - for bank in range(nbanks): - start = (row*nbanks*model_column_size + bank*model_column_size) - end = min(start + model_column_size, len(init)) - if start > len(init): - break - bank_init[bank].extend(init[start:end]) - elif address_mapping == "BANK_ROW_COL": - for bank in range(nbanks): - start = bank*model_bank_size - end = min(start + model_bank_size, len(init)) - if start > len(init): - break - bank_init[bank] = init[start:end] - - return bank_init - - def __init__(self, module, settings, clk_freq=100e6, - we_granularity = 8, - init = [], - address_mapping = "ROW_BANK_COL", - verbosity = SDRAM_VERBOSE_OFF): - - # Parameters ------------------------------------------------------------------------------- - burst_length = { - "SDR": 1, - "DDR": 2, - "LPDDR": 2, - "DDR2": 2, - "DDR3": 2, - "DDR4": 2, - }[settings.memtype] - - addressbits = module.geom_settings.addressbits - bankbits = module.geom_settings.bankbits - rowbits = module.geom_settings.rowbits - colbits = module.geom_settings.colbits - - self.settings = settings - self.module = module - - # DFI Interface ---------------------------------------------------------------------------- - self.dfi = Interface( - addressbits = addressbits, - bankbits = bankbits, - nranks = self.settings.nranks, - databits = self.settings.dfi_databits, - nphases = self.settings.nphases - ) - - # # # - - nphases = self.settings.nphases - nbanks = 2**bankbits - nrows = 2**rowbits - ncols = 2**colbits - data_width = self.settings.dfi_databits*self.settings.nphases - - # DFI phases ------------------------------------------------------------------------------- - phases = [DFIPhaseModel(self.dfi, n) for n in range(self.settings.nphases)] - self.submodules += phases - - # DFI timing checker ----------------------------------------------------------------------- - if verbosity > SDRAM_VERBOSE_OFF: - timings = {"tCK": (1e9 / clk_freq) / nphases} - - for name in _speedgrade_timings + _technology_timings: - timings[name] = self.module.get(name) - - timing_checker = DFITimingsChecker( - dfi = self.dfi, - nbanks = nbanks, - nphases = nphases, - timings = timings, - refresh_mode = self.module.timing_settings.fine_refresh_mode, - memtype = settings.memtype, - verbose = verbosity > SDRAM_VERBOSE_DBG) - self.submodules += timing_checker - - # Bank init data --------------------------------------------------------------------------- - bank_init = [[] for i in range(nbanks)] - - if init: - bank_init = self.__prepare_bank_init_data( - init = init, - nbanks = nbanks, - nrows = nrows, - ncols = ncols, - data_width = data_width, - address_mapping = address_mapping - ) - - # Banks ------------------------------------------------------------------------------------ - banks = [BankModel( - data_width = data_width, - nrows = nrows, - ncols = ncols, - burst_length = burst_length, - nphases = nphases, - we_granularity = we_granularity, - init = bank_init[i]) for i in range(nbanks)] - self.submodules += banks - - # Connect DFI phases to Banks (CMDs, Write datapath) --------------------------------------- - for nb, bank in enumerate(banks): - # Bank activate - activates = Signal(len(phases)) - cases = {} - for np, phase in enumerate(phases): - self.comb += activates[np].eq(phase.activate) - cases[2**np] = [ - bank.activate.eq(phase.bank == nb), - bank.activate_row.eq(phase.address) - ] - self.comb += Case(activates, cases) - - # Bank precharge - precharges = Signal(len(phases)) - cases = {} - for np, phase in enumerate(phases): - self.comb += precharges[np].eq(phase.precharge) - cases[2**np] = [ - bank.precharge.eq((phase.bank == nb) | phase.address[10]) - ] - self.comb += Case(precharges, cases) - - # Bank writes - bank_write = Signal() - bank_write_col = Signal(max=ncols) - writes = Signal(len(phases)) - cases = {} - for np, phase in enumerate(phases): - self.comb += writes[np].eq(phase.write) - cases[2**np] = [ - bank_write.eq(phase.bank == nb), - bank_write_col.eq(phase.address) - ] - self.comb += Case(writes, cases) - self.comb += [ - bank.write_data.eq(Cat(*[phase.wrdata for phase in phases])), - bank.write_mask.eq(Cat(*[phase.wrdata_mask for phase in phases])) - ] - - # Simulate write latency - for i in range(self.settings.write_latency): - new_bank_write = Signal() - new_bank_write_col = Signal(max=ncols) - self.sync += [ - new_bank_write.eq(bank_write), - new_bank_write_col.eq(bank_write_col) - ] - bank_write = new_bank_write - bank_write_col = new_bank_write_col - - self.comb += [ - bank.write.eq(bank_write), - bank.write_col.eq(bank_write_col) - ] - - # Bank reads - reads = Signal(len(phases)) - cases = {} - for np, phase in enumerate(phases): - self.comb += reads[np].eq(phase.read) - cases[2**np] = [ - bank.read.eq(phase.bank == nb), - bank.read_col.eq(phase.address) - ] - self.comb += Case(reads, cases) - - # Connect Banks to DFI phases (CMDs, Read datapath) ---------------------------------------- - banks_read = Signal() - banks_read_data = Signal(data_width) - self.comb += [ - banks_read.eq(reduce(or_, [bank.read for bank in banks])), - banks_read_data.eq(reduce(or_, [bank.read_data for bank in banks])) - ] - - # Simulate read latency -------------------------------------------------------------------- - for i in range(self.settings.read_latency): - new_banks_read = Signal() - new_banks_read_data = Signal(data_width) - self.sync += [ - new_banks_read.eq(banks_read), - new_banks_read_data.eq(banks_read_data) - ] - banks_read = new_banks_read - banks_read_data = new_banks_read_data - - self.comb += [ - Cat(*[phase.rddata_valid for phase in phases]).eq(banks_read), - Cat(*[phase.rddata for phase in phases]).eq(banks_read_data) - ]