diff --git a/Makefile b/Makefile index 5288a9d..6a0e335 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = gcc LD = $(CC) -CFLAGS = -Wall -Werror -Wshadow -I.. -g -DE6502_DEBUG +CFLAGS = -Wall -Werror -Wshadow -I.. -g #-DE6502_DEBUG LDFLAGS = OBJDIR = obj @@ -11,9 +11,9 @@ BINDIR = bin # nese TARGET_1 = nese -LDLIBS_1 = +LDLIBS_1 = -lSDL -SRC_SRCS_1 = nese.c ines.c nes.c ppu.c +SRC_SRCS_1 = nese.c ines.c nes.c ppu.c sdl_render.c EXT_SRCS_1 = e6502/e6502.c diff --git a/src/nese.c b/src/nese.c index babc6ee..d063221 100644 --- a/src/nese.c +++ b/src/nese.c @@ -2,7 +2,7 @@ #include #include "ines.h" - +#include "render.h" void e6502_print_registers(const e6502_Registers* regs, @@ -33,6 +33,7 @@ void e6502_dump_stack(e6502_Core* core, FILE* file) { } +extern nes_Renderer sdl_renderer; static nes sys = {0}; @@ -44,11 +45,17 @@ int main(int argc, char* argv[]) { status = ines_load(&sys.cart.rom, stdin); + nes_Renderer* rend = &sdl_renderer; + if (status == 0) { + status = nes_render_init(rend); + } + if (status == 0) { nes_init(&sys); nes_reset(&sys); int total_cycles = 0; + int last_frame_rendered = -1; for (int i = 0; i < n_loops && status == 0; ++i) { int run = 0; status = nes_run(&sys, 1000, &run); @@ -61,6 +68,11 @@ int main(int argc, char* argv[]) { us_run, run, status == 0 ? "OK" : "Halted"); */ + if ( status == 0 && + sys.ppu.frame != last_frame_rendered) { + status = nes_render(rend, &sys.ppu); + last_frame_rendered = sys.ppu.frame; + } } float ms_run = ( total_cycles * 1000. * diff --git a/src/ppu.c b/src/ppu.c index cc5ed9a..04eaebc 100644 --- a/src/ppu.c +++ b/src/ppu.c @@ -49,13 +49,13 @@ uint8_t nes_ppu_read(nes_ppu* ppu, uint16_t addr) { 32 : 1; } - fprintf(stderr, "PPU: <-R $%04x %02x\n", addr, val); +// fprintf(stdout, "PPU: <-R $%04x %02x\n", addr, val); return val; } void nes_ppu_write(nes_ppu* ppu, uint16_t addr, uint8_t val) { - fprintf(stderr, "PPU: W-> $%04x %02x\n", addr, val); +// fprintf(stdout, "PPU: W-> $%04x %02x\n", addr, val); if (ppu_reg_ctrl == addr) { ppu->control = val; diff --git a/src/ppu.h b/src/ppu.h index 798240d..91ccca2 100644 --- a/src/ppu.h +++ b/src/ppu.h @@ -10,6 +10,9 @@ #define nes_ppu_postrender (1U) #define nes_ppu_vblank (20U) +#define nes_ppu_render_w (320U) +#define nes_ppu_render_h nes_ppu_height + #define nes_ppu_mem_size (0x4000U) #define nes_ppu_mem_pal_start (0x3F00U) #define nes_ppu_mem_pal_size (0x0020U) diff --git a/src/render.h b/src/render.h new file mode 100644 index 0000000..b51fab1 --- /dev/null +++ b/src/render.h @@ -0,0 +1,27 @@ +#ifndef NES_RENDER_H_ +#define NES_RENDER_H_ + +#include "ppu.h" + + +typedef struct nes_Renderer_t { + int (*init)(struct nes_Renderer_t*); + void (*done)(struct nes_Renderer_t*); + int (*render)(struct nes_Renderer_t*, nes_ppu*); + void* data; +} nes_Renderer; + +static inline int nes_render_init(nes_Renderer* rend) { + return rend->init(rend); +} + +static inline void nes_render_done(nes_Renderer* rend) { + rend->done(rend); +} + +static inline int nes_render(nes_Renderer* rend, nes_ppu* ppu) { + return rend->render(rend, ppu); +} + + +#endif // NES_RENDER_H_ diff --git a/src/sdl_render.c b/src/sdl_render.c new file mode 100644 index 0000000..56b0b57 --- /dev/null +++ b/src/sdl_render.c @@ -0,0 +1,109 @@ +#include + +#include "render.h" +#include "ppu.h" + + +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; +} __attribute__ (( packed )) sPal; + +static struct sPal nes_palette[64] = { + {0x80,0x80,0x80}, {0x00,0x00,0xBB}, {0x37,0x00,0xBF}, {0x84,0x00,0xA6}, + {0xBB,0x00,0x6A}, {0xB7,0x00,0x1E}, {0xB3,0x00,0x00}, {0x91,0x26,0x00}, + {0x7B,0x2B,0x00}, {0x00,0x3E,0x00}, {0x00,0x48,0x0D}, {0x00,0x3C,0x22}, + {0x00,0x2F,0x66}, {0x00,0x00,0x00}, {0x05,0x05,0x05}, {0x05,0x05,0x05}, + + {0xC8,0xC8,0xC8}, {0x00,0x59,0xFF}, {0x44,0x3C,0xFF}, {0xB7,0x33,0xCC}, + {0xFF,0x33,0xAA}, {0xFF,0x37,0x5E}, {0xFF,0x37,0x1A}, {0xD5,0x4B,0x00}, + {0xC4,0x62,0x00}, {0x3C,0x7B,0x00}, {0x1E,0x84,0x15}, {0x00,0x95,0x66}, + {0x00,0x84,0xC4}, {0x11,0x11,0x11}, {0x09,0x09,0x09}, {0x09,0x09,0x09}, + + {0xFF,0xFF,0xFF}, {0x00,0x95,0xFF}, {0x6F,0x84,0xFF}, {0xD5,0x6F,0xFF}, + {0xFF,0x77,0xCC}, {0xFF,0x6F,0x99}, {0xFF,0x7B,0x59}, {0xFF,0x91,0x5F}, + {0xFF,0xA2,0x33}, {0xA6,0xBF,0x00}, {0x51,0xD9,0x6A}, {0x4D,0xD5,0xAE}, + {0x00,0xD9,0xFF}, {0x66,0x66,0x66}, {0x0D,0x0D,0x0D}, {0x0D,0x0D,0x0D}, + + {0xFF,0xFF,0xFF}, {0x84,0xBF,0xFF}, {0xBB,0xBB,0xFF}, {0xD0,0xBB,0xFF}, + {0xFF,0xBF,0xEA}, {0xFF,0xBF,0xCC}, {0xFF,0xC4,0xB7}, {0xFF,0xCC,0xAE}, + {0xFF,0xD9,0xA2}, {0xCC,0xE1,0x99}, {0xAE,0xEE,0xB7}, {0xAA,0xF7,0xEE}, + {0xB3,0xEE,0xFF}, {0xDD,0xDD,0xDD}, {0x11,0x11,0x11}, {0x11,0x11,0x11} +}; + + +typedef struct { + SDL_Surface* surface; + uint8_t buffer[3 * nes_ppu_render_w * nes_ppu_render_h]; +} sdl_render_data; + +static sdl_render_data the_render_data = {0}; + + +static int filter(const SDL_Event* event) { + return event->type == SDL_QUIT; +} + +static int sdl_render_init(nes_Renderer* rend) { + int status = SDL_Init(SDL_INIT_VIDEO); + + if (0 != status) { + fprintf(stderr, "SDL: Failed to initialize\n"); + + } else { + SDL_WM_SetCaption("NESe", "NESe"); + + if (NULL == SDL_SetVideoMode(nes_ppu_render_w, + nes_ppu_render_h, + 24, SDL_HWSURFACE)) { + fprintf(stderr, "SDL: Failed to set video mode\n"); + status = -1; + } + } + + if (0 == status) { + the_render_data.surface = SDL_CreateRGBSurfaceFrom( + the_render_data.buffer, nes_ppu_render_w, + nes_ppu_render_h, 24, nes_ppu_render_w * 3, + 0xFFU, 0xFF00U, 0xFF0000U, 0 + ); + + SDL_SetEventFilter(filter); + + rend->data = &the_render_data; + } + + return status; +} + +static void sdl_render_done(nes_Renderer* rend) { + sdl_render_data* data = (sdl_render_data*)rend->data; + if (NULL != data->surface) { + SDL_FreeSurface(data->surface); + data->surface = NULL; + } + SDL_Quit(); +} + +static int sdl_render(nes_Renderer* rend, nes_ppu* ppu) { + sdl_render_data* data = (sdl_render_data*)rend->data; + + // TODO + + SDL_Surface* screen = SDL_GetVideoSurface(); + if (0 == SDL_BlitSurface(data->surface, NULL, screen, NULL)) { + SDL_UpdateRect(screen, 0, 0, 0, 0); + } + + SDL_Event event = {0}; + return (1 == SDL_PollEvent(&event) && event.type == SDL_QUIT) ? + -1 : 0; +} + + +nes_Renderer sdl_renderer = { + .init = sdl_render_init, + .done = sdl_render_done, + .render = sdl_render, +};