+++ /dev/null
-from migen.fhdl.std import *
-from migen.flow.actor import *
-from migen.genlib.buffers import ReorderBuffer
-
-class SequentialReader(Module):
- def __init__(self, port):
- assert(len(port.slots) == 1)
- self.address = Sink([("a", port.hub.aw)])
- self.data = Source([("d", port.hub.dw)])
- self.busy = Signal()
-
- ###
-
- sample = Signal()
- data_reg_loaded = Signal()
- data_reg = Signal(port.hub.dw)
- accept_new = Signal()
-
- # We check that len(port.slots) == 1
- # and therefore we can assume that port.ack
- # goes low until the data phase.
-
- self.comb += [
- self.busy.eq(~data_reg_loaded | ~port.ack),
- port.adr.eq(self.address.payload.a),
- port.we.eq(0),
- accept_new.eq(~data_reg_loaded | self.data.ack),
- port.stb.eq(self.address.stb & accept_new),
- self.address.ack.eq(port.ack & accept_new),
- self.data.stb.eq(data_reg_loaded),
- self.data.payload.d.eq(data_reg)
- ]
- self.sync += [
- If(self.data.ack, data_reg_loaded.eq(0)),
- If(sample,
- data_reg_loaded.eq(1),
- data_reg.eq(port.dat_r)
- ),
- sample.eq(port.get_call_expression())
- ]
-
-class OOOReader(Module):
- def __init__(self, port):
- assert(len(port.slots) > 1)
- self.address = Sink([("a", port.hub.aw)])
- self.data = Source([("d", port.hub.dw)])
- self.busy = Signal() # TODO: drive busy
-
- ###
-
- tag_width = flen(port.tag_call)
- data_width = port.hub.dw
- depth = len(port.slots)
- rob = ReorderBuffer(tag_width, data_width, depth)
- self.submodules += rob
-
- self.comb += [
- port.adr.eq(self.address.payload.a),
- port.we.eq(0),
- port.stb.eq(self.address.stb & rob.can_issue),
- self.address.ack.eq(port.ack & rob.can_issue),
- rob.issue.eq(self.address.stb & port.ack),
- rob.tag_issue.eq(port.base + port.tag_issue),
-
- rob.data_call.eq(port.dat_r),
-
- self.data.stb.eq(rob.can_read),
- rob.read.eq(self.data.ack),
- self.data.payload.d.eq(rob.data_read)
- ]
- self.sync += [
- # Data is announced one cycle in advance.
- # Register the call to synchronize it with the data signal.
- rob.call.eq(port.call),
- rob.tag_call.eq(port.tag_call)
- ]
-
-class SequentialWriter(Module):
- def __init__(self, port):
- assert(len(port.slots) == 1)
- self.address_data = Sink([("a", port.hub.aw), ("d", port.hub.dw)])
- self.busy = Signal()
-
- ###
-
- data_reg = Signal(port.hub.dw)
- self.comb += [
- port.adr.eq(self.address_data.payload.a),
- port.we.eq(1),
- port.stb.eq(self.address_data.stb),
- self.address_data.ack.eq(port.ack),
- port.dat_wm.eq(0)
- ]
- self.sync += [
- port.dat_w.eq(0),
- If(port.get_call_expression(),
- self.busy.eq(0),
- port.dat_w.eq(data_reg)
- ),
- If(self.address_data.stb & self.address_data.ack,
- self.busy.eq(1),
- data_reg.eq(self.address_data.payload.d)
- )
- ]
-
-class _WriteSlot(Module):
- def __init__(self, port, load_data, n):
- self.busy = Signal()
-
- ###
-
- drive_data = Signal()
- data_reg = Signal(port.hub.dw)
- self.comb += [
- If(drive_data, port.dat_w.eq(data_reg)),
- port.dat_wm.eq(0)
- ]
-
- self.sync += [
- drive_data.eq(0),
- If(port.get_call_expression(n),
- self.busy.eq(0),
- drive_data.eq(1)
- ),
- If(port.stb & port.ack & (port.tag_issue == n),
- self.busy.eq(1),
- data_reg.eq(load_data)
- ),
- ]
-
-class OOOWriter(Module):
- def __init__(self, port):
- assert(len(port.slots) > 1)
- self.address_data = Sink([("a", port.hub.aw), ("d", port.hub.dw)])
- self.busy = Signal()
-
- ###
-
- self.comb += [
- port.adr.eq(self.address_data.payload.a),
- port.we.eq(1),
- port.stb.eq(self.address_data.stb),
- self.address_data.ack.eq(port.ack)
- ]
-
- busy = 0
- for i in range(len(port.slots)):
- write_slot = _WriteSlot(port, self.address_data.payload.d, i)
- self.submodules += write_slot
- busy = busy | write_slot.busy
- self.comb += self.busy.eq(busy)
-
-def Reader(port):
- if len(port.slots) == 1:
- return SequentialReader(port)
- else:
- return OOOReader(port)
-
-def Writer(port):
- if len(port.slots) == 1:
- return SequentialWriter(port)
- else:
- return OOOWriter(port)
+++ /dev/null
-from migen.fhdl.std import *
-from migen.fhdl.module import FinalizeError
-from migen.genlib.misc import optree
-from migen.genlib import roundrobin
-from migen.bus.transactions import *
-from migen.sim.generic import Proxy
-
-(SLOT_EMPTY, SLOT_PENDING, SLOT_PROCESSING) = range(3)
-
-class Slot(Module):
- def __init__(self, aw, time):
- self.time = time
- self.state = Signal(2)
- self.we = Signal()
- self.adr = Signal(aw)
- if self.time:
- self.mature = Signal()
-
- self.allocate = Signal()
- self.allocate_we = Signal()
- self.allocate_adr = Signal(aw)
- self.process = Signal()
- self.call = Signal()
-
- ###
-
- self.sync += [
- If(self.allocate,
- self.state.eq(SLOT_PENDING),
- self.we.eq(self.allocate_we),
- self.adr.eq(self.allocate_adr)
- ),
- If(self.process, self.state.eq(SLOT_PROCESSING)),
- If(self.call, self.state.eq(SLOT_EMPTY))
- ]
- if self.time:
- counter = Signal(max=self.time+1)
- self.comb += self.mature.eq(counter == 0)
- self.sync += [
- If(self.allocate,
- counter.eq(self.time)
- ).Elif(counter != 0,
- counter.eq(counter - 1)
- )
- ]
-
-class Port(Module):
- def __init__(self, hub, base, nslots):
- self.hub = hub
- self.base = base
- self.submodules.slots = [Slot(self.hub.aw, self.hub.time) for i in range(nslots)]
-
- # request issuance
- self.adr = Signal(self.hub.aw)
- self.we = Signal()
- self.stb = Signal()
- # tag_issue is created by finalize()
- self.ack = Signal()
-
- # request completion
- self.call = Signal()
- # tag_call is created by finalize()
- self.dat_r = Signal(self.hub.dw)
- self.dat_w = Signal(self.hub.dw)
- self.dat_wm = Signal(self.hub.dw//8)
-
- def do_finalize(self):
- nslots = len(self.slots)
- if nslots > 1:
- self.tag_issue = Signal(max=nslots)
- self.tag_call = Signal(self.hub.tagbits)
-
- # allocate
- for s in self.slots:
- self.comb += [
- s.allocate_we.eq(self.we),
- s.allocate_adr.eq(self.adr)
- ]
- choose_slot = None
- needs_tags = len(self.slots) > 1
- for n, s in reversed(list(enumerate(self.slots))):
- choose_slot = If(s.state == SLOT_EMPTY,
- s.allocate.eq(self.stb),
- self.tag_issue.eq(n) if needs_tags else None
- ).Else(choose_slot)
- self.comb += choose_slot
- self.comb += self.ack.eq(optree("|",
- [s.state == SLOT_EMPTY for s in self.slots]))
-
- # call
- self.comb += [s.call.eq(self.get_call_expression(n))
- for n, s in enumerate(self.slots)]
-
- def get_call_expression(self, slotn=0):
- if not self.finalized:
- raise FinalizeError
- return self.call \
- & (self.tag_call == (self.base + slotn))
-
-class Hub(Module):
- def __init__(self, aw, dw, time=0):
- self.aw = aw
- self.dw = dw
- self.time = time
-
- self.ports = []
- self._next_base = 0
- self.tagbits = 0
-
- self.call = Signal()
- # tag_call is created by do_finalize()
- self.dat_r = Signal(self.dw)
- self.dat_w = Signal(self.dw)
- self.dat_wm = Signal(self.dw//8)
-
- def get_port(self, nslots=1):
- if self.finalized:
- raise FinalizeError
- new_port = Port(self, self._next_base, nslots)
- self._next_base += nslots
- self.tagbits = bits_for(self._next_base-1)
- self.ports.append(new_port)
- self.submodules += new_port
- return new_port
-
- def do_finalize(self):
- self.tag_call = Signal(self.tagbits)
- for port in self.ports:
- self.comb += [
- port.call.eq(self.call),
- port.tag_call.eq(self.tag_call),
- port.dat_r.eq(self.dat_r)
- ]
- self.comb += [
- self.dat_w.eq(optree("|", [port.dat_w for port in self.ports])),
- self.dat_wm.eq(optree("|", [port.dat_wm for port in self.ports]))
- ]
-
- def get_slots(self):
- if not self.finalized:
- raise FinalizeError
- return sum([port.slots for port in self.ports], [])
-
-class Tap(Module):
- def __init__(self, hub, handler=print):
- self.hub = hub
- self.handler = handler
- self.tag_to_transaction = dict()
- self.transaction = None
-
- def do_simulation(self, s):
- hub = Proxy(s, self.hub)
-
- # Pull any data announced in the previous cycle.
- if isinstance(self.transaction, TWrite):
- self.transaction.data = hub.dat_w
- self.transaction.sel = ~hub.dat_wm
- self.handler(self.transaction)
- self.transaction = None
- if isinstance(self.transaction, TRead):
- self.transaction.data = hub.dat_r
- self.handler(self.transaction)
- self.transaction = None
-
- # Tag issue. Transaction objects are created here
- # and placed into the tag_to_transaction dictionary.
- for tag, slot in enumerate(self.hub.get_slots()):
- if s.rd(slot.allocate):
- adr = s.rd(slot.allocate_adr)
- we = s.rd(slot.allocate_we)
- if we:
- transaction = TWrite(adr)
- else:
- transaction = TRead(adr)
- transaction.latency = s.cycle_counter
- self.tag_to_transaction[tag] = transaction
-
- # Tag call.
- if hub.call:
- transaction = self.tag_to_transaction[hub.tag_call]
- transaction.latency = s.cycle_counter - transaction.latency + 1
- self.transaction = transaction
-
-class Initiator(Module):
- def __init__(self, generator, port):
- self.generator = generator
- self.port = port
- self.done = False
- self._exe = None
-
- def _execute(self, s, generator, port):
- while True:
- transaction = next(generator)
- transaction_start = s.cycle_counter
- if transaction is None:
- yield
- else:
- # tag phase
- s.wr(port.adr, transaction.address)
- if isinstance(transaction, TWrite):
- s.wr(port.we, 1)
- else:
- s.wr(port.we, 0)
- s.wr(port.stb, 1)
- yield
- while not s.rd(port.ack):
- yield
- if hasattr(port, "tag_issue"):
- tag = s.rd(port.tag_issue)
- else:
- tag = 0
- tag += port.base
- s.wr(port.stb, 0)
-
- # data phase
- while not (s.rd(port.call) and (s.rd(port.tag_call) == tag)):
- yield
- if isinstance(transaction, TWrite):
- s.wr(port.dat_w, transaction.data)
- s.wr(port.dat_wm, ~transaction.sel)
- yield
- s.wr(port.dat_w, 0)
- s.wr(port.dat_wm, 0)
- else:
- yield
- transaction.data = s.rd(port.dat_r)
- transaction.latency = s.cycle_counter - transaction_start - 1
-
- def do_simulation(self, s):
- if not self.done:
- if self._exe is None:
- self._exe = self._execute(s, self.generator, self.port)
- try:
- next(self._exe)
- except StopIteration:
- self.done = True
-
-class TargetModel:
- def __init__(self):
- self.last_slot = 0
-
- def read(self, address):
- return 0
-
- def write(self, address, data, mask):
- pass
-
- # Round-robin scheduling.
- def select_slot(self, pending_slots):
- if not pending_slots:
- return -1
- self.last_slot += 1
- if self.last_slot > max(pending_slots):
- self.last_slot = 0
- while self.last_slot not in pending_slots:
- self.last_slot += 1
- return self.last_slot
-
-class Target(Module):
- def __init__(self, model, hub):
- self.model = model
- self.hub = hub
- self._calling_tag = -1
- self._write_request_d = -1
- self._write_request = -1
- self._read_request = -1
-
- def do_simulation(self, s):
- slots = self.hub.get_slots()
-
- # Data I/O
- if self._write_request >= 0:
- self.model.write(self._write_request,
- s.rd(self.hub.dat_w), s.rd(self.hub.dat_wm))
- if self._read_request >= 0:
- s.wr(self.hub.dat_r, self.model.read(self._read_request))
-
- # Request pipeline
- self._read_request = -1
- self._write_request = self._write_request_d
- self._write_request_d = -1
-
- # Examine pending slots and possibly choose one.
- # Note that we do not use the SLOT_PROCESSING state here.
- # Selected slots are immediately called.
- pending_slots = set()
- for tag, slot in enumerate(slots):
- if tag != self._calling_tag and s.rd(slot.state) == SLOT_PENDING:
- pending_slots.add(tag)
- slot_to_call = self.model.select_slot(pending_slots)
-
- # Call slot.
- if slot_to_call >= 0:
- slot = slots[slot_to_call]
- s.wr(self.hub.call, 1)
- s.wr(self.hub.tag_call, slot_to_call)
- self._calling_tag = slot_to_call
- if s.rd(slot.we):
- self._write_request_d = s.rd(slot.adr)
- else:
- self._read_request = s.rd(slot.adr)
- else:
- s.wr(self.hub.call, 0)
- self._calling_tag = -1
+++ /dev/null
-from migen.fhdl.std import *
-from migen.bus import wishbone
-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 WB2ASMI:
- def __init__(self, cachesize, asmiport):
- self.wishbone = wishbone.Interface()
- self.cachesize = cachesize
- self.asmiport = asmiport
- if len(self.asmiport.slots) != 1:
- raise ValueError("ASMI port must have 1 slot")
- if self.asmiport.hub.dw <= 32:
- raise ValueError("ASMI data width must be strictly larger than 32")
- if (self.asmiport.hub.dw % 32) != 0:
- raise ValueError("ASMI data width must be a multiple of 32")
-
- def get_fragment(self):
- comb = []
- sync = []
-
- aaw = self.asmiport.hub.aw
- adw = self.asmiport.hub.dw
-
- # Split address:
- # TAG | LINE NUMBER | LINE OFFSET
- offsetbits = log2_int(adw//32)
- addressbits = aaw + offsetbits
- linebits = log2_int(self.cachesize) - offsetbits
- tagbits = addressbits - linebits
- adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits)
-
- # Data memory
- data_mem = Memory(adw, 2**linebits)
- data_port = data_mem.get_port(write_capable=True, we_granularity=8)
-
- write_from_asmi = Signal()
- write_to_asmi = Signal()
- adr_offset_r = Signal(offsetbits)
- comb += [
- data_port.adr.eq(adr_line),
- If(write_from_asmi,
- data_port.dat_w.eq(self.asmiport.dat_r),
- data_port.we.eq(Replicate(1, adw//8))
- ).Else(
- data_port.dat_w.eq(Replicate(self.wishbone.dat_w, adw//32)),
- 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_asmi, self.asmiport.dat_w.eq(data_port.dat_r)),
- self.asmiport.dat_wm.eq(0),
- chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True)
- ]
- sync += [
- adr_offset_r.eq(adr_offset)
- ]
-
- # 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)
- tag_do = Record(tag_layout)
- tag_di = Record(tag_layout)
- comb += [
- tag_do.raw_bits().eq(tag_port.dat_r),
- tag_port.dat_w.eq(tag_di.raw_bits())
- ]
-
- comb += [
- tag_port.adr.eq(adr_line),
- tag_di.tag.eq(adr_tag),
- self.asmiport.adr.eq(Cat(adr_line, tag_do.tag))
- ]
-
- # Control FSM
- write_to_asmi_pre = Signal()
- sync.append(write_to_asmi.eq(write_to_asmi_pre))
-
- fsm = FSM()
-
- fsm.act("IDLE",
- If(self.wishbone.cyc & self.wishbone.stb, NextState("TEST_HIT"))
- )
- fsm.act("TEST_HIT",
- 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_ISSUE")
- ).Else(
- NextState("REFILL_WRTAG")
- )
- )
- )
-
- fsm.act("EVICT_ISSUE",
- self.asmiport.stb.eq(1),
- self.asmiport.we.eq(1),
- If(self.asmiport.ack, NextState("EVICT_WAIT"))
- )
- fsm.act("EVICT_WAIT",
- # Data is actually sampled by the memory controller in the next state.
- # But since the data memory has one cycle latency, it gets the data
- # at the address given during this cycle.
- If(self.asmiport.get_call_expression(),
- write_to_asmi_pre.eq(1),
- NextState("REFILL_WRTAG")
- )
- )
-
- fsm.act("REFILL_WRTAG",
- # Write the tag first to set the ASMI address
- tag_port.we.eq(1),
- NextState("REFILL_ISSUE")
- )
- fsm.act("REFILL_ISSUE",
- self.asmiport.stb.eq(1),
- If(self.asmiport.ack, NextState("REFILL_WAIT"))
- )
- fsm.act("REFILL_WAIT",
- If(self.asmiport.get_call_expression(), NextState("REFILL_COMPLETE"))
- )
- fsm.act("REFILL_COMPLETE",
- write_from_asmi.eq(1),
- NextState("TEST_HIT")
- )
-
- return Fragment(comb, sync, specials={data_mem, tag_mem, data_port, tag_port}) \
- + fsm.get_fragment()