2013-06-10 12:52:07 -04:00
|
|
|
from migen.fhdl.std import *
|
|
|
|
from migen.bus import wishbone
|
2013-06-25 16:17:39 -04:00
|
|
|
from migen.genlib.fsm import FSM, NextState
|
2013-06-10 12:52:07 -04:00
|
|
|
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):
|
|
|
|
def __init__(self, cachesize, lasmim):
|
|
|
|
self.wishbone = wishbone.Interface()
|
|
|
|
|
|
|
|
###
|
|
|
|
|
2013-08-20 10:53:55 -04:00
|
|
|
if lasmim.dw < 32:
|
|
|
|
raise ValueError("LASMI data width must be >= 32")
|
2013-06-10 12:52:07 -04:00
|
|
|
if (lasmim.dw % 32) != 0:
|
|
|
|
raise ValueError("LASMI data width must be a multiple of 32")
|
|
|
|
|
|
|
|
# Split address:
|
|
|
|
# TAG | LINE NUMBER | LINE OFFSET
|
|
|
|
offsetbits = log2_int(lasmim.dw//32)
|
|
|
|
addressbits = lasmim.aw + offsetbits
|
2013-06-10 16:49:33 -04:00
|
|
|
linebits = log2_int(cachesize) - offsetbits
|
2013-06-10 12:52:07 -04:00
|
|
|
tagbits = addressbits - linebits
|
|
|
|
adr_offset, adr_line, adr_tag = split(self.wishbone.adr, offsetbits, linebits, tagbits)
|
|
|
|
|
|
|
|
# Data memory
|
|
|
|
data_mem = Memory(lasmim.dw, 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()
|
2013-08-20 10:53:55 -04:00
|
|
|
if adr_offset is None:
|
|
|
|
adr_offset_r = None
|
|
|
|
else:
|
|
|
|
adr_offset_r = Signal(offsetbits)
|
|
|
|
self.sync += adr_offset_r.eq(adr_offset)
|
|
|
|
|
2013-06-10 12:52:07 -04:00
|
|
|
self.comb += [
|
|
|
|
data_port.adr.eq(adr_line),
|
|
|
|
If(write_from_lasmi,
|
|
|
|
data_port.dat_w.eq(lasmim.dat_r),
|
|
|
|
data_port.we.eq(Replicate(1, lasmim.dw//8))
|
|
|
|
).Else(
|
|
|
|
data_port.dat_w.eq(Replicate(self.wishbone.dat_w, lasmim.dw//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_lasmi,
|
|
|
|
lasmim.dat_w.eq(data_port.dat_r),
|
|
|
|
lasmim.dat_we.eq(2**(lasmim.dw//8)-1)
|
|
|
|
),
|
|
|
|
chooser(data_port.dat_r, adr_offset_r, self.wishbone.dat_r, reverse=True)
|
|
|
|
]
|
2013-08-20 10:53:55 -04:00
|
|
|
|
2013-06-10 12:52:07 -04:00
|
|
|
|
|
|
|
# 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),
|
|
|
|
lasmim.adr.eq(Cat(adr_line, tag_do.tag))
|
|
|
|
]
|
|
|
|
|
|
|
|
# Control FSM
|
|
|
|
assert(lasmim.write_latency >= 1 and lasmim.read_latency >= 1)
|
2013-06-25 16:17:39 -04:00
|
|
|
fsm = FSM()
|
2013-06-10 12:52:07 -04:00
|
|
|
self.submodules += fsm
|
|
|
|
|
2013-06-25 16:17:39 -04:00
|
|
|
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"))
|
2013-06-10 12:52:07 -04:00
|
|
|
)
|
2013-06-25 16:17:39 -04:00
|
|
|
fsm.act("TEST_HIT",
|
2013-06-10 12:52:07 -04:00
|
|
|
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)
|
|
|
|
),
|
2013-06-25 16:17:39 -04:00
|
|
|
NextState("IDLE")
|
2013-06-10 12:52:07 -04:00
|
|
|
).Else(
|
|
|
|
If(tag_do.dirty,
|
2013-06-25 16:17:39 -04:00
|
|
|
NextState("EVICT_REQUEST")
|
2013-06-10 12:52:07 -04:00
|
|
|
).Else(
|
2013-06-25 16:17:39 -04:00
|
|
|
NextState("REFILL_WRTAG")
|
2013-06-10 12:52:07 -04:00
|
|
|
)
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
2013-06-25 16:17:39 -04:00
|
|
|
fsm.act("EVICT_REQUEST",
|
2013-06-10 12:52:07 -04:00
|
|
|
lasmim.stb.eq(1),
|
|
|
|
lasmim.we.eq(1),
|
2013-06-25 16:17:39 -04:00
|
|
|
If(lasmim.req_ack, NextState("EVICT_WAIT_DATA_ACK"))
|
2013-06-17 17:36:03 -04:00
|
|
|
)
|
2013-06-25 16:17:39 -04:00
|
|
|
fsm.act("EVICT_WAIT_DATA_ACK",
|
|
|
|
If(lasmim.dat_ack, NextState("EVICT_DATAD"))
|
2013-06-10 12:52:07 -04:00
|
|
|
)
|
2013-06-25 16:17:39 -04:00
|
|
|
fsm.act("EVICT_DATA",
|
2013-06-10 12:52:07 -04:00
|
|
|
write_to_lasmi.eq(1),
|
2013-06-25 16:17:39 -04:00
|
|
|
NextState("REFILL_WRTAG")
|
2013-06-10 12:52:07 -04:00
|
|
|
)
|
|
|
|
|
2013-06-25 16:17:39 -04:00
|
|
|
fsm.act("REFILL_WRTAG",
|
2013-06-10 12:52:07 -04:00
|
|
|
# Write the tag first to set the LASMI address
|
|
|
|
tag_port.we.eq(1),
|
2013-06-25 16:17:39 -04:00
|
|
|
NextState("REFILL_REQUEST")
|
2013-06-10 12:52:07 -04:00
|
|
|
)
|
2013-06-25 16:17:39 -04:00
|
|
|
fsm.act("REFILL_REQUEST",
|
2013-06-10 12:52:07 -04:00
|
|
|
lasmim.stb.eq(1),
|
2013-06-25 16:17:39 -04:00
|
|
|
If(lasmim.req_ack, NextState("REFILL_WAIT_DATA_ACK"))
|
2013-06-17 17:36:03 -04:00
|
|
|
)
|
2013-06-25 16:17:39 -04:00
|
|
|
fsm.act("REFILL_WAIT_DATA_ACK",
|
|
|
|
If(lasmim.dat_ack, NextState("REFILL_DATAD"))
|
2013-06-10 12:52:07 -04:00
|
|
|
)
|
2013-06-25 16:17:39 -04:00
|
|
|
fsm.act("REFILL_DATA",
|
2013-06-10 16:49:33 -04:00
|
|
|
write_from_lasmi.eq(1),
|
2013-06-25 16:17:39 -04:00
|
|
|
NextState("TEST_HIT")
|
2013-06-10 12:52:07 -04:00
|
|
|
)
|