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 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
+
-
+
+
+
+
+
@@ -128,11 +107,6 @@
-
-
-
-
-
@@ -315,6 +289,7 @@
+
@@ -350,15 +325,4 @@
-
-
-
-
- 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