aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2022-01-10 14:34:16 -0800
committerGitHub <noreply@github.com>2022-01-10 14:34:16 -0800
commite93b9cbbbcd3ad0a02ae298e9f1a2d98d3ac0153 (patch)
tree9ee8051afa46e09d3c2f349cc41107b21e8098c2
parentd1a3a4255295b742728b8c851a222cfbf06e8116 (diff)
parentfc572daaef35fdc081466e6a67413b1f3b4d6a3e (diff)
downloadspike-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.md1
-rw-r--r--riscv/decode.h6
-rw-r--r--riscv/insn_template.cc27
-rw-r--r--riscv/processor.cc71
-rw-r--r--riscv/processor.h28
5 files changed, 96 insertions, 37 deletions
diff --git a/README.md b/README.md
index c1501c3..0b097ce 100644
--- a/README.md
+++ b/README.md
@@ -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