diff --git a/include/boot.h b/include/boot.h index ceee250..f80ffd4 100644 --- a/include/boot.h +++ b/include/boot.h @@ -3,6 +3,20 @@ #include "util.h" +typedef struct __attribute__((packed)) +{ + uint32_t pc; + uint32_t gp; + uint32_t addr_dest; + uint32_t size_file; + uint32_t addr_data; + uint32_t size_data; + uint32_t addr_bss; + uint32_t size_bss; + uint32_t sp; + uint32_t fp; +} psx_header_t; + void boot_psx_prgm(byte_arr_t *prgm); #endif diff --git a/include/cpu.h b/include/cpu.h index 46a0a0d..8f0933f 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -3,11 +3,25 @@ #include -#define SP(cpu) ((cpu)->regs[29]) +#define REG_GP 28 // Global pointer +#define REG_SP 29 // Stack pointer +#define REG_FP 30 // Frame pointer -typedef struct { +#define MAIN_RAM_SIZE 0x200000 +#define SCRATCHPAD_BASE 0x1F800000 +#define SCRATCHPAD_END 0x1F8003FF +#define SCRATCHPAD_SIZE (SCRATCHPAD_END - SCRATCHPAD_BASE + 1) + +typedef struct +{ uint32_t regs[32]; uint32_t pc; + uint32_t main_ram[MAIN_RAM_SIZE]; + uint32_t sratchpad_ram[SCRATCHPAD_SIZE]; } cpu_t; +void cpu_write32(cpu_t *cpu, uint32_t addr, uint32_t x); + +uint32_t cpu_read32(cpu_t *cpu, uint32_t addr); + #endif diff --git a/include/insn.h b/include/insn.h index 9f0f274..1f0037b 100644 --- a/include/insn.h +++ b/include/insn.h @@ -81,35 +81,7 @@ typedef enum SLTU = 0x2b, } op_secondary_t; -typedef union -{ - struct __attribute__((packed)) - { - uint8_t op : 6; - uint16_t rs : 5; - uint8_t rt : 5; - uint8_t rd : 5; - uint16_t imm5 : 5; - uint8_t tail : 6; - } insn_reg; - - struct __attribute__((packed)) - { - uint8_t op : 6; - uint32_t comment : 20; - uint8_t tail : 6; - } insn_call; - - struct __attribute__((packed)) - { - uint8_t op : 6; - uint16_t rs : 5; - uint8_t rt : 5; - uint16_t imm : 16; - } insn_imm; -} insn_t; - -typedef void (*cpu_insn_handler)(cpu_t *, insn_t); +typedef void (*cpu_insn_handler)(cpu_t *, uint32_t); void insn_execute(cpu_t *cpu, uint32_t insn); diff --git a/include/psx.h b/include/psx.h new file mode 100644 index 0000000..5c63032 --- /dev/null +++ b/include/psx.h @@ -0,0 +1,13 @@ +#ifndef PSXC_PSX_H_ +#define PSXC_PSX_H_ + +#include "boot.h" +#include "cpu.h" + +typedef struct +{ + psx_header_t header; + cpu_t *cpu; +} psx_t; + +#endif diff --git a/src/boot.c b/src/boot.c index 0f28c41..ad2b356 100644 --- a/src/boot.c +++ b/src/boot.c @@ -1,4 +1,7 @@ #include "boot.h" +#include "cpu.h" +#include "insn.h" +#include "psx.h" #include #include @@ -8,23 +11,12 @@ static const uint8_t MAGIC[0x10] = "PS-X EXE"; static const uint8_t RESERVED[0x10] = {0}; -typedef struct __attribute__((packed)) -{ - uint32_t pc; - uint32_t gp; - uint32_t addr_dest; - uint32_t size_file; - uint32_t addr_data; - uint32_t size_data; - uint32_t addr_bss; - uint32_t size_bss; -} psx_header_t; - psx_header_t parse_psx_header(byte_arr_t *prgm) { psx_header_t header; // TODO: Convert asserts into recoverable error + assert(sizeof header == 0x38 - 0x10); assert(prgm->size >= 0x800); assert(memcmp(MAGIC, prgm->data, sizeof MAGIC) == 0); memcpy(&header, &prgm->data[sizeof MAGIC], sizeof header); @@ -35,14 +27,56 @@ psx_header_t parse_psx_header(byte_arr_t *prgm) return header; } +uint32_t translate_addr(uint32_t addr) +{ + if (addr >= 0xA0000000) + { + addr = addr - 0xA0000000; + } + else if (addr >= 0x80000000) + { + addr = addr - 0x80000000; + } + + return addr; +} + void boot_psx_prgm(byte_arr_t *prgm) { + printf("parsing program header\n"); + psx_header_t header = parse_psx_header(prgm); - printf("pc = %08x\n", header.pc); - printf("gp = %08x\n", header.gp); + printf("=== header ===\n"); + printf("pc = %08x, gp = %08x\n", header.pc, header.gp); + printf("sp = %08x, fp = %08x\n", header.sp, header.fp); printf("data = %08x (%u bytes)\n", header.addr_data, header.size_data); printf("bss = %08x (%u bytes)\n", header.addr_bss, header.size_bss); printf("dest = %08x\n", header.addr_dest); printf("size = %08x (%u bytes)\n", header.size_file, header.size_file); + + cpu_t *cpu = malloc(sizeof *cpu); + + uint32_t start = translate_addr(header.addr_dest); + assert(start + header.size_file < MAIN_RAM_SIZE); + memcpy(&cpu->main_ram[start], &prgm->data[0x800], header.size_file); + + cpu->pc = header.pc; + cpu->regs[REG_GP] = header.gp; + cpu->regs[REG_SP] = header.sp; + cpu->regs[REG_FP] = header.fp; + + psx_t psx = {header, cpu}; + const int max_insns = 1; + + for (int i = 0; i < max_insns; i++) + { + printf("=== insn ===\n"); + printf("pc = %08x\n", psx.cpu->pc); + + const uint32_t insn = cpu_read32(cpu, psx.cpu->pc); + insn_execute(cpu, insn); + + psx.cpu->pc += 1; + } } diff --git a/src/cpu.c b/src/cpu.c new file mode 100644 index 0000000..a097ddc --- /dev/null +++ b/src/cpu.c @@ -0,0 +1,29 @@ +#include "cpu.h" + +static uint32_t translate_addr(uint32_t addr) +{ + if (addr >= 0xA0000000) + { + addr = addr - 0xA0000000; + } + else if (addr >= 0x80000000) + { + addr = addr - 0x80000000; + } + + return addr; +} + +void cpu_write32(cpu_t *cpu, uint32_t addr, uint32_t x) +{ + printf("WRITE: %08x to %08x\n", x, addr); + addr = translate_addr(addr); + cpu->main_ram[addr] = x; +} + +uint32_t cpu_read32(cpu_t *cpu, uint32_t addr) +{ + printf("READ: %08x\n", addr); + addr = translate_addr(addr); + return cpu->main_ram[addr]; +} diff --git a/src/insn.c b/src/insn.c index 1e194c1..cfd9d67 100644 --- a/src/insn.c +++ b/src/insn.c @@ -3,38 +3,60 @@ #include "util.h" #include +#include #define TABLE_SIZE 0x34 -static cpu_insn_handler primary_insn_handler[TABLE_SIZE] = {NULL}; +void insn_lw(cpu_t *cpu, uint32_t insn); + +static cpu_insn_handler primary_insn_handler[TABLE_SIZE] = { + [LW] = insn_lw, +}; + static cpu_insn_handler secondary_insn_handler[TABLE_SIZE] = {NULL}; -static inline op_primary_t extract_primary_op(uint32_t insn) { - return (insn >> 26) & 0x3f; -} +#define BITS(x, start, len) (((x) >> (start)) & ((1 << (len)) - 1)) -static inline op_secondary_t extract_secondary_op(uint32_t insn) { - return (insn >> 0) & 0x3f; -} +#define OP(insn) BITS(insn, 26, 6) +#define RS(insn) BITS(insn, 21, 5) +#define RT(insn) BITS(insn, 16, 5) +#define RD(insn) BITS(insn, 11, 5) +#define COMMENT(insn) BITS(insn, 6, 20) +#define IMM5(insn) BITS(insn, 6, 5) +#define OP2(insn) BITS(insn, 0, 6) +#define IMM(insn) BITS(insn, 0, 16) -void insn_execute(cpu_t *cpu, uint32_t raw_insn) { - const op_primary_t op = extract_primary_op(raw_insn); - const insn_t insn = *(insn_t *)&raw_insn; +void insn_execute(cpu_t *cpu, uint32_t insn) +{ + const op_primary_t op = OP(insn); - if (op == SPECIAL) { - const op_secondary_t op2 = extract_secondary_op(raw_insn); + if (op == SPECIAL) + { + const op_secondary_t op2 = OP2(insn); - if (op2 > TABLE_SIZE || secondary_insn_handler[op2] == NULL) { - fatal("unsupported instruction: insn=%08x, op=%02x, op2=%02x", raw_insn, + if (op2 > TABLE_SIZE || secondary_insn_handler[op2] == NULL) + { + fatal("unsupported instruction: insn=%08x, op=%02x, op2=%02x", insn, op, op2); } secondary_insn_handler[op2](cpu, insn); } - if (op > TABLE_SIZE || primary_insn_handler[op] == NULL) { - fatal("unsupported instruction: insn=%08x, op=%02x", raw_insn, op); + if (op > TABLE_SIZE || primary_insn_handler[op] == NULL) + { + fatal("unsupported instruction: insn=%08x, op=%02x", insn, op); } primary_insn_handler[op](cpu, insn); } + +void insn_lw(cpu_t *cpu, uint32_t insn) +{ + const uint8_t rs = RS(insn); + const uint8_t rt = RT(insn); + const uint16_t imm = IMM(insn); + + printf("LW R%u, [R%u + %x]\n", rt, rs, imm); + cpu->regs[rt] = cpu_read32(cpu, cpu->regs[rs] + imm); +} diff --git a/src/main.c b/src/main.c index 8afce62..4eb2085 100644 --- a/src/main.c +++ b/src/main.c @@ -10,6 +10,7 @@ int main() // const insn_t insn = *(insn_t *)&x; // printf("%u", insn.insn_reg.op); + printf("loading boot rom\n"); byte_arr_t *prgm = read_file("boot.rom"); if (prgm == NULL) {