diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a2dc88c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +/examples +/test* +/chip8 +/mos6502 +/riscv64 diff --git a/README.md b/README.md new file mode 100644 index 0000000..3163088 --- /dev/null +++ b/README.md @@ -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 +``` diff --git a/riscv64.c b/riscv64.c index 5b50673..ca79f63 100644 --- a/riscv64.c +++ b/riscv64.c @@ -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 #include "riscv64_dis.h" #include #include +#define MEMORY_SIZE 20 * 1024 * 1024 // should be enough + const char *const REGS[32] = { "zero", "ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1", "a0", "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) { - uint8_t *memory = calloc(20 * 1024 * 1024, 1); + uint8_t *memory = calloc(MEMORY_SIZE, 1); Elf *elf = elf_memory((char *)exe_bytes, exe_size); GElf_Ehdr ehdr; @@ -71,7 +73,7 @@ void riscv64_dump(const RISCV64 *r) { void riscv64_execute(RISCV64 *r) { 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) { r->regs[0] = 0; // clear the zero register @@ -142,9 +144,9 @@ void riscv64_execute(RISCV64 *r) { uint32_t funct6 = (ins >> 26) & 0b111111; 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 - r->regs[rd] = (int32_t)r->regs[rs1] >> shamt; + r->regs[rd] = (int64_t)r->regs[rs1] >> shamt; } else { fprintf(stderr, "I-type 1: funct3=101: unrecognized funct6: %b\n", funct6); @@ -310,6 +312,20 @@ void riscv64_execute(RISCV64 *r) { if (funct7 == 0b0000000) { // sltu r->regs[rd] = ((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 { fprintf(stderr, "R-type 1: funct3=0b011: unrecognized funct7: %b\n", funct7); @@ -362,6 +378,10 @@ void riscv64_execute(RISCV64 *r) { 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) { @@ -376,6 +396,16 @@ void riscv64_execute(RISCV64 *r) { funct7); 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 int32_t a = r->regs[rs1]; int32_t b = r->regs[rs2]; @@ -385,7 +415,13 @@ void riscv64_execute(RISCV64 *r) { r->regs[rd] = (int64_t)(a / b); } } 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) { r->regs[rd] = -1LL; } else { @@ -416,6 +452,17 @@ void riscv64_execute(RISCV64 *r) { } else if (funct3 == 0b001) { uint32_t shamt = (ins >> 20) & 0b11111; 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 { fprintf(stderr, "R-type 4: unrecognized funct3: %03b\n", funct3); exit(1); @@ -444,7 +491,7 @@ void riscv64_execute(RISCV64 *r) { }; break; case 0b0110111: { // lui PARSE_U_INS(ins); - r->regs[rd] = (int64_t)imm << 12; + r->regs[rd] = (int64_t)(int32_t)(imm << 12); }; break; case 0b0010111: { // auipc PARSE_U_INS(ins); @@ -481,9 +528,8 @@ int main(int argc, char *argv[]) { return 1; } - // probably enough for anything we can handle - uint8_t *exe_bytes = malloc(20 * 1024 * 1024); - size_t exe_size = fread(exe_bytes, 1, 20 * 1024 * 1024, file); + uint8_t *exe_bytes = malloc(MEMORY_SIZE); + size_t exe_size = fread(exe_bytes, 1, MEMORY_SIZE, file); fclose(file); RISCV64 r = riscv64_load(exe_bytes, exe_size); diff --git a/riscv64_dis.h b/riscv64_dis.h index 067b532..a296f42 100644 --- a/riscv64_dis.h +++ b/riscv64_dis.h @@ -87,6 +87,8 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT 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); @@ -108,6 +110,8 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT 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) { @@ -126,6 +130,8 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT 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 { @@ -146,6 +152,10 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT 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); @@ -189,7 +199,9 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT exit(1); } } 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]); } else { fprintf(stderr, "R-type 1: funct3=0b001: unrecognized funct7: %b\n", @@ -224,6 +236,18 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT 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]); @@ -250,7 +274,7 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT } }; break; case 0b0101111: - fprintf(stderr, "R-type 2: unimplemented\n"); + fprintf(stderr, "A extension not implemented yet.\n"); exit(1); case 0b0111011: { PARSE_R_INS(ins); @@ -266,16 +290,24 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT 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 == 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]); } 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 { @@ -289,13 +321,28 @@ void riscv64_disassemble_one(const RISCV64 *r) { // NOLINT PARSE_I_INS(ins); printf("addiw %s, %s, %d\n", REGS[rd], REGS[rs1], imm); } else if (funct3 == 0b001) { - PARSE_I_INS(ins); - printf("slliw %s, %s, %d\n", REGS[rd], REGS[rs1], imm); + 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);