#ifndef gb_h #define gb_h #include #include #include #include #include "apu.h" #define GB_STRUCT_VERSION 6 enum { GB_REGISTER_AF, GB_REGISTER_BC, GB_REGISTER_DE, GB_REGISTER_HL, GB_REGISTER_SP, GB_REGISTERS_16_BIT /* Count */ }; /* Todo: Actually use these! */ enum { GB_CARRY_FLAG = 16, GB_HALF_CARRY_FLAG = 32, GB_SUBSTRACT_FLAG = 64, GB_ZERO_FLAG = 128, }; enum { /* Joypad and Serial */ GB_IO_JOYP = 0x00, // Joypad (R/W) GB_IO_SB = 0x01, // Serial transfer data (R/W) GB_IO_SC = 0x02, // Serial Transfer Control (R/W) /* Missing */ /* Timers */ GB_IO_DIV = 0x04, // Divider Register (R/W) GB_IO_TIMA = 0x05, // Timer counter (R/W) GB_IO_TMA = 0x06, // Timer Modulo (R/W) GB_IO_TAC = 0x07, // Timer Control (R/W) /* Missing */ GB_IO_IF = 0x0f, // Interrupt Flag (R/W) /* Sound */ GB_IO_NR10 = 0x10, // Channel 1 Sweep register (R/W) GB_IO_NR11 = 0x11, // Channel 1 Sound length/Wave pattern duty (R/W) GB_IO_NR12 = 0x12, // Channel 1 Volume Envelope (R/W) GB_IO_NR13 = 0x13, // Channel 1 Frequency lo (Write Only) GB_IO_NR14 = 0x14, // Channel 1 Frequency hi (R/W) GB_IO_NR21 = 0x16, // Channel 2 Sound Length/Wave Pattern Duty (R/W) GB_IO_NR22 = 0x17, // Channel 2 Volume Envelope (R/W) GB_IO_NR23 = 0x18, // Channel 2 Frequency lo data (W) GB_IO_NR24 = 0x19, // Channel 2 Frequency hi data (R/W) GB_IO_NR30 = 0x1a, // Channel 3 Sound on/off (R/W) GB_IO_NR31 = 0x1b, // Channel 3 Sound Length GB_IO_NR32 = 0x1c, // Channel 3 Select output level (R/W) GB_IO_NR33 = 0x1d, // Channel 3 Frequency's lower data (W) GB_IO_NR34 = 0x1e, // Channel 3 Frequency's higher data (R/W) /* Missing */ GB_IO_NR41 = 0x20, // Channel 4 Sound Length (R/W) GB_IO_NR42 = 0x21, // Channel 4 Volume Envelope (R/W) GB_IO_NR43 = 0x22, // Channel 4 Polynomial Counter (R/W) GB_IO_NR44 = 0x23, // Channel 4 Counter/consecutive, Inital (R/W) GB_IO_NR50 = 0x24, // Channel control / ON-OFF / Volume (R/W) GB_IO_NR51 = 0x25, // Selection of Sound output terminal (R/W) GB_IO_NR52 = 0x26, // Sound on/off /* Missing */ GB_IO_WAV_START = 0x30, // Wave pattern start GB_IO_WAV_END = 0x3f, // Wave pattern end /* Graphics */ GB_IO_LCDC = 0x40, // LCD Control (R/W) GB_IO_STAT = 0x41, // LCDC Status (R/W) GB_IO_SCY = 0x42, // Scroll Y (R/W) GB_IO_SCX = 0x43, // Scroll X (R/W) GB_IO_LY = 0x44, // LCDC Y-Coordinate (R) GB_IO_LYC = 0x45, // LY Compare (R/W) GB_IO_DMA = 0x46, // DMA Transfer and Start Address (W) GB_IO_BGP = 0x47, // BG Palette Data (R/W) - Non CGB Mode Only GB_IO_OBP0 = 0x48, // Object Palette 0 Data (R/W) - Non CGB Mode Only GB_IO_OBP1 = 0x49, // Object Palette 1 Data (R/W) - Non CGB Mode Only GB_IO_WY = 0x4a, // Window Y Position (R/W) GB_IO_WX = 0x4b, // Window X Position minus 7 (R/W) /* Missing */ /* General CGB features */ GB_IO_KEY1 = 0x4d, // CGB Mode Only - Prepare Speed Switch /* Missing */ GB_IO_VBK = 0x4f, // CGB Mode Only - VRAM Bank GB_IO_BIOS = 0x50, // Write to disable the BIOS mapping /* CGB DMA */ GB_IO_HDMA1 = 0x51, // CGB Mode Only - New DMA Source, High GB_IO_HDMA2 = 0x52, // CGB Mode Only - New DMA Source, Low GB_IO_HDMA3 = 0x53, // CGB Mode Only - New DMA Destination, High GB_IO_HDMA4 = 0x54, // CGB Mode Only - New DMA Destination, Low GB_IO_HDMA5 = 0x55, // CGB Mode Only - New DMA Length/Mode/Start /* IR */ GB_IO_RP = 0x56, // CGB Mode Only - Infrared Communications Port /* Missing */ /* CGB Paletts */ GB_IO_BGPI = 0x68, // CGB Mode Only - Background Palette Index GB_IO_BGPD = 0x69, // CGB Mode Only - Background Palette Data GB_IO_OBPI = 0x6a, // CGB Mode Only - Sprite Palette Index GB_IO_OBPD = 0x6b, // CGB Mode Only - Sprite Palette Data GB_IO_DMG_EMULATION = 0x6c, // (FEh) Bit 0 (Read/Write) - CGB Mode Only /* Missing */ GB_IO_SVBK = 0x70, // CGB Mode Only - WRAM Bank GB_IO_UNKNOWN2 = 0x72, // (00h) - Bit 0-7 (Read/Write) GB_IO_UNKNOWN3 = 0x73, // (00h) - Bit 0-7 (Read/Write) GB_IO_UNKNOWN4 = 0x74, // (00h) - Bit 0-7 (Read/Write) - CGB Mode Only GB_IO_UNKNOWN5 = 0x75, // (8Fh) - Bit 4-6 (Read/Write) GB_IO_PCM_12 = 0x76, // Channels 1 and 2 amplitudes GB_IO_PCM_34 = 0x77, // Channels 3 and 4 amplitudes GB_IO_UNKNOWN8 = 0x7F, // Unknown, write only }; #define LCDC_PERIOD 70224 #define CPU_FREQUENCY 0x400000 #define DIV_CYCLES (0x100) #define FRAME_LENGTH 16742706 // in nanoseconds typedef enum { GB_LOG_BOLD = 1, GB_LOG_DASHED_UNDERLINE = 2, GB_LOG_UNDERLINE = 4, GB_LOG_UNDERLINE_MASK = GB_LOG_DASHED_UNDERLINE | GB_LOG_UNDERLINE } gb_log_attributes; struct GB_gameboy_s; typedef struct GB_gameboy_s GB_gameboy_t; typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb); typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, gb_log_attributes attributes); typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb); typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, unsigned char r, unsigned char g, unsigned char b); typedef struct { enum { NO_MBC, MBC1, MBC2, MBC3, MBC4, // Does this exist??? MBC5, } mbc_type; bool has_ram; bool has_battery; bool has_rtc; bool has_rumble; } GB_cartridge_t; typedef struct GB_gameboy_s{ uintptr_t magic; // States are currently platform dependent int version; // and version dependent /* Registers */ unsigned short pc; unsigned short registers[GB_REGISTERS_16_BIT]; bool ime; unsigned char interrupt_enable; /* CPU and General Hardware Flags*/ bool cgb_mode; bool is_cgb; bool cgb_double_speed; bool halted; bool stopped; /* HDMA */ bool hdma_on; bool hdma_on_hblank; unsigned char hdma_steps_left; unsigned short hdma_cycles; unsigned short hdma_current_src, hdma_current_dest; /* Memory */ unsigned char *rom; size_t rom_size; unsigned short mbc_rom_bank; const GB_cartridge_t *cartridge_type; unsigned char *mbc_ram; unsigned char mbc_ram_bank; size_t mbc_ram_size; bool mbc_ram_enable; bool mbc_ram_banking; unsigned char *ram; unsigned long ram_size; // Different between CGB and DMG unsigned char cgb_ram_bank; unsigned char hram[0xFFFF - 0xFF80]; unsigned char io_registers[0x80]; /* Video Display */ unsigned char *vram; unsigned long vram_size; // Different between CGB and DMG unsigned char cgb_vram_bank; unsigned char oam[0xA0]; unsigned char background_palletes_data[0x40]; unsigned char sprite_palletes_data[0x40]; uint32_t background_palletes_rgb[0x20]; uint32_t sprite_palletes_rgb[0x20]; bool ly151_bug_oam; bool ly151_bug_hblank; signed short previous_lcdc_x; signed short line_x_bias; bool effective_window_enabled; unsigned char effective_window_y; unsigned char bios[0x900]; bool bios_finished; /* Timing */ signed long last_vblank; unsigned long display_cycles; unsigned long div_cycles; unsigned long tima_cycles; unsigned long dma_cycles; double apu_cycles; /* APU */ GB_apu_t apu; int16_t *audio_buffer; unsigned int buffer_size; unsigned int sample_rate; unsigned int audio_position; volatile bool audio_copy_in_progress; bool audio_stream_started; // detects first copy request to minimize lag /* I/O */ uint32_t *screen; GB_vblank_callback_t vblank_callback; bool keys[8]; /* RTC */ union { struct { unsigned char rtc_seconds; unsigned char rtc_minutes; unsigned char rtc_hours; unsigned char rtc_days; unsigned char rtc_high; }; unsigned char rtc_data[5]; }; time_t last_rtc_second; /* Unsaved User */ struct {} first_unsaved_data; bool turbo; bool debug_stopped; unsigned short breakpoint; GB_log_callback_t log_callback; GB_input_callback_t input_callback; GB_rgb_encode_callback_t rgb_encode_callback; void *user_data; int debug_call_depth; bool debug_fin_command, debug_next_command; } GB_gameboy_t; #ifndef __printflike /* Missing from Linux headers. */ #define __printflike(fmtarg, firstvararg) \ __attribute__((__format__ (__printf__, fmtarg, firstvararg))) #endif void gb_init(GB_gameboy_t *gb); void gb_init_cgb(GB_gameboy_t *gb); void gb_free(GB_gameboy_t *gb); int gb_load_bios(GB_gameboy_t *gb, const char *path); int gb_load_rom(GB_gameboy_t *gb, const char *path); int gb_save_battery(GB_gameboy_t *gb, const char *path); void gb_load_battery(GB_gameboy_t *gb, const char *path); int gb_save_state(GB_gameboy_t *gb, const char *path); int gb_load_state(GB_gameboy_t *gb, const char *path); void gb_run(GB_gameboy_t *gb); void gb_set_pixels_output(GB_gameboy_t *gb, uint32_t *output); void gb_set_vblank_callback(GB_gameboy_t *gb, GB_vblank_callback_t callback); void gb_set_log_callback(GB_gameboy_t *gb, GB_log_callback_t callback); void gb_log(GB_gameboy_t *gb, const char *fmt, ...) __printflike(2, 3); void gb_attributed_log(GB_gameboy_t *gb, gb_log_attributes attributes, const char *fmt, ...) __printflike(3, 4); void gb_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback); void gb_set_sample_rate(GB_gameboy_t *gb, unsigned int sample_rate); void gb_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback); #endif /* gb_h */