bus: Wishbone to ASMI caching bridge (untested)
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 13 Feb 2012 15:29:38 +0000 (16:29 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Mon, 13 Feb 2012 15:29:38 +0000 (16:29 +0100)
migen/bus/wishbone2asmi.py [new file with mode: 0644]

diff --git a/migen/bus/wishbone2asmi.py b/migen/bus/wishbone2asmi.py
new file mode 100644 (file)
index 0000000..5a9875b
--- /dev/null
@@ -0,0 +1,147 @@
+from migen.bus import wishbone
+from migen.fhdl.structure import *
+from migen.corelogic.fsm import FSM
+from migen.corelogic.misc import split, displacer, chooser
+from migen.corelogic.record import Record
+
+def _log2_int(n):
+       l = 1
+       r = 0
+       while l < n:
+               l *= 2
+               r += 1
+       if l == n:
+               return r
+       else:
+               raise ValueError("Not a power of 2")
+
+# 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.Slave()
+               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 = aaw - linebits
+               adr_offset, adr_line, adr_tag = split(self.wishbone.adr_i, offsetbits, linebits, tagbits)
+               
+               # Data memory
+               data_adr = Signal(BV(linebits))
+               data_do = Signal(BV(adw))
+               data_di = Signal(BV(adw))
+               data_we = Signal(BV(adw//8))
+               data_port = MemoryPort(data_adr, data_do, data_we, data_di, we_granularity=8)
+               data_mem = Memory(adw, 2**linebits, data_port)
+               
+               write_from_asmi = Signal()
+               adr_offset_r = Signal(BV(offsetbits))
+               comb += [
+                       data_adr.eq(adr_line),
+                       If(write_from_asmi,
+                               data_di.eq(self.asmiport.dat_r),
+                               data_we.eq(Replicate(1, adw//8))
+                       ).Else(
+                               data_di.eq(Replicate(self.wishbone.dat_i, adw//32),
+                               If(self.wishbone.cyc_i & self.wishbone.stb_i & self.wishbone.ack_o,
+                                       displacer(self.wishbone.we_i, adr_offset, data_we)
+                               )
+                       ),
+                       self.asmiport.dat_w.eq(data_do),
+                       chooser(data_do, adr_offset_r, self.wishbone.dat_o)
+               ]
+               sync += [
+                       adr_offset_r.eq(adr_offset)
+               ]
+               
+               # Tag memory
+               tag_layout = [("tag", BV(linebits)), ("dirty", BV(1))]
+               tag_do = Record(tag_layout)
+               tag_do_raw = tag_do.to_signal(comb, False)
+               tag_di = Record(tag_layout)
+               tag_di_raw = tag_di.to_signal(comb, True)
+               
+               tag_adr = Signal(BV(linebits))
+               tag_we = Signal()
+               tag_port = MemoryPort(tag_adr, tag_do_raw, tag_we, tag_di_raw)
+               tag_mem = Memory(tagbits+1, 2**linebits, tag_port)
+               
+               comb += [
+                       tag_adr.eq(adr_line),
+                       tag_di.tag.eq(adr_tag),
+                       self.asmiport.adr.eq(Cat(adr_line, tag_do.tag))
+               ]
+               
+               # Control FSM
+               fsm = FSM("IDLE", "TEST_HIT",
+                       "EVICT_ISSUE", "EVICT_WAIT",
+                       "REFILL_WRTAG", "REFILL_ISSUE", "REFILL_WAIT", "REFILL_COMPLETE")
+               
+               fsm.act(fsm.IDLE,
+                       If(self.wishbone.cyc_i & self.wishbone.stb_i, fsm.next_state(fsm.TEST_HIT))
+               )
+               fsm.act(fsm.TEST_HIT,
+                       If(tag_do.tag == adr_tag,
+                               self.wishbone.ack_o.eq(1),
+                               If(self.wishbone.we_i,
+                                       tag_di.dirty.eq(1),
+                                       tag_we.eq(1)
+                               ),
+                               fsm.next_state(fsm.IDLE)
+                       ).Else(
+                               If(tag_do.dirty,
+                                       fsm.next_state(fsm.EVICT_ISSUE)
+                               ).Else(
+                                       fsm.next_state(fsm.REFILL_WRTAG)
+                               )
+                       )
+               )
+               
+               fsm.act(fsm.EVICT_ISSUE,
+                       self.asmiport.stb.eq(1),
+                       self.asmiport.we.eq(1),
+                       If(self.asmiport.ack, fsm.next_state(fsm.EVICT_WAIT))
+               )
+               fsm.act(fsm.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(), fsm.next_state(fsm.REFILL_WRTAG))
+               )
+               
+               fsm.act(fsm.REFILL_WRTAG,
+                       # Write the tag first to set the ASMI address
+                       tag_we.eq(1),
+                       fsm.next_state(fsm.REFILL_ISSUE)
+               )
+               fsm.act(fsm.REFILL_ISSUE,
+                       self.asmiport.stb.eq(1),
+                       If(self.asmiport.ack, fsm.next_state(fsm.REFILL_WAIT))
+               )
+               fsm.act(fsm.REFILL_WAIT,
+                       If(self.asmiport.get_call_expression(), fsm.next_state(fsm.REFILL_COMPLETE))
+               )
+               fsm.act(fsm.REFILL_COMPLETE,
+                       write_from_asmi.eq(1),
+                       fsm.next_state(fsm.TEST_HIT)
+               )
+               
+               return Fragment(comb, sync, memories=[data_mem, tag_mem]) \
+                       + fsm.get_fragment()