summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2018-06-24 23:31:28 -0400
committerPaul Duncan <pabs@pablotron.org>2018-06-24 23:31:28 -0400
commit39f6ddc3e27b80c17efe4f2d81ce99ed3a297b9a (patch)
tree96203bbe5881906bca3965f7a488427e3ee9a59e
parent969e25bb466c2673b46e1345434a71423f4b9fe0 (diff)
downloadgb-c-39f6ddc3e27b80c17efe4f2d81ce99ed3a297b9a.tar.bz2
gb-c-39f6ddc3e27b80c17efe4f2d81ce99ed3a297b9a.zip
add gb_config_t, gb_disasm(), refactor logic, misc cleanups
-rw-r--r--gb.h27
-rwxr-xr-xgen.rb13
-rw-r--r--ops.yaml750
-rw-r--r--test.c95
4 files changed, 485 insertions, 400 deletions
diff --git a/gb.h b/gb.h
index 44f80b0..a824c4b 100644
--- a/gb.h
+++ b/gb.h
@@ -28,7 +28,23 @@ typedef enum {
// frame size, in bytes
#define GB_FRAME_SIZE (3 * 160 * 144)
+typedef struct gb_t_ gb_t;
+
typedef struct {
+ void (*on_set_rom_bank)(const gb_t *, const uint16_t);
+ void (*on_set_ram_bank)(const gb_t *, const uint16_t);
+ void (*on_vblank)(const gb_t *);
+ void (*on_hblank)(const gb_t *);
+ void (*on_set_cpu_state)(const gb_t *, const gb_cpu_state_t);
+ void (*on_timer)(const gb_t *);
+ void (*on_gpu_step)(const gb_t *);
+ void (*on_gpu_set_mode)(const gb_t *, const uint8_t);
+ void *cb_data;
+} gb_config_t;
+
+struct gb_t_ {
+ const gb_config_t *config;
+
struct {
// _Bool in_bios;
@@ -116,12 +132,19 @@ typedef struct {
// interrupt master enable
_Bool ime;
} cpu;
-} gb_t;
+};
+
+void gb_init(
+ gb_t * const ctx,
+ const gb_config_t * const config,
+ const uint8_t *rom,
+ const uint32_t rom_size
+);
-void gb_init(gb_t * const, const uint8_t *rom, const uint32_t rom_size);
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);
#ifdef __cplusplus
diff --git a/gen.rb b/gen.rb
index 4b468d5..bc8db44 100755
--- a/gen.rb
+++ b/gen.rb
@@ -7,7 +7,17 @@ require 'erb'
DATA = YAML.load_file(File.join(__dir__, 'ops.yaml'))
switches = Hash.new { |h, k| h[k] = [] }
+op_meta = []
DATA['ops'].each do |set_id, ops|
+ op_meta += ops.map { |op|
+ '{ "%s", %d }, /* 0x%02x + 0x%s */' % [
+ op['id'],
+ op['len'] || 0,
+ (set_id == 'main') ? 0 : 255,
+ op['hex'].to_s(16).upcase.rjust(2, '0'),
+ ]
+ }
+
switches[set_id] = ops.select { |op|
op['op'] != 'PREFIX'
}.map { |op|
@@ -63,5 +73,8 @@ DATA['ops'].each do |set_id, ops|
}.join("\n")
end
+# build complete ops list
+ops = op_meta.join("\n")
+
t = ERB.new(DATA['templates']['main'])
puts t.run(binding)
diff --git a/ops.yaml b/ops.yaml
index 9266820..b1d2ad3 100644
--- a/ops.yaml
+++ b/ops.yaml
@@ -761,6 +761,7 @@ ops:
c:
code: |
cpu_wb(ctx, RB_A, cpu_rb(ctx, RB_A) ^ 0xFF);
+ cpu_wf(ctx, F_N | F_H, F_N | F_H);
- id: JR NC, r8
hex: 0x30
cat: "jumps/calls"
@@ -3746,7 +3747,8 @@ ops:
h:
c:
code: |
- cpu_ww(ctx, RW_PC, mmu_rw(ctx, cpu_rw(ctx, RW_HL)));
+ // cpu_ww(ctx, RW_PC, mmu_rw(ctx, cpu_rw(ctx, RW_HL)));
+ cpu_ww(ctx, RW_PC, cpu_rw(ctx, RW_HL));
- id: LD (a16), A
hex: 0xEA
cat: "8-bit load/store/move"
@@ -8073,6 +8075,7 @@ templates:
#include <string.h> // memset()
#include <stdint.h> // uint8_t ,etc
#include <stdbool.h> // bool
+ #include <stdio.h> // snprintf()
#include "gb.h"
#define UNUSED(a) ((void) (a))
@@ -8227,7 +8230,7 @@ templates:
(((ctx->mmu.mbc1.rom_ram_mode ? 0 : ctx->mmu.mbc1.ram_bank) & 0x3) << 19) |
// B: rom_bank (5 bits, low bit set)
- (((ctx->mmu.mbc1.rom_bank & 0x1F) | 0x1) << 15) |
+ (((ctx->mmu.mbc1.rom_bank & 0x1F) | 0x1) << 14) |
// C: address (14 bits)
((addr - 0x4000) & 0x3FFF)
@@ -8262,9 +8265,11 @@ templates:
case 0x6000:
case 0x7000:
// ROM1 (16k, banked)
- // FIXME: clamp to rom size?
- // mbc1 rom1 banking (TCAGBD.pdf, 11.2.2)
- return ctx->mmu.rom[mbc1_rom_get_addr(ctx, addr)];
+ {
+ // mbc1 rom1 banking (TCAGBD.pdf, 11.2.2)
+ const uint32_t addr_ofs = mbc1_rom_get_addr(ctx, addr);
+ return addr_ofs < ctx->mmu.rom_size ? ctx->mmu.rom[addr_ofs] : 0;
+ }
default:
// never reached
return 0;
@@ -8285,13 +8290,24 @@ templates:
break;
case 0x2000:
case 0x3000:
- // set rom bank
ctx->mmu.mbc1.rom_bank = val & 0x1F;
+
+ if (ctx->config && ctx->config->on_set_rom_bank) {
+ // notify callback
+ ctx->config->on_set_rom_bank(ctx, val & 0x1F);
+ }
+
break;
case 0x4000:
case 0x5000:
// set ram_bank/upper_rom_bank bits
- ctx->mmu.mbc1.ram_bank = val & 0x3;
+ ctx->mmu.mbc1.ram_bank = val & 0x03;
+
+ if (ctx->config && ctx->config->on_set_ram_bank) {
+ // notify callback
+ ctx->config->on_set_ram_bank(ctx, val & 0x03);
+ }
+
break;
case 0x6000:
case 0x7000:
@@ -8393,8 +8409,10 @@ templates:
case 0x6000:
case 0x7000:
// ROM1 (16k, banked)
- // FIXME: clamp to rom size?
- return ctx->mmu.rom[mbc2_rom_get_addr(ctx, addr)];
+ {
+ const uint32_t addr_ofs = mbc2_rom_get_addr(ctx, addr);
+ return addr_ofs < ctx->mmu.rom_size ? ctx->mmu.rom[addr_ofs] : 0;
+ }
default:
// never reached
return 0;
@@ -8633,6 +8651,9 @@ templates:
}
}
+ // forward reference for mmu_wp()
+ static void gpu_set_line(gb_t * const ctx, const uint8_t line);
+
static void
mmu_wp(
gb_t * const ctx,
@@ -8700,8 +8721,9 @@ templates:
break;
case PORT_LY:
- // FIXME: according to URL below writing to this register zeroes it:
+ // NOTE: according to URL below writing to this register zeroes it:
// (src: http://gbdev.gg8.se/wiki/articles/Video_Display)
+ gpu_set_line(ctx, 0);
break;
case PORT_LYC:
@@ -8782,7 +8804,7 @@ templates:
const gb_t * const ctx,
const uint16_t addr
) {
- switch (ctx->gpu.mode) {
+ switch (ctx->gpu.mode & 0x3) {
case GPU_MODE_VRAM:
return 0xFF;
default:
@@ -8796,7 +8818,7 @@ templates:
const gb_t * const ctx,
const uint16_t addr
) {
- switch (ctx->gpu.mode) {
+ switch (ctx->gpu.mode & 0x3) {
case GPU_MODE_HBLANK:
case GPU_MODE_VBLANK:
// oam memory (160 bytes):
@@ -8932,7 +8954,7 @@ templates:
const uint16_t addr,
const uint8_t val
) {
- switch (ctx->gpu.mode) {
+ switch (ctx->gpu.mode & 0x3) {
case GPU_MODE_HBLANK:
case GPU_MODE_VBLANK:
case GPU_MODE_OAM:
@@ -8951,7 +8973,7 @@ templates:
const uint16_t addr,
const uint8_t val
) {
- switch (ctx->gpu.mode) {
+ switch (ctx->gpu.mode & 0x3) {
case GPU_MODE_HBLANK:
case GPU_MODE_VBLANK:
// oam memory (160 bytes):
@@ -9171,7 +9193,12 @@ templates:
const gb_cpu_state_t state
) {
ctx->cpu.state = state;
+
UNUSED(pc);
+
+ if (ctx->config && ctx->config->on_set_cpu_state) {
+ ctx->config->on_set_cpu_state(ctx, state);
+ }
}
static void
@@ -9274,13 +9301,12 @@ templates:
}
static void
- add_rb(
+ add(
gb_t * const ctx,
- const rb_t reg
+ const uint8_t n
) {
// get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = cpu_rb(ctx, reg);
+ const uint8_t o = cpu_rb(ctx, RB_A);
const uint16_t v = o + n;
// write value
@@ -9295,44 +9321,26 @@ templates:
}
static void
+ add_rb(
+ gb_t * const ctx,
+ const rb_t reg
+ ) {
+ add(ctx, cpu_rb(ctx, reg));
+ }
+
+ static void
add_d8(
gb_t * const ctx,
const uint16_t addr
) {
- // get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = mmu_rb(ctx, addr);
- const uint16_t v = o + n;
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- ((v & 0xFF) ? 0 : F_Z) |
- ((((o & 0x0F) + (n & 0x0F)) & 0xF0) ? F_H : 0) |
- ((v & 0x100) ? F_C : 0)
- ));
+ add(ctx, mmu_rb(ctx, addr));
}
static void
add_hl_ptr(
gb_t * const ctx
) {
- // get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = mmu_rw(ctx, cpu_rw(ctx, RW_HL));
- const uint16_t v = o + n;
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- ((v & 0xFF) ? 0 : F_Z) |
- ((((o & 0x0F) + (n & 0x0F)) & 0xF0) ? F_H : 0) |
- ((v & 0x100) ? F_C : 0)
- ));
+ add(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL)));
}
static void
@@ -9359,11 +9367,11 @@ templates:
static void
ld_hl_sp_r8(
gb_t * const ctx,
- const uint16_t addr
+ const uint16_t ofs_addr
) {
// get src values
const uint16_t a = cpu_rw(ctx, RW_SP);
- const int8_t b = (int8_t) mmu_rb(ctx, addr);
+ const int8_t b = (int8_t) mmu_rb(ctx, ofs_addr);
const uint16_t v = a + b;
// write dst value
@@ -9377,13 +9385,12 @@ templates:
}
static void
- adc_rb(
+ adc(
gb_t * const ctx,
- const rb_t reg
+ const uint8_t n
) {
- // get old and new value
+ // get old value and carry flag
const uint8_t o = cpu_rb(ctx, RB_A),
- n = cpu_rb(ctx, reg),
c = FLAG(ctx, C) ? 1 : 0;
const uint16_t v = o + n + c;
@@ -9399,24 +9406,18 @@ templates:
}
static void
+ adc_rb(
+ gb_t * const ctx,
+ const rb_t reg
+ ) {
+ adc(ctx, cpu_rb(ctx, reg));
+ }
+
+ static void
adc_hl_ptr(
gb_t * const ctx
) {
- // get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = cpu_rb(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL))),
- c = FLAG(ctx, C) ? 1 : 0;
- const uint16_t v = o + n + c;
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- ((v & 0xFF) ? 0 : F_Z) |
- ((((o & 0x0F) + (n & 0x0F) + c) & 0xF0) ? F_H : 0) |
- ((v & 0x100) ? F_C : 0)
- ));
+ adc(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL)));
}
static void
@@ -9424,31 +9425,16 @@ templates:
gb_t * const ctx,
const uint16_t addr
) {
- // get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = mmu_rb(ctx, addr),
- c = FLAG(ctx, C) ? 1 : 0;
- const uint16_t v = o + n + c;
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- ((v & 0xFF) ? 0 : F_Z) |
- ((((o & 0x0F) + (n & 0x0F) + c) & 0xF0) ? F_H : 0) |
- ((v & 0x100) ? F_C : 0)
- ));
+ adc(ctx, mmu_rb(ctx, addr));
}
static void
- sub_rb(
+ sub(
gb_t * const ctx,
- const rb_t reg
+ const uint8_t n
) {
// get old and new value
const uint8_t o = cpu_rb(ctx, RB_A),
- n = cpu_rb(ctx, reg),
v = o - n;
// write value
@@ -9464,24 +9450,18 @@ templates:
}
static void
+ sub_rb(
+ gb_t * const ctx,
+ const rb_t reg
+ ) {
+ sub(ctx, cpu_rb(ctx, reg));
+ }
+
+ static void
sub_hl_ptr(
gb_t * const ctx
) {
- // get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = mmu_rb(ctx, cpu_rw(ctx, RW_HL)),
- v = o - n;
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- F_N |
- ((((o & 0x0F) - (n & 0x0F)) & 0xF0) ? F_H : 0) |
- ((n > o) ? F_C : 0)
- ));
+ sub(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL)));
}
static void
@@ -9489,31 +9469,16 @@ templates:
gb_t * const ctx,
const uint16_t addr
) {
- // get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = mmu_rb(ctx, addr),
- v = o - n;
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- F_N |
- ((((o & 0x0F) - (n & 0x0F)) & 0xF0) ? F_H : 0) |
- ((n > o) ? F_C : 0)
- ));
+ sub(ctx, mmu_rb(ctx, addr));
}
static void
- sbc_rb(
+ sbc(
gb_t * const ctx,
- const rb_t reg
+ const uint8_t n
) {
// get old and new value
const uint8_t o = cpu_rb(ctx, RB_A),
- n = cpu_rb(ctx, reg),
c = FLAG(ctx, C) ? 1 : 0,
v = o - (n + c);
@@ -9530,34 +9495,27 @@ templates:
}
static void
+ sbc_rb(
+ gb_t * const ctx,
+ const rb_t reg
+ ) {
+ sbc(ctx, cpu_rb(ctx, reg));
+ }
+
+ static void
sbc_hl_ptr(
gb_t * const ctx
) {
- // get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = mmu_rb(ctx, cpu_rw(ctx, RW_HL)),
- c = FLAG(ctx, C) ? 1 : 0,
- v = o - (n + c);
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- F_N |
- ((((o & 0x0F) - (n & 0x0F)) & 0xF0) ? F_H : 0) |
- (((((uint16_t) n) + c) > o) ? F_C : 0) // FIXME: is this right for sub/sbc?
- ));
+ sbc(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL)));
}
static void
- and_rb(
+ and(
gb_t * const ctx,
- const rb_t reg
+ const uint8_t val
) {
// get value
- const uint8_t v = cpu_rb(ctx, RB_A) & cpu_rb(ctx, reg);
+ const uint8_t v = cpu_rb(ctx, RB_A) & val;
// write value
cpu_wb(ctx, RB_A, v);
@@ -9570,20 +9528,18 @@ templates:
}
static void
+ and_rb(
+ gb_t * const ctx,
+ const rb_t reg
+ ) {
+ and(ctx, cpu_rb(ctx, reg));
+ }
+
+ static void
and_hl_ptr(
gb_t * const ctx
) {
- // get value
- const uint8_t v = cpu_rb(ctx, RB_A) & mmu_rb(ctx, cpu_rb(ctx, RW_HL));
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- F_H
- ));
+ and(ctx, mmu_rb(ctx, cpu_rb(ctx, RW_HL)));
}
static void
@@ -9591,8 +9547,16 @@ templates:
gb_t * const ctx,
const uint16_t addr
) {
+ and(ctx, mmu_rb(ctx, addr));
+ }
+
+ static void
+ xor(
+ gb_t * const ctx,
+ const uint8_t val
+ ) {
// get value
- const uint8_t v = cpu_rb(ctx, RB_A) & mmu_rb(ctx, addr);
+ const uint8_t v = cpu_rb(ctx, RB_A) ^ val;
// write value
cpu_wb(ctx, RB_A, v);
@@ -9608,32 +9572,14 @@ templates:
gb_t * const ctx,
const rb_t reg
) {
- // get value
- const uint8_t v = cpu_rb(ctx, RB_A) ^ cpu_rb(ctx, reg);
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z)
- ));
+ xor(ctx, cpu_rb(ctx, reg));
}
static void
xor_hl_ptr(
gb_t * const ctx
) {
- // get value
- const uint8_t v = cpu_rb(ctx, RB_A) ^ mmu_rb(ctx, cpu_rw(ctx, RW_HL));
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z)
- ));
+ xor(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL)));
}
static void
@@ -9641,8 +9587,15 @@ templates:
gb_t * const ctx,
const uint16_t addr
) {
- // get value
- const uint8_t v = cpu_rb(ctx, RB_A) ^ mmu_rb(ctx, addr);
+ xor(ctx, mmu_rb(ctx, addr));
+ }
+
+ static void
+ or(
+ gb_t * const ctx,
+ const uint8_t val
+ ) {
+ const uint8_t v = cpu_rb(ctx, RB_A) | val;
// write value
cpu_wb(ctx, RB_A, v);
@@ -9658,30 +9611,14 @@ templates:
gb_t * const ctx,
const rb_t reg
) {
- const uint8_t v = cpu_rb(ctx, RB_A) | cpu_rb(ctx, reg);
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z)
- ));
+ or(ctx, cpu_rb(ctx, reg));
}
static void
or_hl_ptr(
gb_t * const ctx
) {
- // get value
- const uint8_t v = cpu_rb(ctx, RB_A) | mmu_rb(ctx, cpu_rw(ctx, RW_HL));
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z)
- ));
+ or(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL)));
}
static void
@@ -9689,26 +9626,16 @@ templates:
gb_t * const ctx,
const uint16_t addr
) {
- // get value
- const uint8_t v = cpu_rb(ctx, RB_A) | mmu_rb(ctx, addr);
-
- // write value
- cpu_wb(ctx, RB_A, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z)
- ));
+ or(ctx, mmu_rb(ctx, addr));
}
static void
- cp_rb(
+ cp(
gb_t * const ctx,
- const rb_t reg
+ const uint8_t n
) {
// get old and new value
const uint8_t o = cpu_rb(ctx, RB_A),
- n = cpu_rb(ctx, reg),
v = o - n;
// set flags
@@ -9721,21 +9648,18 @@ templates:
}
static void
+ cp_rb(
+ gb_t * const ctx,
+ const rb_t reg
+ ) {
+ cp(ctx, cpu_rb(ctx, reg));
+ }
+
+ static void
cp_hl_ptr(
gb_t * const ctx
) {
- // get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = mmu_rb(ctx, cpu_rw(ctx, RW_HL)),
- v = o - n;
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- F_N |
- ((((o & 0x0F) - (n & 0x0F)) & 0xF0) ? F_H : 0) |
- ((n > o) ? F_C : 0)
- ));
+ cp(ctx, mmu_rb(ctx, cpu_rw(ctx, RW_HL)));
}
static void
@@ -9743,18 +9667,7 @@ templates:
gb_t * const ctx,
const uint16_t addr
) {
- // get old and new value
- const uint8_t o = cpu_rb(ctx, RB_A),
- n = mmu_rb(ctx, addr),
- v = o - n;
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- F_N |
- ((((o & 0x0F) - (n & 0x0F)) & 0xF0) ? F_H : 0) |
- ((n > o) ? F_C : 0)
- ));
+ cp(ctx, mmu_rb(ctx, addr));
}
static void
@@ -9787,42 +9700,56 @@ templates:
cpu_ww(ctx, RW_SP, sp + 2);
}
- static void
- rlc_rb(
+ static uint8_t
+ rlc(
gb_t * const ctx,
- const rb_t reg
+ const uint8_t o
) {
- // get old value, carry bit, and new value
- const uint8_t o = cpu_rb(ctx, reg),
- c = (o & 0x80) ? 1 : 0,
+ // get carry bit and new value
+ const uint8_t c = (o & 0x80) ? 1 : 0,
n = ((o & 0x7F) << 1) + c;
- // set value
- cpu_wb(ctx, reg, n);
-
// set flags
cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
(n ? 0 : F_Z) |
(c ? F_C : 0)
));
+
+ // return new value
+ return n;
+ }
+
+ static void
+ rlc_rb(
+ gb_t * const ctx,
+ const rb_t reg
+ ) {
+ cpu_wb(ctx, reg, rlc(ctx, cpu_rb(ctx, reg)));
}
static void
rlc_hl(
gb_t * const ctx
) {
- // get old value, carry bit, and new value
const uint16_t addr = cpu_rw(ctx, RW_HL);
- const uint8_t o = mmu_rb(ctx, addr),
- c = (o & 0x80) ? 1 : 0,
- n = ((o & 0x7F) << 1) + c;
- // set value
- mmu_wb(ctx, addr, n);
+ mmu_wb(ctx, addr, rlc(ctx, mmu_rb(ctx, addr)));
+ }
+ static uint8_t
+ rrc(
+ gb_t * const ctx,
+ const uint8_t o
+ ) {
+ // get carry bit and new value
+ const uint8_t c = (o & 0x01) ? 1 : 0,
+ n = (o >> 1) | (c ? 0x80 : 0);
// set flags
cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
(n ? 0 : F_Z) |
(c ? F_C : 0)
));
+
+ // return new value
+ return n;
}
static void
@@ -9830,37 +9757,32 @@ templates:
gb_t * const ctx,
const rb_t reg
) {
- // get old value, carry bit, and new value
- const uint8_t o = cpu_rb(ctx, reg),
- c = (o & 0x01) ? 1 : 0,
- n = (o >> 1) | (c ? 0x80 : 0);
- // set value
- cpu_wb(ctx, reg, n);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (n ? 0 : F_Z) |
- (c ? F_C : 0)
- ));
+ cpu_wb(ctx, reg, rrc(ctx, cpu_rb(ctx, reg)));
}
static void
rrc_hl_ptr(
gb_t * const ctx
) {
- // get old value, carry bit, and new value
const uint16_t addr = cpu_rw(ctx, RW_HL);
- const uint8_t o = mmu_rb(ctx, addr),
- c = (o & 0x01) ? 1 : 0,
- n = (o >> 1) | (c ? 0x80 : 0);
- // set value
- mmu_wb(ctx, addr, n);
+ mmu_wb(ctx, addr, rrc(ctx, mmu_rb(ctx, addr)));
+ }
+
+ static uint8_t
+ rl(
+ gb_t * const ctx,
+ const uint8_t o
+ ) {
+ const uint8_t n = (o << 1) + (FLAG(ctx, C) ? 1 : 0);
// set flags
cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
(n ? 0 : F_Z) |
- (c ? F_C : 0)
+ ((o & 0x80) ? F_C : 0)
));
+
+ // return result
+ return n;
}
static void
@@ -9868,35 +9790,32 @@ templates:
gb_t * const ctx,
const rb_t reg
) {
- // get old value and new value
- const uint8_t o = cpu_rb(ctx, reg),
- n = (o << 1) + (FLAG(ctx, C) ? 1 : 0);
- // set value
- cpu_wb(ctx, reg, n);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (n ? 0 : F_Z) |
- ((o & 0x80) ? F_C : 0)
- ));
+ cpu_wb(ctx, reg, rl(ctx, cpu_rb(ctx, reg)));
}
static void
rl_hl_ptr(
gb_t * const ctx
) {
- // get old value and new value
const uint16_t addr = cpu_rw(ctx, RW_HL);
- const uint8_t o = mmu_rb(ctx, addr),
- n = (o << 1) + (FLAG(ctx, C) ? 1 : 0);
- // set value
- mmu_wb(ctx, addr, n);
+ mmu_wb(ctx, addr, rl(ctx, mmu_rb(ctx, addr)));
+ }
+
+ static uint8_t
+ rr(
+ gb_t * const ctx,
+ const uint8_t o
+ ) {
+ const uint8_t n = (FLAG(ctx, C) ? 0x80 : 0) | (o >> 1);
// set flags
cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
(n ? 0 : F_Z) |
- ((o & 0x80) ? F_C : 0)
+ ((o & 0x01) ? F_C : 0)
));
+
+ // return result
+ return n;
}
static void
@@ -9904,35 +9823,32 @@ templates:
gb_t * const ctx,
const rb_t reg
) {
- // get old value and new value
- const uint8_t o = cpu_rb(ctx, reg),
- n = (FLAG(ctx, C) ? 0x80 : 0) | (o >> 1);
- // set value
- cpu_wb(ctx, reg, n);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (n ? 0 : F_Z) |
- ((o & 0x01) ? F_C : 0)
- ));
+ cpu_wb(ctx, reg, rr(ctx, cpu_rb(ctx, reg)));
}
static void
rr_hl_ptr(
gb_t * const ctx
) {
- // get old value and new value
const uint16_t addr = cpu_rw(ctx, RW_HL);
- const uint8_t o = mmu_rb(ctx, addr),
- n = (FLAG(ctx, C) ? 0x80 : 0) | (o >> 1);
- // set value
- mmu_wb(ctx, addr, n);
+ mmu_wb(ctx, addr, rr(ctx, mmu_rb(ctx, addr)));
+ }
+
+ static uint8_t
+ sla(
+ gb_t * const ctx,
+ const uint8_t o
+ ) {
+ const uint8_t v = o << 1;
// set flags
cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (n ? 0 : F_Z) |
- ((o & 0x01) ? F_C : 0)
+ (v ? 0 : F_Z) |
+ ((o & 0x80) ? F_C : 0)
));
+
+ // return value
+ return v;
}
static void
@@ -9940,17 +9856,7 @@ templates:
gb_t * const ctx,
const rb_t reg
) {
- const uint8_t o = cpu_rb(ctx, reg),
- v = o << 1;
-
- // set value
- cpu_wb(ctx, reg, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- ((o & 0x80) ? F_C : 0)
- ));
+ cpu_wb(ctx, reg, sla(ctx, cpu_rb(ctx, reg)));
}
static void
@@ -9958,17 +9864,24 @@ templates:
gb_t * const ctx
) {
const uint16_t addr = cpu_rw(ctx, RW_HL);
- const uint8_t o = mmu_rb(ctx, addr),
- v = o << 1;
+ mmu_wb(ctx, addr, sla(ctx, mmu_rb(ctx, addr)));
+ }
- // set value
- mmu_wb(ctx, addr, v);
+ static uint8_t
+ sra(
+ gb_t * const ctx,
+ const uint8_t o
+ ) {
+ const uint8_t v = ((o & 0x80) ? 0x80 : 0) | (o >> 1);
// set flags
cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
(v ? 0 : F_Z) |
- ((o & 0x80) ? F_C : 0)
+ ((o & 0x01) ? F_C : 0)
));
+
+ // return result
+ return v;
}
static void
@@ -9976,17 +9889,7 @@ templates:
gb_t * const ctx,
const rb_t reg
) {
- const uint8_t o = cpu_rb(ctx, reg),
- v = ((o & 0x80) ? 0x80 : 0) | (o >> 1);
-
- // set value
- cpu_wb(ctx, reg, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- ((o & 0x01) ? F_C : 0)
- ));
+ cpu_wb(ctx, reg, sra(ctx, cpu_rb(ctx, reg)));
}
static void
@@ -9994,17 +9897,24 @@ templates:
gb_t * const ctx
) {
const uint16_t addr = cpu_rw(ctx, RW_HL);
- const uint8_t o = mmu_rb(ctx, addr),
- v = ((o & 0x80) ? 0x80 : 0) | (o >> 1);
+ mmu_wb(ctx, addr, sra(ctx, mmu_rb(ctx, addr)));
+ }
- // set value
- mmu_wb(ctx, addr, v);
+ static uint8_t
+ srl(
+ gb_t * const ctx,
+ const uint8_t o
+ ) {
+ const uint8_t v = (o >> 1);
// set flags
cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
(v ? 0 : F_Z) |
((o & 0x01) ? F_C : 0)
));
+
+ // return result
+ return v;
}
static void
@@ -10012,17 +9922,7 @@ templates:
gb_t * const ctx,
const rb_t reg
) {
- const uint8_t o = cpu_rb(ctx, reg),
- v = (o >> 1);
-
- // set value
- cpu_wb(ctx, reg, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- ((o & 0x01) ? F_C : 0)
- ));
+ cpu_wb(ctx, reg, srl(ctx, cpu_rb(ctx, reg)));
}
static void
@@ -10030,17 +9930,7 @@ templates:
gb_t * const ctx
) {
const uint16_t addr = cpu_rw(ctx, RW_HL);
- const uint8_t o = mmu_rb(ctx, addr),
- v = (o >> 1);
-
- // set value
- mmu_wb(ctx, addr, v);
-
- // set flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z) |
- ((o & 0x01) ? F_C : 0)
- ));
+ mmu_wb(ctx, addr, srl(ctx, mmu_rb(ctx, addr)));
}
static void
@@ -10121,21 +10011,25 @@ templates:
mmu_wb(ctx, addr, mmu_rb(ctx, addr) | ~(bit ? (1 << bit) : 1));
}
- static void
- swap_rb(
+ static uint8_t
+ swap(
gb_t * const ctx,
- const rb_t reg
+ const uint8_t v
) {
- // get old value
- const uint8_t v = cpu_rb(ctx, reg);
-
- // write value
- cpu_wb(ctx, reg, ((v & (0x0F)) << 4) | ((v & 0xF0) >> 4));
-
// write flags
cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
(v ? 0 : F_Z)
));
+
+ return ((v & (0x0F)) << 4) | ((v & 0xF0) >> 4);
+ }
+
+ static void
+ swap_rb(
+ gb_t * const ctx,
+ const rb_t reg
+ ) {
+ cpu_wb(ctx, reg, swap(ctx, cpu_rb(ctx, reg)));
}
static void
@@ -10143,15 +10037,7 @@ templates:
gb_t * const ctx
) {
const uint16_t addr = cpu_rw(ctx, RW_HL);
- const uint8_t v = mmu_rb(ctx, addr);
-
- // write value
- mmu_wb(ctx, addr, ((v & (0x0F)) << 4) | ((v & 0xF0) >> 4));
-
- // write flags
- cpu_wf(ctx, F_Z | F_N | F_H | F_C, (
- (v ? 0 : F_Z)
- ));
+ mmu_wb(ctx, addr, swap(ctx, mmu_rb(ctx, addr)));
}
static void
@@ -10203,6 +10089,13 @@ templates:
}
}
+ static uint8_t
+ gpu_get_mode(
+ const gb_t * const ctx
+ ) {
+ return ctx->gpu.mode & 0x3;
+ }
+
static void
gpu_set_mode(
gb_t * const ctx,
@@ -10210,18 +10103,29 @@ templates:
) {
ctx->gpu.mode = mode;
- switch (mode) {
+ if (ctx->config && ctx->config->on_gpu_set_mode) {
+ ctx->config->on_gpu_set_mode(ctx, mode);
+ }
+
+ switch (gpu_get_mode(ctx)) {
case GPU_MODE_OAM:
if (ctx->gpu.stat & (1 << 5)) {
- // vblank interrupt is enabled, trigger LCDC interrupt
+ // lcd status interrupt is enabled, trigger LCDC interrupt
mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) & (1 << 1));
}
break;
+ case GPU_MODE_VRAM:
+ // do nothing
+ break;
case GPU_MODE_HBLANK:
if (ctx->gpu.stat & (1 << 3)) {
- // hblank interrupt is enabled, trigger LCDC interrupt
+ // lcd status interrupt is enabled, trigger LCDC interrupt
mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) & (1 << 1));
+
+ if (ctx->config && ctx->config->on_hblank) {
+ ctx->config->on_hblank(ctx);
+ }
}
break;
@@ -10229,12 +10133,13 @@ templates:
if (ctx->gpu.stat & (1 << 4)) {
// vblank interrupt is enabled, trigger vblank interrupt
mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) & 1);
+
+ if (ctx->config && ctx->config->on_vblank) {
+ ctx->config->on_vblank(ctx);
+ }
}
break;
- default:
- // do nothing
- break;
}
}
@@ -10332,19 +10237,21 @@ templates:
// increment clock
ctx->gpu.clock += clock;
- switch (ctx->gpu.mode) {
+ if (ctx->config && ctx->config->on_gpu_step) {
+ ctx->config->on_gpu_step(ctx);
+ }
+
+ switch (gpu_get_mode(ctx)) {
case GPU_MODE_OAM:
- if (ctx->gpu.clock > 80) {
+ if (ctx->gpu.clock > 79) {
// clear clock, set mode
ctx->gpu.clock = 0;
- ctx->gpu.mode = GPU_MODE_VRAM;
+ gpu_set_mode(ctx, GPU_MODE_VRAM);
}
break;
case GPU_MODE_VRAM:
- if (ctx->gpu.clock > 172) {
- // TODO: write scanline
-
+ if (ctx->gpu.clock > 171) {
// clear clock, set mode
ctx->gpu.clock = 0;
gpu_set_mode(ctx, GPU_MODE_HBLANK);
@@ -10352,13 +10259,13 @@ templates:
break;
case GPU_MODE_HBLANK:
- if (ctx->gpu.clock > 204) {
+ if (ctx->gpu.clock > 203) {
// clear clock, draw line, increment line
ctx->gpu.clock = 0;
gpu_draw(ctx);
gpu_set_line(ctx, ctx->gpu.line + 1);
- if (ctx->gpu.line < 143) {
+ if (ctx->gpu.line < 144) {
// set mode
gpu_set_mode(ctx, GPU_MODE_OAM);
} else {
@@ -10386,9 +10293,6 @@ templates:
}
break;
- default:
- /* do nothing, unknown gpu mode */
- break;
}
}
@@ -10412,6 +10316,11 @@ templates:
// trigger timer interrupt
mmu_wb(ctx, PORT_IF, mmu_rb(ctx, PORT_IF) & (1 << 2));
+
+ if (ctx->config && ctx->config->on_timer) {
+ // notify callback
+ ctx->config->on_timer(ctx);
+ }
}
}
}
@@ -10450,8 +10359,8 @@ templates:
// return 4 clock step
return 4;
} else {
- // return 4 clock step
- return 0;
+ // return 0 clock step
+ return 1;
}
}
@@ -10461,7 +10370,7 @@ templates:
) {
if (ctx->cpu.state == GB_CPU_STATE_RUN) {
if (ctx->cpu.ime) {
- // get interrupt vector (masked against enabled interrupts)
+ // get interrupt flags, masked against enabled interrupts
const uint8_t iv = mmu_rb(ctx, PORT_IE) & mmu_rb(ctx, PORT_IF);
bool done = false;
@@ -10546,6 +10455,59 @@ templates:
gpu_step(ctx, clock);
}
+ static const struct {
+ const char * const name;
+ const uint8_t len;
+ } OPS[] = {
+ <%= ops %>
+ };
+
+ bool
+ gb_disasm(
+ gb_t * const ctx,
+ char * const dst_buf,
+ size_t * const dst_len
+ ) {
+ if (!dst_buf || !dst_len) {
+ return false;
+ }
+
+ const uint8_t op = mmu_rb(ctx, cpu_rw(ctx, RW_PC));
+ const uint16_t ofs = (op == 0xCB) ? (255 + mmu_rb(ctx, cpu_rw(ctx, RW_PC) + 1)) : op;
+ int len = -1;
+
+ switch (OPS[ofs].len) {
+ case 1:
+ len = snprintf(dst_buf, *dst_len, "%s; %02x",
+ OPS[ofs].name,
+ op
+ );
+
+ break;
+ case 2:
+ len = snprintf(dst_buf, *dst_len, "%s; %02x %02x",
+ OPS[ofs].name,
+ op,
+ mmu_rb(ctx, cpu_rw(ctx, RW_PC) + 1)
+ );
+
+ break;
+ case 3:
+ len = snprintf(dst_buf, *dst_len, "%s; %02x %02x %02x",
+ OPS[ofs].name,
+ op,
+ mmu_rb(ctx, cpu_rw(ctx, RW_PC) + 1),
+ mmu_rb(ctx, cpu_rw(ctx, RW_PC) + 2)
+ );
+
+ break;
+ default:
+ len = snprintf(dst_buf, *dst_len, "%s", OPS[ofs].name);
+ }
+
+ return (len > 0) && (len < (int) *dst_len);
+ }
+
void
gb_set_buttons(
gb_t * const ctx,
@@ -10584,9 +10546,6 @@ templates:
cpu_init(
gb_t * const ctx
) {
- // set cpu state
- cpu_set_state(ctx, 0, GB_CPU_STATE_RUN);
-
// init cpu registers
// (src: TCAGBD.pdf, 3.2)
// TODO: this varies by model (DGB/CGB/SGB/GBA/etc)
@@ -10596,16 +10555,23 @@ templates:
ctx->cpu.rs[RW_HL] = 0x014D;
ctx->cpu.rs[RW_SP] = 0xFFFE;
ctx->cpu.rs[RW_PC] = 0x0100;
+
+ // set cpu state
+ cpu_set_state(ctx, 0, GB_CPU_STATE_RUN);
}
void gb_init(
gb_t * const ctx,
- const uint8_t * const rom,
+ const gb_config_t * const config,
+ const uint8_t *rom,
const uint32_t rom_size
) {
// clear context
memset(ctx, 0, sizeof(gb_t));
+ // save config
+ ctx->config = config;
+
// init cpu
cpu_init(ctx);
@@ -10614,6 +10580,6 @@ templates:
ctx->mmu.rom_size = rom_size;
// init gpu
- ctx->gpu.mode = GPU_MODE_OAM;
- ctx->gpu.line = 0;
+ gpu_set_mode(ctx, GPU_MODE_OAM);
+ gpu_set_line(ctx, 0);
}
diff --git a/test.c b/test.c
index f20301c..7a2ea70 100644
--- a/test.c
+++ b/test.c
@@ -11,7 +11,8 @@
#define NUM_FRAMES 600
// #define SKIP_STEPS 1000000
-#define NUM_STEPS 200000
+#define NUM_STEPS 300000
+#define UNUSED(a) ((void) (a))
static uint32_t
file_size(
@@ -63,6 +64,81 @@ load(
static uint8_t frames[NUM_FRAMES * GB_FRAME_SIZE];
static void
+on_set_rom_bank(
+ const gb_t * const ctx,
+ const uint16_t bank
+) {
+ printf("set rom bank: bank = %u, PC = %04x\n", bank, ctx->cpu.rs[5]);
+}
+
+static void
+on_set_ram_bank(
+ const gb_t * const ctx,
+ const uint16_t bank
+) {
+ printf("set ram bank: bank = %u, PC = %04x\n", bank, ctx->cpu.rs[5]);
+}
+
+static void
+on_vblank(
+ const gb_t * const ctx
+) {
+ printf("vblank: PC = %04x\n", ctx->cpu.rs[5]);
+}
+
+static void
+on_hblank(
+ const gb_t * const ctx
+) {
+ printf("hblank: PC = %04x\n", ctx->cpu.rs[5]);
+}
+
+static void
+on_timer(
+ const gb_t * const ctx
+) {
+ printf("timer: PC = %04x\n", ctx->cpu.rs[5]);
+}
+
+/*
+ * static void
+ * on_gpu_step(
+ * const gb_t * const ctx
+ * ) {
+ * printf("gpu step: gpu clock = 0x%04x\n", ctx->gpu.clock);
+ * }
+ */
+
+static void
+on_gpu_set_mode(
+ const gb_t * const ctx,
+ const uint8_t mode
+) {
+ UNUSED(ctx);
+ printf("gpu mode: %u, line = %u\n", mode, ctx->gpu.line);
+}
+
+static void
+on_set_cpu_state(
+ const gb_t * const ctx,
+ const gb_cpu_state_t state
+) {
+ printf("cpu state: PC = %04x, state = %d\n", ctx->cpu.rs[5], state);
+}
+
+static const gb_config_t
+EXECUTE_CONFIG = {
+ .on_set_rom_bank = on_set_rom_bank,
+ .on_set_ram_bank = on_set_ram_bank,
+ .on_vblank = on_vblank,
+ .on_hblank = on_hblank,
+ .on_timer = on_timer,
+ // .on_gpu_step = on_gpu_step,
+ .on_gpu_set_mode = on_gpu_set_mode,
+ .on_set_cpu_state = on_set_cpu_state,
+};
+
+static void
test_render_frames(
const char * const png_path,
const char * const rom_path
@@ -74,7 +150,7 @@ test_render_frames(
// init context
gb_t ctx;
- gb_init(&ctx, rom_data, rom_size);
+ gb_init(&ctx, NULL, rom_data, rom_size);
fprintf(stderr, "gb context initialized\n");
// render frames
@@ -109,12 +185,19 @@ const char * const RWS[] = {
static void
gb_dump_context(
- const gb_t * const ctx
+ gb_t * const ctx
) {
for (int i = 0; RWS[i]; i++) {
- printf("%s%s: 0x%04X", (!i) ? "" : ", ", RWS[i], ctx->cpu.rs[i]);
+ printf("%s:%04X ", RWS[i], ctx->cpu.rs[i]);
+ }
+
+ char buf[128];
+ size_t buf_len = sizeof(buf);
+ if (gb_disasm(ctx, buf, &buf_len)) {
+ printf("%s\n", buf);
+ } else {
+ printf("\n");
}
- printf("\n");
}
static void
@@ -128,7 +211,7 @@ test_execute_steps(
// init context
gb_t ctx;
- gb_init(&ctx, rom_data, rom_size);
+ gb_init(&ctx, &EXECUTE_CONFIG, rom_data, rom_size);
fprintf(stderr, "gb context initialized\n");
#ifdef SKIP_STEPS