From: Florent Kermarrec Date: Tue, 3 Mar 2015 08:49:57 +0000 (+0100) Subject: sdram: move lasmibus to core, rename crossbar to lasmixbar and move it to core, move... X-Git-Tag: 24jan2021_ls180~2517 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=905be504514359ad4b354484982ee4a4a0e747e3;p=litex.git sdram: move lasmibus to core, rename crossbar to lasmixbar and move it to core, move dfi to phy --- diff --git a/misoclib/mem/sdram/bus/dfi.py b/misoclib/mem/sdram/bus/dfi.py deleted file mode 100644 index fa80f9c8..00000000 --- a/misoclib/mem/sdram/bus/dfi.py +++ /dev/null @@ -1,67 +0,0 @@ -from migen.fhdl.std import * -from migen.genlib.record import * - -def phase_cmd_description(a, ba): - return [ - ("address", a, DIR_M_TO_S), - ("bank", ba, DIR_M_TO_S), - ("cas_n", 1, DIR_M_TO_S), - ("cs_n", 1, DIR_M_TO_S), - ("ras_n", 1, DIR_M_TO_S), - ("we_n", 1, DIR_M_TO_S), - ("cke", 1, DIR_M_TO_S), - ("odt", 1, DIR_M_TO_S), - ("reset_n", 1, DIR_M_TO_S) - ] - -def phase_wrdata_description(d): - return [ - ("wrdata", d, DIR_M_TO_S), - ("wrdata_en", 1, DIR_M_TO_S), - ("wrdata_mask", d//8, DIR_M_TO_S) - ] - -def phase_rddata_description(d): - return [ - ("rddata_en", 1, DIR_M_TO_S), - ("rddata", d, DIR_S_TO_M), - ("rddata_valid", 1, DIR_S_TO_M) - ] - -def phase_description(a, ba, d): - r = phase_cmd_description(a, ba) - r += phase_wrdata_description(d) - r += phase_rddata_description(d) - return r - -class Interface(Record): - def __init__(self, a, ba, d, nphases=1): - layout = [("p"+str(i), phase_description(a, ba, d)) for i in range(nphases)] - Record.__init__(self, layout) - self.phases = [getattr(self, "p"+str(i)) for i in range(nphases)] - for p in self.phases: - p.cas_n.reset = 1 - p.cs_n.reset = 1 - p.ras_n.reset = 1 - p.we_n.reset = 1 - - # Returns pairs (DFI-mandated signal name, Migen signal object) - def get_standard_names(self, m2s=True, s2m=True): - r = [] - add_suffix = len(self.phases) > 1 - for n, phase in enumerate(self.phases): - for field, size, direction in phase.layout: - if (m2s and direction == DIR_M_TO_S) or (s2m and direction == DIR_S_TO_M): - if add_suffix: - if direction == DIR_M_TO_S: - suffix = "_p" + str(n) - else: - suffix = "_w" + str(n) - else: - suffix = "" - r.append(("dfi_" + field + suffix, getattr(phase, field))) - return r - -class Interconnect(Module): - def __init__(self, master, slave): - self.comb += master.connect(slave) diff --git a/misoclib/mem/sdram/bus/lasmibus.py b/misoclib/mem/sdram/bus/lasmibus.py deleted file mode 100644 index 7578d0ec..00000000 --- a/misoclib/mem/sdram/bus/lasmibus.py +++ /dev/null @@ -1,159 +0,0 @@ -from migen.fhdl.std import * -from migen.bus.transactions import * -from migen.genlib import roundrobin -from migen.genlib.record import * -from migen.genlib.misc import optree - -class Interface(Record): - def __init__(self, aw, dw, nbanks, req_queue_size, read_latency, write_latency): - self.aw = aw - self.dw = dw - self.nbanks = nbanks - self.req_queue_size = req_queue_size - self.read_latency = read_latency - self.write_latency = write_latency - - bank_layout = [ - ("adr", aw, DIR_M_TO_S), - ("we", 1, DIR_M_TO_S), - ("stb", 1, DIR_M_TO_S), - ("req_ack", 1, DIR_S_TO_M), - ("dat_w_ack", 1, DIR_S_TO_M), - ("dat_r_ack", 1, DIR_S_TO_M), - ("lock", 1, DIR_S_TO_M) - ] - if nbanks > 1: - layout = [("bank"+str(i), bank_layout) for i in range(nbanks)] - else: - layout = bank_layout - layout += [ - ("dat_w", dw, DIR_M_TO_S), - ("dat_we", dw//8, DIR_M_TO_S), - ("dat_r", dw, DIR_S_TO_M) - ] - Record.__init__(self, layout) - -class Initiator(Module): - def __init__(self, generator, bus): - self.generator = generator - self.bus = bus - self.transaction_start = 0 - self.transaction = None - self.transaction_end = None - - def do_simulation(self, selfp): - selfp.bus.dat_w = 0 - selfp.bus.dat_we = 0 - - if self.transaction is not None: - if selfp.bus.req_ack: - selfp.bus.stb = 0 - if selfp.bus.dat_ack: - if isinstance(self.transaction, TRead): - self.transaction_end = selfp.simulator.cycle_counter + self.bus.read_latency - else: - self.transaction_end = selfp.simulator.cycle_counter + self.bus.write_latency - 1 - - if self.transaction is None or selfp.simulator.cycle_counter == self.transaction_end: - if self.transaction is not None: - self.transaction.latency = selfp.simulator.cycle_counter - self.transaction_start - 1 - if isinstance(self.transaction, TRead): - self.transaction.data = selfp.bus.dat_r - else: - selfp.bus.dat_w = self.transaction.data - selfp.bus.dat_we = self.transaction.sel - try: - self.transaction = next(self.generator) - except StopIteration: - raise StopSimulation - if self.transaction is not None: - self.transaction_start = selfp.simulator.cycle_counter - selfp.bus.stb = 1 - selfp.bus.adr = self.transaction.address - if isinstance(self.transaction, TRead): - selfp.bus.we = 0 - else: - selfp.bus.we = 1 - -class TargetModel: - def __init__(self): - self.last_bank = 0 - - def read(self, bank, address): - return 0 - - def write(self, bank, address, data, we): - pass - - # Round-robin scheduling - def select_bank(self, pending_banks): - if not pending_banks: - return -1 - self.last_bank += 1 - if self.last_bank > max(pending_banks): - self.last_bank = 0 - while self.last_bank not in pending_banks: - self.last_bank += 1 - return self.last_bank - -class _ReqFIFO(Module): - def __init__(self, req_queue_size, bank): - self.req_queue_size = req_queue_size - self.bank = bank - self.contents = [] - - def do_simulation(self, selfp): - if len(self.contents) < self.req_queue_size: - if selfp.bank.stb: - self.contents.append((selfp.bank.we, selfp.bank.adr)) - selfp.bank.req_ack = 1 - else: - selfp.bank.req_ack = 0 - selfp.bank.lock = bool(self.contents) - do_simulation.passive = True - -class Target(Module): - def __init__(self, model, *ifargs, **ifkwargs): - self.model = model - self.bus = Interface(*ifargs, **ifkwargs) - self.req_fifos = [_ReqFIFO(self.bus.req_queue_size, getattr(self.bus, "bank"+str(nb))) - for nb in range(self.bus.nbanks)] - self.submodules += self.req_fifos - self.rd_pipeline = [None]*self.bus.read_latency - self.wr_pipeline = [None]*(self.bus.write_latency + 1) - - def do_simulation(self, selfp): - # determine banks with pending requests - pending_banks = set(nb for nb, rf in enumerate(self.req_fifos) if rf.contents) - - # issue new transactions - selected_bank_n = self.model.select_bank(pending_banks) - selected_transaction = None - for nb in range(self.bus.nbanks): - bank = getattr(selfp.bus, "bank"+str(nb)) - if nb == selected_bank_n: - bank.dat_ack = 1 - selected_transaction = self.req_fifos[nb].contents.pop(0) - else: - bank.dat_ack = 0 - - rd_transaction = None - wr_transaction = None - if selected_bank_n >= 0: - we, adr = selected_transaction - if we: - wr_transaction = selected_bank_n, adr - else: - rd_transaction = selected_bank_n, adr - - # data pipeline - self.rd_pipeline.append(rd_transaction) - self.wr_pipeline.append(wr_transaction) - done_rd_transaction = self.rd_pipeline.pop(0) - done_wr_transaction = self.wr_pipeline.pop(0) - if done_rd_transaction is not None: - selfp.bus.dat_r = self.model.read(done_rd_transaction[0], done_rd_transaction[1]) - if done_wr_transaction is not None: - self.model.write(done_wr_transaction[0], done_wr_transaction[1], - selfp.bus.dat_w, selfp.bus.dat_we) - do_simulation.passive = True diff --git a/misoclib/mem/sdram/core/__init__.py b/misoclib/mem/sdram/core/__init__.py index a4b526c5..f3127752 100644 --- a/misoclib/mem/sdram/core/__init__.py +++ b/misoclib/mem/sdram/core/__init__.py @@ -4,7 +4,7 @@ from migen.bank.description import * from misoclib.mem.sdram.phy import dfii from misoclib.mem.sdram.core import minicon, lasmicon -from misoclib.mem.sdram.core.lasmicon.crossbar import Crossbar +from misoclib.mem.sdram.core import lasmixbar class SDRAMCore(Module, AutoCSR): def __init__(self, phy, ramcon_type, sdram_geom, sdram_timing, **kwargs): @@ -18,7 +18,7 @@ class SDRAMCore(Module, AutoCSR): self.submodules.controller = controller = lasmicon.LASMIcon(phy.settings, sdram_geom, sdram_timing, **kwargs) self.comb += Record.connect(controller.dfi, self.dfii.slave) - self.submodules.crossbar = crossbar = Crossbar([controller.lasmic], controller.nrowbits) + self.submodules.crossbar = crossbar = lasmixbar.LASMIxbar([controller.lasmic], controller.nrowbits) # MINICON elif ramcon_type == "minicon": diff --git a/misoclib/mem/sdram/core/lasmibus.py b/misoclib/mem/sdram/core/lasmibus.py new file mode 100644 index 00000000..7578d0ec --- /dev/null +++ b/misoclib/mem/sdram/core/lasmibus.py @@ -0,0 +1,159 @@ +from migen.fhdl.std import * +from migen.bus.transactions import * +from migen.genlib import roundrobin +from migen.genlib.record import * +from migen.genlib.misc import optree + +class Interface(Record): + def __init__(self, aw, dw, nbanks, req_queue_size, read_latency, write_latency): + self.aw = aw + self.dw = dw + self.nbanks = nbanks + self.req_queue_size = req_queue_size + self.read_latency = read_latency + self.write_latency = write_latency + + bank_layout = [ + ("adr", aw, DIR_M_TO_S), + ("we", 1, DIR_M_TO_S), + ("stb", 1, DIR_M_TO_S), + ("req_ack", 1, DIR_S_TO_M), + ("dat_w_ack", 1, DIR_S_TO_M), + ("dat_r_ack", 1, DIR_S_TO_M), + ("lock", 1, DIR_S_TO_M) + ] + if nbanks > 1: + layout = [("bank"+str(i), bank_layout) for i in range(nbanks)] + else: + layout = bank_layout + layout += [ + ("dat_w", dw, DIR_M_TO_S), + ("dat_we", dw//8, DIR_M_TO_S), + ("dat_r", dw, DIR_S_TO_M) + ] + Record.__init__(self, layout) + +class Initiator(Module): + def __init__(self, generator, bus): + self.generator = generator + self.bus = bus + self.transaction_start = 0 + self.transaction = None + self.transaction_end = None + + def do_simulation(self, selfp): + selfp.bus.dat_w = 0 + selfp.bus.dat_we = 0 + + if self.transaction is not None: + if selfp.bus.req_ack: + selfp.bus.stb = 0 + if selfp.bus.dat_ack: + if isinstance(self.transaction, TRead): + self.transaction_end = selfp.simulator.cycle_counter + self.bus.read_latency + else: + self.transaction_end = selfp.simulator.cycle_counter + self.bus.write_latency - 1 + + if self.transaction is None or selfp.simulator.cycle_counter == self.transaction_end: + if self.transaction is not None: + self.transaction.latency = selfp.simulator.cycle_counter - self.transaction_start - 1 + if isinstance(self.transaction, TRead): + self.transaction.data = selfp.bus.dat_r + else: + selfp.bus.dat_w = self.transaction.data + selfp.bus.dat_we = self.transaction.sel + try: + self.transaction = next(self.generator) + except StopIteration: + raise StopSimulation + if self.transaction is not None: + self.transaction_start = selfp.simulator.cycle_counter + selfp.bus.stb = 1 + selfp.bus.adr = self.transaction.address + if isinstance(self.transaction, TRead): + selfp.bus.we = 0 + else: + selfp.bus.we = 1 + +class TargetModel: + def __init__(self): + self.last_bank = 0 + + def read(self, bank, address): + return 0 + + def write(self, bank, address, data, we): + pass + + # Round-robin scheduling + def select_bank(self, pending_banks): + if not pending_banks: + return -1 + self.last_bank += 1 + if self.last_bank > max(pending_banks): + self.last_bank = 0 + while self.last_bank not in pending_banks: + self.last_bank += 1 + return self.last_bank + +class _ReqFIFO(Module): + def __init__(self, req_queue_size, bank): + self.req_queue_size = req_queue_size + self.bank = bank + self.contents = [] + + def do_simulation(self, selfp): + if len(self.contents) < self.req_queue_size: + if selfp.bank.stb: + self.contents.append((selfp.bank.we, selfp.bank.adr)) + selfp.bank.req_ack = 1 + else: + selfp.bank.req_ack = 0 + selfp.bank.lock = bool(self.contents) + do_simulation.passive = True + +class Target(Module): + def __init__(self, model, *ifargs, **ifkwargs): + self.model = model + self.bus = Interface(*ifargs, **ifkwargs) + self.req_fifos = [_ReqFIFO(self.bus.req_queue_size, getattr(self.bus, "bank"+str(nb))) + for nb in range(self.bus.nbanks)] + self.submodules += self.req_fifos + self.rd_pipeline = [None]*self.bus.read_latency + self.wr_pipeline = [None]*(self.bus.write_latency + 1) + + def do_simulation(self, selfp): + # determine banks with pending requests + pending_banks = set(nb for nb, rf in enumerate(self.req_fifos) if rf.contents) + + # issue new transactions + selected_bank_n = self.model.select_bank(pending_banks) + selected_transaction = None + for nb in range(self.bus.nbanks): + bank = getattr(selfp.bus, "bank"+str(nb)) + if nb == selected_bank_n: + bank.dat_ack = 1 + selected_transaction = self.req_fifos[nb].contents.pop(0) + else: + bank.dat_ack = 0 + + rd_transaction = None + wr_transaction = None + if selected_bank_n >= 0: + we, adr = selected_transaction + if we: + wr_transaction = selected_bank_n, adr + else: + rd_transaction = selected_bank_n, adr + + # data pipeline + self.rd_pipeline.append(rd_transaction) + self.wr_pipeline.append(wr_transaction) + done_rd_transaction = self.rd_pipeline.pop(0) + done_wr_transaction = self.wr_pipeline.pop(0) + if done_rd_transaction is not None: + selfp.bus.dat_r = self.model.read(done_rd_transaction[0], done_rd_transaction[1]) + if done_wr_transaction is not None: + self.model.write(done_wr_transaction[0], done_wr_transaction[1], + selfp.bus.dat_w, selfp.bus.dat_we) + do_simulation.passive = True diff --git a/misoclib/mem/sdram/core/lasmicon/__init__.py b/misoclib/mem/sdram/core/lasmicon/__init__.py index bfe3a130..393e218b 100644 --- a/misoclib/mem/sdram/core/lasmicon/__init__.py +++ b/misoclib/mem/sdram/core/lasmicon/__init__.py @@ -1,6 +1,7 @@ from migen.fhdl.std import * -from misoclib.mem.sdram.bus import dfi, lasmibus +from misoclib.mem.sdram.phy import dfi +from misoclib.mem.sdram.core import lasmibus from misoclib.mem.sdram.core.lasmicon.refresher import * from misoclib.mem.sdram.core.lasmicon.bankmachine import * from misoclib.mem.sdram.core.lasmicon.multiplexer import * diff --git a/misoclib/mem/sdram/core/lasmicon/crossbar.py b/misoclib/mem/sdram/core/lasmicon/crossbar.py deleted file mode 100644 index e4414900..00000000 --- a/misoclib/mem/sdram/core/lasmicon/crossbar.py +++ /dev/null @@ -1,176 +0,0 @@ -from migen.fhdl.std import * -from migen.genlib import roundrobin -from migen.genlib.record import * -from migen.genlib.misc import optree - -from misoclib.mem.sdram.bus.lasmibus import Interface - -def _getattr_all(l, attr): - it = iter(l) - r = getattr(next(it), attr) - for e in it: - if getattr(e, attr) != r: - raise ValueError - return r - -class Crossbar(Module): - def __init__(self, controllers, cba_shift): - self._controllers = controllers - self._cba_shift = cba_shift - - self._rca_bits = _getattr_all(controllers, "aw") - self._dw = _getattr_all(controllers, "dw") - self._nbanks = _getattr_all(controllers, "nbanks") - self._req_queue_size = _getattr_all(controllers, "req_queue_size") - self._read_latency = _getattr_all(controllers, "read_latency") - self._write_latency = _getattr_all(controllers, "write_latency") - - self._bank_bits = log2_int(self._nbanks, False) - self._controller_bits = log2_int(len(self._controllers), False) - - self._masters = [] - - def get_master(self): - if self.finalized: - raise FinalizeError - lasmi_master = Interface(self._rca_bits + self._bank_bits + self._controller_bits, - self._dw, 1, self._req_queue_size, self._read_latency, self._write_latency) - self._masters.append(lasmi_master) - return lasmi_master - - def do_finalize(self): - nmasters = len(self._masters) - - m_ca, m_ba, m_rca = self._split_master_addresses(self._controller_bits, - self._bank_bits, self._rca_bits, self._cba_shift) - - for nc, controller in enumerate(self._controllers): - if self._controller_bits: - controller_selected = [ca == nc for ca in m_ca] - else: - controller_selected = [1]*nmasters - master_req_acks = [0]*nmasters - master_dat_w_acks = [0]*nmasters - master_dat_r_acks = [0]*nmasters - - rrs = [roundrobin.RoundRobin(nmasters, roundrobin.SP_CE) for n in range(self._nbanks)] - self.submodules += rrs - for nb, rr in enumerate(rrs): - bank = getattr(controller, "bank"+str(nb)) - - # for each master, determine if another bank locks it - master_locked = [] - for nm, master in enumerate(self._masters): - locked = 0 - for other_nb, other_rr in enumerate(rrs): - if other_nb != nb: - other_bank = getattr(controller, "bank"+str(other_nb)) - locked = locked | (other_bank.lock & (other_rr.grant == nm)) - master_locked.append(locked) - - # arbitrate - bank_selected = [cs & (ba == nb) & ~locked for cs, ba, locked in zip(controller_selected, m_ba, master_locked)] - bank_requested = [bs & master.stb for bs, master in zip(bank_selected, self._masters)] - self.comb += [ - rr.request.eq(Cat(*bank_requested)), - rr.ce.eq(~bank.stb & ~bank.lock) - ] - - # route requests - self.comb += [ - bank.adr.eq(Array(m_rca)[rr.grant]), - bank.we.eq(Array(self._masters)[rr.grant].we), - bank.stb.eq(Array(bank_requested)[rr.grant]) - ] - master_req_acks = [master_req_ack | ((rr.grant == nm) & bank_selected[nm] & bank.req_ack) - for nm, master_req_ack in enumerate(master_req_acks)] - master_dat_w_acks = [master_dat_w_ack | ((rr.grant == nm) & bank.dat_w_ack) - for nm, master_dat_w_ack in enumerate(master_dat_w_acks)] - master_dat_r_acks = [master_dat_r_ack | ((rr.grant == nm) & bank.dat_r_ack) - for nm, master_dat_r_ack in enumerate(master_dat_r_acks)] - - for nm, master_dat_w_ack in enumerate(master_dat_w_acks): - for i in range(self._write_latency): - new_master_dat_w_ack = Signal() - self.sync += new_master_dat_w_ack.eq(master_dat_w_ack) - master_dat_w_ack = new_master_dat_w_ack - master_dat_w_acks[nm] = master_dat_w_ack - - for nm, master_dat_r_ack in enumerate(master_dat_r_acks): - for i in range(self._read_latency): - new_master_dat_r_ack = Signal() - self.sync += new_master_dat_r_ack.eq(master_dat_r_ack) - master_dat_r_ack = new_master_dat_r_ack - master_dat_r_acks[nm] = master_dat_r_ack - - self.comb += [master.req_ack.eq(master_req_ack) for master, master_req_ack in zip(self._masters, master_req_acks)] - self.comb += [master.dat_w_ack.eq(master_dat_w_ack) for master, master_dat_w_ack in zip(self._masters, master_dat_w_acks)] - self.comb += [master.dat_r_ack.eq(master_dat_r_ack) for master, master_dat_r_ack in zip(self._masters, master_dat_r_acks)] - - # route data writes - controller_selected_wl = controller_selected - for i in range(self._write_latency): - n_controller_selected_wl = [Signal() for i in range(nmasters)] - self.sync += [n.eq(o) for n, o in zip(n_controller_selected_wl, controller_selected_wl)] - controller_selected_wl = n_controller_selected_wl - dat_w_maskselect = [] - dat_we_maskselect = [] - for master, selected in zip(self._masters, controller_selected_wl): - o_dat_w = Signal(self._dw) - o_dat_we = Signal(self._dw//8) - self.comb += If(selected, - o_dat_w.eq(master.dat_w), - o_dat_we.eq(master.dat_we) - ) - dat_w_maskselect.append(o_dat_w) - dat_we_maskselect.append(o_dat_we) - self.comb += [ - controller.dat_w.eq(optree("|", dat_w_maskselect)), - controller.dat_we.eq(optree("|", dat_we_maskselect)) - ] - - # route data reads - if self._controller_bits: - for master in self._masters: - controller_sel = Signal(self._controller_bits) - for nc, controller in enumerate(self._controllers): - for nb in range(nbanks): - bank = getattr(controller, "bank"+str(nb)) - self.comb += If(bank.stb & bank.ack, controller_sel.eq(nc)) - for i in range(self._read_latency): - n_controller_sel = Signal(self._controller_bits) - self.sync += n_controller_sel.eq(controller_sel) - controller_sel = n_controller_sel - self.comb += master.dat_r.eq(Array(self._controllers)[controller_sel].dat_r) - else: - self.comb += [master.dat_r.eq(self._controllers[0].dat_r) for master in self._masters] - - def _split_master_addresses(self, controller_bits, bank_bits, rca_bits, cba_shift): - m_ca = [] # controller address - m_ba = [] # bank address - m_rca = [] # row and column address - for master in self._masters: - cba = Signal(self._controller_bits + self._bank_bits) - rca = Signal(self._rca_bits) - cba_upper = cba_shift + controller_bits + bank_bits - self.comb += cba.eq(master.adr[cba_shift:cba_upper]) - if cba_shift < self._rca_bits: - if cba_shift: - self.comb += rca.eq(Cat(master.adr[:cba_shift], master.adr[cba_upper:])) - else: - self.comb += rca.eq(master.adr[cba_upper:]) - else: - self.comb += rca.eq(master.adr[:cba_shift]) - - if self._controller_bits: - ca = Signal(self._controller_bits) - ba = Signal(self._bank_bits) - self.comb += Cat(ba, ca).eq(cba) - else: - ca = None - ba = cba - - m_ca.append(ca) - m_ba.append(ba) - m_rca.append(rca) - return m_ca, m_ba, m_rca diff --git a/misoclib/mem/sdram/core/lasmixbar.py b/misoclib/mem/sdram/core/lasmixbar.py new file mode 100644 index 00000000..d4da8093 --- /dev/null +++ b/misoclib/mem/sdram/core/lasmixbar.py @@ -0,0 +1,176 @@ +from migen.fhdl.std import * +from migen.genlib import roundrobin +from migen.genlib.record import * +from migen.genlib.misc import optree + +from misoclib.mem.sdram.core.lasmibus import Interface + +def _getattr_all(l, attr): + it = iter(l) + r = getattr(next(it), attr) + for e in it: + if getattr(e, attr) != r: + raise ValueError + return r + +class LASMIxbar(Module): + def __init__(self, controllers, cba_shift): + self._controllers = controllers + self._cba_shift = cba_shift + + self._rca_bits = _getattr_all(controllers, "aw") + self._dw = _getattr_all(controllers, "dw") + self._nbanks = _getattr_all(controllers, "nbanks") + self._req_queue_size = _getattr_all(controllers, "req_queue_size") + self._read_latency = _getattr_all(controllers, "read_latency") + self._write_latency = _getattr_all(controllers, "write_latency") + + self._bank_bits = log2_int(self._nbanks, False) + self._controller_bits = log2_int(len(self._controllers), False) + + self._masters = [] + + def get_master(self): + if self.finalized: + raise FinalizeError + lasmi_master = Interface(self._rca_bits + self._bank_bits + self._controller_bits, + self._dw, 1, self._req_queue_size, self._read_latency, self._write_latency) + self._masters.append(lasmi_master) + return lasmi_master + + def do_finalize(self): + nmasters = len(self._masters) + + m_ca, m_ba, m_rca = self._split_master_addresses(self._controller_bits, + self._bank_bits, self._rca_bits, self._cba_shift) + + for nc, controller in enumerate(self._controllers): + if self._controller_bits: + controller_selected = [ca == nc for ca in m_ca] + else: + controller_selected = [1]*nmasters + master_req_acks = [0]*nmasters + master_dat_w_acks = [0]*nmasters + master_dat_r_acks = [0]*nmasters + + rrs = [roundrobin.RoundRobin(nmasters, roundrobin.SP_CE) for n in range(self._nbanks)] + self.submodules += rrs + for nb, rr in enumerate(rrs): + bank = getattr(controller, "bank"+str(nb)) + + # for each master, determine if another bank locks it + master_locked = [] + for nm, master in enumerate(self._masters): + locked = 0 + for other_nb, other_rr in enumerate(rrs): + if other_nb != nb: + other_bank = getattr(controller, "bank"+str(other_nb)) + locked = locked | (other_bank.lock & (other_rr.grant == nm)) + master_locked.append(locked) + + # arbitrate + bank_selected = [cs & (ba == nb) & ~locked for cs, ba, locked in zip(controller_selected, m_ba, master_locked)] + bank_requested = [bs & master.stb for bs, master in zip(bank_selected, self._masters)] + self.comb += [ + rr.request.eq(Cat(*bank_requested)), + rr.ce.eq(~bank.stb & ~bank.lock) + ] + + # route requests + self.comb += [ + bank.adr.eq(Array(m_rca)[rr.grant]), + bank.we.eq(Array(self._masters)[rr.grant].we), + bank.stb.eq(Array(bank_requested)[rr.grant]) + ] + master_req_acks = [master_req_ack | ((rr.grant == nm) & bank_selected[nm] & bank.req_ack) + for nm, master_req_ack in enumerate(master_req_acks)] + master_dat_w_acks = [master_dat_w_ack | ((rr.grant == nm) & bank.dat_w_ack) + for nm, master_dat_w_ack in enumerate(master_dat_w_acks)] + master_dat_r_acks = [master_dat_r_ack | ((rr.grant == nm) & bank.dat_r_ack) + for nm, master_dat_r_ack in enumerate(master_dat_r_acks)] + + for nm, master_dat_w_ack in enumerate(master_dat_w_acks): + for i in range(self._write_latency): + new_master_dat_w_ack = Signal() + self.sync += new_master_dat_w_ack.eq(master_dat_w_ack) + master_dat_w_ack = new_master_dat_w_ack + master_dat_w_acks[nm] = master_dat_w_ack + + for nm, master_dat_r_ack in enumerate(master_dat_r_acks): + for i in range(self._read_latency): + new_master_dat_r_ack = Signal() + self.sync += new_master_dat_r_ack.eq(master_dat_r_ack) + master_dat_r_ack = new_master_dat_r_ack + master_dat_r_acks[nm] = master_dat_r_ack + + self.comb += [master.req_ack.eq(master_req_ack) for master, master_req_ack in zip(self._masters, master_req_acks)] + self.comb += [master.dat_w_ack.eq(master_dat_w_ack) for master, master_dat_w_ack in zip(self._masters, master_dat_w_acks)] + self.comb += [master.dat_r_ack.eq(master_dat_r_ack) for master, master_dat_r_ack in zip(self._masters, master_dat_r_acks)] + + # route data writes + controller_selected_wl = controller_selected + for i in range(self._write_latency): + n_controller_selected_wl = [Signal() for i in range(nmasters)] + self.sync += [n.eq(o) for n, o in zip(n_controller_selected_wl, controller_selected_wl)] + controller_selected_wl = n_controller_selected_wl + dat_w_maskselect = [] + dat_we_maskselect = [] + for master, selected in zip(self._masters, controller_selected_wl): + o_dat_w = Signal(self._dw) + o_dat_we = Signal(self._dw//8) + self.comb += If(selected, + o_dat_w.eq(master.dat_w), + o_dat_we.eq(master.dat_we) + ) + dat_w_maskselect.append(o_dat_w) + dat_we_maskselect.append(o_dat_we) + self.comb += [ + controller.dat_w.eq(optree("|", dat_w_maskselect)), + controller.dat_we.eq(optree("|", dat_we_maskselect)) + ] + + # route data reads + if self._controller_bits: + for master in self._masters: + controller_sel = Signal(self._controller_bits) + for nc, controller in enumerate(self._controllers): + for nb in range(nbanks): + bank = getattr(controller, "bank"+str(nb)) + self.comb += If(bank.stb & bank.ack, controller_sel.eq(nc)) + for i in range(self._read_latency): + n_controller_sel = Signal(self._controller_bits) + self.sync += n_controller_sel.eq(controller_sel) + controller_sel = n_controller_sel + self.comb += master.dat_r.eq(Array(self._controllers)[controller_sel].dat_r) + else: + self.comb += [master.dat_r.eq(self._controllers[0].dat_r) for master in self._masters] + + def _split_master_addresses(self, controller_bits, bank_bits, rca_bits, cba_shift): + m_ca = [] # controller address + m_ba = [] # bank address + m_rca = [] # row and column address + for master in self._masters: + cba = Signal(self._controller_bits + self._bank_bits) + rca = Signal(self._rca_bits) + cba_upper = cba_shift + controller_bits + bank_bits + self.comb += cba.eq(master.adr[cba_shift:cba_upper]) + if cba_shift < self._rca_bits: + if cba_shift: + self.comb += rca.eq(Cat(master.adr[:cba_shift], master.adr[cba_upper:])) + else: + self.comb += rca.eq(master.adr[cba_upper:]) + else: + self.comb += rca.eq(master.adr[:cba_shift]) + + if self._controller_bits: + ca = Signal(self._controller_bits) + ba = Signal(self._bank_bits) + self.comb += Cat(ba, ca).eq(cba) + else: + ca = None + ba = cba + + m_ca.append(ca) + m_ba.append(ba) + m_rca.append(rca) + return m_ca, m_ba, m_rca diff --git a/misoclib/mem/sdram/core/minicon/__init__.py b/misoclib/mem/sdram/core/minicon/__init__.py index 1f7660ee..19a76373 100644 --- a/misoclib/mem/sdram/core/minicon/__init__.py +++ b/misoclib/mem/sdram/core/minicon/__init__.py @@ -2,7 +2,7 @@ from migen.fhdl.std import * from migen.bus import wishbone from migen.genlib.fsm import FSM, NextState -from misoclib.mem.sdram.bus import dfi as dfibus +from misoclib.mem.sdram.phy import dfi as dfibus class _AddressSlicer: def __init__(self, col_a, bank_a, row_a, address_align): diff --git a/misoclib/mem/sdram/phy/dfi.py b/misoclib/mem/sdram/phy/dfi.py new file mode 100644 index 00000000..fa80f9c8 --- /dev/null +++ b/misoclib/mem/sdram/phy/dfi.py @@ -0,0 +1,67 @@ +from migen.fhdl.std import * +from migen.genlib.record import * + +def phase_cmd_description(a, ba): + return [ + ("address", a, DIR_M_TO_S), + ("bank", ba, DIR_M_TO_S), + ("cas_n", 1, DIR_M_TO_S), + ("cs_n", 1, DIR_M_TO_S), + ("ras_n", 1, DIR_M_TO_S), + ("we_n", 1, DIR_M_TO_S), + ("cke", 1, DIR_M_TO_S), + ("odt", 1, DIR_M_TO_S), + ("reset_n", 1, DIR_M_TO_S) + ] + +def phase_wrdata_description(d): + return [ + ("wrdata", d, DIR_M_TO_S), + ("wrdata_en", 1, DIR_M_TO_S), + ("wrdata_mask", d//8, DIR_M_TO_S) + ] + +def phase_rddata_description(d): + return [ + ("rddata_en", 1, DIR_M_TO_S), + ("rddata", d, DIR_S_TO_M), + ("rddata_valid", 1, DIR_S_TO_M) + ] + +def phase_description(a, ba, d): + r = phase_cmd_description(a, ba) + r += phase_wrdata_description(d) + r += phase_rddata_description(d) + return r + +class Interface(Record): + def __init__(self, a, ba, d, nphases=1): + layout = [("p"+str(i), phase_description(a, ba, d)) for i in range(nphases)] + Record.__init__(self, layout) + self.phases = [getattr(self, "p"+str(i)) for i in range(nphases)] + for p in self.phases: + p.cas_n.reset = 1 + p.cs_n.reset = 1 + p.ras_n.reset = 1 + p.we_n.reset = 1 + + # Returns pairs (DFI-mandated signal name, Migen signal object) + def get_standard_names(self, m2s=True, s2m=True): + r = [] + add_suffix = len(self.phases) > 1 + for n, phase in enumerate(self.phases): + for field, size, direction in phase.layout: + if (m2s and direction == DIR_M_TO_S) or (s2m and direction == DIR_S_TO_M): + if add_suffix: + if direction == DIR_M_TO_S: + suffix = "_p" + str(n) + else: + suffix = "_w" + str(n) + else: + suffix = "" + r.append(("dfi_" + field + suffix, getattr(phase, field))) + return r + +class Interconnect(Module): + def __init__(self, master, slave): + self.comb += master.connect(slave) diff --git a/misoclib/mem/sdram/phy/dfii.py b/misoclib/mem/sdram/phy/dfii.py index c3fa216f..abe4ce37 100644 --- a/misoclib/mem/sdram/phy/dfii.py +++ b/misoclib/mem/sdram/phy/dfii.py @@ -1,7 +1,7 @@ from migen.fhdl.std import * from migen.bank.description import * -from misoclib.mem.sdram.bus import dfi +from misoclib.mem.sdram.phy import dfi class PhaseInjector(Module, AutoCSR): def __init__(self, phase): diff --git a/misoclib/mem/sdram/phy/gensdrphy.py b/misoclib/mem/sdram/phy/gensdrphy.py index f7af68d4..befd6509 100644 --- a/misoclib/mem/sdram/phy/gensdrphy.py +++ b/misoclib/mem/sdram/phy/gensdrphy.py @@ -25,7 +25,7 @@ from migen.fhdl.std import * from migen.genlib.record import * from migen.fhdl.specials import * -from misoclib.mem.sdram.bus.dfi import * +from misoclib.mem.sdram.phy.dfi import * from misoclib.mem import sdram class GENSDRPHY(Module): diff --git a/misoclib/mem/sdram/phy/k7ddrphy.py b/misoclib/mem/sdram/phy/k7ddrphy.py index 42021944..8d86931d 100644 --- a/misoclib/mem/sdram/phy/k7ddrphy.py +++ b/misoclib/mem/sdram/phy/k7ddrphy.py @@ -3,7 +3,7 @@ from migen.fhdl.std import * from migen.bank.description import * -from misoclib.mem.sdram.bus.dfi import * +from misoclib.mem.sdram.phy.dfi import * from misoclib.mem import sdram class K7DDRPHY(Module, AutoCSR): diff --git a/misoclib/mem/sdram/phy/s6ddrphy.py b/misoclib/mem/sdram/phy/s6ddrphy.py index 1d5fe0f7..aacdf04c 100644 --- a/misoclib/mem/sdram/phy/s6ddrphy.py +++ b/misoclib/mem/sdram/phy/s6ddrphy.py @@ -17,7 +17,7 @@ from migen.fhdl.std import * from migen.genlib.record import * -from misoclib.mem.sdram.bus.dfi import * +from misoclib.mem.sdram.phy.dfi import * from misoclib.mem import sdram class S6DDRPHY(Module): diff --git a/misoclib/mem/sdram/test/abstract_transactions_lasmi.py b/misoclib/mem/sdram/test/abstract_transactions_lasmi.py index 6bfb1fdb..cdd78e70 100644 --- a/misoclib/mem/sdram/test/abstract_transactions_lasmi.py +++ b/misoclib/mem/sdram/test/abstract_transactions_lasmi.py @@ -2,7 +2,7 @@ from migen.fhdl.std import * from migen.bus.transactions import * from migen.sim.generic import run_simulation -from misoclib.mem.sdram.bus import lasmibus +from misoclib.mem.sdram.core import lasmibus def my_generator(n): bank = n % 4 diff --git a/misoclib/mem/sdram/test/bankmachine_tb.py b/misoclib/mem/sdram/test/bankmachine_tb.py index 12ae5da0..77841e43 100644 --- a/misoclib/mem/sdram/test/bankmachine_tb.py +++ b/misoclib/mem/sdram/test/bankmachine_tb.py @@ -1,7 +1,7 @@ from migen.fhdl.std import * from migen.sim.generic import run_simulation -from misoclib.mem.sdram.bus import lasmibus +from misoclib.mem.sdram.code import lasmibus from misoclib.mem.sdram.core.lasmicon.bankmachine import * from common import sdram_phy, sdram_geom, sdram_timing, CommandLogger diff --git a/misoclib/mem/sdram/test/lasmicon_df_tb.py b/misoclib/mem/sdram/test/lasmicon_df_tb.py index e06722f0..d239d49a 100644 --- a/misoclib/mem/sdram/test/lasmicon_df_tb.py +++ b/misoclib/mem/sdram/test/lasmicon_df_tb.py @@ -1,7 +1,7 @@ from migen.fhdl.std import * from migen.sim.generic import run_simulation -from misoclib.mem.sdram.bus import lasmibus +from misoclib.mem.sdram.core import lasmibus from misoclib.mem.sdram.core.lasmicon import * from misoclib.mem.sdram.frontend import dma_lasmi diff --git a/misoclib/mem/sdram/test/lasmicon_tb.py b/misoclib/mem/sdram/test/lasmicon_tb.py index a102b07c..0352c060 100644 --- a/misoclib/mem/sdram/test/lasmicon_tb.py +++ b/misoclib/mem/sdram/test/lasmicon_tb.py @@ -1,7 +1,7 @@ from migen.fhdl.std import * from migen.sim.generic import run_simulation -from misoclib.mem.sdram.bus import lasmibus +from misoclib.mem.sdram.core import lasmibus from misoclib.mem.sdram.core.lasmicon import * from common import sdram_phy, sdram_geom, sdram_timing, DFILogger diff --git a/misoclib/mem/sdram/test/lasmicon_wb.py b/misoclib/mem/sdram/test/lasmicon_wb.py index 978655dc..dae6c634 100644 --- a/misoclib/mem/sdram/test/lasmicon_wb.py +++ b/misoclib/mem/sdram/test/lasmicon_wb.py @@ -3,7 +3,7 @@ from migen.bus import wishbone from migen.bus.transactions import * from migen.sim.generic import run_simulation -from misoclib.mem.sdram.bus import lasmibus +from misoclib.mem.sdram.core import lasmibus from misoclib.mem.sdram.core.lasmicon import * from misoclib.mem.sdram.frontend import wishbone2lasmi diff --git a/misoclib/soc/sdram.py b/misoclib/soc/sdram.py index ac4024c3..4acc4297 100644 --- a/misoclib/soc/sdram.py +++ b/misoclib/soc/sdram.py @@ -2,7 +2,6 @@ from migen.fhdl.std import * from migen.bus import wishbone, csr from migen.genlib.record import * -from misoclib.mem.sdram.bus import dfi, lasmibus from misoclib.mem.sdram.core import SDRAMCore from misoclib.mem.sdram.frontend import memtest, wishbone2lasmi from misoclib.soc import SoC, mem_decoder