Skip to content

Commit

Permalink
Simplified DummyLSU (#427)
Browse files Browse the repository at this point in the history
  • Loading branch information
tilk committed Jul 5, 2023
1 parent 6bf3b70 commit df6653b
Showing 1 changed file with 53 additions and 99 deletions.
152 changes: 53 additions & 99 deletions coreblocks/lsu/dummyLsu.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,13 @@ def __init__(self, gen_params: GenParams, bus: WishboneMaster, current_instr: Re
self.loadedData = Signal(self.gen_params.isa.xlen)
self.get_result_ack = Signal()
self.result_ready = Signal()
self.execute_store = Signal()
self.execute = Signal()
self.op_exception = Signal()

def calculate_addr(self):
"""Calculate Load/Store address as defined by RiscV spec"""
return self.current_instr.s1_val + self.current_instr.imm
def calculate_addr(self, m: ModuleLike):
addr = Signal(self.gen_params.isa.xlen)
m.d.comb += addr.eq(self.current_instr.s1_val + self.current_instr.imm)
return addr

def prepare_bytes_mask(self, m: ModuleLike, addr: Signal) -> Signal:
mask_len = self.gen_params.isa.xlen // self.bus.wb_params.granularity
Expand Down Expand Up @@ -99,116 +100,70 @@ def prepare_data_to_save(self, m: ModuleLike, raw_data: Signal, addr: Signal):
return data

def check_align(self, m: TModule, addr: Signal):
misaligned = Signal()
aligned = Signal()
with m.Switch(self.current_instr.exec_fn.funct3):
with m.Case(Funct3.W):
m.d.comb += misaligned.eq(addr[0:2] != 0)
m.d.comb += aligned.eq(addr[0:2] == 0)
with m.Case(Funct3.H, Funct3.HU):
m.d.comb += misaligned.eq(addr[0] != 0)
return misaligned
m.d.comb += aligned.eq(addr[0] == 0)
with m.Case():
m.d.comb += aligned.eq(1)
return aligned

def op_init(self, m: TModule, op_initiated: Signal, is_store: bool):
addr = Signal(self.gen_params.isa.xlen)
m.d.comb += addr.eq(self.calculate_addr())
misaligned = Signal()
m.d.comb += misaligned.eq(self.check_align(m, addr))
def elaborate(self, platform):
m = TModule()

instr_ready = (
(self.current_instr.rp_s1 == 0)
& (self.current_instr.rp_s2 == 0)
& self.current_instr.valid
& ~self.result_ready
)

is_load = self.current_instr.exec_fn.op_type == OpType.LOAD

addr = self.calculate_addr(m)
aligned = self.check_align(m, addr)
bytes_mask = self.prepare_bytes_mask(m, addr)
req = Record(self.bus.requestLayout)
m.d.comb += req.addr.eq(addr >> 2) # calculate word address
m.d.comb += req.we.eq(is_store)
m.d.comb += req.sel.eq(bytes_mask)
m.d.comb += req.data.eq(self.prepare_data_to_save(m, self.current_instr.s2_val, addr))

with Transaction().body(m):
with m.If(~misaligned):
# load_init is under an "if" so that this transaction requests to be executed
# after all "if"s above are taken, so there is no need to add any additional
# signal here as a "request"
self.bus.request(m, req)
with m.Else():
m.d.sync += self.op_exception.eq(1)

cause = ExceptionCause.STORE_ADDRESS_MISALIGNED if is_store else ExceptionCause.LOAD_ADDRESS_MISALIGNED
self.report(m, rob_id=self.current_instr.rob_id, cause=cause)

m.d.sync += op_initiated.eq(1)

def op_end(self, m: TModule, op_initiated: Signal, is_store: bool):
addr = Signal(self.gen_params.isa.xlen)
m.d.comb += addr.eq(self.calculate_addr())
data = self.prepare_data_to_save(m, self.current_instr.s2_val, addr)

with m.If(~self.op_exception):
with Transaction().body(m):
fetched = self.bus.result(m)
m.d.sync += op_initiated.eq(0)
with m.FSM("Start"):
with m.State("Start"):
with m.If(instr_ready & (self.execute | is_load)):
with m.If(aligned):
with Transaction().body(m):
self.bus.request(m, addr=addr >> 2, we=~is_load, sel=bytes_mask, data=data)
m.next = "End"
with m.Else():
with Transaction().body(m):
m.d.sync += self.op_exception.eq(1)
m.d.sync += self.result_ready.eq(1)

if not is_store:
with m.If(fetched.err == 0):
m.d.sync += self.loadedData.eq(self.postprocess_load_data(m, fetched.data, addr))
cause = Mux(
is_load, ExceptionCause.LOAD_ADDRESS_MISALIGNED, ExceptionCause.STORE_ADDRESS_MISALIGNED
)
self.report(m, rob_id=self.current_instr.rob_id, cause=cause)

with m.If(fetched.err):
cause = ExceptionCause.STORE_ACCESS_FAULT if is_store else ExceptionCause.LOAD_ACCESS_FAULT
self.report(m, rob_id=self.current_instr.rob_id, cause=cause)
m.next = "End"

m.d.sync += self.op_exception.eq(fetched.err)
m.d.sync += self.result_ready.eq(1)
with m.Else():
m.d.sync += self.result_ready.eq(1)
with m.State("End"):
with Transaction().body(m):
fetched = self.bus.result(m)

def elaborate(self, platform):
def check_if_instr_ready(current_instr: Record, result_ready: Signal) -> Value:
"""Check if all values needed by instruction are already calculated."""
return (
(current_instr.rp_s1 == 0)
& (current_instr.rp_s2 == 0)
& (current_instr.valid == 1)
& (result_ready == 0)
)

def check_if_instr_is_load(current_instr: Record) -> Value:
return current_instr.exec_fn.op_type == OpType.LOAD
m.d.sync += self.loadedData.eq(self.postprocess_load_data(m, fetched.data, addr))

m = TModule()
with m.If(fetched.err):
cause = Mux(is_load, ExceptionCause.LOAD_ACCESS_FAULT, ExceptionCause.STORE_ACCESS_FAULT)
self.report(m, rob_id=self.current_instr.rob_id, cause=cause)

instr_ready = check_if_instr_ready(self.current_instr, self.result_ready)
instr_is_load = check_if_instr_is_load(self.current_instr)
op_initiated = Signal()
m.d.sync += self.op_exception.eq(fetched.err)
m.d.sync += self.result_ready.eq(1)

with m.FSM("Start"):
with m.State("Start"):
with m.If(instr_ready & instr_is_load):
self.op_init(m, op_initiated, False)
m.next = "LoadInit"
with m.If(instr_ready & ~instr_is_load):
m.next = "StoreWaitForExec"
with m.State("LoadInit"):
with m.If(~op_initiated):
self.op_init(m, op_initiated, False)
with m.Else():
m.next = "LoadEnd"
with m.State("LoadEnd"):
self.op_end(m, op_initiated, False)
with m.If(self.get_result_ack):
m.d.sync += self.result_ready.eq(0)
m.d.sync += self.loadedData.eq(0)
m.d.sync += self.op_exception.eq(0)
m.next = "Start"
with m.State("StoreWaitForExec"):
with m.If(self.execute_store):
self.op_init(m, op_initiated, True)
m.next = "StoreInit"
with m.State("StoreInit"):
with m.If(~op_initiated):
self.op_init(m, op_initiated, True)
with m.Else():
m.next = "StoreEnd"
with m.State("StoreEnd"):
self.op_end(m, op_initiated, True)
with m.If(self.get_result_ack):
m.d.sync += self.result_ready.eq(0)
m.d.sync += self.op_exception.eq(0)
m.next = "Start"

return m


Expand Down Expand Up @@ -302,9 +257,8 @@ def _():

@def_method(m, self.precommit)
def _(rob_id: Value):
# TODO: I/O reads
with m.If((current_instr.exec_fn.op_type == OpType.STORE) & (rob_id == current_instr.rob_id)):
m.d.comb += internal.execute_store.eq(1)
with m.If(current_instr.valid & (rob_id == current_instr.rob_id)):
m.d.comb += internal.execute.eq(1)

return m

Expand Down

0 comments on commit df6653b

Please sign in to comment.