+++ /dev/null
-# This file is Copyright (c) 2018-2019 Florent Kermarrec <florent@enjoy-digital.fr>
-# 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)
+++ /dev/null
-# This file is Copyright (c) 2015-2020 Florent Kermarrec <florent@enjoy-digital.fr>
-# This file is Copyright (c) 2020 Antmicro <www.antmicro.com>
-# 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)
- ]