Skip to content

Commit 002d273

Browse files
authored
Merge pull request #1617 from arrv-sc/master
workaround to support custom extensions that use standard prefixes
2 parents 581e0da + 7da36db commit 002d273

File tree

7 files changed

+165
-32
lines changed

7 files changed

+165
-32
lines changed

ci-tests/create-ci-binary-tarball

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@ mkdir -p build/hello && cd "$_"
1212
riscv64-unknown-elf-gcc -O2 -o hello `git rev-parse --show-toplevel`/ci-tests/hello.c
1313
cd -
1414

15+
mkdir -p build/dummy-slliuw && cd "$_"
16+
riscv64-unknown-elf-gcc -O2 -o dummy-slliuw `git rev-parse --show-toplevel`/ci-tests/dummy-slliuw.c
17+
cd -
18+
1519
mv build/pk/pk .
1620
mv build/hello/hello .
21+
mv build/dummy-slliuw/dummy-slliuw .
22+
tar -cf spike-ci.tar pk hello dummy-slliuw
1723

18-
tar -cf spike-ci.tar pk hello
19-
20-
rm pk hello
24+
rm pk hello dummy-slliuw

ci-tests/dummy-slliuw.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include <stdio.h>
2+
3+
int main() {
4+
// as if slli.uw zero, t1, 3
5+
asm(".4byte 0x0833101b");
6+
printf("Executed successfully\n");
7+
return 0;
8+
}

ci-tests/test-customext.cc

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
#include <riscv/extension.h>
2+
#include <riscv/sim.h>
3+
4+
struct : public arg_t {
5+
std::string to_string(insn_t insn) const { return xpr_name[insn.rd()]; }
6+
} xrd;
7+
8+
struct : public arg_t {
9+
std::string to_string(insn_t insn) const { return xpr_name[insn.rs1()]; }
10+
} xrs1;
11+
12+
struct : public arg_t {
13+
std::string to_string(insn_t insn) const { return xpr_name[insn.rs2()]; }
14+
} xrs2;
15+
16+
struct : public arg_t {
17+
std::string to_string(insn_t insn) const {
18+
return std::to_string((int)insn.shamt());
19+
}
20+
} shamt;
21+
22+
static reg_t do_nop4([[maybe_unused]] processor_t *p,
23+
[[maybe_unused]] insn_t insn, reg_t pc) {
24+
return pc + 4;
25+
}
26+
27+
// dummy extension that uses the same prefix as standard zba extension
28+
struct xslliuw_dummy_t : public extension_t {
29+
const char *name() { return "dummyslliuw"; }
30+
31+
xslliuw_dummy_t() {}
32+
33+
std::vector<insn_desc_t> get_instructions() {
34+
std::vector<insn_desc_t> insns;
35+
insns.push_back(insn_desc_t{MATCH_SLLI_UW, MASK_SLLI_UW, do_nop4, do_nop4,
36+
do_nop4, do_nop4, do_nop4, do_nop4, do_nop4,
37+
do_nop4});
38+
return insns;
39+
}
40+
41+
std::vector<disasm_insn_t *> get_disasms() {
42+
std::vector<disasm_insn_t *> insns;
43+
insns.push_back(new disasm_insn_t("dummy_slliuw", MATCH_SLLI_UW,
44+
MASK_SLLI_UW, {&xrd, &xrs1, &shamt}));
45+
return insns;
46+
}
47+
};
48+
49+
REGISTER_EXTENSION(dummyslliuw, []() { return new xslliuw_dummy_t; })
50+
51+
// Copied from spike main.
52+
// TODO: This should really be provided in libriscv
53+
static std::vector<std::pair<reg_t, abstract_mem_t *>>
54+
make_mems(const std::vector<mem_cfg_t> &layout) {
55+
std::vector<std::pair<reg_t, abstract_mem_t *>> mems;
56+
mems.reserve(layout.size());
57+
for (const auto &cfg : layout) {
58+
mems.push_back(std::make_pair(cfg.get_base(), new mem_t(cfg.get_size())));
59+
}
60+
return mems;
61+
}
62+
63+
int main(int argc, char **argv) {
64+
cfg_t cfg;
65+
cfg.isa = "RV64IMAFDCV_xdummyslliuw";
66+
std::vector<device_factory_t *> plugin_devices;
67+
if (argc != 3) {
68+
std::cerr << "Error: invalid arguments\n";
69+
exit(1);
70+
}
71+
std::vector<std::string> htif_args{argv[1] /* pk */, argv[2] /* executable */};
72+
debug_module_config_t dm_config = {.progbufsize = 2,
73+
.max_sba_data_width = 0,
74+
.require_authentication = false,
75+
.abstract_rti = 0,
76+
.support_hasel = true,
77+
.support_abstract_csr_access = true,
78+
.support_abstract_fpr_access = true,
79+
.support_haltgroups = true,
80+
.support_impebreak = true};
81+
std::vector<std::pair<reg_t, abstract_mem_t *>> mems =
82+
make_mems(cfg.mem_layout);
83+
sim_t sim(&cfg, false, mems, plugin_devices, htif_args, dm_config,
84+
nullptr, // log_path
85+
true, // dtb_enabled
86+
nullptr, // dtb_file
87+
false, // socket_enabled
88+
nullptr); // cmd_file
89+
sim.run();
90+
}

