bus: Wishbone to ASMI caching bridge (untested)
This commit is contained in:
parent
244bf17db7
commit
cad9d3b960
|
@ -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()
|
Loading…
Reference in New Issue