Skip to content

Commit

Permalink
Merge branch 'master' into fpu_rounding
Browse files Browse the repository at this point in the history
  • Loading branch information
tilk authored Oct 22, 2024
2 parents 1187955 + c3edca0 commit 14fa0fd
Show file tree
Hide file tree
Showing 107 changed files with 1,561 additions and 755 deletions.
37 changes: 36 additions & 1 deletion coreblocks/arch/csr_address.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
from amaranth.lib.enum import IntEnum, unique

__all__ = [
"CSRAddress",
"MstatusFieldOffsets",
]


@unique
class CSRAddress(IntEnum, shape=12):
Expand Down Expand Up @@ -430,4 +435,34 @@ class CSRAddress(IntEnum, shape=12):
DSCRATCH1 = 0x7B3 # Debug scratch register 1.

# Internal Coreblocks CSRs
COREBLOCKS_TEST_CSR = 0x7FF # used only for testbench verification
# used only for testbench verification

# CSR for custom communication with testbenches
COREBLOCKS_TEST_CSR = 0x7FF
# CSR providing writable current privilege mode (U-mode accesible)
COREBLOCKS_TEST_PRIV_MODE = 0x8FF


@unique
class MstatusFieldOffsets(IntEnum):
SIE = 1 # Supervisor Interrupt Enable
MIE = 3 # Machine Interrupt Enable
SPIE = 5 # Supervisor Previous Interrupt Enable
UBE = 6 # User Endianess Control
MPIE = 7 # Machine Previous Interrupt Enable
SPP = 8 # Supervisor Previous Pirvilege
VS = 9 # Vector Context Status
MPP = 11 # Machine Previous Pirvilege
FS = 13 # Float Context Status
XS = 15 # Additional Extension State Context Status
MPRV = 17 # Modify Pirvilege
SUM = 18 # Supervisor User Memory Access
MXR = 19 # Make Executable Readable
TVM = 20 # Trap Virtual Memory
TW = 21 # Timeout Wait
TSR = 22 # Trap SRET
UXL = 32 # User XLEN
SXL = 34 # Supervisor XLEN
SBE = 36 # Supervisor Endianess Control
MBE = 37 # Machine Endianess Contorol
SD = -1 # Context Status Dirty bit. Placed on last bit of mstatus
8 changes: 8 additions & 0 deletions coreblocks/arch/isa_consts.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"Registers",
"PrivilegeLevel",
"InterruptCauseNumber",
"XlenEncoding",
]


Expand Down Expand Up @@ -172,3 +173,10 @@ class InterruptCauseNumber(IntEnum):
MTI = 7 # machine timer interrupt
SEI = 9 # supervisor external interrupt
MEI = 11 # machine external interrupt


@unique
class XlenEncoding(IntEnum, shape=2):
W32 = 1
W64 = 2
W128 = 3
9 changes: 5 additions & 4 deletions coreblocks/backend/retirement.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from coreblocks.params.genparams import GenParams
from coreblocks.arch import ExceptionCause
from coreblocks.interface.keys import CoreStateKey, GenericCSRRegistersKey, InstructionPrecommitKey
from coreblocks.interface.keys import CoreStateKey, CSRInstancesKey, InstructionPrecommitKey
from coreblocks.priv.csr.csr_instances import CSRAddress, DoubleCounterCSR


Expand Down Expand Up @@ -67,10 +67,10 @@ def elaborate(self, platform):

m.submodules += [self.perf_instr_ret, self.perf_trap_latency]

m_csr = self.dependency_manager.get_dependency(GenericCSRRegistersKey()).m_mode
m_csr = self.dependency_manager.get_dependency(CSRInstancesKey()).m_mode
m.submodules.instret_csr = self.instret_csr

side_fx = Signal(reset=1)
side_fx = Signal(init=1)

def free_phys_reg(rp_dst: Value):
# mark reg in Register File as free
Expand Down Expand Up @@ -129,7 +129,7 @@ def flush_instr(rob_entry):

cause_entry = Signal(self.gen_params.isa.xlen)

arch_trap = Signal(reset=1)
arch_trap = Signal(init=1)

with m.If(cause_register.cause == ExceptionCause._COREBLOCKS_ASYNC_INTERRUPT):
# Async interrupts are inserted only by JumpBranchUnit and conditionally by MRET and CSR
Expand Down Expand Up @@ -162,6 +162,7 @@ def flush_instr(rob_entry):
# Register RISC-V architectural trap in CSRs
m_csr.mcause.write(m, cause_entry)
m_csr.mepc.write(m, cause_register.pc)
m_csr.mtval.write(m, cause_register.mtval)
self.trap_entry(m)

