Skip to content

Commit

Permalink
E extension (#440)
Browse files Browse the repository at this point in the history
  • Loading branch information
piotro888 committed Jul 13, 2023
1 parent 59dddc5 commit b4869f0
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 24 deletions.
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

0 comments on commit b4869f0

Please sign in to comment.