HareBoy API Reference
Index
Types
type apu = struct {
ch1: square_ch,
ch2: square_ch,
ch3: wave_ch,
ch4: noise_ch,
nr50: u8,
nr51: u8,
nr52: u8,
frame_seq_timer: i32,
frame_seq_step: i32,
sample_timer: i32,
sample_period: i32,
audio_buf: [2048]i16,
audio_len: size,
audio_dev: u32,
};
type cartridge = struct {
mbc: mbc_type,
rom: []u8,
ram: []u8,
rom_bank: uint,
ram_bank: uint,
ram_enabled: bool,
banking_mode: uint,
mbc1_low5: uint,
mbc1_high2: uint,
rom_bank_mask: uint,
ram_bank_mask: uint,
};
type cpu = struct {
a: u8,
f: u8,
b: u8,
c: u8,
d: u8,
e: u8,
h: u8,
l: u8,
pc: u16,
sp: u16,
halted: bool,
locked: bool,
ime: bool,
ime_scheduled: bool,
halt_bug: bool,
};
type gameboy = struct {
cpu: cpu,
mmu: mmu,
ppu: ppu,
tmr: timer,
joy: joypad,
cart: cartridge,
snd: apu,
total_cycles: u64,
frame_count: u64,
leftover_cycles: i32,
};
type joy_key = enum {
RIGHT,
LEFT,
UP,
DOWN,
A,
B,
START,
SELECT,
};
type joypad = struct {
up: bool,
down: bool,
left: bool,
right: bool,
a: bool,
b: bool,
start: bool,
select: bool,
select_buttons: bool,
select_dpad: bool,
};
type mbc_type = enum {
NONE,
MBC1,
MBC3,
MBC5,
};
type mmu = struct {
cart: nullable *cartridge,
tmr: nullable *timer,
joy: nullable *joypad,
snd: nullable *apu,
wram: [8192]u8,
vram: [8192]u8,
oam: [160]u8,
hram: [127]u8,
io: [128]u8,
ie: u8,
serial_buffer: [256]u8,
serial_len: size,
dma_active: bool,
dma_source: u16,
dma_index: uint,
dma_delay: i32,
dma_cycles: i32,
};
type noise_ch = struct {
enabled: bool,
dac_enabled: bool,
length_counter: i32,
length_enabled: bool,
volume: i32,
volume_init: i32,
volume_env_add: bool,
volume_env_per: i32,
volume_env_timer: i32,
clock_shift: i32,
width_mode: bool,
divisor_code: i32,
freq_timer: i32,
lfsr: u16,
};
type ppu = struct {
framebuffer: [SCREEN_W * SCREEN_H]u8,
bg_color_idx: [SCREEN_W * SCREEN_H]u8,
scanline: uint,
scanline_cycles: uint,
window_line: uint,
window_was_on: bool,
lcd_enabled: bool,
stat_line_high: bool,
};
type square_ch = struct {
enabled: bool,
dac_enabled: bool,
duty: i32,
duty_pos: i32,
length_counter: i32,
length_enabled: bool,
volume: i32,
volume_init: i32,
volume_env_add: bool,
volume_env_per: i32,
volume_env_timer: i32,
frequency: i32,
freq_timer: i32,
sweep_enabled: bool,
sweep_period: i32,
sweep_negate: bool,
sweep_shift: i32,
sweep_timer: i32,
sweep_shadow: i32,
sweep_calc_done: bool,
};
type timer = struct {
tima: u8,
tma: u8,
tac: u8,
div: u16,
reload_delay: i32,
reload_cycle_b: i32,
};
type wave_ch = struct {
enabled: bool,
dac_enabled: bool,
length_counter: i32,
length_enabled: bool,
volume_code: i32,
frequency: i32,
freq_timer: i32,
sample_pos: i32,
sample_buffer: u8,
wave_ram: [16]u8,
};
Errors
type audio_error = !void;
Constants
def SCREEN_H: size = 144;
def SCREEN_W: size = 160;
Globals
const PALETTE: [4][4]u8;
Functions
fn apu_close(a: *apu) void;
fn apu_flush(a: *apu) void;
fn apu_init_audio(a: *apu) (void | audio_error);
fn apu_read(a: *apu, addr: u16) u8;
fn apu_update(a: *apu, cycles: i32) void;
fn apu_write(a: *apu, addr: u16, value: u8) void;
fn audio_strerror(err: audio_error) str;
fn cart_free(c: *cartridge) void;
fn cart_read_ram(c: *cartridge, addr: u16) u8;
fn cart_read_rom(c: *cartridge, addr: u16) u8;
fn cart_write_control(c: *cartridge, addr: u16, val: u8) void;
fn cart_write_ram(c: *cartridge, addr: u16, val: u8) void;
fn cpu_step(c: *cpu, m: *mmu) i32;
fn finish(gb: *gameboy) void;
fn init(gb: *gameboy) void;
fn joypad_read(j: *joypad) u8;
fn joypad_set_key(j: *joypad, key: joy_key, pressed: bool) bool;
fn joypad_write(j: *joypad, value: u8) bool;
fn mmu_read(m: *mmu, addr: u16) u8;
fn mmu_tick_dma(m: *mmu, cycles: i32) void;
fn mmu_write(m: *mmu, addr: u16, value: u8) void;
fn newapu() apu;
fn newcart(rom: []u8) cartridge;
fn newgameboy(rom: []u8) gameboy;
fn newtimer() timer;
fn ppu_update(g: *ppu, m: *mmu) void;
fn run_frame(gb: *gameboy) void;
fn timer_read(t: *timer, addr: u16) u8;
fn timer_update(t: *timer, cycles: i32) bool;
fn timer_write(t: *timer, addr: u16, value: u8) void;
fn main() void;
Types
type apu
type apu = struct {
ch1: square_ch,
ch2: square_ch,
ch3: wave_ch,
ch4: noise_ch,
nr50: u8,
nr51: u8,
nr52: u8,
frame_seq_timer: i32,
frame_seq_step: i32,
sample_timer: i32,
sample_period: i32,
audio_buf: [2048]i16,
audio_len: size,
audio_dev: u32,
};
Audio processing unit with four sound channels and an output sample buffer.
type cartridge
type cartridge = struct {
mbc: mbc_type,
rom: []u8,
ram: []u8,
rom_bank: uint,
ram_bank: uint,
ram_enabled: bool,
banking_mode: uint,
mbc1_low5: uint,
mbc1_high2: uint,
rom_bank_mask: uint,
ram_bank_mask: uint,
};
ROM cartridge with optional MBC and external RAM.
type cpu
type cpu = struct {
a: u8,
f: u8,
b: u8,
c: u8,
d: u8,
e: u8,
h: u8,
l: u8,
pc: u16,
sp: u16,
halted: bool,
locked: bool,
ime: bool,
ime_scheduled: bool,
halt_bug: bool,
};
CPU register file and execution state.
type gameboy
type gameboy = struct {
cpu: cpu,
mmu: mmu,
ppu: ppu,
tmr: timer,
joy: joypad,
cart: cartridge,
snd: apu,
total_cycles: u64,
frame_count: u64,
leftover_cycles: i32,
};
Top-level emulator state holding all subsystems.
type joy_key
type joy_key = enum {
RIGHT,
LEFT,
UP,
DOWN,
A,
B,
START,
SELECT,
};
Joypad key identifiers for joypad_set_key.
type joypad
type joypad = struct {
up: bool,
down: bool,
left: bool,
right: bool,
a: bool,
b: bool,
start: bool,
select: bool,
select_buttons: bool,
select_dpad: bool,
};
Joypad button and selection state.
type mbc_type
type mbc_type = enum {
NONE,
MBC1,
MBC3,
MBC5,
};
Memory bank controller type.
type mmu
type mmu = struct {
cart: nullable *cartridge,
tmr: nullable *timer,
joy: nullable *joypad,
snd: nullable *apu,
wram: [8192]u8,
vram: [8192]u8,
oam: [160]u8,
hram: [127]u8,
io: [128]u8,
ie: u8,
serial_buffer: [256]u8,
serial_len: size,
dma_active: bool,
dma_source: u16,
dma_index: uint,
dma_delay: i32,
dma_cycles: i32,
};
Memory management unit. Routes bus reads and writes to the cartridge, timer, joypad, and apu via internal pointers set up by init.
type noise_ch
type noise_ch = struct {
enabled: bool,
dac_enabled: bool,
length_counter: i32,
length_enabled: bool,
volume: i32,
volume_init: i32,
volume_env_add: bool,
volume_env_per: i32,
volume_env_timer: i32,
clock_shift: i32,
width_mode: bool,
divisor_code: i32,
freq_timer: i32,
lfsr: u16,
};
Noise channel state (CH4).
type ppu
type ppu = struct {
framebuffer: [SCREEN_W * SCREEN_H]u8,
bg_color_idx: [SCREEN_W * SCREEN_H]u8,
scanline: uint,
scanline_cycles: uint,
window_line: uint,
window_was_on: bool,
lcd_enabled: bool,
stat_line_high: bool,
};
PPU state including framebuffer, scanline counters, and window tracking.
type square_ch
type square_ch = struct {
enabled: bool,
dac_enabled: bool,
duty: i32,
duty_pos: i32,
length_counter: i32,
length_enabled: bool,
volume: i32,
volume_init: i32,
volume_env_add: bool,
volume_env_per: i32,
volume_env_timer: i32,
frequency: i32,
freq_timer: i32,
sweep_enabled: bool,
sweep_period: i32,
sweep_negate: bool,
sweep_shift: i32,
sweep_timer: i32,
sweep_shadow: i32,
sweep_calc_done: bool,
};
Square wave channel state (used by CH1 and CH2).
type timer
type timer = struct {
tima: u8,
tma: u8,
tac: u8,
div: u16,
reload_delay: i32,
reload_cycle_b: i32,
};
Timer subsystem state.
type wave_ch
type wave_ch = struct {
enabled: bool,
dac_enabled: bool,
length_counter: i32,
length_enabled: bool,
volume_code: i32,
frequency: i32,
freq_timer: i32,
sample_pos: i32,
sample_buffer: u8,
wave_ram: [16]u8,
};
Wave channel state (CH3).
Errors
type audio_error
type audio_error = !void;
Returned when apu_init_audio cannot open the SDL audio device.
Constants
def SCREEN_H
def SCREEN_H: size = 144;
Screen height in pixels.
def SCREEN_W
def SCREEN_W: size = 160;
Screen width in pixels.
Globals
let PALETTE
const PALETTE: [4][4]u8;
DMG shade palette: index 0-3 -> RGBA (greenish Game Boy colors).
Functions
fn apu_close
fn apu_close(a: *apu) void;
Closes the audio device.
fn apu_flush
fn apu_flush(a: *apu) void;
Flushes buffered audio samples to SDL via apu_init_audio's device.
fn apu_init_audio
fn apu_init_audio(a: *apu) (void | audio_error);
Opens the SDL audio device for playback.
fn apu_read
fn apu_read(a: *apu, addr: u16) u8;
Reads an apu register (0xFF10-0xFF3F).
fn apu_update
fn apu_update(a: *apu, cycles: i32) void;
Advances the apu by the given number of T-cycles.
fn apu_write
fn apu_write(a: *apu, addr: u16, value: u8) void;
Writes to an apu register (0xFF10-0xFF3F).
fn audio_strerror
fn audio_strerror(err: audio_error) str;
Returns a human-readable message for an audio_error.
fn cart_free
fn cart_free(c: *cartridge) void;
Frees the RAM allocated by cart_init_ram. Must be called when the cartridge is no longer needed.
fn cart_read_ram
fn cart_read_ram(c: *cartridge, addr: u16) u8;
Reads from external RAM.
fn cart_read_rom
fn cart_read_rom(c: *cartridge, addr: u16) u8;
Reads from ROM with bank switching.
fn cart_write_control
fn cart_write_control(c: *cartridge, addr: u16, val: u8) void;
Handles MBC register writes (0x0000-0x7FFF).
fn cart_write_ram
fn cart_write_ram(c: *cartridge, addr: u16, val: u8) void;
Writes to external RAM.
fn cpu_step
fn cpu_step(c: *cpu, m: *mmu) i32;
Execute one instruction. Reads from mmu_read and writes via mmu_write. Returns T-cycles consumed.
fn finish
fn finish(gb: *gameboy) void;
Frees resources owned by the gameboy.
fn init
fn init(gb: *gameboy) void;
Links the mmu bus to its peripheral components. Must be called once after newgameboy, before calling run_frame.
fn joypad_read
fn joypad_read(j: *joypad) u8;
Returns the JOYP register value based on current button state.
fn joypad_set_key
fn joypad_set_key(j: *joypad, key: joy_key, pressed: bool) bool;
Updates one joypad key and returns true when this change should request INT_JOYPAD.
fn joypad_write
fn joypad_write(j: *joypad, value: u8) bool;
Sets the JOYP selection bits from a write to 0xFF00.
fn mmu_read
fn mmu_read(m: *mmu, addr: u16) u8;
Reads a byte from the memory bus. Routes to cartridge, timer, joypad, or apu as appropriate for the given address.
fn mmu_tick_dma
fn mmu_tick_dma(m: *mmu, cycles: i32) void;
Advances an active OAM DMA transfer by the given number of T-cycles.
fn mmu_write
fn mmu_write(m: *mmu, addr: u16, value: u8) void;
Writes a byte to the memory bus. Routes to cartridge, timer, joypad, or apu as appropriate for the given address.
fn newapu
fn newapu() apu;
Creates an apu initialized to DMG post-boot state.
fn newcart
fn newcart(rom: []u8) cartridge;
Creates a cartridge from ROM data. The caller retains ownership of rom.
fn newgameboy
fn newgameboy(rom: []u8) gameboy;
Creates a new gameboy initialized to DMG post-boot state. The caller must call init before run_frame.
fn newtimer
fn newtimer() timer;
Creates a timer initialized to DMG post-boot state.
fn ppu_update
fn ppu_update(g: *ppu, m: *mmu) void;
Advances the ppu by one T-cycle. Updates STAT, LY, and triggers scanline rendering and INT_VBLANK / INT_STAT interrupts as needed.
fn run_frame
fn run_frame(gb: *gameboy) void;
Runs one frame (70224 T-cycles) of emulation. Carries over excess cycles from the previous frame so the PPU stays aligned with presentation and never overwrites the framebuffer with next-frame content.
fn timer_read
fn timer_read(t: *timer, addr: u16) u8;
Returns the value of a timer register.
fn timer_update
fn timer_update(t: *timer, cycles: i32) bool;
Advances the timer by n T-cycles. Returns true if an INT_TIMER interrupt should fire.
fn timer_write
fn timer_write(t: *timer, addr: u16, value: u8) void;
Sets a timer register value.
fn main
Show undocumented member
fn main() void;