# Fetch is already stalled by ExceptionCauseRegister
Expand Down
27 changes: 13 additions & 14 deletions coreblocks/cache/icache.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from amaranth import *
from amaranth.lib.data import View
import amaranth.lib.memory as memory
from amaranth.utils import exact_log2

from transactron.core import def_method, Priority, TModule
Expand Down Expand Up @@ -156,7 +157,7 @@ def elaborate(self, platform):
with Transaction().body(m):
self.perf_flushes.incr(m, cond=flush_finish)

with m.FSM(reset="FLUSH") as fsm:
with m.FSM(init="FLUSH") as fsm:
with m.State("FLUSH"):
with m.If(flush_finish):
m.next = "LOOKUP"
Expand All @@ -172,7 +173,7 @@ def elaborate(self, platform):
m.next = "LOOKUP"

# Replacement policy
way_selector = Signal(self.params.num_of_ways, reset=1)
way_selector = Signal(self.params.num_of_ways, init=1)
with m.If(refill_finish):
m.d.sync += way_selector.eq(way_selector.rotate_left(1))

Expand Down Expand Up @@ -329,27 +330,25 @@ def elaborate(self, platform):
for i in range(self.params.num_of_ways):
way_wr = self.way_wr_en[i]

tag_mem = Memory(width=len(Value.cast(self.tag_wr_data)), depth=self.params.num_of_sets)
tag_mem_rp = tag_mem.read_port()
tag_mem = memory.Memory(shape=self.tag_data_layout, depth=self.params.num_of_sets, init=[])
tag_mem_wp = tag_mem.write_port()
m.submodules[f"tag_mem_{i}_rp"] = tag_mem_rp
m.submodules[f"tag_mem_{i}_wp"] = tag_mem_wp
tag_mem_rp = tag_mem.read_port(transparent_for=[tag_mem_wp])
m.submodules[f"tag_mem_{i}"] = tag_mem

