summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2018-06-26 18:51:44 -0400
committerPaul Duncan <pabs@pablotron.org>2018-06-26 18:51:44 -0400
commitd5d0b54054f5db7cad86fc08c1a12857b2ac04ca (patch)
tree86de7598cf0251ed243479652d7c221367777474
parente608f0d1449fe112ff1c0be2aec0ca5f8bab3232 (diff)
downloadgb-c-d5d0b54054f5db7cad86fc08c1a12857b2ac04ca.tar.bz2
gb-c-d5d0b54054f5db7cad86fc08c1a12857b2ac04ca.zip
s/rgb_frame/fb/, add oam_cache, fix several instructions
-rw-r--r--gb.h22
-rw-r--r--ops.yaml159
-rw-r--r--test.c4
3 files changed, 111 insertions, 74 deletions
diff --git a/gb.h b/gb.h
index 15bd75e..e027ee7 100644
--- a/gb.h
+++ b/gb.h
@@ -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
};
diff --git a/ops.yaml b/ops.yaml
index 61db5ee..6bf9870 100644
--- a/ops.yaml
+++ b/ops.yaml
@@ -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);
}
diff --git a/test.c b/test.c
index 5900cf7..e2c66f0 100644
--- a/test.c
+++ b/test.c
@@ -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