This commit is contained in:
2026-03-05 15:24:40 +01:00
parent d0659f9f8b
commit 3d14448de7
4 changed files with 125 additions and 15 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
/examples
/test*
/chip8
/mos6502
/riscv64

12
README.md Normal file
View File

@@ -0,0 +1,12 @@
# emu
Emulators written in C
* `chip8.c` - [CHIP8](https://en.wikipedia.org/wiki/CHIP-8)
* `mos6502.c` - [MOS 6502](https://en.wikipedia.org/wiki/MOS_Technology_6502)
* `riscv64.c & riscv64_dis.h` - [RV64IM instruction set](https://en.wikipedia.org/wiki/RISC-V) (more extensions coming soon-ish)
## Building
```
./build.sh
```

View File

@@ -1,9 +1,11 @@
// https://docs.riscv.org/reference/isa/_attachments/riscv-unprivileged.pdf // 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 "riscv64_dis.h" #include "riscv64_dis.h"
#include <gelf.h> #include <gelf.h>
#include <libelf.h> #include <libelf.h>
#define MEMORY_SIZE 20 * 1024 * 1024 // should be enough
const char *const REGS[32] = { const char *const REGS[32] = {
"zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1", "a0", "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1", "a0",
"a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5", "a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", "s5",
@@ -35,7 +37,7 @@ Section riscv64_get_code_section(Elf *elf, GElf_Ehdr ehdr) {
} }
RISCV64 riscv64_load(uint8_t *exe_bytes, size_t exe_size) { RISCV64 riscv64_load(uint8_t *exe_bytes, size_t exe_size) {
uint8_t *memory = calloc(20 * 1024 * 1024, 1); uint8_t *memory = calloc(MEMORY_SIZE, 1);
Elf *elf = elf_memory((char *)exe_bytes, exe_size); Elf *elf = elf_memory((char *)exe_bytes, exe_size);
GElf_Ehdr ehdr; GElf_Ehdr ehdr;
@@ -71,7 +73,7 @@ void riscv64_dump(const RISCV64 *r) {
void riscv64_execute(RISCV64 *r) { void riscv64_execute(RISCV64 *r) {
r->pc = r->code_section.entrypoint; r->pc = r->code_section.entrypoint;
r->regs[2] = (20 * 1024 * 1024) - 1; // set the stack pointer r->regs[2] = MEMORY_SIZE - 1024; // set the stack pointer
while (r->pc < r->code_section.offset + r->code_section.size) { while (r->pc < r->code_section.offset + r->code_section.size) {
r->regs[0] = 0; // clear the zero register r->regs[0] = 0; // clear the zero register
@@ -142,9 +144,9 @@ void riscv64_execute(RISCV64 *r) {
uint32_t funct6 = (ins >> 26) & 0b111111; uint32_t funct6 = (ins >> 26) & 0b111111;
if (funct6 == 0b000000) { // srli if (funct6 == 0b000000) { // srli
r->regs[rd] = r->regs[rs1] >> shamt; r->regs[rd] = (uint64_t)r->regs[rs1] >> shamt;
} else if (funct6 == 0b010000) { // srai } else if (funct6 == 0b010000) { // srai
r->regs[rd] = (int32_t)r->regs[rs1] >> shamt; r->regs[rd] = (int64_t)r->regs[rs1] >> shamt;
} else { } else {
fprintf(stderr, "I-type 1: funct3=101: unrecognized funct6: %b\n", fprintf(stderr, "I-type 1: funct3=101: unrecognized funct6: %b\n",
funct6); funct6);
@@ -310,6 +312,20 @@ void riscv64_execute(RISCV64 *r) {
if (funct7 == 0b0000000) { // sltu if (funct7 == 0b0000000) { // sltu
r->regs[rd] = r->regs[rd] =
((uint64_t)r->regs[rs1] < (uint64_t)r->regs[rs2]) ? 1 : 0; ((uint64_t)r->regs[rs1] < (uint64_t)r->regs[rs2]) ? 1 : 0;
} else if (funct7 == 0b0000001) { // mulhu
uint64_t a = r->regs[rs1];
uint64_t b = r->regs[rs2];
uint64_t a_lo = a & 0xffffffff;
uint64_t a_hi = a >> 32;
uint64_t b_lo = b & 0xffffffff;
uint64_t b_hi = b >> 32;
uint64_t lo_lo = a_lo * b_lo;
uint64_t hi_lo = a_hi * b_lo;
uint64_t lo_hi = a_lo * b_hi;
uint64_t hi_hi = a_hi * b_hi;
uint64_t mid =
(lo_lo >> 32) + (hi_lo & 0xffffffff) + (lo_hi & 0xffffffff);
r->regs[rd] = hi_hi + (hi_lo >> 32) + (lo_hi >> 32) + (mid >> 32);
} else { } else {
fprintf(stderr, "R-type 1: funct3=0b011: unrecognized funct7: %b\n", fprintf(stderr, "R-type 1: funct3=0b011: unrecognized funct7: %b\n",
funct7); funct7);
@@ -362,6 +378,10 @@ void riscv64_execute(RISCV64 *r) {
exit(1); exit(1);
} }
}; break; }; break;
case 0b0101111: {
fprintf(stderr, "A extension not implemented yet.\n");
exit(1);
}; break;
case 0b0111011: { case 0b0111011: {
PARSE_R_INS(ins); PARSE_R_INS(ins);
if (funct3 == 0b000) { if (funct3 == 0b000) {
@@ -376,6 +396,16 @@ void riscv64_execute(RISCV64 *r) {
funct7); funct7);
exit(1); exit(1);
} }
} else if (funct3 == 0b001) {
if (funct7 == 0b0000000) { // sllw
r->regs[rd] =
(int32_t)(uint32_t)((uint32_t)r->regs[rs1]
<< ((uint32_t)r->regs[rs2] & 0b11111));
} else {
fprintf(stderr, "R-type 3: funct3=001: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else if (funct3 == 0b100) { // divw } else if (funct3 == 0b100) { // divw
int32_t a = r->regs[rs1]; int32_t a = r->regs[rs1];
int32_t b = r->regs[rs2]; int32_t b = r->regs[rs2];
@@ -385,7 +415,13 @@ void riscv64_execute(RISCV64 *r) {
r->regs[rd] = (int64_t)(a / b); r->regs[rd] = (int64_t)(a / b);
} }
} else if (funct3 == 0b101) { } else if (funct3 == 0b101) {
if (funct7 == 0b0000001) { // divuw if (funct7 == 0b0000000) { // srlw
r->regs[rd] = (int32_t)((uint32_t)r->regs[rs1] >>
((uint32_t)r->regs[rs2] & 0b11111));
} else if (funct7 == 0b0100000) { // sraw
r->regs[rd] =
((int32_t)r->regs[rs1]) >> ((uint32_t)r->regs[rs2] & 0b11111);
} else if (funct7 == 0b0000001) { // divuw
if (r->regs[rs2] == 0) { if (r->regs[rs2] == 0) {
r->regs[rd] = -1LL; r->regs[rd] = -1LL;
} else { } else {
@@ -416,6 +452,17 @@ void riscv64_execute(RISCV64 *r) {
} else if (funct3 == 0b001) { } else if (funct3 == 0b001) {
uint32_t shamt = (ins >> 20) & 0b11111; uint32_t shamt = (ins >> 20) & 0b11111;
r->regs[rd] = (int32_t)r->regs[rs1] << shamt; r->regs[rd] = (int32_t)r->regs[rs1] << shamt;
} else if (funct3 == 0b101) {
PARSE_R_INS(ins);
if (funct7 == 0b0000000) { // srliw
r->regs[rd] = (int32_t)((uint32_t)r->regs[rs1] >> rs2);
} else if (funct7 == 0b0100000) { // sraiw
r->regs[rd] = (int32_t)r->regs[rs1] >> rs2;
} else {
fprintf(stderr, "R-type 4: funct3=101: unrecognized funct7: %b\n",
funct7);
exit(1);
}
} else { } else {
fprintf(stderr, "R-type 4: unrecognized funct3: %03b\n", funct3); fprintf(stderr, "R-type 4: unrecognized funct3: %03b\n", funct3);
exit(1); exit(1);
@@ -444,7 +491,7 @@ void riscv64_execute(RISCV64 *r) {
}; break; }; break;
case 0b0110111: { // lui case 0b0110111: { // lui
PARSE_U_INS(ins); PARSE_U_INS(ins);
r->regs[rd] = (int64_t)imm << 12; r->regs[rd] = (int64_t)(int32_t)(imm << 12);
}; break; }; break;
case 0b0010111: { // auipc case 0b0010111: { // auipc
PARSE_U_INS(ins); PARSE_U_INS(ins);
@@ -481,9 +528,8 @@ int main(int argc, char *argv[]) {
return 1; return 1;
} }
// probably enough for anything we can handle uint8_t *exe_bytes = malloc(MEMORY_SIZE);
uint8_t *exe_bytes = malloc(20 * 1024 * 1024); size_t exe_size = fread(exe_bytes, 1, MEMORY_SIZE, file);
size_t exe_size = fread(exe_bytes, 1, 20 * 1024 * 1024, file);
fclose(file); fclose(file);
RISCV64 r = riscv64_load(exe_bytes, exe_size); RISCV64 r = riscv64_load(exe_bytes, exe_size);

View File

@@ -87,6 +87,8 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT
printf("bge %s, %s, %d\n", REGS[rs1], REGS[rs2], imm); printf("bge %s, %s, %d\n", REGS[rs1], REGS[rs2], imm);
} else if (funct3 == 0b110) { } else if (funct3 == 0b110) {
printf("bltu %s, %s, %d\n", REGS[rs1], REGS[rs2], imm); 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 { } else {
fprintf(stderr, "B-type: unrecognized funct3: %03b\n", funct3); fprintf(stderr, "B-type: unrecognized funct3: %03b\n", funct3);
exit(1); exit(1);
@@ -108,6 +110,8 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT
funct6); funct6);
exit(1); exit(1);
} }
} else if (funct3 == 0b010) {
printf("slti %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b011) { } else if (funct3 == 0b011) {
printf("sltiu %s, %s, %d\n", REGS[rd], REGS[rs1], imm); printf("sltiu %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b100) { } else if (funct3 == 0b100) {
@@ -126,6 +130,8 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT
funct6); funct6);
exit(1); exit(1);
} }
} else if (funct3 == 0b110) {
printf("ori %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b111) { } else if (funct3 == 0b111) {
printf("andi %s, %s, %d\n", REGS[rd], REGS[rs1], imm); printf("andi %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else { } else {
@@ -146,6 +152,10 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT
printf("ld %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]); printf("ld %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]);
} else if (funct3 == 0b100) { } else if (funct3 == 0b100) {
printf("lbu %s, %d(%s)\n", REGS[rd], imm, REGS[rs1]); 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 { } else {
fprintf(stderr, "I-type 2: unrecognized funct3: %03b\n", funct3); fprintf(stderr, "I-type 2: unrecognized funct3: %03b\n", funct3);
exit(1); exit(1);
@@ -189,7 +199,9 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT
exit(1); exit(1);
} }
} else if (funct3 == 0b001) { } else if (funct3 == 0b001) {
if (funct7 == 0b0000001) { 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]); printf("mulh %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else { } else {
fprintf(stderr, "R-type 1: funct3=0b001: unrecognized funct7: %b\n", fprintf(stderr, "R-type 1: funct3=0b001: unrecognized funct7: %b\n",
@@ -224,6 +236,18 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT
funct7); funct7);
exit(1); 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) { } else if (funct3 == 0b110) {
if (funct7 == 0b0000001) { if (funct7 == 0b0000001) {
printf("rem %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]); printf("rem %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
@@ -250,7 +274,7 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT
} }
}; break; }; break;
case 0b0101111: case 0b0101111:
fprintf(stderr, "R-type 2: unimplemented\n"); fprintf(stderr, "A extension not implemented yet.\n");
exit(1); exit(1);
case 0b0111011: { case 0b0111011: {
PARSE_R_INS(ins); PARSE_R_INS(ins);
@@ -266,16 +290,24 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT
funct7); funct7);
exit(1); exit(1);
} }
} else if (funct3 == 0b001) {
printf("sllw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct3 == 0b100) { } else if (funct3 == 0b100) {
printf("divw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]); printf("divw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct3 == 0b101) { } else if (funct3 == 0b101) {
if (funct7 == 0b0000001) { 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]); printf("divuw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else { } else {
fprintf(stderr, "R-type 3: funct3=101: unrecognized funct7: %b\n", fprintf(stderr, "R-type 3: funct3=101: unrecognized funct7: %b\n",
funct7); funct7);
exit(1); exit(1);
} }
} else if (funct3 == 0b110) {
printf("remw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else if (funct3 == 0b111) { } else if (funct3 == 0b111) {
printf("remuw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]); printf("remuw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]);
} else { } else {
@@ -289,13 +321,28 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT
PARSE_I_INS(ins); PARSE_I_INS(ins);
printf("addiw %s, %s, %d\n", REGS[rd], REGS[rs1], imm); printf("addiw %s, %s, %d\n", REGS[rd], REGS[rs1], imm);
} else if (funct3 == 0b001) { } else if (funct3 == 0b001) {
PARSE_I_INS(ins); PARSE_R_INS(ins);
printf("slliw %s, %s, %d\n", REGS[rd], REGS[rs1], imm); 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 { } else {
fprintf(stderr, "R-type 4: unrecognized funct3: %03b\n", funct3); fprintf(stderr, "R-type 4: unrecognized funct3: %03b\n", funct3);
exit(1); exit(1);
} }
}; break; }; break;
case 0b0100111: {
fprintf(stderr, "F extension not implemented yet.\n");
exit(1);
}; break;
case 0b0100011: { case 0b0100011: {
PARSE_S_INS(ins); PARSE_S_INS(ins);