diff options
author | Andrew Waterman <andrew@sifive.com> | 2022-01-10 14:34:16 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-01-10 14:34:16 -0800 |
commit | e93b9cbbbcd3ad0a02ae298e9f1a2d98d3ac0153 (patch) | |
tree | 9ee8051afa46e09d3c2f349cc41107b21e8098c2 | |
parent | d1a3a4255295b742728b8c851a222cfbf06e8116 (diff) | |
parent | fc572daaef35fdc081466e6a67413b1f3b4d6a3e (diff) | |
download | spike-e93b9cbbbcd3ad0a02ae298e9f1a2d98d3ac0153.zip spike-e93b9cbbbcd3ad0a02ae298e9f1a2d98d3ac0153.tar.gz spike-e93b9cbbbcd3ad0a02ae298e9f1a2d98d3ac0153.tar.bz2 |
Merge pull request #899 from riscv-software-src/rv32e
Add RV32E/RV64E base ISA support
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | riscv/decode.h | 6 | ||||
-rw-r--r-- | riscv/insn_template.cc | 27 | ||||
-rw-r--r-- | riscv/processor.cc | 71 | ||||
-rw-r--r-- | riscv/processor.h | 28 |
5 files changed, 96 insertions, 37 deletions
@@ -10,6 +10,7 @@ completion of the US transcontinental railway. Spike supports the following RISC-V ISA features: - RV32I and RV64I base ISAs, v2.1 + - RV32E and RV64E base ISAs, v1.9 - Zifencei extension, v2.0 - Zicsr extension, v2.0 - M extension, v2.0 diff --git a/riscv/decode.h b/riscv/decode.h index e709d03..8b372c2 100644 --- a/riscv/decode.h +++ b/riscv/decode.h @@ -175,7 +175,8 @@ private: #define MMU (*p->get_mmu()) #define STATE (*p->get_state()) #define FLEN (p->get_flen()) -#define READ_REG(reg) STATE.XPR[reg] +#define CHECK_REG(reg) ((void) 0) +#define READ_REG(reg) ({ CHECK_REG(reg); STATE.XPR[reg]; }) #define READ_FREG(reg) STATE.FPR[reg] #define RD READ_REG(insn.rd()) #define RS1 READ_REG(insn.rs1()) @@ -184,7 +185,7 @@ private: #define WRITE_RD(value) WRITE_REG(insn.rd(), value) #ifndef RISCV_ENABLE_COMMITLOG -# define WRITE_REG(reg, value) STATE.XPR.write(reg, value) +# define WRITE_REG(reg, value) ({ CHECK_REG(reg); STATE.XPR.write(reg, value); }) # define WRITE_FREG(reg, value) DO_WRITE_FREG(reg, freg(value)) # define WRITE_VSTATUS {} #else @@ -197,6 +198,7 @@ private: # define WRITE_REG(reg, value) ({ \ reg_t wdata = (value); /* value may have side effects */ \ STATE.log_reg_write[(reg) << 4] = {wdata, 0}; \ + CHECK_REG(reg); \ STATE.XPR.write(reg, wdata); \ }) # define WRITE_FREG(reg, value) ({ \ diff --git a/riscv/insn_template.cc b/riscv/insn_template.cc index b3dd330..e6a2f52 100644 --- a/riscv/insn_template.cc +++ b/riscv/insn_template.cc @@ -3,7 +3,7 @@ #include "insn_template.h" #include "insn_macros.h" -reg_t rv32_NAME(processor_t* p, insn_t insn, reg_t pc) +reg_t rv32i_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 32 reg_t npc = sext_xlen(pc + insn_length(OPCODE)); @@ -13,7 +13,30 @@ reg_t rv32_NAME(processor_t* p, insn_t insn, reg_t pc) return npc; } -reg_t rv64_NAME(processor_t* p, insn_t insn, reg_t pc) +reg_t rv64i_NAME(processor_t* p, insn_t insn, reg_t pc) +{ + #define xlen 64 + reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + #include "insns/NAME.h" + trace_opcode(p, OPCODE, insn); + #undef xlen + return npc; +} + +#undef CHECK_REG +#define CHECK_REG(reg) require((reg) < 16) + +reg_t rv32e_NAME(processor_t* p, insn_t insn, reg_t pc) +{ + #define xlen 32 + reg_t npc = sext_xlen(pc + insn_length(OPCODE)); + #include "insns/NAME.h" + trace_opcode(p, OPCODE, insn); + #undef xlen + return npc; +} + +reg_t rv64e_NAME(processor_t* p, insn_t insn, reg_t pc) { #define xlen 64 reg_t npc = sext_xlen(pc + insn_length(OPCODE)); diff --git a/riscv/processor.cc b/riscv/processor.cc index 61197a5..920792f 100644 --- a/riscv/processor.cc +++ b/riscv/processor.cc @@ -198,7 +198,7 @@ void processor_t::parse_priv_string(const char* str) void processor_t::parse_isa_string(const char* str) { isa_string = strtolower(str); - const char* all_subsets = "imafdqchp" + const char* all_subsets = "mafdqchp" #ifdef __SIZEOF_INT128__ "v" #endif @@ -210,24 +210,39 @@ void processor_t::parse_isa_string(const char* str) else if (isa_string.compare(0, 4, "rv64") == 0) max_xlen = 64; else - bad_isa_string(str, "Spike supports either RV32I or RV64I"); + bad_isa_string(str, "ISA strings must begin with RV32 or RV64"); + + switch (isa_string[4]) { + case 'g': + // G = IMAFD_Zicsr_Zifencei, but Spike includes the latter two + // unconditionally, so they need not be explicitly added here. + isa_string = isa_string.substr(0, 4) + "imafd" + isa_string.substr(5); + // Fall through + case 'i': + max_isa |= 1L << ('i' - 'a'); + break; - if (isa_string[4] == 'g') { - // G = IMAFD_Zicsr_Zifencei, but Spike includes the latter two - // unconditionally, so they need not be explicitly added here. - isa_string = isa_string.substr(0, 4) + "imafd" + isa_string.substr(5); - } + case 'e': + max_isa |= 1L << ('e' - 'a'); + break; - if (isa_string[4] != 'i') - bad_isa_string(str, "'I' extension is required"); + default: + bad_isa_string(str, ("'" + isa_string.substr(0, 4) + "' must be followed by I, E, or G").c_str()); + } const char* isa_str = isa_string.c_str(); - auto p = isa_str; - for (p += 4; islower(*p) && !strchr("zsx", *p); ++p) { - while (*all_subsets && (*p != *all_subsets)) - ++all_subsets; - if (!*all_subsets) - bad_isa_string(str, "Wrong order"); + auto p = isa_str, subset = all_subsets; + for (p += 5; islower(*p) && !strchr("zsx", *p); ++p) { + while (*subset && (*p != *subset)) + ++subset; + + if (!*subset) { + if (strchr(all_subsets, *p)) + bad_isa_string(str, ("Extension '" + std::string(1, *p) + "' appears too late in ISA string").c_str()); + else + bad_isa_string(str, ("Unsupported extension '" + std::string(1, *p) + "'").c_str()); + } + switch (*p) { case 'p': extension_table[EXT_ZBPBO] = true; extension_table[EXT_ZPN] = true; @@ -1028,11 +1043,13 @@ insn_func_t processor_t::decode_insn(insn_t insn) size_t idx = insn.bits() % OPCODE_CACHE_SIZE; insn_desc_t desc = opcode_cache[idx]; - if (unlikely(insn.bits() != desc.match || !(xlen == 64 ? desc.rv64 : desc.rv32))) { + bool rve = extension_enabled('E'); + + if (unlikely(insn.bits() != desc.match || !desc.func(xlen, rve))) { // fall back to linear search int cnt = 0; insn_desc_t* p = &instructions[0]; - while ((insn.bits() & p->mask) != p->match || !(xlen == 64 ? p->rv64 : p->rv32)) + while ((insn.bits() & p->mask) != p->match || !desc.func(xlen, rve)) p++, cnt++; desc = *p; @@ -1049,7 +1066,7 @@ insn_func_t processor_t::decode_insn(insn_t insn) opcode_cache[idx].match = insn.bits(); } - return xlen == 64 ? desc.rv64 : desc.rv32; + return desc.func(xlen, rve); } void processor_t::register_insn(insn_desc_t desc) @@ -1069,7 +1086,7 @@ void processor_t::build_opcode_map() std::sort(instructions.begin(), instructions.end(), cmp()); for (size_t i = 0; i < OPCODE_CACHE_SIZE; i++) - opcode_cache[i] = {0, 0, &illegal_instruction, &illegal_instruction}; + opcode_cache[i] = insn_desc_t::illegal(); } void processor_t::register_extension(extension_t* x) @@ -1098,17 +1115,23 @@ void processor_t::register_base_instructions() #undef DECLARE_INSN #define DEFINE_INSN(name) \ - extern reg_t rv32_##name(processor_t*, insn_t, reg_t); \ - extern reg_t rv64_##name(processor_t*, insn_t, reg_t); \ + extern reg_t rv32i_##name(processor_t*, insn_t, reg_t); \ + extern reg_t rv64i_##name(processor_t*, insn_t, reg_t); \ + extern reg_t rv32e_##name(processor_t*, insn_t, reg_t); \ + extern reg_t rv64e_##name(processor_t*, insn_t, reg_t); \ register_insn((insn_desc_t){ \ name##_match, \ name##_mask, \ - rv32_##name, \ - rv64_##name}); + rv32i_##name, \ + rv64i_##name, \ + rv32e_##name, \ + rv64e_##name}); #include "insn_list.h" #undef DEFINE_INSN - register_insn({0, 0, &illegal_instruction, &illegal_instruction}); + // terminate instruction list with a catch-all + register_insn(insn_desc_t::illegal()); + build_opcode_map(); } diff --git a/riscv/processor.h b/riscv/processor.h index c32f624..35f8afc 100644 --- a/riscv/processor.h +++ b/riscv/processor.h @@ -23,12 +23,29 @@ class trap_t; class extension_t; class disassembler_t; +reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc); + struct insn_desc_t { insn_bits_t match; insn_bits_t mask; - insn_func_t rv32; - insn_func_t rv64; + insn_func_t rv32i; + insn_func_t rv64i; + insn_func_t rv32e; + insn_func_t rv64e; + + insn_func_t func(int xlen, bool rve) + { + if (rve) + return xlen == 64 ? rv64e : rv32e; + else + return xlen == 64 ? rv64i : rv32i; + } + + static insn_desc_t illegal() + { + return {0, 0, &illegal_instruction, &illegal_instruction, &illegal_instruction, &illegal_instruction}; + } }; // regnum, data @@ -594,11 +611,4 @@ public: vectorUnit_t VU; }; -reg_t illegal_instruction(processor_t* p, insn_t insn, reg_t pc); - -#define REGISTER_INSN(proc, name, match, mask, archen) \ - extern reg_t rv32_##name(processor_t*, insn_t, reg_t); \ - extern reg_t rv64_##name(processor_t*, insn_t, reg_t); \ - proc->register_insn((insn_desc_t){match, mask, rv32_##name, rv64_##name,archen}); - #endif |