ci-tests/test-spike

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,7 @@ time ../install/bin/spike --isa=rv64gc pk hello | grep "Hello, world! Pi is app
1414

1515
# check that including sim.h in an external project works
1616
g++ -std=c++17 -I../install/include -L../install/lib $DIR/testlib.c -lriscv -o test-libriscv
17-
LD_LIBRARY_PATH=../install/lib ./test-libriscv | grep "Hello, world! Pi is approximately 3.141588."
17+
g++ -std=c++17 -I../install/include -L../install/lib $DIR/test-customext.cc -lriscv -o test-customext
18+
19+
LD_LIBRARY_PATH=../install/lib ./test-libriscv pk hello| grep "Hello, world! Pi is approximately 3.141588."
20+
LD_LIBRARY_PATH=../install/lib ./test-customext pk dummy-slliuw | grep "Executed successfully"

ci-tests/testlib.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@ static std::vector<std::pair<reg_t, abstract_mem_t*>> make_mems(const std::vecto
1212
return mems;
1313
}
1414

15-
int main()
16-
{
15+
int main(int argc, char **argv) {
1716
cfg_t cfg;
1817
std::vector<device_factory_t*> plugin_devices;
19-
std::vector<std::string> htif_args {"pk", "hello"};
18+
19+
if (argc != 3) {
20+
std::cerr << "Error: invalid arguments\n";
21+
exit(1);
22+
}
23+
std::vector<std::string> htif_args{argv[1] /* pk */,
24+
argv[2] /* executable */};
2025
debug_module_config_t dm_config;
2126
std::vector<std::pair<reg_t, abstract_mem_t*>> mems =
2227
make_mems(cfg.mem_layout);

riscv/processor.cc

Lines changed: 40 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1037,6 +1037,24 @@ reg_t illegal_instruction(processor_t UNUSED *p, insn_t insn, reg_t UNUSED pc)
10371037
throw trap_illegal_instruction(insn.bits() & 0xffffffffULL);
10381038
}
10391039

1040+
static insn_desc_t
1041+
propagate_instruction_in_vector(std::vector<insn_desc_t> &instructions,
1042+
std::vector<insn_desc_t>::iterator it) {
1043+
assert(it != instructions.end());
1044+
insn_desc_t desc = *it;
1045+
if (it->mask != 0 && it != instructions.begin() &&
1046+
std::next(it) != instructions.end()) {
1047+
if (it->match != std::prev(it)->match &&
1048+
it->match != std::next(it)->match) {
1049+
// move to front of opcode list to reduce miss penalty
1050+
while (--it >= instructions.begin())
1051+
*std::next(it) = *it;
1052+
instructions[0] = desc;
1053+
}
1054+
}
1055+
return desc;
1056+
}
1057+
10401058
insn_func_t processor_t::decode_insn(insn_t insn)
10411059
{
10421060
// look up opcode in hash table
@@ -1047,34 +1065,33 @@ insn_func_t processor_t::decode_insn(insn_t insn)
10471065

10481066
if (unlikely(insn.bits() != desc.match)) {
10491067
// fall back to linear search
1050-
int cnt = 0;
1051-
insn_desc_t* p = &instructions[0];
1052-
while ((insn.bits() & p->mask) != p->match)
1053-
p++, cnt++;
1054-
desc = *p;
1055-
1056-
if (p->mask != 0 && p > &instructions[0]) {
1057-
if (p->match != (p - 1)->match && p->match != (p + 1)->match) {
1058-
// move to front of opcode list to reduce miss penalty
1059-
while (--p >= &instructions[0])
1060-
*(p + 1) = *p;
1061-
instructions[0] = desc;
1062-
}
1068+
auto matching = [insn_bits = insn.bits()](const insn_desc_t &d) {
1069+
return (insn_bits & d.mask) == d.match;
1070+
};
1071+
auto p = std::find_if(custom_instructions.begin(),
1072+
custom_instructions.end(), matching);
1073+
if (p != custom_instructions.end()) {
1074+
desc = propagate_instruction_in_vector(custom_instructions, p);
1075+
} else {
1076+
p = std::find_if(instructions.begin(), instructions.end(), matching);
1077+
assert(p != instructions.end());
1078+
desc = propagate_instruction_in_vector(instructions, p);
10631079
}
1064-
10651080
opcode_cache[idx] = desc;
10661081
opcode_cache[idx].match = insn.bits();
10671082
}
10681083

10691084
return desc.func(xlen, rve, log_commits_enabled);
10701085
}
10711086

1072-
void processor_t::register_insn(insn_desc_t desc)
1073-
{
1087+
void processor_t::register_insn(insn_desc_t desc, bool is_custom) {
10741088
assert(desc.fast_rv32i && desc.fast_rv64i && desc.fast_rv32e && desc.fast_rv64e &&
10751089
desc.logged_rv32i && desc.logged_rv64i && desc.logged_rv32e && desc.logged_rv64e);
10761090

1077-
instructions.push_back(desc);
1091+
if (is_custom)
1092+
custom_instructions.push_back(desc);
1093+
else
1094+
instructions.push_back(desc);
10781095
}
10791096

10801097
void processor_t::build_opcode_map()
@@ -1086,16 +1103,17 @@ void processor_t::build_opcode_map()
10861103
return lhs.match > rhs.match;
10871104
}
10881105
};
1106+
10891107
std::sort(instructions.begin(), instructions.end(), cmp());
1108+
std::sort(custom_instructions.begin(), custom_instructions.end(), cmp());
10901109

10911110
for (size_t i = 0; i < OPCODE_CACHE_SIZE; i++)
10921111
opcode_cache[i] = insn_desc_t::illegal();
10931112
}
10941113

