Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

E extension #440

Merged
merged 6 commits into from
Jul 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 28 additions & 4 deletions coreblocks/frontend/decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,11 @@ def elaborate(self, platform):
m = Module()

extensions = self.gen.isa.extensions

# We need to support all I instructions in E extension, but this is not extension implication
if Extension.E in extensions:
extensions |= Extension.I

supported_encodings: set[Encoding] = set()
encoding_to_optype: dict[Encoding, OpType] = dict()
for ext, optypes in optypes_by_extensions.items():
Expand Down Expand Up @@ -397,10 +402,20 @@ def elaborate(self, platform):
self._extract(20, self.funct12),
]

rd_field = Signal(self.gen.isa.reg_field_bits)
rs1_field = Signal(self.gen.isa.reg_field_bits)
rs2_field = Signal(self.gen.isa.reg_field_bits)

m.d.comb += [
self._extract(7, rd_field),
self._extract(15, rs1_field),
self._extract(20, rs2_field),
]

m.d.comb += [
self._extract(7, self.rd),
self._extract(15, self.rs1),
self._extract(20, self.rs2),
self.rd.eq(rd_field),
self.rs1.eq(rs1_field),
self.rs2.eq(rs2_field),
]

rd_invalid = Signal()
Expand Down Expand Up @@ -480,6 +495,15 @@ def elaborate(self, platform):
self._extract(28, self.fm),
]

# Check if register field bits outside of logical register space are zeroed

register_space_invalid = Signal()
m.d.comb += register_space_invalid.eq(
(self.rd_v & (rd_field[len(self.rd) :]).any())
| (self.rs1_v & (rs1_field[len(self.rs1) :]).any())
| (self.rs2_v & (rs2_field[len(self.rs2) :]).any())
)

# CSR address

m.d.comb += self._extract(20, self.csr)
Expand Down Expand Up @@ -510,6 +534,6 @@ def elaborate(self, platform):
# 0b11 at field [0:2] of instruction specify standard 32-bit instruction encoding space (not checked by opcode)
encoding_space = Signal(2)
m.d.comb += self._extract(0, encoding_space)
m.d.comb += self.illegal.eq((self.optype == OpType.UNKNOWN) | (encoding_space != 0b11))
m.d.comb += self.illegal.eq((self.optype == OpType.UNKNOWN) | (encoding_space != 0b11) | register_space_invalid)

return m
4 changes: 3 additions & 1 deletion coreblocks/params/configurations.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,11 +89,13 @@ def replace(self, **kwargs):

# Minimal core configuration
tiny_core_config = CoreConfiguration(
embedded=True,
func_units_config=(
RSBlockComponent([ALUComponent(), ShiftUnitComponent(), JumpComponent()], rs_entries=2),
LSUBlockComponent(),
),
rob_entries_bits=6,
phys_regs_bits=basic_core_config.phys_regs_bits - 1,
rob_entries_bits=basic_core_config.rob_entries_bits - 1,
allow_partial_extensions=True, # No exception unit
)

Expand Down
3 changes: 0 additions & 3 deletions coreblocks/params/genparams.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,6 @@ def __init__(self, cfg: CoreConfiguration):
if not cfg.allow_partial_extensions and ext_partial != ext_full:
raise RuntimeError(f"Extensions {ext_partial&~ext_full!r} are only partially supported")

if cfg.embedded:
raise RuntimeError("E extension is not supported yet") # TODO: Remove after implementing E in decode

extensions |= cfg._implied_extensions
self.isa_str = gen_isa_string(extensions, cfg.xlen)

Expand Down
18 changes: 4 additions & 14 deletions coreblocks/params/isa.py
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,6 @@ class Extension(enum.IntFlag):
G = I | M | A | F | D | ZICSR | ZIFENCEI


# Extensions which are mutually exclusive
_extension_exclusive = [
[Extension.I, Extension.E],
]

# Extensions which explicitly require another extension in order to be valid (can be joined using | operator)
_extension_requirements = {
Extension.D: Extension.F,
Expand Down Expand Up @@ -344,14 +339,6 @@ def parse_extension(e):
if ext in self.extensions:
self.extensions |= imply

for exclusive in _extension_exclusive:
for i in range(len(exclusive)):
for j in range(i + 1, len(exclusive)):
if exclusive[i] | exclusive[j] in self.extensions:
raise RuntimeError(
f"ISA extensions {exclusive[i].name} and {exclusive[j].name} are mutually exclusive"
)

for ext, requirements in _extension_requirements.items():
if ext in self.extensions and requirements not in self.extensions:
for req in Extension:
Expand All @@ -360,7 +347,8 @@ def parse_extension(e):
f"ISA extension {ext.name} requires the {req.name} extension to be supported"
)

if self.extensions & Extension.E:
# I & E extensions can coexist if I extenstion can be disableable at runtime
if self.extensions & Extension.E and not self.extensions & Extension.I:
self.reg_cnt = 16
else:
self.reg_cnt = 32
Expand All @@ -370,6 +358,8 @@ def parse_extension(e):
self.ilen_bytes = self.ilen // 8
self.ilen_log = self.ilen.bit_length() - 1

self.reg_field_bits = 5

self.csr_alen = 12


Expand Down
25 changes: 25 additions & 0 deletions test/frontend/test_decoder.py
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,31 @@ def test_zbb(self):
self.do_test(test)


class TestDecoderEExtLegal(TestCaseWithSimulator):
E_TEST = [
(0x00000033, False), # add x0, x0, x0
(0x00F787B3, False), # add x15, x15, x15
(0x00F807B3, True), # add x15, x16, x15
(0xFFF78793, False), # addi x15, x15, -1
(0xFFF78813, True), # addi x16, x15, -1
(0xFFFFF06F, False), # jal x0, -2
(0xFFFFFF6F, True), # jal x30, -2
]

def test_e(self):
gen = GenParams(test_core_config.replace(embedded=True, _implied_extensions=Extension.E))
self.decoder = InstrDecoder(gen)

def process():
for encoding, illegal in self.E_TEST:
yield self.decoder.instr.eq(encoding)
yield Settle()
self.assertEqual((yield self.decoder.illegal), illegal)

with self.run_simulation(self.decoder) as sim:
sim.add_process(process)


class TestEncodingUniqueness(TestCase):
def test_encoding_uniqueness(self):
code_type = tuple[Optional[int], Optional[int], Optional[int], Optional[int]]
Expand Down
2 changes: 1 addition & 1 deletion test/params/test_configurations.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class ISAStrTest:
TEST_CASES = [
ISAStrTest(basic_core_config, "rv32i", "rv32i", "rv32i"),
ISAStrTest(full_core_config, "rv32imcbzicsr", "rv32imcbzicsr", "rv32imcbzicsr"),
ISAStrTest(tiny_core_config, "rv32i", "rv32", "rv32i"),
ISAStrTest(tiny_core_config, "rv32e", "rv32", "rv32e"),
ISAStrTest(test_core_config, "rv32", "rv32", "rv32i"),
]

Expand Down
2 changes: 1 addition & 1 deletion test/params/test_isa.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,8 @@ def __init__(self, isa_str, valid, xlen=None, reg_cnt=None, extensions=None):
| Extension.ZIFENCEI
| Extension.ZICSR,
),
ISATestEntry("rv32ie", True, 32, 32, Extension.I | Extension.E),
ISATestEntry("rv32", False),
ISATestEntry("rv32ie", False),
ISATestEntry("rv64e", False),
ISATestEntry("rv32fdc", False),
ISATestEntry("rv32izicsrzmmul", False),
Expand Down