+++ /dev/null
-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)
+++ /dev/null
-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_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)
-
-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_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_acks = [master_dat_ack | ((rr.grant == nm) & bank.dat_ack)
- for nm, master_dat_ack in enumerate(master_dat_acks)]
-
- 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_ack.eq(master_dat_ack) for master, master_dat_ack in zip(self._masters, master_dat_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
-
-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
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus import wishbone
-from migen.bank.description import *
-from migen.genlib.fsm import FSM, NextState
-from migen.genlib.misc import split, displacer, chooser
-from migen.genlib.record import Record, layout_len
-
-# cachesize (in 32-bit words) is the size of the data store, must be a power of 2
-class WB2LASMI(Module, AutoCSR):
- def __init__(self, cachesize, lasmim):
- self._cachesize = CSRStatus(8, reset=log2_int(cachesize))
- self.wishbone = wishbone.Interface()
-
- ###
-
- data_width = flen(self.wishbone.dat_r)
- if lasmim.dw > data_width and (lasmim.dw % data_width) != 0:
- raise ValueError("LASMI data width must be a multiple of {dw}".format(dw=data_width))
- if lasmim.dw < data_width and (data_width % lasmim.dw) != 0:
- raise ValueError("WISHBONE data width must be a multiple of {dw}".format(dw=lasmim.dw))
-
- # Split address:
- # TAG | LINE NUMBER | LINE OFFSET
- offsetbits = log2_int(max(lasmim.dw//data_width, 1))
- addressbits = lasmim.aw + offsetbits
- linebits = log2_int(cachesize) - offsetbits
- tagbits = addressbits - linebits
- wordbits = log2_int(max(data_width//lasmim.dw, 1))
- adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits)
- word = Signal(wordbits) if wordbits else None
-
- # Data memory
- data_mem = Memory(lasmim.dw*2**wordbits, 2**linebits)
- data_port = data_mem.get_port(write_capable=True, we_granularity=8)
- self.specials += data_mem, data_port
-
- write_from_lasmi = Signal()
- write_to_lasmi = Signal()
- if adr_offset is None:
- adr_offset_r = None
- else:
- adr_offset_r = Signal(offsetbits)
- self.sync += adr_offset_r.eq(adr_offset)
-
- self.comb += [
- data_port.adr.eq(adr_line),
- If(write_from_lasmi,
- displacer(lasmim.dat_r, word, data_port.dat_w),
- displacer(Replicate(1, lasmim.dw//8), word, data_port.we)
- ).Else(
- data_port.dat_w.eq(Replicate(self.wishbone.dat_w, max(lasmim.dw//data_width, 1))),
- If(self.wishbone.cyc & self.wishbone.stb & self.wishbone.we & self.wishbone.ack,
- displacer(self.wishbone.sel, adr_offset, data_port.we, 2**offsetbits, reverse=True)
- )
- ),
- If(write_to_lasmi,
- chooser(data_port.dat_r, word, lasmim.dat_w),
- lasmim.dat_we.eq(2**(lasmim.dw//8)-1)
- ),
- chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True)
- ]
-
-
- # Tag memory
- tag_layout = [("tag", tagbits), ("dirty", 1)]
- tag_mem = Memory(layout_len(tag_layout), 2**linebits)
- tag_port = tag_mem.get_port(write_capable=True)
- self.specials += tag_mem, tag_port
- tag_do = Record(tag_layout)
- tag_di = Record(tag_layout)
- self.comb += [
- tag_do.raw_bits().eq(tag_port.dat_r),
- tag_port.dat_w.eq(tag_di.raw_bits())
- ]
-
- self.comb += [
- tag_port.adr.eq(adr_line),
- tag_di.tag.eq(adr_tag)
- ]
- if word is not None:
- self.comb += lasmim.adr.eq(Cat(word, adr_line, tag_do.tag))
- else:
- self.comb += lasmim.adr.eq(Cat(adr_line, tag_do.tag))
-
- # Lasmim word computation, word_clr and word_inc will be simplified
- # at synthesis when wordbits=0
- word_clr = Signal()
- word_inc = Signal()
- if word is not None:
- self.sync += \
- If(word_clr,
- word.eq(0),
- ).Elif(word_inc,
- word.eq(word+1)
- )
-
- def word_is_last(word):
- if word is not None:
- return word == 2**wordbits-1
- else:
- return 1
-
- # Control FSM
- assert(lasmim.write_latency >= 1 and lasmim.read_latency >= 1)
- fsm = FSM(reset_state="IDLE")
- self.submodules += fsm
-
- fsm.delayed_enter("EVICT_DATAD", "EVICT_DATA", lasmim.write_latency-1)
- fsm.delayed_enter("REFILL_DATAD", "REFILL_DATA", lasmim.read_latency-1)
-
- fsm.act("IDLE",
- If(self.wishbone.cyc & self.wishbone.stb, NextState("TEST_HIT"))
- )
- fsm.act("TEST_HIT",
- word_clr.eq(1),
- If(tag_do.tag == adr_tag,
- self.wishbone.ack.eq(1),
- If(self.wishbone.we,
- tag_di.dirty.eq(1),
- tag_port.we.eq(1)
- ),
- NextState("IDLE")
- ).Else(
- If(tag_do.dirty,
- NextState("EVICT_REQUEST")
- ).Else(
- NextState("REFILL_WRTAG")
- )
- )
- )
-
- fsm.act("EVICT_REQUEST",
- lasmim.stb.eq(1),
- lasmim.we.eq(1),
- If(lasmim.req_ack, NextState("EVICT_WAIT_DATA_ACK"))
- )
- fsm.act("EVICT_WAIT_DATA_ACK",
- If(lasmim.dat_ack, NextState("EVICT_DATAD"))
- )
- fsm.act("EVICT_DATA",
- write_to_lasmi.eq(1),
- word_inc.eq(1),
- If(word_is_last(word),
- NextState("REFILL_WRTAG"),
- ).Else(
- NextState("EVICT_REQUEST")
- )
- )
-
- fsm.act("REFILL_WRTAG",
- # Write the tag first to set the LASMI address
- tag_port.we.eq(1),
- word_clr.eq(1),
- NextState("REFILL_REQUEST")
- )
- fsm.act("REFILL_REQUEST",
- lasmim.stb.eq(1),
- If(lasmim.req_ack, NextState("REFILL_WAIT_DATA_ACK"))
- )
- fsm.act("REFILL_WAIT_DATA_ACK",
- If(lasmim.dat_ack, NextState("REFILL_DATAD"))
- )
- fsm.act("REFILL_DATA",
- write_from_lasmi.eq(1),
- word_inc.eq(1),
- If(word_is_last(word),
- NextState("TEST_HIT"),
- ).Else(
- NextState("REFILL_REQUEST")
- )
- )