1095-
void processor_t::register_extension(extension_t* x)
1096-
{
1114+
void processor_t::register_extension(extension_t *x) {
10971115
for (auto insn : x->get_instructions())
1098-
register_insn(insn);
1116+
register_custom_insn(insn);
10991117
build_opcode_map();
11001118

11011119
for (auto disasm_insn : x->get_disasms())
@@ -1131,7 +1149,7 @@ void processor_t::register_base_instructions()
11311149
extern reg_t logged_rv32e_##name(processor_t*, insn_t, reg_t); \
11321150
extern reg_t logged_rv64e_##name(processor_t*, insn_t, reg_t); \
11331151
if (name##_supported) { \
1134-
register_insn((insn_desc_t) { \
1152+
register_base_insn((insn_desc_t) { \
11351153
name##_match, \
11361154
name##_mask, \
11371155
fast_rv32i_##name, \
@@ -1144,10 +1162,8 @@ void processor_t::register_base_instructions()
11441162
logged_rv64e_##name}); \
11451163
}
11461164
#include "insn_list.h"
1147-
#undef DEFINE_INSN
1148-
11491165
// terminate instruction list with a catch-all
1150-
register_insn(insn_desc_t::illegal());
1166+
register_base_insn(insn_desc_t::illegal());
11511167

11521168
build_opcode_map();
11531169
}

riscv/processor.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,12 @@ class processor_t : public abstract_device_t
281281

282282
FILE *get_log_file() { return log_file; }
283283

284-
void register_insn(insn_desc_t);
284+
void register_base_insn(insn_desc_t insn) {
285+
register_insn(insn, false /* is_custom */);
286+
}
287+
void register_custom_insn(insn_desc_t insn) {
288+
register_insn(insn, true /* is_custom */);
289+
}
285290
void register_extension(extension_t*);
286291

287292
// MMIO slave interface
@@ -336,6 +341,7 @@ class processor_t : public abstract_device_t
336341
mutable std::bitset<NUM_ISA_EXTENSIONS> extension_assumed_const;
337342

338343
std::vector<insn_desc_t> instructions;
344+
std::vector<insn_desc_t> custom_instructions;
339345
std::unordered_map<reg_t,uint64_t> pc_histogram;
340346

341347
static const size_t OPCODE_CACHE_SIZE = 8191;
@@ -346,6 +352,7 @@ class processor_t : public abstract_device_t
346352
void take_trap(trap_t& t, reg_t epc); // take an exception
347353
void take_trigger_action(triggers::action_t action, reg_t breakpoint_tval, reg_t epc, bool virt);
348354
void disasm(insn_t insn); // disassemble and print an instruction
355+
void register_insn(insn_desc_t, bool);
349356
int paddr_bits();
350357

351358
void enter_debug_mode(uint8_t cause);

0 commit comments

Comments
 (0)