| @@ -31,7 +31,7 @@ NESE_SRC_SRCS = f6502.c f6502_opcodes.c | |||
| NESE_SRC_SRCS += nese.c nes.c cart.c mapper.c | |||
| NESE_SRC_SRCS += ppu.c | |||
| NESE_SRC_SRCS += $(OS)/port.c | |||
| NESE_MAP_SRCS = $(notdir $(wildcard $(MAPDIR)/*)) | |||
| NESE_MAP_SRCS = $(notdir $(wildcard $(MAPDIR)/*.c)) | |||
| NESE_DEBUG = CART | |||
| @@ -0,0 +1,29 @@ | |||
| #ifndef NESE_INPUT_H_ | |||
| #define NESE_INPUT_H_ | |||
| #define nes_controller_bus_mask (0b11111000) | |||
| typedef enum { | |||
| Button_A = 0, | |||
| Button_B, | |||
| Button_Select, | |||
| Button_Start, | |||
| Button_Up, | |||
| Button_Down, | |||
| Button_Left, | |||
| Button_Right, | |||
| } nes_Input_Button; | |||
| typedef struct { | |||
| uint8_t buttons; | |||
| int8_t shift; | |||
| } nes_Gamepad; | |||
| typedef struct { | |||
| nes_Gamepad gamepads[2]; | |||
| } nes_Input; | |||
| #endif // NESE_INPUT_H_ | |||
| @@ -1,6 +1,7 @@ | |||
| #include <errno.h> | |||
| #include <stdio.h> | |||
| #include <time.h> | |||
| #include <sys/mman.h> | |||
| #include "nese.h" | |||
| @@ -24,6 +25,37 @@ int nese_unmap_file(void* addr, int size) { | |||
| return munmap(addr, size); | |||
| } | |||
| int nese_frame_ready() { | |||
| /* | |||
| static int frame = 0; | |||
| static int ignore = 1; | |||
| static struct timespec t_last = {0}; | |||
| struct timespec t_now = {0}; | |||
| ++frame; | |||
| clock_gettime(CLOCK_MONOTONIC, &t_now); | |||
| if (t_now.tv_sec > t_last.tv_sec) { | |||
| if (!ignore) printf("%d\n", frame); | |||
| frame = 0; | |||
| ignore = 0; | |||
| } | |||
| t_last = t_now; | |||
| */ | |||
| // TODO: Render frame | |||
| // TODO: Time sync | |||
| // TODO: Handle quit signal | |||
| // TODO: Perform menu actions | |||
| return 0; | |||
| } | |||
| int nese_update_input(nes_Input* input) { | |||
| // TODO: Populate the gamepad states | |||
| return 0; | |||
| } | |||
| static nes sys = {0}; | |||
| @@ -1,6 +1,7 @@ | |||
| #include <stddef.h> | |||
| #include "nes.h" | |||
| #include "port.h" | |||
| void nes_init(nes* sys) { | |||
| @@ -11,19 +12,54 @@ void nes_done(nes* sys) { | |||
| // TODO: deallocate RAM, etc. | |||
| } | |||
| static int nes_vsync(nes* sys) { | |||
| int status = 0; | |||
| // TODO: PPU Set VBlank flag | |||
| // TODO: APU Sync | |||
| // TODO: APU Frame IRQ | |||
| nes_Memory* mem = &sys->core.memory; | |||
| if (0 == status && NULL != mem->mapper.vsync) { | |||
| mem->mapper.vsync(&mem->mapper); | |||
| status = nese_update_input(&sys->input); | |||
| } | |||
| // TODO: NMI | |||
| return status; | |||
| } | |||
| static int nes_hsync(nes* sys) { | |||
| int status = 0; | |||
| // TODO: APU sync | |||
| // TODO: PPU Update H Bytes & Select Nametable | |||
| // TODO: PPU draw line if visible | |||
| // TODO: PPU update regs | |||
| // TODO: Increment scanline | |||
| sys->ppu.scanline++; | |||
| if (nes_ppu_frame_end_line == sys->ppu.scanline) { | |||
| sys->ppu.scanline = 0; | |||
| } | |||
| // TODO: Scanline region updates | |||
| // TODO: nese_vsync called in nes_vsync | |||
| switch (sys->ppu.scanline) { | |||
| case nes_ppu_prerender_line: | |||
| // TODO: Reset PPU Status | |||
| // TODO: Get Sprite 0 Hit | |||
| break; | |||
| return 0; | |||
| case nes_ppu_postrender_line: | |||
| status = nese_frame_ready(); | |||
| break; | |||
| case nes_ppu_vblank_line: | |||
| status = nes_vsync(sys); | |||
| break; | |||
| } | |||
| return status; | |||
| } | |||
| int nes_loop(nes* sys) { | |||
| @@ -37,9 +73,6 @@ int nes_loop(nes* sys) { | |||
| dot += 3 * f6502_step(&sys->core, cpu_cycles); | |||
| dot -= nes_ppu_scanline_dots; | |||
| // TODO: Validate dot >= 0? | |||
| // TODO: Frame IRQ | |||
| nes_Memory* mem = &sys->core.memory; | |||
| if (NULL != mem->mapper.hsync) { | |||
| mem->mapper.hsync(&mem->mapper); | |||
| @@ -2,15 +2,18 @@ | |||
| #define NES_H_ | |||
| #include "ines.h" | |||
| #include "input.h" | |||
| #include "f6502.h" | |||
| #include "ppu.h" | |||
| typedef struct { | |||
| const ines_Header* cart_header; | |||
| f6502_Core core; | |||
| nes_PPU ppu; | |||
| // TODO: PPU | |||
| // TODO: APU | |||
| // TODO: Input | |||
| nes_Input input; | |||
| } nes; | |||
| void nes_init(nes*); | |||
| @@ -1,9 +1,16 @@ | |||
| #ifndef NESE_PORT_H_ | |||
| #define NESE_PORT_H_ | |||
| #include <stdio.h> | |||
| #include "input.h" | |||
| void* nese_map_file(FILE* file, int size); | |||
| int nese_unmap_file(void* addr, int size); | |||
| int nese_frame_ready(); | |||
| int nese_update_input(nes_Input*); | |||
| #endif // NESE_PORT_H_ | |||
| @@ -5,6 +5,7 @@ | |||
| #define nes_ppu_scanline_dots (341U) | |||
| #define nes_ppu_prerender_line (0U) | |||
| #define nes_ppu_visible_line (1U) | |||
| #define nes_ppu_postrender_line (241U) | |||
| #define nes_ppu_vblank_line (242U) | |||
| @@ -53,4 +54,9 @@ void nes_PPU_set_mirroring(nes_PPU_Memory* mem, | |||
| nes_Nametable_Mirroring mirror); | |||
| typedef struct { | |||
| int scanline; | |||
| } nes_PPU; | |||
| #endif // NESE_PPU_H_ | |||