diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 4af0041..f9bd56e 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -23,40 +23,19 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + - + + - + + + + + - - - - @@ -315,6 +289,7 @@ + - - - - - file://$PROJECT_DIR$/rom/rom.c - 32 - - - - \ No newline at end of file diff --git a/cpu/cpu.c b/cpu/cpu.c index 9a582e6..5e7654e 100644 --- a/cpu/cpu.c +++ b/cpu/cpu.c @@ -1,6 +1,7 @@ #include "../include/cpu.h" #include "cpu.h" #include "memory.h" +#include "op.h" /* * ===================================================================================== @@ -24,12 +25,27 @@ CpuRegisters registers; Mapper mapper; void cpu_init() { - registers.program_counter = 0x0000; + registers.program_counter = 0xc000; registers.stack_pointer = 0xff; registers.accumulator = 0x00; registers.x = 0x00; registers.y = 0x00; registers.status = 0x00; + + mapper = get_mapper(MAPPER_TYPE_SIMPLE); +} + +void cpu_step() { + int i = 0; + while (i < 10) { + byte op = cpu_get_next_byte(); + process_op_code(op); + i += 1; + } +} + +void cpu_add_cycles(unsigned int cycle_count) { + } // === Registers === diff --git a/cpu/cpu.h b/cpu/cpu.h index faaea60..5653508 100644 --- a/cpu/cpu.h +++ b/cpu/cpu.h @@ -58,4 +58,6 @@ void cpu_stack_push_context(); byte cpu_stack_pop(); void cpu_stack_pop_context(); +void cpu_add_cycles(unsigned int cycle_count); + #endif //CPU_CPU_H diff --git a/cpu/memory.c b/cpu/memory.c index 00df8c7..57d4337 100644 --- a/cpu/memory.c +++ b/cpu/memory.c @@ -4,15 +4,30 @@ #include "memory.h" #include "ram.h" +#include "../include/rom.h" byte mem_get_byte(Mapper *mapper, address addr) { address redirected_addr = mapper->redirect_addr(addr); - return ram_get_byte(redirected_addr); + + if (redirected_addr < 0x0800) { + return ram_get_byte(redirected_addr); + } else if (redirected_addr >= 0x4020) { + return rom_prg_get_byte(redirected_addr - 0x4020); + } + + return 0; } word mem_get_word(Mapper *mapper, address addr) { address redirected_addr = mapper->redirect_addr(addr); - return ram_get_word(redirected_addr); + + if (redirected_addr < 0x0800) { + return ram_get_word(redirected_addr); + } else if (redirected_addr >= 0x4020) { + return rom_prg_get_word(redirected_addr - 0x4020); + } + + return 0; } void mem_set_byte(Mapper *mapper, address addr, byte byte) { diff --git a/cpu/op.c b/cpu/op.c index a548ecf..196f437 100644 --- a/cpu/op.c +++ b/cpu/op.c @@ -10,7 +10,7 @@ #define IS_OP_CODE_MODE(op, op_code, addr_mode) \ case op_code: \ - log_debug("OP: %s", "op"); \ + log_debug("OP: %s", #op); \ op_ ## op(ADDR_MODE_ ## addr_mode); \ break; @@ -809,7 +809,7 @@ void op_XAA(AddressingMode addr_mode) { assert(false); } -void process_op_code(int op) { +void process_op_code(byte op) { switch (op) { // CTRL IS_OP_CODE(BRK, 0x00) diff --git a/cpu/op.h b/cpu/op.h index 9a8a8bc..9ffe03c 100644 --- a/cpu/op.h +++ b/cpu/op.h @@ -1,3 +1,5 @@ +#include "../include/cpu.h" + #ifndef CPU_OP_H #define CPU_OP_H @@ -31,4 +33,6 @@ typedef enum { ADDR_MODE_ZERO_PAGE_INDEXED_Y, // d,y } AddressingMode; -#endif +void process_op_code(byte op); + +#endif \ No newline at end of file diff --git a/include/cpu.h b/include/cpu.h index 92468cb..7236bae 100644 --- a/include/cpu.h +++ b/include/cpu.h @@ -23,11 +23,7 @@ typedef unsigned char byte; typedef unsigned short address; typedef unsigned short word; -/** - * @brief Set clock - */ -void cpu_step_to(int cycle); - -void cpu_add_cycles(int count); +void cpu_init(); +void cpu_step(); #endif diff --git a/include/rom.h b/include/rom.h index 62f67d3..af5afca 100644 --- a/include/rom.h +++ b/include/rom.h @@ -5,12 +5,25 @@ #ifndef NESEMULATOR_ROM_H #define NESEMULATOR_ROM_H +// The size of the header in a ROM file, in bytes +#include "cpu.h" + +#define ROM_HEADER_SIZE 16 +// The size of the trainer in a ROM file, in bytes +#define ROM_TRAINER_SIZE 512 + typedef struct { - char* prg_rom; - char* chr_rom; - void* header; + byte *prg_rom; + byte *chr_rom; + void *header; } Rom; -int read_rom(char* path); +int rom_load(char *path); + +void rom_uninit(); + +byte rom_prg_get_byte(address addr); + +word rom_prg_get_word(address addr); #endif //NESEMULATOR_ROM_H \ No newline at end of file diff --git a/main.c b/main.c index b1059a9..00a111c 100644 --- a/main.c +++ b/main.c @@ -20,8 +20,14 @@ #include "include/rom.h" int main() { - char *rom_path = "../tests/cpu_exec_space/test_cpu_exec_space_ppuio.nes"; - read_rom(rom_path); + char *rom_path = "../tests/smb.nes"; + + cpu_init(); + rom_load(rom_path); + + cpu_step(); + + rom_uninit(); return EXIT_SUCCESS; } diff --git a/rom/ines.c b/rom/ines.c index 63eaf71..5828424 100644 --- a/rom/ines.c +++ b/rom/ines.c @@ -110,31 +110,60 @@ INesHeader read_header(const char header_buf[16]) { return header; } -bool rom_nes_read(const char header_buf[16], FILE *file, Rom *rom) { - INesHeader header = read_header(header_buf); - rom->header = &header; - - // We don't support the trainer, so we skip ahead by 512 bytes if needed. - if (header.flags.has_trainer && !fseek(file, 512, SEEK_CUR)) { - perror("Failed to seek ahead of trainer ROM section"); - return false; +bool rom_ines_read_trainer(FILE *file, INesHeader *header) { + if (!header->flags.has_trainer) { + log_debug("ROM does not contains trainer"); + return true; } - unsigned int prg_rom_size = header.prg_rom_size * 16384; + // We don't support the trainer, so we skip ahead instead. + if (fseek(file, ROM_TRAINER_SIZE, SEEK_CUR)) { + log_debug("ROM has trainer, skipping %d bytes", ROM_TRAINER_SIZE); + return true; + } + + log_error("Failed to skip trainer"); + return false; +} + +bool rom_ines_read_prg_rom(FILE *file, INesHeader *header, Rom *rom) { + unsigned int prg_rom_size = header->prg_rom_size * 16384; rom->prg_rom = (char *) malloc(prg_rom_size * sizeof(char)); - if (fread(rom->prg_rom, sizeof(char), prg_rom_size, file) < prg_rom_size) { - perror("Failed to read PRG ROM"); - return false; - } - if (header.chr_rom_size > 0) { - unsigned int chr_rom_size = header.chr_rom_size * 8192; - rom->chr_rom = (char *) malloc(chr_rom_size * sizeof(char)); - if (fread(rom->chr_rom, sizeof(char), chr_rom_size, file) < chr_rom_size) { - perror("Failed to read CHR ROM"); - return false; - } + log_debug("Reading %d bytes PRG ROM", prg_rom_size); + + if (fread(rom->prg_rom, sizeof(char), prg_rom_size, file) < prg_rom_size) { + log_error("Failed to read PRG ROM"); + return false; } return true; +} + +bool rom_ines_read_chr_rom(FILE *file, INesHeader *header, Rom *rom) { + if (header->chr_rom_size <= 0) { + log_debug("No CHR ROM to read"); + return true; + } + + unsigned int chr_rom_size = header->chr_rom_size * 8192; + rom->chr_rom = (char *) malloc(chr_rom_size * sizeof(char)); + + log_debug("Reading %d bytes CHR ROM", chr_rom_size); + + if (fread(rom->chr_rom, sizeof(char), chr_rom_size, file) < chr_rom_size) { + log_error("Failed to read CHR ROM"); + return false; + } + + return true; +} + +bool rom_ines_read(const char header_buf[ROM_HEADER_SIZE], FILE *file, Rom *rom) { + INesHeader header = read_header(header_buf); + rom->header = &header; + + return rom_ines_read_trainer(file, &header) && + rom_ines_read_prg_rom(file, &header, rom) && + rom_ines_read_chr_rom(file, &header, rom); } \ No newline at end of file diff --git a/rom/rom.c b/rom/rom.c index 82a29a2..50eab4f 100644 --- a/rom/rom.c +++ b/rom/rom.c @@ -4,51 +4,73 @@ #include #include +#include #include "../include/rom.h" #include "ines.c" #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) -void rom_init(Rom *rom) { - rom->header = NULL; - rom->prg_rom = NULL; - rom->chr_rom = NULL; +Rom rom; + +void rom_init() { + rom.header = NULL; + rom.prg_rom = NULL; + rom.chr_rom = NULL; } -void rom_uninit(Rom *rom) { - free(rom->prg_rom); - free(rom->chr_rom); -} +int rom_load(char *path) { + rom_init(); -int read_rom(char *path) { FILE *file = fopen(path, "r"); if (!file) { - perror("Failed to open ROM"); + log_error("Failed to open ROM"); return EXIT_FAILURE; } - char header_buffer[16] = {0}; + char header_buffer[ROM_HEADER_SIZE] = {0}; size_t read_size = fread(header_buffer, sizeof(char), ARRAY_SIZE(header_buffer), file); if (read_size < ARRAY_SIZE(header_buffer)) { - perror("Failed to read ROM"); + log_error("Failed to read ROM"); return EXIT_FAILURE; } if (!rom_is_ines(header_buffer)) { - perror("Only iNes ROMs are supported"); + log_error("Only iNes ROMs are supported"); return EXIT_FAILURE; } - Rom rom; - rom_init(&rom); - rom_nes_read(header_buffer, file, &rom); - rom_uninit(&rom); + log_info("Reading iNes 1.0 ROM at %s", path); + rom_ines_read(header_buffer, file, &rom); if (fclose(file) != 0) { - perror("Failed to close ROM file"); + log_error("Failed to close ROM file"); return EXIT_FAILURE; } return 0; +} + +void rom_uninit() { + assert(rom.prg_rom != NULL); + assert(rom.chr_rom != NULL); + + free(rom.prg_rom); + free(rom.chr_rom); + + log_info("Cleared ROM data"); +} + +byte rom_prg_get_byte(address addr) { + assert(rom.prg_rom != NULL); + + return rom.prg_rom[addr]; +} + +word rom_prg_get_word(address addr) { + assert(rom.prg_rom != NULL); + + word word = rom.prg_rom[addr]; + word += rom.prg_rom[addr + 1] << 8; // Little endian + return word; } \ No newline at end of file diff --git a/tests/smb.nes b/tests/smb.nes new file mode 100644 index 0000000..4342b2e Binary files /dev/null and b/tests/smb.nes differ