m.d.comb += [ # remove Value.cast after Amaranth upgrade
assign(Value.cast(self.tag_rd_data[i]), tag_mem_rp.data),
m.d.comb += [
assign(self.tag_rd_data[i], tag_mem_rp.data),
tag_mem_rp.addr.eq(self.tag_rd_index),
tag_mem_wp.addr.eq(self.tag_wr_index),
assign(tag_mem_wp.data, Value.cast(self.tag_wr_data)),
assign(tag_mem_wp.data, self.tag_wr_data),
tag_mem_wp.en.eq(self.tag_wr_en & way_wr),
]

data_mem = Memory(
width=self.fetch_block_bits, depth=self.params.num_of_sets * self.params.fetch_blocks_in_line
data_mem = memory.Memory(
shape=self.fetch_block_bits, depth=self.params.num_of_sets * self.params.fetch_blocks_in_line, init=[]
)
data_mem_rp = data_mem.read_port()
data_mem_wp = data_mem.write_port()
m.submodules[f"data_mem_{i}_rp"] = data_mem_rp
m.submodules[f"data_mem_{i}_wp"] = data_mem_wp
data_mem_rp = data_mem.read_port(transparent_for=[data_mem_wp])
m.submodules[f"data_mem_{i}"] = data_mem

# We address the data RAM using fetch blocks, so we have to
# discard a few least significant bits from the address.
Expand Down
16 changes: 8 additions & 8 deletions coreblocks/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from coreblocks.interface.layouts import *
from coreblocks.interface.keys import (
FetchResumeKey,
GenericCSRRegistersKey,
CSRInstancesKey,
CommonBusDataKey,
)
from coreblocks.params.genparams import GenParams
Expand All @@ -20,7 +20,7 @@
from coreblocks.core_structs.rf import RegisterFile
from coreblocks.priv.csr.csr_instances import GenericCSRRegisters
from coreblocks.frontend.frontend import CoreFrontend
from coreblocks.priv.traps.exception import ExceptionCauseRegister
from coreblocks.priv.traps.exception import ExceptionInformationRegister
from coreblocks.scheduler.scheduler import Scheduler
from coreblocks.backend.annoucement import ResultAnnouncement
from coreblocks.backend.retirement import Retirement
Expand Down Expand Up @@ -69,7 +69,7 @@ def __init__(self, *, gen_params: GenParams):

self.connections.add_dependency(CommonBusDataKey(), self.bus_master_data_adapter)

self.exception_cause_register = ExceptionCauseRegister(
self.exception_information_register = ExceptionInformationRegister(
self.gen_params,
rob_get_indices=self.ROB.get_indices,
fetch_stall_exception=self.frontend.stall,
Expand All @@ -89,7 +89,7 @@ def __init__(self, *, gen_params: GenParams):
)

self.csr_generic = GenericCSRRegisters(self.gen_params)
self.connections.add_dependency(GenericCSRRegistersKey(), self.csr_generic)
self.connections.add_dependency(CSRInstancesKey(), self.csr_generic)

self.interrupt_controller = InternalInterruptController(self.gen_params)

Expand Down Expand Up @@ -134,7 +134,7 @@ def elaborate(self, platform):
gen_params=self.gen_params,
)

m.submodules.exception_cause_register = self.exception_cause_register
m.submodules.exception_information_register = self.exception_information_register

fetch_resume_fb, fetch_resume_unifiers = self.connections.get_dependency(FetchResumeKey())
m.submodules.fetch_resume_unifiers = ModuleConnector(**fetch_resume_unifiers)
Expand All @@ -151,8 +151,8 @@ def elaborate(self, platform):
r_rat_peek=rrat.peek,
free_rf_put=free_rf_fifo.write,
rf_free=rf.free,
exception_cause_get=self.exception_cause_register.get,
exception_cause_clear=self.exception_cause_register.clear,
exception_cause_get=self.exception_information_register.get,
exception_cause_clear=self.exception_information_register.clear,
frat_rename=frat.rename,
fetch_continue=self.frontend.resume_from_exception,
instr_decrement=core_counter.decrement,
Expand All @@ -161,7 +161,7 @@ def elaborate(self, platform):
)

# push all registers to FreeRF at reset. r0 should be skipped, stop when counter overflows to 0
free_rf_reg = Signal(self.gen_params.phys_regs_bits, reset=1)
free_rf_reg = Signal(self.gen_params.phys_regs_bits, init=1)
with Transaction(name="InitFreeRFFifo").body(m, request=(free_rf_reg.bool())):
free_rf_fifo.write(m, free_rf_reg)
m.d.sync += free_rf_reg.eq(free_rf_reg + 1)
Expand Down
19 changes: 9 additions & 10 deletions coreblocks/core_structs/rf.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ def __init__(self, *, gen_params: GenParams):
layouts = gen_params.get(RFLayouts)
self.internal_layout = make_layout(("reg_val", gen_params.isa.xlen), ("valid", 1))
self.read_layout = layouts.rf_read_out
self.entries = Array(Signal(self.internal_layout) for _ in range(2**gen_params.phys_regs_bits))
self.entries = Array(
Signal(self.internal_layout, reset={"reg_val": 0, "valid": k == 0})
for k in range(2**gen_params.phys_regs_bits)
)

self.read1 = Method(i=layouts.rf_read_in, o=layouts.rf_read_out)
self.read2 = Method(i=layouts.rf_read_in, o=layouts.rf_read_out)
Expand Down Expand Up @@ -43,23 +46,19 @@ def elaborate(self, platform):
being_written = Signal(self.gen_params.phys_regs_bits)
written_value = Signal(self.gen_params.isa.xlen)

# Register 0 always valid (this field won't be updated in methods below) - not sure
# how to set 0th entry valid signal at initialization stage so doing it here instead
# with a 1-cycle delay. I believe this has to be in sync domain like every other
# RF entry or else bad things will happen.
m.d.sync += self.entries[0].valid.eq(1)

@def_method(m, self.read1)
def _(reg_id: Value):
forward = being_written == reg_id
forward = Signal()
m.d.av_comb += forward.eq((being_written == reg_id) & (reg_id != 0))
return {
"reg_val": Mux(forward, written_value, self.entries[reg_id].reg_val),
"valid": Mux(forward, 1, self.entries[reg_id].valid),
}

@def_method(m, self.read2)
def _(reg_id: Value):
forward = being_written == reg_id
forward = Signal()
m.d.av_comb += forward.eq((being_written == reg_id) & (reg_id != 0))
return {
"reg_val": Mux(forward, written_value, self.entries[reg_id].reg_val),
"valid": Mux(forward, 1, self.entries[reg_id].valid),
Expand All @@ -69,7 +68,7 @@ def _(reg_id: Value):
def _(reg_id: Value, reg_val: Value):
zero_reg = reg_id == 0
m.d.comb += being_written.eq(reg_id)
m.d.comb += written_value.eq(Mux(zero_reg, 0, reg_val))
m.d.av_comb += written_value.eq(reg_val)
with m.If(~(zero_reg)):
m.d.sync += self.entries[reg_id].reg_val.eq(reg_val)
m.d.sync += self.entries[reg_id].valid.eq(1)
Expand Down
8 changes: 5 additions & 3 deletions coreblocks/core_structs/rob.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from amaranth import *
from amaranth.lib.data import View
import amaranth.lib.memory as memory
from transactron import Method, Transaction, def_method, TModule
from transactron.lib.metrics import *
from coreblocks.interface.layouts import ROBLayouts
Expand All @@ -18,7 +19,7 @@ def __init__(self, gen_params: GenParams) -> None:
self.retire = Method()
self.done = Array(Signal() for _ in range(2**self.params.rob_entries_bits))
self.exception = Array(Signal() for _ in range(2**self.params.rob_entries_bits))
self.data = Memory(width=layouts.data_layout.size, depth=2**self.params.rob_entries_bits)
self.data = memory.Memory(shape=layouts.data_layout.size, depth=2**self.params.rob_entries_bits, init=[])
self.get_indices = Method(o=layouts.get_indices, nonexclusive=True)

self.perf_rob_wait_time = FIFOLatencyMeasurer(
Expand All @@ -45,8 +46,9 @@ def elaborate(self, platform):
peek_possible = start_idx != end_idx
put_possible = (end_idx + 1)[0 : len(end_idx)] != start_idx

m.submodules.read_port = read_port = self.data.read_port()
m.submodules.write_port = write_port = self.data.write_port()
m.submodules.data = self.data
write_port = self.data.write_port()
read_port = self.data.read_port(transparent_for=[write_port])

m.d.comb += read_port.addr.eq(start_idx)

Expand Down
14 changes: 11 additions & 3 deletions coreblocks/frontend/decoder/decode_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ def elaborate(self, platform):
]

exception_override = Signal()
m.d.comb += exception_override.eq(instr_decoder.illegal | raw.access_fault)
m.d.comb += exception_override.eq(instr_decoder.illegal | raw.access_fault.any())
exception_funct = Signal(Funct3)
with m.If(raw.access_fault):
with m.If(raw.access_fault.any()):
m.d.comb += exception_funct.eq(Funct3._EINSTRACCESSFAULT)
with m.Elif(instr_decoder.illegal):
self.perf_illegal_instr.incr(m)
Expand Down Expand Up @@ -95,7 +95,15 @@ def elaborate(self, platform):
"rl_s1": Mux(instr_decoder.rs1_v & (~exception_override), instr_decoder.rs1, 0),
"rl_s2": Mux(instr_decoder.rs2_v & (~exception_override), instr_decoder.rs2, 0),
},
"imm": instr_decoder.imm,
"imm": Mux(
~exception_override,
instr_decoder.imm,
Mux(
raw.access_fault.any(),
raw.access_fault, # pass access fault details to FU
raw.instr, # illegal instruction - pass raw instruction bits for `mtval`
),
),
"csr": instr_decoder.csr,
"pc": raw.pc,
},
Expand Down
8 changes: 8 additions & 0 deletions coreblocks/frontend/decoder/instr_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,14 @@ def elaborate(self, platform):
self.rs1_v.eq(0),
]

