flybrain/services/flysim/vendor/binjgb/src/emulator.h
acamilo 660c3cf00d
Some checks failed
ci / node 22 (test + typecheck) (push) Has been cancelled
ci / rust stable (cargo test --workspace --release) (push) Has been cancelled
ci / infra/tests/lint.sh (push) Has been cancelled
ci / playwright apps/stage (allowed to fail) (push) Has been cancelled
flybrain v0.4.0: public tree (history retained privately)
2026-09-21 15:09:46 +00:00

251 lines
6.2 KiB
C

/*
* Copyright (C) 2017 Ben Smith
*
* This software may be modified and distributed under the terms
* of the MIT license. See the LICENSE file for details.
*/
#ifndef BINJGB_EMULATOR_H_
#define BINJGB_EMULATOR_H_
#include "common.h"
#ifdef __cplusplus
extern "C" {
#endif
#define MAXIMUM_ROM_SIZE MEGABYTES(8)
#define MINIMUM_ROM_SIZE KILOBYTES(32)
#define SCREEN_WIDTH 160
#define SCREEN_HEIGHT 144
#define SCREEN_HEIGHT_WITH_VBLANK 154
#define SGB_SCREEN_WIDTH 256
#define SGB_SCREEN_HEIGHT 224
#define SGB_SCREEN_LEFT ((SGB_SCREEN_WIDTH - SCREEN_WIDTH) / 2)
#define SGB_SCREEN_RIGHT ((SGB_SCREEN_WIDTH + SCREEN_WIDTH) / 2)
#define SGB_SCREEN_TOP ((SGB_SCREEN_HEIGHT - SCREEN_HEIGHT) / 2)
#define SGB_SCREEN_BOTTOM ((SGB_SCREEN_HEIGHT + SCREEN_HEIGHT) / 2)
#define CPU_TICKS_PER_SECOND 4194304
#define APU_TICKS_PER_SECOND 2097152
#define PPU_LINE_TICKS 456
#define PPU_VBLANK_TICKS (PPU_LINE_TICKS * 10)
#define PPU_FRAME_TICKS (PPU_LINE_TICKS * SCREEN_HEIGHT_WITH_VBLANK)
#define SOUND_OUTPUT_COUNT 2
#define PALETTE_COLOR_COUNT 4
#define OBJ_COUNT 40
#define OBJ_X_OFFSET 8
#define OBJ_Y_OFFSET 16
#define BUILTIN_PALETTE_COUNT 84
#define RGBA_WHITE 0xffffffffu
#define RGBA_LIGHT_GRAY 0xffaaaaaau
#define RGBA_DARK_GRAY 0xff555555u
#define RGBA_BLACK 0xff000000u
#define MAX_APU_LOG_FRAME_WRITES 1024
typedef struct Emulator Emulator;
enum {
APU_CHANNEL1,
APU_CHANNEL2,
APU_CHANNEL3,
APU_CHANNEL4,
APU_CHANNEL_COUNT,
};
typedef void (*JoypadCallback)(struct JoypadButtons* joyp, void* user_data);
typedef struct JoypadCallbackInfo {
JoypadCallback callback;
void* user_data;
} JoypadCallbackInfo;
typedef RGBA FrameBuffer[SCREEN_WIDTH * SCREEN_HEIGHT];
typedef RGBA SgbFrameBuffer[SGB_SCREEN_WIDTH * SGB_SCREEN_HEIGHT];
typedef enum Color {
COLOR_WHITE = 0,
COLOR_LIGHT_GRAY = 1,
COLOR_DARK_GRAY = 2,
COLOR_BLACK = 3,
} Color;
typedef enum PaletteType {
PALETTE_TYPE_BGP,
PALETTE_TYPE_OBP0,
PALETTE_TYPE_OBP1,
PALETTE_TYPE_COUNT,
} PaletteType;
typedef enum {
TILE_DATA_8800_97FF = 0,
TILE_DATA_8000_8FFF = 1,
} TileDataSelect;
typedef enum TileMapSelect {
TILE_MAP_9800_9BFF = 0,
TILE_MAP_9C00_9FFF = 1,
} TileMapSelect;
typedef enum {
OBJ_SIZE_8X8 = 0,
OBJ_SIZE_8X16 = 1,
} ObjSize;
typedef enum ObjPriority {
OBJ_PRIORITY_ABOVE_BG = 0,
OBJ_PRIORITY_BEHIND_BG = 1,
} ObjPriority;
typedef enum {
TIMER_CLOCK_4096_HZ = 0,
TIMER_CLOCK_262144_HZ = 1,
TIMER_CLOCK_65536_HZ = 2,
TIMER_CLOCK_16384_HZ = 3,
} TimerClock;
/* TODO(binji): endianness */
#define REGISTER_PAIR(X, Y) \
union { \
struct { u8 Y; u8 X; }; \
u16 X##Y; \
}
typedef struct {
u8 A;
REGISTER_PAIR(B, C);
REGISTER_PAIR(D, E);
REGISTER_PAIR(H, L);
u16 SP;
u16 PC;
struct { Bool Z, N, H, C; } F;
} Registers;
typedef struct Obj {
u8 y;
u8 x;
u8 tile;
u8 byte3;
ObjPriority priority;
Bool yflip;
Bool xflip;
u8 palette;
u8 bank;
u8 cgb_palette;
} Obj;
typedef struct { Color color[PALETTE_COLOR_COUNT]; } Palette;
typedef struct PaletteRGBA {
RGBA color[PALETTE_COLOR_COUNT];
} PaletteRGBA;
typedef struct AudioBuffer {
u32 frequency; /* Sample frequency, as N samples per second */
u32 freq_counter; /* Used for resampling; [0..APU_TICKS_PER_SECOND). */
u32 divisor;
u32 frames; /* Number of frames to generate per call to emulator_run. */
u8* data; /* Unsigned 8-bit 2-channel samples @ |frequency| */
u8* end;
u8* position;
} AudioBuffer;
typedef enum CgbColorCurve {
CGB_COLOR_CURVE_NONE,
CGB_COLOR_CURVE_SAMEBOY_EMULATE_HARDWARE,
CGB_COLOR_CURVE_GAMBATTE,
} CgbColorCurve;
typedef struct EmulatorInit {
FileData rom;
int audio_frequency;
int audio_frames;
u32 random_seed;
u32 builtin_palette;
Bool force_dmg;
CgbColorCurve cgb_color_curve;
} EmulatorInit;
typedef struct EmulatorConfig {
Bool disable_sound[APU_CHANNEL_COUNT];
Bool disable_bg;
Bool disable_window;
Bool disable_obj;
Bool allow_simulataneous_dpad_opposites;
Bool log_apu_writes;
} EmulatorConfig;
typedef struct {
u8 addr;
u8 value;
} ApuWrite;
typedef struct {
ApuWrite writes[MAX_APU_LOG_FRAME_WRITES];
size_t write_count;
} ApuLog;
typedef u32 EmulatorEvent;
enum {
EMULATOR_EVENT_NEW_FRAME = 0x1,
EMULATOR_EVENT_AUDIO_BUFFER_FULL = 0x2,
EMULATOR_EVENT_UNTIL_TICKS = 0x4,
EMULATOR_EVENT_BREAKPOINT = 0x8,
EMULATOR_EVENT_INVALID_OPCODE = 0x10,
};
extern const size_t s_emulator_state_size;
Emulator* emulator_new(const EmulatorInit*);
void emulator_delete(Emulator*);
void emulator_set_joypad_buttons(Emulator*, JoypadButtons*);
void emulator_set_joypad_callback(Emulator*, JoypadCallback, void* user_data);
JoypadCallbackInfo emulator_get_joypad_callback(Emulator*);
void emulator_set_config(Emulator*, const EmulatorConfig*);
EmulatorConfig emulator_get_config(Emulator*);
FrameBuffer* emulator_get_frame_buffer(Emulator*);
SgbFrameBuffer* emulator_get_sgb_frame_buffer(Emulator*);
AudioBuffer* emulator_get_audio_buffer(Emulator*);
Ticks emulator_get_ticks(Emulator*);
u32 emulator_get_ppu_frame(Emulator*);
u32 audio_buffer_get_frames(AudioBuffer*);
void emulator_set_builtin_palette(Emulator*, u32 index);
void emulator_set_bw_palette(Emulator*, PaletteType, const PaletteRGBA*);
void emulator_set_all_bw_palettes(Emulator*, const PaletteRGBA*);
void emulator_ticks_to_time(Ticks, u32* day, u32* hr, u32* min, u32* sec,
u32* ms);
Bool emulator_was_ext_ram_updated(Emulator*);
void emulator_init_state_file_data(FileData*);
void emulator_init_ext_ram_file_data(Emulator*, FileData*);
Result emulator_read_state(Emulator*, const FileData*);
Result emulator_write_state(Emulator*, FileData*);
Result emulator_read_ext_ram(Emulator*, const FileData*);
Result emulator_write_ext_ram(Emulator*, FileData*);
#ifndef __wasm__
Result emulator_read_state_from_file(Emulator*, const char* filename);
Result emulator_write_state_to_file(Emulator*, const char* filename);
Result emulator_read_ext_ram_from_file(Emulator*, const char* filename);
Result emulator_write_ext_ram_to_file(Emulator*, const char* filename);
#endif
EmulatorEvent emulator_step(Emulator*);
EmulatorEvent emulator_run_until(Emulator*, Ticks until_ticks);
ApuLog* emulator_get_apu_log(Emulator*);
void emulator_reset_apu_log(Emulator*);
#ifdef __cplusplus
}
#endif
#endif /* BINJGB_EMULATOR_H_ */