diff --git a/build.sh b/build.sh index 9a99dad..890df72 100755 --- a/build.sh +++ b/build.sh @@ -1,15 +1,15 @@ #!/bin/bash -WARNINGS="-Wall -Wextra -Wpedantic -Wno-unused-variable -Wno-gnu-binary-literal" +COMMON="-g -Wall -Wextra -Wpedantic -Wno-unused-variable -Wno-gnu-binary-literal" echo "building mos6502..." -cc $WARNINGS -std=c99 -o mos6502 mos6502.c +cc $COMMON -std=c99 -o mos6502 mos6502.c if command -v pkg-config >/dev/null; then RAYLIB_FLAGS=$(pkg-config --cflags --libs raylib 2>/dev/null) if [ $? -eq 0 ]; then echo "building chip8..." - cc $WARNINGS -std=c99 -o chip8 chip8.c $RAYLIB_FLAGS + cc $COMMON -std=c99 -o chip8 chip8.c $RAYLIB_FLAGS else echo "raylib not found - skipping chip8..." fi @@ -17,7 +17,7 @@ if command -v pkg-config >/dev/null; then LIBELF_FLAGS=$(pkg-config --cflags --libs libelf 2>/dev/null) if [ $? -eq 0 ]; then echo "building riscv64..." - cc $WARNINGS -std=gnu11 -o riscv64 riscv64.c $LIBELF_FLAGS + cc $COMMON -std=gnu11 -o riscv64 riscv64.c $LIBELF_FLAGS else echo "libelf not found - skipping riscv64..." fi diff --git a/riscv64.c b/riscv64.c index 47dc8e7..27acbaf 100644 --- a/riscv64.c +++ b/riscv64.c @@ -63,6 +63,7 @@ static const char *const REGS[32] = { typedef struct { size_t offset; size_t size; + size_t entrypoint; } Section; typedef struct { @@ -85,6 +86,12 @@ Section riscv64_get_code_section(uint8_t *exe_bytes, size_t exe_size) { exit(1); } + GElf_Ehdr ehdr; + if (gelf_getehdr(elf, &ehdr) == 0) { + fprintf(stderr, "gelf_getehdr failed: %s\n", elf_errmsg(-1)); + exit(1); + } + Elf_Scn *section = NULL; while ((section = elf_nextscn(elf, section)) != NULL) { GElf_Shdr header; @@ -94,7 +101,10 @@ Section riscv64_get_code_section(uint8_t *exe_bytes, size_t exe_size) { const char *name = elf_strptr(elf, str_table_index, header.sh_name); if (name && strcmp(name, ".text") == 0) { elf_end(elf); - return (Section){.offset = header.sh_offset, .size = header.sh_size}; + return (Section){.offset = header.sh_offset, + .size = header.sh_size, + .entrypoint = + ehdr.e_entry - header.sh_addr + header.sh_offset}; } } @@ -140,7 +150,8 @@ void riscv64_disassemble_one(const RISCV64 *r) { 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); - break; + } else if (funct3 == 0b110) { + printf("bltu %s, %s, %d\n", REGS[rs1], REGS[rs2], imm); } else { fprintf(stderr, "B-type: unrecognized funct3: %03b\n", funct3); exit(1); @@ -152,7 +163,36 @@ void riscv64_disassemble_one(const RISCV64 *r) { if (funct3 == 0b000) { printf("addi %s, %s, %d\n", REGS[rd], REGS[rs1], imm); } else if (funct3 == 0b001) { - printf("slli %s, %s, %d\n", REGS[rd], REGS[rs1], imm); + uint32_t shamt = (ins >> 20) & 0b111111; + uint32_t 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 == 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 + uint32_t shamt = (ins >> 20) & 0b111111; + uint32_t 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 == 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); @@ -163,8 +203,14 @@ void riscv64_disassemble_one(const RISCV64 *r) { 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 { fprintf(stderr, "I-type 2: unrecognized funct3: %03b\n", funct3); exit(1); @@ -184,7 +230,6 @@ void riscv64_disassemble_one(const RISCV64 *r) { 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); @@ -208,6 +253,60 @@ void riscv64_disassemble_one(const RISCV64 *r) { funct7); exit(1); } + } else if (funct3 == 0b001) { + 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 == 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 { + 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); @@ -218,7 +317,19 @@ void riscv64_disassemble_one(const RISCV64 *r) { exit(1); case 0b0111011: { PARSE_R_INS(ins); - if (funct3 == 0b101) { + 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 == 0b101) { if (funct7 == 0b0000001) { printf("divuw %s, %s, %s\n", REGS[rd], REGS[rs1], REGS[rs2]); } else { @@ -238,6 +349,9 @@ void riscv64_disassemble_one(const RISCV64 *r) { if (funct3 == 0b000) { 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); } else { fprintf(stderr, "R-type 4: unrecognized funct3: %03b\n", funct3); exit(1); @@ -248,6 +362,10 @@ void riscv64_disassemble_one(const RISCV64 *r) { 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 { @@ -270,7 +388,7 @@ void riscv64_disassemble_one(const RISCV64 *r) { } void riscv64_execute(RISCV64 *r) { - r->pc = r->code_section.offset; + r->pc = r->code_section.entrypoint; r->regs[2] = (20 * 1024 * 1024) - 1; // set the stack pointer @@ -307,6 +425,11 @@ void riscv64_execute(RISCV64 *r) { r->pc += imm; continue; } + } else if (funct3 == 0b110) { // bltu + if ((uint64_t)r->regs[rs1] < (uint64_t)r->regs[rs2]) { + r->pc += imm; + continue; + } } else { fprintf(stderr, "B-type: unrecognized funct3: %03b\n", funct3); exit(1); @@ -318,7 +441,36 @@ void riscv64_execute(RISCV64 *r) { if (funct3 == 0b000) { // addi r->regs[rd] = r->regs[rs1] + imm; } else if (funct3 == 0b001) { // slli - r->regs[rd] = r->regs[rs1] << (imm & 0b111111); + uint32_t shamt = (ins >> 20) & 0b111111; + uint32_t funct6 = (ins >> 26) & 0b111111; + + if (funct6 == 0b000000) { + r->regs[rd] = r->regs[rs1] << shamt; + } else { + fprintf(stderr, "I-type 1: funct3=001: unrecognized funct6: %b\n", + funct6); + exit(1); + } + } else if (funct3 == 0b011) { // sltiu + r->regs[rd] = (r->regs[rs1] < (uint64_t)(int64_t)imm) ? 1 : 0; + } else if (funct3 == 0b100) { // xori + r->regs[rd] = r->regs[rs1] ^ imm; + } else if (funct3 == 0b101) { + // of course this one just has to be different + uint32_t shamt = (ins >> 20) & 0b111111; + uint32_t funct6 = (ins >> 26) & 0b111111; + + if (funct6 == 0b000000) { // srli + r->regs[rd] = r->regs[rs1] >> shamt; + } else if (funct6 == 0b010000) { // srai + r->regs[rd] = (int32_t)r->regs[rs1] >> shamt; + } else { + fprintf(stderr, "I-type 1: funct3=101: unrecognized funct6: %b\n", + funct6); + exit(1); + } + } else if (funct3 == 0b111) { + r->regs[rd] = r->regs[rs1] & imm; } else { fprintf(stderr, "I-type 1: unrecognized funct3: %03b\n", funct3); exit(1); @@ -328,9 +480,15 @@ void riscv64_execute(RISCV64 *r) { PARSE_I_INS(ins); if (funct3 == 0b000) { // lb - r->regs[rd] = r->memory[r->regs[rs1] + imm]; + r->regs[rd] = (int8_t)r->memory[r->regs[rs1] + imm]; + } else if (funct3 == 0b001) { // lh + r->regs[rd] = *(int16_t *)&r->memory[r->regs[rs1] + imm]; + } else if (funct3 == 0b010) { // lw + r->regs[rd] = *(int32_t *)&r->memory[r->regs[rs1] + imm]; } else if (funct3 == 0b011) { // ld r->regs[rd] = *(uint64_t *)&r->memory[r->regs[rs1] + imm]; + } else if (funct3 == 0b100) { // lbu + r->regs[rd] = r->memory[r->regs[rs1] + imm]; } else { fprintf(stderr, "I-type 2: unrecognized funct3: %03b\n", funct3); exit(1); @@ -338,7 +496,7 @@ void riscv64_execute(RISCV64 *r) { }; break; case 0b1100111: { // jalr PARSE_I_INS(ins); - uint32_t target = (r->regs[rs1] + imm) & ~1; + size_t target = (r->regs[rs1] + imm) & ~(size_t)1; r->regs[rd] = r->pc + 4; r->pc = target; continue; @@ -432,18 +590,86 @@ void riscv64_execute(RISCV64 *r) { if (funct3 == 0b000) { if (funct7 == 0b0000000) { // add r->regs[rd] = r->regs[rs1] + r->regs[rs2]; - break; } else if (funct7 == 0b0100000) { // sub r->regs[rd] = r->regs[rs1] - r->regs[rs2]; - break; } else if (funct7 == 0b0000001) { // mul r->regs[rd] = r->regs[rs1] * r->regs[rs2]; - break; } else { fprintf(stderr, "R-type 1: funct3=0b000: unrecognized funct7: %b\n", funct7); exit(1); } + } else if (funct3 == 0b001) { + if (funct7 == 0b0000001) { // mulh + int64_t a_hi = r->regs[rs1] >> 32; + int64_t b_hi = r->regs[rs2] >> 32; + uint64_t a_lo = (uint32_t)r->regs[rs1]; + uint64_t b_lo = (uint32_t)r->regs[rs2]; + uint64_t p0 = a_lo * b_lo; + int64_t p1 = a_hi * b_lo; + int64_t p2 = b_hi * a_lo; + int64_t p3 = a_hi * b_hi; + int64_t carry = (p0 >> 32); + int64_t mid = p1 + p2 + carry; + r->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 + r->regs[rd] = ((int64_t)r->regs[rs1] < (int64_t)r->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 + r->regs[rd] = + ((uint64_t)r->regs[rs1] < (uint64_t)r->regs[rs2]) ? 1 : 0; + } else { + fprintf(stderr, "R-type 1: funct3=0b011: unrecognized funct7: %b\n", + funct7); + exit(1); + } + } else if (funct3 == 0b100) { + if (funct7 == 0b0000000) { // xor + r->regs[rd] = r->regs[rs1] ^ r->regs[rs2]; + } else if (funct7 == 0b0000001) { // div + if (r->regs[rs2] == 0) { + r->regs[rd] = -1; + } else { + r->regs[rd] = (int64_t)r->regs[rs1] / (int64_t)r->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 (r->regs[rs2] == 0) { + r->regs[rd] = r->regs[rs1]; + } else { + r->regs[rd] = (int64_t)r->regs[rs1] % (int64_t)r->regs[rs2]; + } + } else if (funct7 == 0b0000000) { // or + r->regs[rd] = r->regs[rs1] | r->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 + r->regs[rd] = r->regs[rs1] & r->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); @@ -451,23 +677,37 @@ void riscv64_execute(RISCV64 *r) { }; break; case 0b0111011: { PARSE_R_INS(ins); - if (funct3 == 0b101) { - if (funct7 == 0b0000001) { + if (funct3 == 0b000) { + if (funct7 == 0b0000000) { // addw + r->regs[rd] = (int32_t)(r->regs[rs1] + r->regs[rs2]); + } else if (funct7 == 0b0100000) { // subw + r->regs[rd] = (int32_t)(r->regs[rs1] - r->regs[rs2]); + } else if (funct7 == 0b0000001) { // mulw + r->regs[rd] = (int32_t)(r->regs[rs1] * r->regs[rs2]); + } else { + fprintf(stderr, "R-type 3: funct3=000: unrecognized funct7: %b\n", + funct7); + exit(1); + } + } else if (funct3 == 0b101) { + if (funct7 == 0b0000001) { // divuw if (r->regs[rs2] == 0) { r->regs[rd] = -1LL; } else { - r->regs[rd] = (int32_t)(r->regs[rs1] / r->regs[rs2]); + r->regs[rd] = + (int32_t)((uint32_t)r->regs[rs1] / (uint32_t)r->regs[rs2]); } } else { fprintf(stderr, "R-type 3: funct3=101: unrecognized funct7: %b\n", funct7); exit(1); } - } else if (funct3 == 0b111) { + } else if (funct3 == 0b111) { // remuw if (r->regs[rs2] == 0) { r->regs[rd] = (int32_t)r->regs[rs1]; } else { - r->regs[rd] = (int32_t)(r->regs[rs1] % r->regs[rs2]); + r->regs[rd] = + (int32_t)((uint32_t)r->regs[rs1] % (uint32_t)r->regs[rs2]); } } else { fprintf(stderr, "R-type 3: unrecognized funct3: %03b\n", funct3); @@ -475,11 +715,12 @@ void riscv64_execute(RISCV64 *r) { } }; break; case 0b0011011: { - uint8_t funct3 = (ins >> 12) & 0b111; - if (funct3 == 0b000) { - PARSE_I_INS(ins); - int32_t result = r->regs[rs1] + imm; - r->regs[rd] = result; + PARSE_I_INS(ins); + if (funct3 == 0b000) { // addiw + r->regs[rd] = (int32_t)r->regs[rs1] + (int32_t)imm; + } else if (funct3 == 0b001) { + uint32_t shamt = (ins >> 20) & 0b11111; + r->regs[rd] = (int32_t)r->regs[rs1] << shamt; } else { fprintf(stderr, "R-type 4: unrecognized funct3: %03b\n", funct3); exit(1); @@ -491,6 +732,12 @@ void riscv64_execute(RISCV64 *r) { if (funct3 == 0b000) { // sb size_t addr = r->regs[rs1] + imm; r->memory[addr] = r->regs[rs2]; + } else if (funct3 == 0b001) { // sh + size_t addr = r->regs[rs1] + imm; + *(uint16_t *)(&r->memory[addr]) = r->regs[rs2]; + } else if (funct3 == 0b010) { // sw + size_t addr = r->regs[rs1] + imm; + *(uint32_t *)(&r->memory[addr]) = r->regs[rs2]; } else if (funct3 == 0b011) { // sd size_t addr = r->regs[rs1] + imm; // take this rust @@ -502,11 +749,11 @@ void riscv64_execute(RISCV64 *r) { }; break; case 0b0110111: { // lui PARSE_U_INS(ins); - r->regs[rd] = imm << 12; + r->regs[rd] = (int64_t)imm << 12; }; break; case 0b0010111: { // auipc PARSE_U_INS(ins); - r->regs[rd] = r->pc + (imm << 12); + r->regs[rd] = r->pc + ((int64_t)imm << 12); }; break; default: fprintf(stderr, "Unrecognized opcode: %07b\n", opcode);