# HACK: pass logical registers in unused high bits of CSR instruction for `mtval` reconstruction
with m.If((self.optype == OpType.CSR_REG) | (self.optype == OpType.CSR_IMM)):
m.d.comb += self.imm[32 - self.gen_params.isa.reg_cnt_log : 32].eq(self.rd)
m.d.comb += self.imm[32 - self.gen_params.isa.reg_cnt_log * 2 : 32 - self.gen_params.isa.reg_cnt_log].eq(
self.rs1
)
assert 32 - self.gen_params.isa.reg_cnt_log * 2 >= 5

# Instruction simplification

# lui rd, imm -> addi rd, x0, (imm << 12)
Expand Down
4 changes: 3 additions & 1 deletion coreblocks/frontend/decoder/rvc.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,8 @@ def elaborate(self, platform):

res = self.instr_mux(quadrant, quadrants)

m.d.comb += self.instr_out.eq(Mux(res[1], res[0], IllegalInstr()))
# In case of illegal instruction, output `instr_in` to be able to save it into `mtval` CSR.
# Decoder would still recognize it as illegal because of quadrant != 0b11
m.d.comb += self.instr_out.eq(Mux(res[1], res[0], self.instr_in))

return m
Loading

0 comments on commit 14fa0fd

Please sign in to comment.