copy the rest of the logic

This commit is contained in:
2026-03-08 18:00:40 +01:00
parent 3f62e1ec2b
commit 1705cbceeb
3 changed files with 820 additions and 9 deletions

4
.clangd Normal file
View File

@@ -0,0 +1,4 @@
If:
Language: c++
CompileFlags:
Add: [-std=c++20]

View File

@@ -17,7 +17,7 @@ if command -v pkg-config >/dev/null; then
LIBELF_FLAGS=$(pkg-config --cflags --libs libelf 2>/dev/null) LIBELF_FLAGS=$(pkg-config --cflags --libs libelf 2>/dev/null)
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
echo "building riscv64..." echo "building riscv64..."
c++ $COMMON -o riscv64 riscv64.cc $LIBELF_FLAGS c++ -std=c++20 $COMMON -o riscv64 riscv64.cc $LIBELF_FLAGS
else else
echo "libelf not found - skipping riscv64..." echo "libelf not found - skipping riscv64..."
fi fi

View File

@@ -1,7 +1,9 @@
// https://docs.riscv.org/reference/isa/unpriv/rv-32-64g.html // https://docs.riscv.org/reference/isa/unpriv/rv-32-64g.html
// https://riscv.org/wp-content/uploads/2024/12/riscv-calling.pdf // https://riscv.org/wp-content/uploads/2024/12/riscv-calling.pdf
#include <algorithm>
#include <array> #include <array>
#include <bit>
#include <cstring> #include <cstring>
#include <fstream> #include <fstream>
#include <gelf.h> #include <gelf.h>
@@ -9,6 +11,55 @@
#include <libelf.h> #include <libelf.h>
#include <vector> #include <vector>
// TODO: dont use macros now that we're in an actual language
#define PARSE_I_INS(ins) \
u8 rd = (ins >> 7) & 0b11111; \
u8 funct3 = (ins >> 12) & 0b111; \
u8 rs1 = (ins >> 15) & 0b11111; \
i32 imm = ((i32)ins) >> 20
#define PARSE_R_INS(ins) \
u8 rd = (ins >> 7) & 0b11111; \
u8 funct3 = (ins >> 12) & 0b111; \
u8 rs1 = (ins >> 15) & 0b11111; \
u8 rs2 = (ins >> 20) & 0b11111; \
i32 funct7 = ((i32)ins) >> 25
#define PARSE_B_INS(ins) \
u8 funct3 = (ins >> 12) & 0b111; \
u8 rs1 = (ins >> 15) & 0b11111; \
u8 rs2 = (ins >> 20) & 0b11111; \
i32 imm_12 = (ins >> 31) & 0b1; \
i32 imm_10_5 = (ins >> 25) & 0b111111; \
i32 imm_4_1 = (ins >> 8) & 0b1111; \
i32 imm_11 = (ins >> 7) & 0b1; \
i32 imm = \
(imm_12 << 12) | (imm_11 << 11) | (imm_10_5 << 5) | (imm_4_1 << 1); \
imm = (imm << 19) >> 19
#define PARSE_S_INS(ins) \
u8 funct3 = (ins >> 12) & 0b111; \
u8 rs1 = (ins >> 15) & 0b11111; \
u8 rs2 = (ins >> 20) & 0b11111; \
i32 imm_11_5 = (ins >> 25) & 0b1111111; \
i32 imm_4_0 = (ins >> 7) & 0b11111; \
i32 imm = (imm_11_5 << 5) | imm_4_0; \
imm = (imm << 20) >> 20
#define PARSE_J_INS(ins) \
u8 rd = (ins >> 7) & 0b11111; \
i32 imm_20 = (ins >> 31) & 0b1; \
i32 imm_10_1 = (ins >> 21) & 0b1111111111; \
i32 imm_11 = (ins >> 20) & 0b1; \
i32 imm_19_12 = (ins >> 12) & 0b11111111; \
i32 imm = \
(imm_20 << 20) | (imm_19_12 << 12) | (imm_11 << 11) | (imm_10_1 << 1); \
imm = (imm << 11) >> 11
#define PARSE_U_INS(ins) \
u8 rd = (ins >> 7) & 0b11111; \
i32 imm = ins >> 12
using i8 = int8_t; using i8 = int8_t;
using i16 = int16_t; using i16 = int16_t;
using i32 = int32_t; using i32 = int32_t;
@@ -17,7 +68,9 @@ using u8 = uint8_t;
using u16 = uint16_t; using u16 = uint16_t;
using u32 = uint32_t; using u32 = uint32_t;
using u64 = uint64_t; using u64 = uint64_t;
static_assert(sizeof(size_t) == sizeof(u64), "size_t must be 64-bit"); static_assert(sizeof(size_t) == sizeof(u64), "u64 must be 64-bit");
static_assert(std::endian::native == std::endian::little,
"Big endianness not supported");
static constexpr u64 MEMORY_SIZE = 20 * 1024 * 1024; // should be enough static constexpr u64 MEMORY_SIZE = 20 * 1024 * 1024; // should be enough
@@ -47,17 +100,770 @@ public:
GElf_Phdr phdr; GElf_Phdr phdr;
gelf_getphdr(elf, i, &phdr); gelf_getphdr(elf, i, &phdr);
if (phdr.p_type == PT_LOAD) { if (phdr.p_type == PT_LOAD) {
memcpy(m_memory.data() + phdr.p_vaddr, exe_bytes.data() + phdr.p_offset, std::copy_n(exe_bytes.data() + phdr.p_offset, phdr.p_filesz,
phdr.p_filesz); m_memory.data() + phdr.p_vaddr);
} }
} }
elf_end(elf); elf_end(elf);
} }
void disassemble_all() {
for (m_pc = m_code_section.offset;
m_pc < m_code_section.offset + m_code_section.size; m_pc += 4) {
disassemble_one();
}
}
void disassemble_one() {
u32 ins;
std::memcpy(&ins, m_memory.data() + m_pc, sizeof(ins));
u16 opcode = ins & 0b1111111;
// https://stackoverflow.com/questions/62939410/how-can-i-find-out-the-instruction-format-of-a-risc-v-instruction
switch (opcode) {
case 0b1100011: {
PARSE_B_INS(ins);
if (funct3 == 0b000) {
printf("beq %s, %s, %d\n", REGS[rs1], REGS[rs2], imm);
} else if (funct3 == 0b001) {
printf("bne %s, %s, %d\n", REGS[rs1], REGS[rs2], imm);
} else if (funct3 == 0b100) {
printf("blt %s, %s, %d\n", REGS[rs1], REGS[rs2], imm);
} else if (funct3 == 0b101) {
printf("bge %s, %s, %d\n", REGS[rs1], REGS[rs2], imm);
} else if (funct3 == 0b110) {
printf("bltu %s, %s, %d\n", REGS[rs1], REGS[rs2], imm);
} else if (funct3 == 0b111) {
printf("bgeu %s, %s, %d\n", REGS[rs1], REGS[rs2], imm);
} else {
fprintf(stderr, "B-type: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0010011: {
PARSE_I_INS(ins);
if (funct3 == 0b000) {
printf("addi %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b001) {
u32 shamt = (ins >> 20) & 0b111111;
u32 funct6 = (ins >> 26) & 0b111111;
if (funct6 == 0b000000) {
printf("slli %s, %s, %d\n", REGS[rd], REGS[rs1], shamt);
} else {
fprintf(stderr, "I-type 1: funct3=001: unrecognized funct6: %b\n",
funct6);
exit(1);
}
} else if (funct3 == 0b010) {
printf("slti %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b011) {
printf("sltiu %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b100) {
printf("xori %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b101) {
// of course this one just has to be different
u32 shamt = (ins >> 20) & 0b111111;
u32 funct6 = (ins >> 26) & 0b111111;
if (funct6 == 0b000000) {
printf("srli %s, %s, %d\n", REGS[rd], REGS[rs1], shamt);
} else if (funct6 == 0b010000) {
printf("srai %s, %s, %d\n", REGS[rd], REGS[rs1], shamt);
} else {
fprintf(stderr, "I-type 1: funct3=101: unrecognized funct6: %b\n",
funct6);
exit(1);
}
} else if (funct3 == 0b110) {
printf("ori %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b111) {
printf("andi %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else {
fprintf(stderr, "I-type 1: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0000011: {
PARSE_I_INS(ins);
if (funct3 == 0b000) {
printf("lb %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]);
} else if (funct3 == 0b001) {
printf("lh %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]);
} else if (funct3 == 0b010) {
printf("lw %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]);
} else if (funct3 == 0b011) {
printf("ld %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]);
} else if (funct3 == 0b100) {
printf("lbu %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]);
} else if (funct3 == 0b101) {
printf("lhu %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]);
} else if (funct3 == 0b110) {
printf("lwu %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]);
} else {
fprintf(stderr, "I-type 2: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b1100111: {
PARSE_I_INS(ins);
printf("jalr %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
}; break;
case 0b1110011: {
PARSE_I_INS(ins);
if (funct3 == 0b000) {
if (imm == 0) {
printf("ecall\n");
} else {
fprintf(stderr, "I-type 4: funct3=000 unrecognized imm: %b\n", imm);
exit(1);
}
} else {
fprintf(stderr, "I-type 4: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b1101111: {
PARSE_J_INS(ins);
printf("jal %s, %d\n", REGS[rd], imm);
}; break;
case 0b0110011: {
PARSE_R_INS(ins);
if (funct3 == 0b000) {
if (funct7 == 0b0000000) {
printf("add %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0100000) {
printf("sub %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0000001) {
printf("mul %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 1: funct3=0b000: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b001) {
if (funct7 == 0b0000000) {
printf("sll %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0000001) {
printf("mulh %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 1: funct3=0b001: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b010) {
if (funct7 == 0b0000000) {
printf("slt %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 1: funct3=0b010: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b011) {
if (funct7 == 0b0000000) {
printf("sltu %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0000001) {
printf("mulhu %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 1: funct3=0b011: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b100) {
if (funct7 == 0b0000000) {
printf("xor %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0000001) {
printf("div %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 1: funct3=0b100: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b101) {
if (funct7 == 0b0000000) {
printf("srl %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0000001) {
printf("divu %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0100000) {
printf("sra %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 1: funct3=0b101: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b110) {
if (funct7 == 0b0000001) {
printf("rem %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0000000) {
printf("or %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 1: funct3=0b110: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b111) {
if (funct7 == 0b000) {
printf("and %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b001) {
printf("remu %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 1: funct3=0b111: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else {
fprintf(stderr, "R-type 1: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0101111:
fprintf(stderr, "A extension not implemented yet.\n");
exit(1);
case 0b0111011: {
PARSE_R_INS(ins);
if (funct3 == 0b000) {
if (funct7 == 0b0000000) {
printf("addw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0100000) {
printf("subw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0000001) {
printf("mulw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 3: funct3=000: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b001) {
printf("sllw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct3 == 0b100) {
printf("divw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct3 == 0b101) {
if (funct7 == 0b0000000) {
printf("srlw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0100000) {
printf("sraw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct7 == 0b0000001) {
printf("divuw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 3: funct3=101: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b110) {
printf("remw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct3 == 0b111) {
printf("remuw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else {
fprintf(stderr, "R-type 3: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0011011: {
u8 funct3 = (ins >> 12) & 0b111;
if (funct3 == 0b000) {
PARSE_I_INS(ins);
printf("addiw %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b001) {
PARSE_R_INS(ins);
printf("slliw %s, %s, %d\n", REGS[rd], REGS[rs1], rs2);
} else if (funct3 == 0b101) {
PARSE_R_INS(ins);
if (funct7 == 0b0000000) {
printf("srliw %s, %s, %d\n", REGS[rd], REGS[rs1], rs2);
} else if (funct7 == 0b0100000) {
printf("sraiw %s, %s, %d\n", REGS[rd], REGS[rs1], rs2);
} else {
fprintf(stderr, "R-type 4: funct3=101: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else {
fprintf(stderr, "R-type 4: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0100111: {
fprintf(stderr, "F extension not implemented yet.\n");
exit(1);
}; break;
case 0b0100011: {
PARSE_S_INS(ins);
if (funct3 == 0b000) {
printf("sb %s, %d(%s)\n", REGS[rs2], imm, REGS[rs1]);
} else if (funct3 == 0b001) {
printf("sh %s, %d(%s)\n", REGS[rs2], imm, REGS[rs1]);
} else if (funct3 == 0b010) {
printf("sw %s, %d(%s)\n", REGS[rs2], imm, REGS[rs1]);
} else if (funct3 == 0b011) {
printf("sd %s, %d(%s)\n", REGS[rs2], imm, REGS[rs1]);
} else {
fprintf(stderr, "S-type: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0110111: {
PARSE_U_INS(ins);
printf("lui %s, %d\n", REGS[rd], imm);
}; break;
case 0b0010111: {
PARSE_U_INS(ins);
printf("auipc %s, %d\n", REGS[rd], imm);
}; break;
default:
fprintf(stderr, "Unrecognized opcode: %07b\n", opcode);
exit(1);
}
}
void dump() {
std::cout << "REGS:";
for (u64 i = 0; i < 32; i++) {
std::cout << " " << m_regs[i];
}
std::cout << "\n";
}
void execute() {
m_pc = m_code_section.entrypoint;
m_regs[2] = MEMORY_SIZE - 1024; // set the stack pointer
while (m_pc < m_code_section.offset + m_code_section.size) {
m_regs[0] = 0; // clear the zero register
u32 ins;
std::memcpy(&ins, m_memory.data() + m_pc, sizeof(ins));
u16 opcode = ins & 0b1111111;
// https://stackoverflow.com/questions/62939410/how-can-i-find-out-the-instruction-format-of-a-risc-v-instruction
switch (opcode) {
case 0b1100011: {
PARSE_B_INS(ins);
if (funct3 == 0b000) { // beq
if (m_regs[rs1] == m_regs[rs2]) {
m_pc += imm;
continue;
}
} else if (funct3 == 0b001) { // bne
if (m_regs[rs1] != m_regs[rs2]) {
m_pc += imm;
continue;
}
} else if (funct3 == 0b101) { // bge
if (m_regs[rs1] >= m_regs[rs2]) {
m_pc += imm;
continue;
}
} else if (funct3 == 0b100) { // blt
if (m_regs[rs1] < m_regs[rs2]) {
m_pc += imm;
continue;
}
} else if (funct3 == 0b110) { // bltu
if ((u64)m_regs[rs1] < (u64)m_regs[rs2]) {
m_pc += imm;
continue;
}
} else {
fprintf(stderr, "B-type: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0010011: {
PARSE_I_INS(ins);
if (funct3 == 0b000) { // addi
m_regs[rd] = m_regs[rs1] + imm;
} else if (funct3 == 0b001) { // slli
u32 shamt = (ins >> 20) & 0b111111;
u32 funct6 = (ins >> 26) & 0b111111;
if (funct6 == 0b000000) {
m_regs[rd] = m_regs[rs1] << shamt;
} else {
fprintf(stderr, "I-type 1: funct3=001: unrecognized funct6: %b\n",
funct6);
exit(1);
}
} else if (funct3 == 0b011) { // sltiu
m_regs[rd] = ((u64)m_regs[rs1] < (u64)(i64)imm) ? 1 : 0;
} else if (funct3 == 0b100) { // xori
m_regs[rd] = m_regs[rs1] ^ imm;
} else if (funct3 == 0b101) {
// of course this one just has to be different
u32 shamt = (ins >> 20) & 0b111111;
u32 funct6 = (ins >> 26) & 0b111111;
if (funct6 == 0b000000) { // srli
m_regs[rd] = (u64)m_regs[rs1] >> shamt;
} else if (funct6 == 0b010000) { // srai
m_regs[rd] = (i64)m_regs[rs1] >> shamt;
} else {
fprintf(stderr, "I-type 1: funct3=101: unrecognized funct6: %b\n",
funct6);
exit(1);
}
} else if (funct3 == 0b111) {
m_regs[rd] = m_regs[rs1] & imm;
} else {
fprintf(stderr, "I-type 1: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0000011: {
PARSE_I_INS(ins);
if (funct3 == 0b000) { // lb
m_regs[rd] = (i8)m_memory[m_regs[rs1] + imm];
} else if (funct3 == 0b001) { // lh
m_regs[rd] = *(i16 *)&m_memory[m_regs[rs1] + imm];
} else if (funct3 == 0b010) { // lw
m_regs[rd] = *(i32 *)&m_memory[m_regs[rs1] + imm];
} else if (funct3 == 0b011) { // ld
m_regs[rd] = *(u64 *)&m_memory[m_regs[rs1] + imm];
} else if (funct3 == 0b100) { // lbu
m_regs[rd] = m_memory[m_regs[rs1] + imm];
} else {
fprintf(stderr, "I-type 2: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b1100111: { // jalr
PARSE_I_INS(ins);
u64 target = (m_regs[rs1] + imm) & ~(u64)1;
m_regs[rd] = m_pc + 4;
m_pc = target;
continue;
}; break;
case 0b1110011: {
PARSE_I_INS(ins);
if (funct3 == 0b000) {
if (imm == 0) { // ecall
// https://jborza.com/post/2021-05-11-riscv-linux-syscalls/
switch (m_regs[17]) {
case 63: { // read
if (m_regs[10] != 0) {
fprintf(stderr, "read syscall implemented only for stdin.\n");
exit(1);
}
u64 start = m_regs[11];
u64 count = m_regs[12];
u64 bytes_read = 0;
for (u64 i = 0; i < count; i++) {
int c = getchar();
if (c == EOF)
break;
m_memory[start + i] = (u8)c;
bytes_read++;
if (c == '\n')
break;
}
m_regs[10] = bytes_read;
}; break;
case 64: { // write
if (m_regs[10] != 1) {
fprintf(stderr, "write syscall implemented only for stdout.\n");
exit(1);
}
u64 start = m_regs[11];
u64 end = m_regs[11] + m_regs[12];
for (u64 i = start; i < end; i++) {
putchar(m_memory[i]);
}
}; break;
case 93: { // exit
printf("Program exited with code %lu.\n", m_regs[10]);
return;
}; break;
case 169: { // gettimeofday
// TODO: actually return the time
i64 tv_addr = m_regs[10];
i64 tz_addr = m_regs[11];
u8 tv_buf[16] = {
0xD2, 0x02, 0x96, 0x49,
0x00, 0x00, 0x00, 0x00, // tv_sec = 1234567890
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, // tv_usec = 0
};
memcpy(&m_memory[tv_addr], tv_buf, 16);
memset(&m_memory[tz_addr], 0, 8);
m_regs[10] = 0;
}; break;
default:
fprintf(stderr, "Unimplemented syscall: %lu\n", m_regs[17]);
exit(1);
}
break;
} else {
fprintf(stderr, "I-type 4: funct3=000 unrecognized imm: %b\n", imm);
exit(1);
};
break;
} else {
fprintf(stderr, "I-type 4: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b1101111: { // jal
PARSE_J_INS(ins);
m_regs[rd] = m_pc + 4;
m_pc += imm;
continue;
}; break;
case 0b0110011: {
PARSE_R_INS(ins);
if (funct3 == 0b000) {
if (funct7 == 0b0000000) { // add
m_regs[rd] = m_regs[rs1] + m_regs[rs2];
} else if (funct7 == 0b0100000) { // sub
m_regs[rd] = m_regs[rs1] - m_regs[rs2];
} else if (funct7 == 0b0000001) { // mul
m_regs[rd] = m_regs[rs1] * m_regs[rs2];
} else {
fprintf(stderr, "R-type 1: funct3=0b000: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b001) {
if (funct7 == 0b0000001) { // mulh
i64 a_hi = m_regs[rs1] >> 32;
i64 b_hi = m_regs[rs2] >> 32;
u64 a_lo = (u32)m_regs[rs1];
u64 b_lo = (u32)m_regs[rs2];
u64 p0 = a_lo * b_lo;
i64 p1 = a_hi * b_lo;
i64 p2 = b_hi * a_lo;
i64 p3 = a_hi * b_hi;
i64 carry = (p0 >> 32);
i64 mid = p1 + p2 + carry;
m_regs[rd] = p3 + (mid >> 32);
} else {
fprintf(stderr, "R-type 1: funct3=0b001: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b010) {
if (funct7 == 0b0000000) { // slt
m_regs[rd] = (m_regs[rs1] < m_regs[rs2]) ? 1 : 0;
} else {
fprintf(stderr, "R-type 1: funct3=0b010: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b011) {
if (funct7 == 0b0000000) { // sltu
m_regs[rd] = ((u64)m_regs[rs1] < (u64)m_regs[rs2]) ? 1 : 0;
} else if (funct7 == 0b0000001) { // mulhu
u64 a = m_regs[rs1];
u64 b = m_regs[rs2];
u64 a_lo = a & 0xffffffff;
u64 a_hi = a >> 32;
u64 b_lo = b & 0xffffffff;
u64 b_hi = b >> 32;
u64 lo_lo = a_lo * b_lo;
u64 hi_lo = a_hi * b_lo;
u64 lo_hi = a_lo * b_hi;
u64 hi_hi = a_hi * b_hi;
u64 mid =
(lo_lo >> 32) + (hi_lo & 0xffffffff) + (lo_hi & 0xffffffff);
m_regs[rd] = hi_hi + (hi_lo >> 32) + (lo_hi >> 32) + (mid >> 32);
} else {
fprintf(stderr, "R-type 1: funct3=0b011: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b100) {
if (funct7 == 0b0000000) { // xor
m_regs[rd] = m_regs[rs1] ^ m_regs[rs2];
} else if (funct7 == 0b0000001) { // div
if (m_regs[rs2] == 0) {
m_regs[rd] = -1;
} else {
m_regs[rd] = m_regs[rs1] / m_regs[rs2];
}
} else {
fprintf(stderr, "R-type 1: funct3=0b100: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b110) {
if (funct7 == 0b0000001) { // rem
if (m_regs[rs2] == 0) {
m_regs[rd] = m_regs[rs1];
} else {
m_regs[rd] = m_regs[rs1] % m_regs[rs2];
}
} else if (funct7 == 0b0000000) { // or
m_regs[rd] = m_regs[rs1] | m_regs[rs2];
} else {
fprintf(stderr, "R-type 1: funct3=0b110: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b111) {
if (funct7 == 0b000) { // and
m_regs[rd] = m_regs[rs1] & m_regs[rs2];
} else if (funct7 == 0b001) { // remu
if (m_regs[rs2] == 0) {
m_regs[rd] = m_regs[rs1];
} else {
m_regs[rd] = (u64)m_regs[rs1] % (u64)m_regs[rs2];
}
} else {
fprintf(stderr, "R-type 1: funct3=0b111: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else {
fprintf(stderr, "R-type 1: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0101111: {
fprintf(stderr, "A extension not implemented yet.\n");
exit(1);
}; break;
case 0b0111011: {
PARSE_R_INS(ins);
if (funct3 == 0b000) {
if (funct7 == 0b0000000) { // addw
m_regs[rd] = (i32)(m_regs[rs1] + m_regs[rs2]);
} else if (funct7 == 0b0100000) { // subw
m_regs[rd] = (i32)(m_regs[rs1] - m_regs[rs2]);
} else if (funct7 == 0b0000001) { // mulw
m_regs[rd] = (i32)(m_regs[rs1] * m_regs[rs2]);
} else {
fprintf(stderr, "R-type 3: funct3=000: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b001) {
if (funct7 == 0b0000000) { // sllw
m_regs[rd] =
(i32)(u32)((u32)m_regs[rs1] << ((u32)m_regs[rs2] & 0b11111));
} else {
fprintf(stderr, "R-type 3: funct3=001: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b100) { // divw
i32 a = m_regs[rs1];
i32 b = m_regs[rs2];
if (b == 0) {
m_regs[rd] = (u64)(i64)(-1);
} else {
m_regs[rd] = (i64)(a / b);
}
} else if (funct3 == 0b101) {
if (funct7 == 0b0000000) { // srlw
m_regs[rd] =
(i32)((u32)m_regs[rs1] >> ((u32)m_regs[rs2] & 0b11111));
} else if (funct7 == 0b0100000) { // sraw
m_regs[rd] = ((i32)m_regs[rs1]) >> ((u32)m_regs[rs2] & 0b11111);
} else if (funct7 == 0b0000001) { // divuw
if (m_regs[rs2] == 0) {
m_regs[rd] = -1LL;
} else {
m_regs[rd] = (i32)((u32)m_regs[rs1] / (u32)m_regs[rs2]);
}
} else {
fprintf(stderr, "R-type 3: funct3=101: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b111) { // remuw
if (m_regs[rs2] == 0) {
m_regs[rd] = (i32)m_regs[rs1];
} else {
m_regs[rd] = (i32)((u32)m_regs[rs1] % (u32)m_regs[rs2]);
}
} else {
fprintf(stderr, "R-type 3: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0011011: {
PARSE_I_INS(ins);
if (funct3 == 0b000) { // addiw
m_regs[rd] = (i32)m_regs[rs1] + (i32)imm;
} else if (funct3 == 0b001) {
u32 shamt = (ins >> 20) & 0b11111;
m_regs[rd] = (i32)m_regs[rs1] << shamt;
} else if (funct3 == 0b101) {
PARSE_R_INS(ins);
if (funct7 == 0b0000000) { // srliw
m_regs[rd] = (i32)((u32)m_regs[rs1] >> rs2);
} else if (funct7 == 0b0100000) { // sraiw
m_regs[rd] = (i32)m_regs[rs1] >> rs2;
} else {
fprintf(stderr, "R-type 4: funct3=101: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else {
fprintf(stderr, "R-type 4: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0100011: {
PARSE_S_INS(ins);
if (funct3 == 0b000) { // sb
u64 addr = m_regs[rs1] + imm;
m_memory[addr] = m_regs[rs2];
} else if (funct3 == 0b001) { // sh
u64 addr = m_regs[rs1] + imm;
*(u16 *)(&m_memory[addr]) = m_regs[rs2];
} else if (funct3 == 0b010) { // sw
u64 addr = m_regs[rs1] + imm;
*(u32 *)(&m_memory[addr]) = m_regs[rs2];
} else if (funct3 == 0b011) { // sd
u64 addr = m_regs[rs1] + imm;
// take this rust
*(u64 *)(&m_memory[addr]) = m_regs[rs2];
} else {
fprintf(stderr, "S-type: unrecognized funct3: %03b\n", funct3);
exit(1);
}
}; break;
case 0b0110111: { // lui
PARSE_U_INS(ins);
m_regs[rd] = (i64)(i32)(imm << 12);
}; break;
case 0b0010111: { // auipc
PARSE_U_INS(ins);
m_regs[rd] = m_pc + ((i64)imm << 12);
}; break;
default:
fprintf(stderr, "Unrecognized opcode: %07b\n", opcode);
exit(1);
}
m_pc += 4;
}
}
private: private:
std::vector<u8> m_memory = std::vector<u8>(MEMORY_SIZE, 0); std::vector<u8> m_memory = std::vector<u8>(MEMORY_SIZE, 0);
u64 m_pc; u64 m_pc;
std::array<i64, 32> m_regs = {0}; std::array<i64, 32> m_regs{};
Section m_code_section; Section m_code_section;
static Section get_code_section(Elf *elf, GElf_Ehdr ehdr) { static Section get_code_section(Elf *elf, GElf_Ehdr ehdr) {
@@ -117,10 +923,11 @@ int main(int argc, char *argv[]) {
RISCV64 r(exe_bytes); RISCV64 r(exe_bytes);
exe_bytes = {}; exe_bytes.clear();
exe_bytes.shrink_to_fit();
// r.disassemble_all(); r.disassemble_all();
// printf("END DISASSEMBLY\n"); printf("END DISASSEMBLY\n");
// r.execute(); r.execute();
} }