diff options
-rw-r--r-- | gb.h | 22 | ||||
-rw-r--r-- | ops.yaml | 159 | ||||
-rw-r--r-- | test.c | 4 |
3 files changed, 111 insertions, 74 deletions
@@ -25,8 +25,8 @@ typedef enum { #define GB_BTN_SELECT (1 << 6) #define GB_BTN_START (1 << 7) -// frame size, in bytes -#define GB_FRAME_SIZE (3 * 160 * 144) +// frame buffer size, in bytes +#define GB_FB_SIZE (3 * 160 * 144) typedef struct gb_t_ gb_t; @@ -116,8 +116,22 @@ struct gb_t_ { obp1, line, lyc; - uint8_t rgb[GB_FRAME_SIZE]; + + // frame buffer + uint8_t fb[GB_FB_SIZE]; + + // frame counter uint32_t frame; + + struct { + uint8_t x, y, tile; + bool priority, + y_flip, + x_flip, + palette; + } oam_cache[40]; + + bool oam_dirty; } gpu; struct { @@ -148,7 +162,7 @@ void gb_set_buttons(gb_t * const, const uint8_t); void gb_frame(gb_t * const); void gb_step(gb_t * const); _Bool gb_disasm(gb_t * const, char * const, size_t * const); -const uint8_t *gb_get_rgb_frame(const gb_t * const); +const uint8_t *gb_get_frame(const gb_t * const); #ifdef __cplusplus }; @@ -1890,7 +1890,7 @@ ops: h: c: code: | - mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_H)); + mmu_wb(ctx, cpu_rw(ctx, RW_HL), cpu_rb(ctx, RB_L)); - id: HALT hex: 0x76 cat: misc @@ -2022,7 +2022,7 @@ ops: cat: "8-bit load/store/move" op: LD dst: A - src: L + src: (HL) len: 1 pc: true time: 8 @@ -2144,7 +2144,7 @@ ops: h: H c: C code: | - add_rb(ctx, RB_H); + add_rb(ctx, RB_L); - id: ADD A, (HL) hex: 0x86 cat: "8-bit math" @@ -3067,6 +3067,7 @@ ops: h: c: code: | + cpu_ww(ctx, RW_PC, old_pc + 1); if (!FLAG(ctx, Z)) { pop_rw(ctx, RW_PC); clock = 20; @@ -3197,7 +3198,7 @@ ops: h: c: code: | - cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); + cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x00); - id: RET Z hex: 0xC8 @@ -3340,7 +3341,7 @@ ops: h: c: code: | - cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); + cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x08); - id: RET NC hex: 0xD0 @@ -3429,7 +3430,7 @@ ops: h: c: code: | - cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 3); + cpu_ww(ctx, RW_PC, old_pc + 3); if (!FLAG(ctx, C)) { call_a16(ctx, old_pc + 1); clock = 24; @@ -3481,7 +3482,7 @@ ops: h: H c: C code: | - cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); + cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x10); - id: RET C hex: 0xD8 @@ -3521,8 +3522,8 @@ ops: c: code: | // pop pc, enable interrupts - pop_rw(ctx, RW_PC); ctx->cpu.ime = true; + pop_rw(ctx, RW_PC); - id: JP C, a16 hex: 0xDA cat: "jumps/calls" @@ -3612,7 +3613,7 @@ ops: h: c: code: | - cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); + cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x18); - id: LDH (a8), A hex: 0xE0 @@ -3666,6 +3667,8 @@ ops: hex: 0xE3 cat: "invalid" op: XX + code: | + cpu_set_state(ctx, old_pc, GB_CPU_STATE_INVALID); - id: XX hex: 0xE4 cat: "invalid" @@ -3718,7 +3721,7 @@ ops: h: c: code: | - cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); + cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x20); - id: ADD SP, r8 hex: 0xE8 @@ -3815,7 +3818,7 @@ ops: h: c: code: | - cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); + cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x28); - id: LDH A, (a8) hex: 0xF0 @@ -3931,7 +3934,7 @@ ops: h: c: code: | - cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); + cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x30); - id: LD HL, SP+r8 hex: 0xF8 @@ -4039,7 +4042,7 @@ ops: h: c: code: | - cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_PC) + 1); + cpu_ww(ctx, RW_PC, old_pc + 1); rst(ctx, 0x38); cb: @@ -8561,6 +8564,7 @@ templates: static void gpu_set_line(gb_t * const ctx, const uint8_t line); static void gpu_set_mode(gb_t * const ctx, const uint8_t mode); static bool gpu_is_active(const gb_t * const ctx); + static uint8_t gpu_get_mode(const gb_t * const ctx); static uint8_t mmu_rp( @@ -8820,7 +8824,7 @@ templates: const gb_t * const ctx, const uint16_t addr ) { - switch (ctx->gpu.mode & 0x3) { + switch (gpu_get_mode(ctx)) { case GPU_MODE_VRAM: return 0xFF; default: @@ -8834,7 +8838,7 @@ templates: const gb_t * const ctx, const uint16_t addr ) { - switch (ctx->gpu.mode & 0x3) { + switch (gpu_get_mode(ctx)) { case GPU_MODE_HBLANK: case GPU_MODE_VBLANK: // oam memory (160 bytes): @@ -8954,7 +8958,7 @@ templates: const uint16_t addr, const uint8_t val ) { - switch (ctx->gpu.mode & 0x3) { + switch (gpu_get_mode(ctx)) { case GPU_MODE_HBLANK: case GPU_MODE_VBLANK: case GPU_MODE_OAM: @@ -8973,13 +8977,14 @@ templates: const uint16_t addr, const uint8_t val ) { - switch (ctx->gpu.mode & 0x3) { + switch (gpu_get_mode(ctx) & 0x3) { case GPU_MODE_HBLANK: case GPU_MODE_VBLANK: // oam memory (160 bytes): ctx->mmu.oam[addr & 0xFF] = val; - // TODO: invalidate OAM cache + // invalidate oam cache + ctx->gpu.oam_dirty = true; break; default: @@ -10115,7 +10120,7 @@ templates: gpu_get_mode( const gb_t * const ctx ) { - return ctx->gpu.mode & 0x3; + return gpu_is_active(ctx) ? (ctx->gpu.mode & 0x3) : GPU_MODE_VBLANK; } static void @@ -10166,86 +10171,94 @@ templates: } static void - gpu_draw_line( + gpu_oam_cache( gb_t * const ctx ) { - struct { - uint8_t x, y, tile; - bool priority, - y_flip, - x_flip, - palette; - } objs[40]; + if (!ctx->gpu.oam_dirty) { + return; + } // decode oam - for (int i = 0; i < 40; i++) { - objs[i].y = (ctx->mmu.oam[i * 4 + 0] + 16) & 0xFF; - objs[i].x = (ctx->mmu.oam[i * 4 + 1] + 8) & 0xFF; - objs[i].tile = ctx->mmu.oam[i * 4 + 2]; + for (uint8_t i = 0; i < 40; i++) { + ctx->gpu.oam_cache[i].y = (ctx->mmu.oam[i * 4 + 0] + 16) & 0xFF; + ctx->gpu.oam_cache[i].x = (ctx->mmu.oam[i * 4 + 1] + 8) & 0xFF; + ctx->gpu.oam_cache[i].tile = ctx->mmu.oam[i * 4 + 2]; const uint8_t flags = ctx->mmu.oam[i * 4 + 3]; - objs[i].priority = flags & (1 << 7); - objs[i].y_flip = flags & (1 << 6); - objs[i].x_flip = flags & (1 << 5); - objs[i].palette = flags & (1 << 4); + ctx->gpu.oam_cache[i].priority = flags & (1 << 7); + ctx->gpu.oam_cache[i].y_flip = flags & (1 << 6); + ctx->gpu.oam_cache[i].x_flip = flags & (1 << 5); + ctx->gpu.oam_cache[i].palette = flags & (1 << 4); } + // clear dirty flag + ctx->gpu.oam_dirty = false; + } + + static void + gpu_draw_line( + gb_t * const ctx + ) { + gpu_oam_cache(ctx); + // draw sprites behind bg - for (int i = 0; i < 40; i++) { + for (uint8_t i = 0; i < 40; i++) { if ( // sprite is below bg - objs[i].priority && + ctx->gpu.oam_cache[i].priority && // sprite is on screen - objs[i].y < 144 && objs[i].x < 160 && + ctx->gpu.oam_cache[i].y < 144 && + ctx->gpu.oam_cache[i].x < 160 && // sprite is on current line - ctx->gpu.line >= objs[i].y && - ctx->gpu.line <= objs[i].y + ctx->gpu.line >= ctx->gpu.oam_cache[i].y && + ctx->gpu.line <= ctx->gpu.oam_cache[i].y ) { - const uint8_t max_j = MIN(8, 160 - objs[i].x); + const uint8_t max_j = MIN(8, 160 - ctx->gpu.oam_cache[i].x); for (uint8_t j = 0; j < max_j; j++) { - const uint32_t ofs = 3 * (objs[i].y * 160 + objs[i].x + j); + const uint32_t ofs = 3 * (ctx->gpu.oam_cache[i].y * 160 + ctx->gpu.oam_cache[i].x + j); // TODO: draw sprite scanline - ctx->gpu.rgb[ofs + 0] = 0xff; - ctx->gpu.rgb[ofs + 1] = 0xff; - ctx->gpu.rgb[ofs + 2] = 0xff; + ctx->gpu.fb[ofs + 0] = 0xff; + ctx->gpu.fb[ofs + 1] = 0xff; + ctx->gpu.fb[ofs + 2] = 0xff; } } } // TODO: draw background - for (int i = 0; i < 160; i++) { + for (uint8_t i = 0; i < 160; i++) { // interim: set line to red - ctx->gpu.rgb[3 * (ctx->gpu.line * 160 + i) + 0] = 0xff; - ctx->gpu.rgb[3 * (ctx->gpu.line * 160 + i) + 1] = 0x00; - ctx->gpu.rgb[3 * (ctx->gpu.line * 160 + i) + 2] = 0x00; + ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 0] = 0xff; + ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 1] = 0x00; + ctx->gpu.fb[3 * (ctx->gpu.line * 160 + i) + 2] = 0x00; } // draw foreground sprites - for (int i = 0; i < 40; i++) { + for (uint8_t i = 0; i < 40; i++) { if ( // sprite is above bg - !objs[i].priority && + !ctx->gpu.oam_cache[i].priority && // sprite is on screen - objs[i].y < 144 && objs[i].x < 160 && + ctx->gpu.oam_cache[i].y < 144 && + ctx->gpu.oam_cache[i].x < 160 && // sprite is on current line - ctx->gpu.line >= objs[i].y && - ctx->gpu.line <= objs[i].y + ctx->gpu.line >= ctx->gpu.oam_cache[i].y && + ctx->gpu.line <= ctx->gpu.oam_cache[i].y ) { - const uint8_t max_j = MIN(8, 160 - objs[i].x); + const uint8_t max_j = MIN(8, 160 - ctx->gpu.oam_cache[i].x); for (int j = 0; j < max_j; j++) { - const uint32_t ofs = 3 * (objs[i].y * 160 + objs[i].x + j); + const uint32_t ofs = 3 * (ctx->gpu.oam_cache[i].y * 160 + ctx->gpu.oam_cache[i].x + j); // TODO: draw sprite scanline - ctx->gpu.rgb[ofs + 0] = 0xff; - ctx->gpu.rgb[ofs + 1] = 0xff; - ctx->gpu.rgb[ofs + 2] = 0xff; + ctx->gpu.fb[ofs + 0] = 0xff; + ctx->gpu.fb[ofs + 1] = 0xff; + ctx->gpu.fb[ofs + 2] = 0xff; } } } @@ -10286,7 +10299,7 @@ templates: break; case GPU_MODE_HBLANK: if (ctx->gpu.clock >= 204) { - // clear clock, draw line, increment line + // clear clock ctx->gpu.clock -= 204; // draw and increment line @@ -10565,10 +10578,10 @@ templates: } const uint8_t * - gb_get_rgb_frame( + gb_get_frame( const gb_t * const ctx ) { - return ctx->gpu.rgb; + return ctx->gpu.fb; } static void @@ -10589,6 +10602,21 @@ templates: cpu_set_state(ctx, 0, GB_CPU_STATE_RUN); } + static void + gpu_init( + gb_t * const ctx + ) { + gpu_set_mode(ctx, GPU_MODE_OAM); + gpu_set_line(ctx, 0); + ctx->gpu.lcdc = 0x91; + ctx->gpu.bgp = 0xFC; + ctx->gpu.obp0 = 0xFF; + ctx->gpu.obp1 = 0xFF; + + // flag oam as dirty + ctx->gpu.oam_dirty = true; + } + void gb_init( gb_t * const ctx, const gb_config_t * const config, @@ -10609,10 +10637,5 @@ templates: ctx->mmu.rom_size = rom_size; // init gpu - gpu_set_mode(ctx, GPU_MODE_OAM); - gpu_set_line(ctx, 0); - ctx->gpu.lcdc = 0x91; - ctx->gpu.bgp = 0xFC; - ctx->gpu.obp0 = 0xFF; - ctx->gpu.obp1 = 0xFF; + gpu_init(ctx); } @@ -61,7 +61,7 @@ load( } // buffer for rendered frames -static uint8_t frames[NUM_FRAMES * GB_FRAME_SIZE]; +static uint8_t frames[NUM_FRAMES * GB_FB_SIZE]; static void on_set_rom_bank( @@ -193,7 +193,7 @@ test_render_frames( gb_frame(&ctx); // copy frame to buffer - memcpy(frames + GB_FRAME_SIZE * j, gb_get_rgb_frame(&ctx), GB_FRAME_SIZE); + memcpy(frames + GB_FB_SIZE * j, gb_get_frame(&ctx), GB_FB_SIZE); } // save png |