diff --git a/.gitignore b/.gitignore index c28de3f..55a9ed2 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ psxc *.o +boot.rom diff --git a/include/boot.h b/include/boot.h new file mode 100644 index 0000000..ceee250 --- /dev/null +++ b/include/boot.h @@ -0,0 +1,8 @@ +#ifndef PSXC_BOOT_H_ +#define PSXC_BOOT_H_ + +#include "util.h" + +void boot_psx_prgm(byte_arr_t *prgm); + +#endif diff --git a/include/cpu.h b/include/cpu.h index 9a1a8cd..46a0a0d 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -10,6 +10,4 @@ typedef struct { uint32_t pc; } cpu_t; -typedef void (*cpu_insn_handler)(cpu_t *, uint32_t); - #endif diff --git a/include/insn.h b/include/insn.h index a35cbf3..9f0f274 100644 --- a/include/insn.h +++ b/include/insn.h @@ -5,7 +5,8 @@ #include -typedef enum { +typedef enum +{ SPECIAL = 0x00, BCONDZ = 0x01, J = 0x02, @@ -48,11 +49,8 @@ typedef enum { SWC3 = 0x3b, } op_primary_t; -static inline op_primary_t extract_primary_op(uint32_t insn) { - return (insn >> 26) & 0x3f; -} - -typedef enum { +typedef enum +{ SLL = 0x00, SRL = 0x02, SRA = 0x03, @@ -83,9 +81,35 @@ typedef enum { SLTU = 0x2b, } op_secondary_t; -static inline op_secondary_t extract_secondary_op(uint32_t insn) { - return (insn >> 0) & 0x3f; -} +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); void insn_execute(cpu_t *cpu, uint32_t insn); diff --git a/src/boot.c b/src/boot.c new file mode 100644 index 0000000..0f28c41 --- /dev/null +++ b/src/boot.c @@ -0,0 +1,48 @@ +#include "boot.h" + +#include +#include +#include +#include + +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(prgm->size >= 0x800); + assert(memcmp(MAGIC, prgm->data, sizeof MAGIC) == 0); + memcpy(&header, &prgm->data[sizeof MAGIC], sizeof header); + + assert(header.size_file == prgm->size - 0x800); + assert(memcmp(RESERVED, &prgm->data[0x38], sizeof RESERVED) == 0); + + return header; +} + +void boot_psx_prgm(byte_arr_t *prgm) +{ + psx_header_t header = parse_psx_header(prgm); + + printf("pc = %08x\n", header.pc); + printf("gp = %08x\n", header.gp); + 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); +} diff --git a/src/insn.c b/src/insn.c index e3491d4..1e194c1 100644 --- a/src/insn.c +++ b/src/insn.c @@ -9,22 +9,31 @@ static cpu_insn_handler primary_insn_handler[TABLE_SIZE] = {NULL}; static cpu_insn_handler secondary_insn_handler[TABLE_SIZE] = {NULL}; -void insn_execute(cpu_t *cpu, uint32_t insn) { - const op_primary_t op = extract_primary_op(insn); +static inline op_primary_t extract_primary_op(uint32_t insn) { + return (insn >> 26) & 0x3f; +} + +static inline op_secondary_t extract_secondary_op(uint32_t insn) { + return (insn >> 0) & 0x3f; +} + +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; if (op == SPECIAL) { - const op_secondary_t op2 = extract_secondary_op(insn); + const op_secondary_t op2 = extract_secondary_op(raw_insn); if (op2 > TABLE_SIZE || secondary_insn_handler[op2] == NULL) { - fatal("unsupported instruction: insn=%08x, op=%02x, op2=%02x", insn, op, - op2); + fatal("unsupported instruction: insn=%08x, op=%02x, op2=%02x", raw_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", insn, op); + fatal("unsupported instruction: insn=%08x, op=%02x", raw_insn, op); } primary_insn_handler[op](cpu, insn); diff --git a/src/main.c b/src/main.c index 76e8197..8afce62 100644 --- a/src/main.c +++ b/src/main.c @@ -1 +1,22 @@ -int main() { return 0; } +#include "boot.h" +#include "insn.h" +#include "util.h" + +#include + +int main() +{ + // uint32_t x = 0xffcdefab; + // const insn_t insn = *(insn_t *)&x; + // printf("%u", insn.insn_reg.op); + + byte_arr_t *prgm = read_file("boot.rom"); + if (prgm == NULL) + { + fatal("couldn't load boot.rom"); + } + + boot_psx_prgm(prgm); + + return 0; +} diff --git a/src/util.c b/src/util.c index ccffa03..ddd9559 100644 --- a/src/util.c +++ b/src/util.c @@ -4,28 +4,40 @@ #include #include -void fatal(const char *fmt, ...) { +void fatal(const char *fmt, ...) +{ va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); va_end(args); exit(EXIT_FAILURE); } -byte_arr_t *read_file(const char *filepath) { +byte_arr_t *read_file(const char *filepath) +{ FILE *fp = fopen(filepath, "rb"); byte_arr_t *arr = NULL; + if (fp == NULL) + { + fprintf(stderr, "%s: ", filepath); + perror("could not open"); + goto end; + } + fseek(fp, 0, SEEK_END); const long size = ftell(fp); - if (size < 0) { + if (size < 0) + { goto end; } arr = malloc(sizeof *arr + size); - if (arr == NULL) { + if (arr == NULL) + { goto end; } @@ -35,6 +47,9 @@ byte_arr_t *read_file(const char *filepath) { fread(arr->data, 1, size, fp); end: - fclose(fp); + if (fp != NULL) + { + fclose(fp); + } return arr; }