2016-06-18 17:29:11 +00:00
|
|
|
|
#ifndef GB_h
|
|
|
|
|
#define GB_h
|
2019-08-16 14:38:43 +00:00
|
|
|
|
#define typeof __typeof__
|
2016-03-30 20:07:55 +00:00
|
|
|
|
#include <stdbool.h>
|
|
|
|
|
#include <stdint.h>
|
|
|
|
|
#include <time.h>
|
2017-04-17 17:16:17 +00:00
|
|
|
|
|
|
|
|
|
#include "gb_struct_def.h"
|
2017-06-13 21:23:34 +00:00
|
|
|
|
#include "save_state.h"
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
2017-04-17 17:16:17 +00:00
|
|
|
|
#include "apu.h"
|
|
|
|
|
#include "camera.h"
|
|
|
|
|
#include "debugger.h"
|
|
|
|
|
#include "display.h"
|
|
|
|
|
#include "joypad.h"
|
|
|
|
|
#include "mbc.h"
|
2017-10-12 16:42:30 +00:00
|
|
|
|
#include "memory.h"
|
2017-04-17 17:16:17 +00:00
|
|
|
|
#include "printer.h"
|
|
|
|
|
#include "timing.h"
|
2018-02-10 12:42:14 +00:00
|
|
|
|
#include "rewind.h"
|
2019-01-11 22:42:16 +00:00
|
|
|
|
#include "sm83_cpu.h"
|
2017-04-17 17:16:17 +00:00
|
|
|
|
#include "symbol_hash.h"
|
2018-11-10 23:16:32 +00:00
|
|
|
|
#include "sgb.h"
|
2020-04-09 17:11:55 +00:00
|
|
|
|
#include "cheats.h"
|
2020-04-29 13:06:11 +00:00
|
|
|
|
#include "rumble.h"
|
2020-09-19 16:31:24 +00:00
|
|
|
|
#include "workboy.h"
|
2016-06-11 11:52:09 +00:00
|
|
|
|
|
2018-06-16 10:59:33 +00:00
|
|
|
|
#define GB_STRUCT_VERSION 13
|
|
|
|
|
|
2018-07-14 18:52:54 +00:00
|
|
|
|
#define GB_MODEL_FAMILY_MASK 0xF00
|
|
|
|
|
#define GB_MODEL_DMG_FAMILY 0x000
|
|
|
|
|
#define GB_MODEL_MGB_FAMILY 0x100
|
|
|
|
|
#define GB_MODEL_CGB_FAMILY 0x200
|
2021-01-16 12:51:06 +00:00
|
|
|
|
#define GB_MODEL_PAL_BIT 0x40
|
|
|
|
|
#define GB_MODEL_NO_SFC_BIT 0x80
|
|
|
|
|
|
|
|
|
|
#define GB_MODEL_PAL_BIT_OLD 0x1000
|
|
|
|
|
#define GB_MODEL_NO_SFC_BIT_OLD 0x2000
|
2019-05-10 18:51:11 +00:00
|
|
|
|
|
2019-07-15 20:02:58 +00:00
|
|
|
|
#ifdef GB_INTERNAL
|
2019-05-10 18:51:11 +00:00
|
|
|
|
#if __clang__
|
2021-02-22 12:45:30 +00:00
|
|
|
|
#define unrolled _Pragma("unroll")
|
2020-04-25 11:46:01 +00:00
|
|
|
|
#elif __GNUC__ >= 8
|
2021-02-22 12:45:30 +00:00
|
|
|
|
#define unrolled _Pragma("GCC unroll 8")
|
2019-05-10 18:51:11 +00:00
|
|
|
|
#else
|
2021-02-22 12:45:30 +00:00
|
|
|
|
#define unrolled
|
2019-05-10 18:51:11 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2018-06-16 10:59:33 +00:00
|
|
|
|
#endif
|
2018-07-14 18:52:54 +00:00
|
|
|
|
|
2018-11-02 23:31:14 +00:00
|
|
|
|
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
|
|
|
|
|
#define GB_BIG_ENDIAN
|
|
|
|
|
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
|
|
|
|
#define GB_LITTLE_ENDIAN
|
|
|
|
|
#else
|
|
|
|
|
#error Unable to detect endianess
|
|
|
|
|
#endif
|
|
|
|
|
|
2021-03-28 23:47:57 +00:00
|
|
|
|
#ifdef GB_INTERNAL
|
|
|
|
|
/* Todo: similar macros are everywhere, clean this up and remove direct calls to bswap */
|
|
|
|
|
#ifdef GB_BIG_ENDIAN
|
|
|
|
|
#define LE16(x) __builtin_bswap16(x)
|
|
|
|
|
#define LE32(x) __builtin_bswap32(x)
|
|
|
|
|
#define LE64(x) __builtin_bswap64(x)
|
|
|
|
|
#define BE16(x) (x)
|
|
|
|
|
#define BE32(x) (x)
|
|
|
|
|
#define BE64(x) (x)
|
|
|
|
|
#else
|
|
|
|
|
#define LE16(x) (x)
|
|
|
|
|
#define LE32(x) (x)
|
|
|
|
|
#define LE64(x) (x)
|
|
|
|
|
#define BE16(x) __builtin_bswap16(x)
|
|
|
|
|
#define BE32(x) __builtin_bswap32(x)
|
|
|
|
|
#define BE64(x) __builtin_bswap64(x)
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-06-22 20:14:32 +00:00
|
|
|
|
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 8)
|
|
|
|
|
#define __builtin_bswap16(x) ({ typeof(x) _x = (x); _x >> 8 | _x << 8; })
|
|
|
|
|
#endif
|
|
|
|
|
|
2020-01-29 12:19:11 +00:00
|
|
|
|
typedef struct {
|
|
|
|
|
struct {
|
2020-04-24 17:37:57 +00:00
|
|
|
|
uint8_t r, g, b;
|
2020-01-29 12:19:11 +00:00
|
|
|
|
} colors[5];
|
|
|
|
|
} GB_palette_t;
|
|
|
|
|
|
|
|
|
|
extern const GB_palette_t GB_PALETTE_GREY;
|
|
|
|
|
extern const GB_palette_t GB_PALETTE_DMG;
|
|
|
|
|
extern const GB_palette_t GB_PALETTE_MGB;
|
|
|
|
|
extern const GB_palette_t GB_PALETTE_GBL;
|
|
|
|
|
|
2018-11-02 23:31:14 +00:00
|
|
|
|
typedef union {
|
|
|
|
|
struct {
|
|
|
|
|
uint8_t seconds;
|
|
|
|
|
uint8_t minutes;
|
|
|
|
|
uint8_t hours;
|
|
|
|
|
uint8_t days;
|
|
|
|
|
uint8_t high;
|
|
|
|
|
};
|
|
|
|
|
uint8_t data[5];
|
|
|
|
|
} GB_rtc_time_t;
|
|
|
|
|
|
2021-04-12 20:36:35 +00:00
|
|
|
|
typedef struct __attribute__((packed)) {
|
|
|
|
|
uint64_t last_rtc_second;
|
|
|
|
|
uint16_t minutes;
|
|
|
|
|
uint16_t days;
|
|
|
|
|
uint16_t alarm_minutes, alarm_days;
|
|
|
|
|
uint8_t alarm_enabled;
|
|
|
|
|
} GB_huc3_rtc_time_t;
|
|
|
|
|
|
2018-07-14 18:52:54 +00:00
|
|
|
|
typedef enum {
|
2018-06-16 10:59:33 +00:00
|
|
|
|
// GB_MODEL_DMG_0 = 0x000,
|
|
|
|
|
// GB_MODEL_DMG_A = 0x001,
|
|
|
|
|
GB_MODEL_DMG_B = 0x002,
|
|
|
|
|
// GB_MODEL_DMG_C = 0x003,
|
2018-11-10 23:16:32 +00:00
|
|
|
|
GB_MODEL_SGB = 0x004,
|
|
|
|
|
GB_MODEL_SGB_NTSC = GB_MODEL_SGB,
|
2019-07-15 17:47:16 +00:00
|
|
|
|
GB_MODEL_SGB_PAL = GB_MODEL_SGB | GB_MODEL_PAL_BIT,
|
2019-10-08 12:10:24 +00:00
|
|
|
|
GB_MODEL_SGB_NTSC_NO_SFC = GB_MODEL_SGB | GB_MODEL_NO_SFC_BIT,
|
|
|
|
|
GB_MODEL_SGB_NO_SFC = GB_MODEL_SGB_NTSC_NO_SFC,
|
|
|
|
|
GB_MODEL_SGB_PAL_NO_SFC = GB_MODEL_SGB | GB_MODEL_NO_SFC_BIT | GB_MODEL_PAL_BIT,
|
2018-06-16 10:59:33 +00:00
|
|
|
|
// GB_MODEL_MGB = 0x100,
|
2018-11-10 23:16:32 +00:00
|
|
|
|
GB_MODEL_SGB2 = 0x101,
|
2019-07-15 17:47:16 +00:00
|
|
|
|
GB_MODEL_SGB2_NO_SFC = GB_MODEL_SGB2 | GB_MODEL_NO_SFC_BIT,
|
2018-06-16 10:59:33 +00:00
|
|
|
|
// GB_MODEL_CGB_0 = 0x200,
|
|
|
|
|
// GB_MODEL_CGB_A = 0x201,
|
|
|
|
|
// GB_MODEL_CGB_B = 0x202,
|
2018-07-03 18:43:46 +00:00
|
|
|
|
GB_MODEL_CGB_C = 0x203,
|
2018-06-16 10:59:33 +00:00
|
|
|
|
// GB_MODEL_CGB_D = 0x204,
|
|
|
|
|
GB_MODEL_CGB_E = 0x205,
|
|
|
|
|
GB_MODEL_AGB = 0x206,
|
|
|
|
|
} GB_model_t;
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
|
|
|
|
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,
|
2020-01-03 19:11:45 +00:00
|
|
|
|
GB_SUBTRACT_FLAG = 64,
|
2016-03-30 20:07:55 +00:00
|
|
|
|
GB_ZERO_FLAG = 128,
|
|
|
|
|
};
|
|
|
|
|
|
2020-02-08 11:28:46 +00:00
|
|
|
|
typedef enum {
|
|
|
|
|
GB_BORDER_SGB,
|
|
|
|
|
GB_BORDER_NEVER,
|
|
|
|
|
GB_BORDER_ALWAYS,
|
|
|
|
|
} GB_border_mode_t;
|
|
|
|
|
|
2016-03-30 20:07:55 +00:00
|
|
|
|
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)
|
2017-07-27 20:11:33 +00:00
|
|
|
|
/* NR20 does not exist */
|
2016-03-30 20:07:55 +00:00
|
|
|
|
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)
|
2017-07-27 20:11:33 +00:00
|
|
|
|
/* NR40 does not exist */
|
2016-03-30 20:07:55 +00:00
|
|
|
|
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)
|
2016-04-05 20:21:51 +00:00
|
|
|
|
// Has some undocumented compatibility flags written at boot.
|
|
|
|
|
// Unfortunately it is not readable or writable after boot has finished, so research of this
|
|
|
|
|
// register is quite limited. The value written to this register, however, can be controlled
|
|
|
|
|
// in some cases.
|
2020-04-08 23:36:27 +00:00
|
|
|
|
GB_IO_KEY0 = 0x4c,
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
|
|
|
|
/* General CGB features */
|
|
|
|
|
GB_IO_KEY1 = 0x4d, // CGB Mode Only - Prepare Speed Switch
|
|
|
|
|
|
|
|
|
|
/* Missing */
|
|
|
|
|
|
|
|
|
|
GB_IO_VBK = 0x4f, // CGB Mode Only - VRAM Bank
|
2020-04-08 23:36:27 +00:00
|
|
|
|
GB_IO_BANK = 0x50, // Write to disable the BIOS mapping
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
|
|
|
|
/* 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
|
2020-04-08 23:36:27 +00:00
|
|
|
|
GB_IO_OPRI = 0x6c, // Affects object priority (X based or index based)
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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
|
2016-06-18 17:29:11 +00:00
|
|
|
|
} GB_log_attributes;
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
2020-01-29 18:29:30 +00:00
|
|
|
|
typedef enum {
|
|
|
|
|
GB_BOOT_ROM_DMG0,
|
|
|
|
|
GB_BOOT_ROM_DMG,
|
|
|
|
|
GB_BOOT_ROM_MGB,
|
|
|
|
|
GB_BOOT_ROM_SGB,
|
|
|
|
|
GB_BOOT_ROM_SGB2,
|
|
|
|
|
GB_BOOT_ROM_CGB0,
|
|
|
|
|
GB_BOOT_ROM_CGB,
|
|
|
|
|
GB_BOOT_ROM_AGB,
|
|
|
|
|
} GB_boot_rom_t;
|
|
|
|
|
|
2021-02-25 20:12:14 +00:00
|
|
|
|
typedef enum {
|
|
|
|
|
GB_RTC_MODE_SYNC_TO_HOST,
|
|
|
|
|
GB_RTC_MODE_ACCURATE,
|
|
|
|
|
} GB_rtc_mode_t;
|
|
|
|
|
|
2017-04-17 17:16:17 +00:00
|
|
|
|
#ifdef GB_INTERNAL
|
|
|
|
|
#define LCDC_PERIOD 70224
|
|
|
|
|
#define CPU_FREQUENCY 0x400000
|
2018-11-10 23:16:32 +00:00
|
|
|
|
#define SGB_NTSC_FREQUENCY (21477272 / 5)
|
|
|
|
|
#define SGB_PAL_FREQUENCY (21281370 / 5)
|
2017-04-17 17:16:17 +00:00
|
|
|
|
#define DIV_CYCLES (0x100)
|
|
|
|
|
#define INTERNAL_DIV_CYCLES (0x40000)
|
2017-10-12 14:22:22 +00:00
|
|
|
|
|
|
|
|
|
#if !defined(MIN)
|
2020-04-24 17:37:57 +00:00
|
|
|
|
#define MIN(A, B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __a : __b; })
|
2017-10-12 14:22:22 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#if !defined(MAX)
|
2020-04-24 17:37:57 +00:00
|
|
|
|
#define MAX(A, B) ({ __typeof__(A) __a = (A); __typeof__(B) __b = (B); __a < __b ? __b : __a; })
|
2017-10-12 14:22:22 +00:00
|
|
|
|
#endif
|
2017-04-17 17:16:17 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
2016-03-30 20:07:55 +00:00
|
|
|
|
typedef void (*GB_vblank_callback_t)(GB_gameboy_t *gb);
|
2016-06-18 17:29:11 +00:00
|
|
|
|
typedef void (*GB_log_callback_t)(GB_gameboy_t *gb, const char *string, GB_log_attributes attributes);
|
2016-03-30 20:07:55 +00:00
|
|
|
|
typedef char *(*GB_input_callback_t)(GB_gameboy_t *gb);
|
2016-06-18 17:29:11 +00:00
|
|
|
|
typedef uint32_t (*GB_rgb_encode_callback_t)(GB_gameboy_t *gb, uint8_t r, uint8_t g, uint8_t b);
|
2020-11-20 22:52:54 +00:00
|
|
|
|
typedef void (*GB_infrared_callback_t)(GB_gameboy_t *gb, bool on);
|
2019-10-19 16:26:04 +00:00
|
|
|
|
typedef void (*GB_rumble_callback_t)(GB_gameboy_t *gb, double rumble_amplitude);
|
2019-03-15 12:36:10 +00:00
|
|
|
|
typedef void (*GB_serial_transfer_bit_start_callback_t)(GB_gameboy_t *gb, bool bit_to_send);
|
|
|
|
|
typedef bool (*GB_serial_transfer_bit_end_callback_t)(GB_gameboy_t *gb);
|
2019-06-07 15:27:25 +00:00
|
|
|
|
typedef void (*GB_update_input_hint_callback_t)(GB_gameboy_t *gb);
|
2019-07-15 19:01:41 +00:00
|
|
|
|
typedef void (*GB_joyp_write_callback_t)(GB_gameboy_t *gb, uint8_t value);
|
2019-07-16 17:44:27 +00:00
|
|
|
|
typedef void (*GB_icd_pixel_callback_t)(GB_gameboy_t *gb, uint8_t row);
|
|
|
|
|
typedef void (*GB_icd_hreset_callback_t)(GB_gameboy_t *gb);
|
2019-07-15 20:02:58 +00:00
|
|
|
|
typedef void (*GB_icd_vreset_callback_t)(GB_gameboy_t *gb);
|
2020-01-29 18:29:30 +00:00
|
|
|
|
typedef void (*GB_boot_rom_load_callback_t)(GB_gameboy_t *gb, GB_boot_rom_t type);
|
2016-11-11 23:58:53 +00:00
|
|
|
|
|
2016-07-06 21:29:25 +00:00
|
|
|
|
struct GB_breakpoint_s;
|
|
|
|
|
struct GB_watchpoint_s;
|
|
|
|
|
|
2018-03-03 13:47:36 +00:00
|
|
|
|
typedef struct {
|
|
|
|
|
uint8_t pixel; // Color, 0-3
|
|
|
|
|
uint8_t palette; // Palette, 0 - 7 (CGB); 0-1 in DMG (or just 0 for BG)
|
|
|
|
|
uint8_t priority; // Sprite priority – 0 in DMG, OAM index in CGB
|
|
|
|
|
bool bg_priority; // For sprite FIFO – the BG priority bit. For the BG FIFO – the CGB attributes priority bit
|
|
|
|
|
} GB_fifo_item_t;
|
|
|
|
|
|
2018-04-06 15:26:04 +00:00
|
|
|
|
#define GB_FIFO_LENGTH 16
|
2018-03-03 13:47:36 +00:00
|
|
|
|
typedef struct {
|
2018-04-06 15:26:04 +00:00
|
|
|
|
GB_fifo_item_t fifo[GB_FIFO_LENGTH];
|
2018-03-03 13:47:36 +00:00
|
|
|
|
uint8_t read_end;
|
|
|
|
|
uint8_t write_end;
|
|
|
|
|
} GB_fifo_t;
|
|
|
|
|
|
2021-04-02 16:08:03 +00:00
|
|
|
|
typedef struct {
|
|
|
|
|
uint32_t magic;
|
|
|
|
|
uint8_t track_count;
|
|
|
|
|
uint8_t first_track;
|
|
|
|
|
uint16_t load_address;
|
|
|
|
|
uint16_t init_address;
|
|
|
|
|
uint16_t play_address;
|
|
|
|
|
uint16_t sp;
|
|
|
|
|
uint8_t TMA;
|
|
|
|
|
uint8_t TAC;
|
|
|
|
|
char title[32];
|
|
|
|
|
char author[32];
|
|
|
|
|
char copyright[32];
|
|
|
|
|
} GB_gbs_header_t;
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
uint8_t track_count;
|
|
|
|
|
uint8_t first_track;
|
|
|
|
|
char title[33];
|
|
|
|
|
char author[33];
|
|
|
|
|
char copyright[33];
|
|
|
|
|
} GB_gbs_info_t;
|
|
|
|
|
|
2016-06-11 11:52:09 +00:00
|
|
|
|
/* When state saving, each section is dumped independently of other sections.
|
|
|
|
|
This allows adding data to the end of the section without worrying about future compatibility.
|
2016-06-18 17:29:11 +00:00
|
|
|
|
Some other changes might be "safe" as well.
|
|
|
|
|
This struct is not packed, but dumped sections exclusively use types that have the same alignment in both 32 and 64
|
|
|
|
|
bit platforms. */
|
|
|
|
|
|
2017-04-17 17:16:17 +00:00
|
|
|
|
#ifdef GB_INTERNAL
|
|
|
|
|
struct GB_gameboy_s {
|
|
|
|
|
#else
|
|
|
|
|
struct GB_gameboy_internal_s {
|
|
|
|
|
#endif
|
2016-06-11 11:52:09 +00:00
|
|
|
|
GB_SECTION(header,
|
2016-06-18 17:29:11 +00:00
|
|
|
|
/* The magic makes sure a state file is:
|
|
|
|
|
- Indeed a SameBoy state file.
|
|
|
|
|
- Has the same endianess has the current platform. */
|
2017-02-24 13:14:00 +00:00
|
|
|
|
volatile uint32_t magic;
|
2016-06-18 17:29:11 +00:00
|
|
|
|
/* The version field makes sure we don't load save state files with a completely different structure.
|
|
|
|
|
This happens when struct fields are removed/resized in an backward incompatible manner. */
|
|
|
|
|
uint32_t version;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
GB_SECTION(core_state,
|
|
|
|
|
/* Registers */
|
2016-06-18 17:29:11 +00:00
|
|
|
|
uint16_t pc;
|
2016-10-21 21:49:32 +00:00
|
|
|
|
union {
|
|
|
|
|
uint16_t registers[GB_REGISTERS_16_BIT];
|
|
|
|
|
struct {
|
|
|
|
|
uint16_t af,
|
|
|
|
|
bc,
|
|
|
|
|
de,
|
|
|
|
|
hl,
|
|
|
|
|
sp;
|
|
|
|
|
};
|
|
|
|
|
struct {
|
2018-11-02 23:31:14 +00:00
|
|
|
|
#ifdef GB_BIG_ENDIAN
|
2016-10-21 21:49:32 +00:00
|
|
|
|
uint8_t a, f,
|
|
|
|
|
b, c,
|
|
|
|
|
d, e,
|
|
|
|
|
h, l;
|
2018-11-02 23:31:14 +00:00
|
|
|
|
#else
|
2016-10-21 21:49:32 +00:00
|
|
|
|
uint8_t f, a,
|
|
|
|
|
c, b,
|
|
|
|
|
e, d,
|
|
|
|
|
l, h;
|
|
|
|
|
#endif
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
};
|
2016-08-05 13:36:38 +00:00
|
|
|
|
uint8_t ime;
|
2016-06-18 17:29:11 +00:00
|
|
|
|
uint8_t interrupt_enable;
|
|
|
|
|
uint8_t cgb_ram_bank;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
|
|
|
|
|
/* CPU and General Hardware Flags*/
|
2018-06-16 10:59:33 +00:00
|
|
|
|
GB_model_t model;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
bool cgb_mode;
|
|
|
|
|
bool cgb_double_speed;
|
|
|
|
|
bool halted;
|
|
|
|
|
bool stopped;
|
2016-06-18 17:29:11 +00:00
|
|
|
|
bool boot_rom_finished;
|
2018-02-25 20:32:41 +00:00
|
|
|
|
bool ime_toggle; /* ei has delayed a effect.*/
|
2016-09-21 22:51:09 +00:00
|
|
|
|
bool halt_bug;
|
2018-05-12 19:13:52 +00:00
|
|
|
|
bool just_halted;
|
2016-07-18 19:05:11 +00:00
|
|
|
|
|
2017-01-13 19:27:37 +00:00
|
|
|
|
/* Misc state */
|
2016-07-18 19:05:11 +00:00
|
|
|
|
bool infrared_input;
|
2017-01-13 19:27:37 +00:00
|
|
|
|
GB_printer_t printer;
|
2018-07-03 18:43:46 +00:00
|
|
|
|
uint8_t extra_oam[0xff00 - 0xfea0];
|
2019-06-07 16:18:07 +00:00
|
|
|
|
uint32_t ram_size; // Different between CGB and DMG
|
2020-09-19 16:31:24 +00:00
|
|
|
|
GB_workboy_t workboy;
|
2020-11-20 22:52:54 +00:00
|
|
|
|
|
|
|
|
|
int32_t ir_sensor;
|
|
|
|
|
bool effective_ir_input;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
);
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
2016-08-03 20:31:10 +00:00
|
|
|
|
/* DMA and HDMA */
|
|
|
|
|
GB_SECTION(dma,
|
2016-06-11 11:52:09 +00:00
|
|
|
|
bool hdma_on;
|
|
|
|
|
bool hdma_on_hblank;
|
2016-06-18 17:29:11 +00:00
|
|
|
|
uint8_t hdma_steps_left;
|
2018-04-13 11:41:39 +00:00
|
|
|
|
int16_t hdma_cycles; // in 8MHz units
|
2016-06-18 17:29:11 +00:00
|
|
|
|
uint16_t hdma_current_src, hdma_current_dest;
|
2016-08-03 20:31:10 +00:00
|
|
|
|
|
|
|
|
|
uint8_t dma_steps_left;
|
|
|
|
|
uint8_t dma_current_dest;
|
|
|
|
|
uint16_t dma_current_src;
|
2016-08-06 10:57:38 +00:00
|
|
|
|
int16_t dma_cycles;
|
2016-08-06 11:24:43 +00:00
|
|
|
|
bool is_dma_restarting;
|
2018-02-25 20:32:41 +00:00
|
|
|
|
uint8_t last_opcode_read; /* Required to emulte HDMA reads from Exxx */
|
2018-03-19 18:01:31 +00:00
|
|
|
|
bool hdma_starting;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* MBC */
|
|
|
|
|
GB_SECTION(mbc,
|
2016-06-18 17:29:11 +00:00
|
|
|
|
uint16_t mbc_rom_bank;
|
|
|
|
|
uint8_t mbc_ram_bank;
|
|
|
|
|
uint32_t mbc_ram_size;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
bool mbc_ram_enable;
|
2016-07-09 14:34:55 +00:00
|
|
|
|
union {
|
|
|
|
|
struct {
|
|
|
|
|
uint8_t bank_low:5;
|
2017-06-20 22:07:11 +00:00
|
|
|
|
uint8_t bank_high:2;
|
2016-07-09 14:34:55 +00:00
|
|
|
|
uint8_t mode:1;
|
|
|
|
|
} mbc1;
|
|
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
uint8_t rom_bank:4;
|
|
|
|
|
} mbc2;
|
|
|
|
|
|
|
|
|
|
struct {
|
2020-04-08 16:07:29 +00:00
|
|
|
|
uint8_t rom_bank:8;
|
|
|
|
|
uint8_t ram_bank:3;
|
2016-07-09 14:34:55 +00:00
|
|
|
|
} mbc3;
|
|
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
uint8_t rom_bank_low;
|
|
|
|
|
uint8_t rom_bank_high:1;
|
|
|
|
|
uint8_t ram_bank:4;
|
|
|
|
|
} mbc5;
|
2017-02-16 19:07:35 +00:00
|
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
uint8_t bank_low:6;
|
|
|
|
|
uint8_t bank_high:3;
|
2020-05-22 21:05:43 +00:00
|
|
|
|
bool mode:1;
|
2020-05-22 21:09:30 +00:00
|
|
|
|
bool ir_mode:1;
|
2017-02-16 19:07:35 +00:00
|
|
|
|
} huc1;
|
2016-10-17 15:51:43 +00:00
|
|
|
|
|
|
|
|
|
struct {
|
2020-05-16 20:27:17 +00:00
|
|
|
|
uint8_t rom_bank:7;
|
|
|
|
|
uint8_t padding:1;
|
|
|
|
|
uint8_t ram_bank:4;
|
2016-10-17 15:51:43 +00:00
|
|
|
|
} huc3;
|
2016-07-09 14:34:55 +00:00
|
|
|
|
};
|
|
|
|
|
uint16_t mbc_rom0_bank; /* For some MBC1 wirings. */
|
2016-10-02 00:40:11 +00:00
|
|
|
|
bool camera_registers_mapped;
|
2016-10-02 14:14:58 +00:00
|
|
|
|
uint8_t camera_registers[0x36];
|
2021-04-10 20:56:41 +00:00
|
|
|
|
uint8_t rumble_strength;
|
2020-05-13 19:21:31 +00:00
|
|
|
|
bool cart_ir;
|
2020-05-16 20:27:17 +00:00
|
|
|
|
|
2021-04-10 20:56:41 +00:00
|
|
|
|
// TODO: move to huc3/mbc3/tpp1 struct when breaking save compat
|
2020-05-16 20:27:17 +00:00
|
|
|
|
uint8_t huc3_mode;
|
|
|
|
|
uint8_t huc3_access_index;
|
|
|
|
|
uint16_t huc3_minutes, huc3_days;
|
2020-05-23 11:50:54 +00:00
|
|
|
|
uint16_t huc3_alarm_minutes, huc3_alarm_days;
|
|
|
|
|
bool huc3_alarm_enabled;
|
2020-05-16 20:27:17 +00:00
|
|
|
|
uint8_t huc3_read;
|
|
|
|
|
uint8_t huc3_access_flags;
|
2020-08-04 18:32:27 +00:00
|
|
|
|
bool mbc3_rtc_mapped;
|
2021-04-10 20:56:41 +00:00
|
|
|
|
uint16_t tpp1_rom_bank;
|
|
|
|
|
uint8_t tpp1_ram_bank;
|
|
|
|
|
uint8_t tpp1_mode;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* HRAM and HW Registers */
|
|
|
|
|
GB_SECTION(hram,
|
2016-06-18 17:29:11 +00:00
|
|
|
|
uint8_t hram[0xFFFF - 0xFF80];
|
|
|
|
|
uint8_t io_registers[0x80];
|
2016-06-11 11:52:09 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Timing */
|
|
|
|
|
GB_SECTION(timing,
|
2018-02-24 22:48:45 +00:00
|
|
|
|
GB_UNIT(display);
|
2018-02-23 11:16:05 +00:00
|
|
|
|
GB_UNIT(div);
|
2018-06-09 12:11:20 +00:00
|
|
|
|
uint16_t div_counter;
|
2016-08-06 10:56:29 +00:00
|
|
|
|
uint8_t tima_reload_state; /* After TIMA overflows, it becomes 0 for 4 cycles before actually reloading. */
|
2017-09-22 21:25:21 +00:00
|
|
|
|
uint16_t serial_cycles;
|
2017-06-23 14:58:04 +00:00
|
|
|
|
uint16_t serial_length;
|
2019-01-12 23:09:41 +00:00
|
|
|
|
uint8_t double_speed_alignment;
|
2019-03-15 12:36:10 +00:00
|
|
|
|
uint8_t serial_count;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
);
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
2016-06-11 11:52:09 +00:00
|
|
|
|
/* APU */
|
|
|
|
|
GB_SECTION(apu,
|
|
|
|
|
GB_apu_t apu;
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* RTC */
|
|
|
|
|
GB_SECTION(rtc,
|
2018-11-02 23:31:14 +00:00
|
|
|
|
GB_rtc_time_t rtc_real, rtc_latched;
|
|
|
|
|
uint64_t last_rtc_second;
|
2016-08-21 19:33:57 +00:00
|
|
|
|
bool rtc_latch;
|
2021-02-25 20:12:14 +00:00
|
|
|
|
uint32_t rtc_cycles;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Video Display */
|
|
|
|
|
GB_SECTION(video,
|
2016-06-18 17:29:11 +00:00
|
|
|
|
uint32_t vram_size; // Different between CGB and DMG
|
|
|
|
|
uint8_t cgb_vram_bank;
|
|
|
|
|
uint8_t oam[0xA0];
|
2017-04-19 20:26:39 +00:00
|
|
|
|
uint8_t background_palettes_data[0x40];
|
|
|
|
|
uint8_t sprite_palettes_data[0x40];
|
2018-02-24 22:48:45 +00:00
|
|
|
|
uint8_t position_in_line;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
bool stat_interrupt_line;
|
2016-06-18 17:29:11 +00:00
|
|
|
|
uint8_t effective_scx;
|
2020-02-23 21:16:45 +00:00
|
|
|
|
uint8_t window_y;
|
2017-06-03 17:06:52 +00:00
|
|
|
|
/* The LCDC will skip the first frame it renders after turning it on.
|
|
|
|
|
On the CGB, a frame is not skipped if the previous frame was skipped as well.
|
2017-06-03 13:42:42 +00:00
|
|
|
|
See https://www.reddit.com/r/EmuDev/comments/6exyxu/ */
|
2019-07-16 17:44:27 +00:00
|
|
|
|
|
|
|
|
|
/* TODO: Drop this and properly emulate the dropped vreset signal*/
|
2017-06-03 13:42:42 +00:00
|
|
|
|
enum {
|
2017-06-03 17:06:52 +00:00
|
|
|
|
GB_FRAMESKIP_LCD_TURNED_ON, // On a DMG, the LCD renders a blank screen during this state,
|
|
|
|
|
// on a CGB, the previous frame is repeated (which might be
|
|
|
|
|
// blank if the LCD was off for more than a few cycles)
|
|
|
|
|
GB_FRAMESKIP_FIRST_FRAME_SKIPPED, // This state is 'skipped' when emulating a DMG
|
2017-06-03 13:42:42 +00:00
|
|
|
|
GB_FRAMESKIP_SECOND_FRAME_RENDERED,
|
|
|
|
|
} frame_skip_state;
|
2017-06-18 18:27:07 +00:00
|
|
|
|
bool oam_read_blocked;
|
|
|
|
|
bool vram_read_blocked;
|
|
|
|
|
bool oam_write_blocked;
|
|
|
|
|
bool vram_write_blocked;
|
2020-02-28 20:36:51 +00:00
|
|
|
|
bool fifo_insertion_glitch;
|
2018-02-24 22:48:45 +00:00
|
|
|
|
uint8_t current_line;
|
|
|
|
|
uint16_t ly_for_comparison;
|
2018-03-03 13:47:36 +00:00
|
|
|
|
GB_fifo_t bg_fifo, oam_fifo;
|
|
|
|
|
uint8_t fetcher_x;
|
2018-03-03 18:51:38 +00:00
|
|
|
|
uint8_t fetcher_y;
|
2018-03-03 13:47:36 +00:00
|
|
|
|
uint16_t cycles_for_line;
|
|
|
|
|
uint8_t current_tile;
|
2018-03-09 16:52:36 +00:00
|
|
|
|
uint8_t current_tile_attributes;
|
2018-03-03 13:47:36 +00:00
|
|
|
|
uint8_t current_tile_data[2];
|
2018-04-06 16:29:49 +00:00
|
|
|
|
uint8_t fetcher_state;
|
2020-02-29 15:06:08 +00:00
|
|
|
|
bool window_is_being_fetched;
|
2020-03-01 21:58:28 +00:00
|
|
|
|
bool wx166_glitch;
|
2020-02-23 21:16:45 +00:00
|
|
|
|
bool wx_triggered;
|
2018-03-04 20:21:56 +00:00
|
|
|
|
uint8_t visible_objs[10];
|
2019-03-16 18:56:22 +00:00
|
|
|
|
uint8_t obj_comparators[10];
|
2018-03-04 20:21:56 +00:00
|
|
|
|
uint8_t n_visible_objs;
|
2018-03-23 16:07:14 +00:00
|
|
|
|
uint8_t oam_search_index;
|
2018-03-27 12:46:00 +00:00
|
|
|
|
uint8_t accessed_oam_row;
|
2018-03-30 14:06:27 +00:00
|
|
|
|
uint8_t extra_penalty_for_sprite_at_0;
|
2018-06-03 23:07:38 +00:00
|
|
|
|
uint8_t mode_for_interrupt;
|
2018-04-27 10:40:39 +00:00
|
|
|
|
bool lyc_interrupt_line;
|
2019-01-19 17:32:26 +00:00
|
|
|
|
bool cgb_palettes_blocked;
|
2019-02-15 15:04:48 +00:00
|
|
|
|
uint8_t current_lcd_line; // The LCD can go out of sync since the vsync signal is skipped in some cases.
|
2019-06-07 10:53:50 +00:00
|
|
|
|
uint32_t cycles_in_stop_mode;
|
2020-02-15 13:32:06 +00:00
|
|
|
|
uint8_t object_priority;
|
2020-02-15 17:21:43 +00:00
|
|
|
|
bool oam_ppu_blocked;
|
|
|
|
|
bool vram_ppu_blocked;
|
|
|
|
|
bool cgb_palettes_ppu_blocked;
|
2020-02-21 13:14:33 +00:00
|
|
|
|
bool object_fetch_aborted;
|
2020-02-21 14:16:02 +00:00
|
|
|
|
bool during_object_fetch;
|
2020-02-21 14:43:51 +00:00
|
|
|
|
uint16_t object_low_line_address;
|
2020-02-23 21:16:45 +00:00
|
|
|
|
bool wy_triggered;
|
|
|
|
|
uint8_t window_tile_x;
|
2020-03-06 12:41:13 +00:00
|
|
|
|
uint8_t lcd_x; // The LCD can go out of sync since the push signal is skipped in some cases.
|
2020-03-26 18:54:18 +00:00
|
|
|
|
bool is_odd_frame;
|
2020-05-29 20:10:23 +00:00
|
|
|
|
uint16_t last_tile_data_address;
|
|
|
|
|
uint16_t last_tile_index_address;
|
2020-05-29 22:25:21 +00:00
|
|
|
|
bool cgb_repeated_a_frame;
|
2020-11-20 14:24:16 +00:00
|
|
|
|
uint8_t data_for_sel_glitch;
|
2016-06-11 11:52:09 +00:00
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/* Unsaved data. This includes all pointers, as well as everything that shouldn't be on a save state */
|
2017-04-17 17:16:17 +00:00
|
|
|
|
/* This data is reserved on reset and must come last in the struct */
|
|
|
|
|
GB_SECTION(unsaved,
|
|
|
|
|
/* ROM */
|
|
|
|
|
uint8_t *rom;
|
|
|
|
|
uint32_t rom_size;
|
|
|
|
|
const GB_cartridge_t *cartridge_type;
|
|
|
|
|
enum {
|
|
|
|
|
GB_STANDARD_MBC1_WIRING,
|
|
|
|
|
GB_MBC1M_WIRING,
|
|
|
|
|
} mbc1_wiring;
|
2020-04-08 16:07:29 +00:00
|
|
|
|
bool is_mbc30;
|
2017-04-17 17:16:17 +00:00
|
|
|
|
|
2018-04-14 10:23:33 +00:00
|
|
|
|
unsigned pending_cycles;
|
|
|
|
|
|
2017-04-17 17:16:17 +00:00
|
|
|
|
/* Various RAMs */
|
|
|
|
|
uint8_t *ram;
|
|
|
|
|
uint8_t *vram;
|
|
|
|
|
uint8_t *mbc_ram;
|
|
|
|
|
|
|
|
|
|
/* I/O */
|
|
|
|
|
uint32_t *screen;
|
2017-10-12 14:22:22 +00:00
|
|
|
|
uint32_t background_palettes_rgb[0x20];
|
|
|
|
|
uint32_t sprite_palettes_rgb[0x20];
|
2020-01-29 12:19:11 +00:00
|
|
|
|
const GB_palette_t *dmg_palette;
|
2017-10-12 14:22:22 +00:00
|
|
|
|
GB_color_correction_mode_t color_correction_mode;
|
2020-12-25 12:14:17 +00:00
|
|
|
|
double light_temperature;
|
2018-11-11 22:37:06 +00:00
|
|
|
|
bool keys[4][GB_KEY_MAX];
|
2020-02-08 11:28:46 +00:00
|
|
|
|
GB_border_mode_t border_mode;
|
|
|
|
|
GB_sgb_border_t borrowed_border;
|
|
|
|
|
bool tried_loading_sgb_border;
|
|
|
|
|
bool has_sgb_border;
|
2017-04-21 13:00:53 +00:00
|
|
|
|
|
|
|
|
|
/* Timing */
|
|
|
|
|
uint64_t last_sync;
|
2018-02-20 19:17:12 +00:00
|
|
|
|
uint64_t cycles_since_last_sync; // In 8MHz units
|
2021-02-25 20:12:14 +00:00
|
|
|
|
GB_rtc_mode_t rtc_mode;
|
2017-04-17 17:16:17 +00:00
|
|
|
|
|
2017-04-21 13:00:53 +00:00
|
|
|
|
/* Audio */
|
2017-07-21 20:06:02 +00:00
|
|
|
|
GB_apu_output_t apu_output;
|
2017-04-17 17:16:17 +00:00
|
|
|
|
|
|
|
|
|
/* Callbacks */
|
|
|
|
|
void *user_data;
|
|
|
|
|
GB_log_callback_t log_callback;
|
|
|
|
|
GB_input_callback_t input_callback;
|
|
|
|
|
GB_input_callback_t async_input_callback;
|
|
|
|
|
GB_rgb_encode_callback_t rgb_encode_callback;
|
|
|
|
|
GB_vblank_callback_t vblank_callback;
|
|
|
|
|
GB_infrared_callback_t infrared_callback;
|
|
|
|
|
GB_camera_get_pixel_callback_t camera_get_pixel_callback;
|
|
|
|
|
GB_camera_update_request_callback_t camera_update_request_callback;
|
|
|
|
|
GB_rumble_callback_t rumble_callback;
|
2019-03-15 12:36:10 +00:00
|
|
|
|
GB_serial_transfer_bit_start_callback_t serial_transfer_bit_start_callback;
|
|
|
|
|
GB_serial_transfer_bit_end_callback_t serial_transfer_bit_end_callback;
|
2019-06-07 15:27:25 +00:00
|
|
|
|
GB_update_input_hint_callback_t update_input_hint_callback;
|
2019-07-15 19:01:41 +00:00
|
|
|
|
GB_joyp_write_callback_t joyp_write_callback;
|
2019-07-16 17:44:27 +00:00
|
|
|
|
GB_icd_pixel_callback_t icd_pixel_callback;
|
|
|
|
|
GB_icd_vreset_callback_t icd_hreset_callback;
|
2019-07-15 20:02:58 +00:00
|
|
|
|
GB_icd_vreset_callback_t icd_vreset_callback;
|
2019-08-16 14:38:43 +00:00
|
|
|
|
GB_read_memory_callback_t read_memory_callback;
|
2020-01-29 18:29:30 +00:00
|
|
|
|
GB_boot_rom_load_callback_t boot_rom_load_callback;
|
2020-06-10 19:46:19 +00:00
|
|
|
|
GB_print_image_callback_t printer_callback;
|
2020-09-19 16:31:24 +00:00
|
|
|
|
GB_workboy_set_time_callback workboy_set_time_callback;
|
|
|
|
|
GB_workboy_get_time_callback workboy_get_time_callback;
|
2017-04-17 17:16:17 +00:00
|
|
|
|
|
|
|
|
|
/*** Debugger ***/
|
|
|
|
|
volatile bool debug_stopped, debug_disable;
|
|
|
|
|
bool debug_fin_command, debug_next_command;
|
|
|
|
|
|
|
|
|
|
/* Breakpoints */
|
|
|
|
|
uint16_t n_breakpoints;
|
|
|
|
|
struct GB_breakpoint_s *breakpoints;
|
2020-05-30 20:35:07 +00:00
|
|
|
|
bool has_jump_to_breakpoints, has_software_breakpoints;
|
2019-04-12 17:29:43 +00:00
|
|
|
|
void *nontrivial_jump_state;
|
|
|
|
|
bool non_trivial_jump_breakpoint_occured;
|
2017-04-17 17:16:17 +00:00
|
|
|
|
|
|
|
|
|
/* SLD (Todo: merge with backtrace) */
|
|
|
|
|
bool stack_leak_detection;
|
2020-04-09 11:32:52 +00:00
|
|
|
|
signed debug_call_depth;
|
2017-04-17 17:16:17 +00:00
|
|
|
|
uint16_t sp_for_call_depth[0x200]; /* Should be much more than enough */
|
|
|
|
|
uint16_t addr_for_call_depth[0x200];
|
|
|
|
|
|
|
|
|
|
/* Backtrace */
|
2019-06-15 20:22:27 +00:00
|
|
|
|
unsigned backtrace_size;
|
2017-04-17 17:16:17 +00:00
|
|
|
|
uint16_t backtrace_sps[0x200];
|
|
|
|
|
struct {
|
|
|
|
|
uint16_t bank;
|
|
|
|
|
uint16_t addr;
|
|
|
|
|
} backtrace_returns[0x200];
|
|
|
|
|
|
|
|
|
|
/* Watchpoints */
|
|
|
|
|
uint16_t n_watchpoints;
|
|
|
|
|
struct GB_watchpoint_s *watchpoints;
|
|
|
|
|
|
|
|
|
|
/* Symbol tables */
|
|
|
|
|
GB_symbol_map_t *bank_symbols[0x200];
|
|
|
|
|
GB_reversed_symbol_map_t reversed_symbol_map;
|
|
|
|
|
|
|
|
|
|
/* Ticks command */
|
2020-04-09 11:32:52 +00:00
|
|
|
|
uint64_t debugger_ticks;
|
2018-02-10 12:42:14 +00:00
|
|
|
|
|
2020-11-21 14:19:58 +00:00
|
|
|
|
/* Undo */
|
|
|
|
|
uint8_t *undo_state;
|
|
|
|
|
const char *undo_label;
|
|
|
|
|
|
2018-02-10 12:42:14 +00:00
|
|
|
|
/* Rewind */
|
|
|
|
|
#define GB_REWIND_FRAMES_PER_KEY 255
|
|
|
|
|
size_t rewind_buffer_length;
|
|
|
|
|
struct {
|
|
|
|
|
uint8_t *key_state;
|
|
|
|
|
uint8_t *compressed_states[GB_REWIND_FRAMES_PER_KEY];
|
|
|
|
|
unsigned pos;
|
|
|
|
|
} *rewind_sequences; // lasts about 4 seconds
|
|
|
|
|
size_t rewind_pos;
|
2018-11-15 23:53:01 +00:00
|
|
|
|
|
|
|
|
|
/* SGB - saved and allocated optionally */
|
|
|
|
|
GB_sgb_t *sgb;
|
2018-11-24 11:21:00 +00:00
|
|
|
|
|
|
|
|
|
double sgb_intro_jingle_phases[7];
|
|
|
|
|
double sgb_intro_sweep_phase;
|
2018-12-01 11:39:43 +00:00
|
|
|
|
double sgb_intro_sweep_previous_sample;
|
2020-04-09 17:11:55 +00:00
|
|
|
|
|
|
|
|
|
/* Cheats */
|
2020-04-11 15:03:10 +00:00
|
|
|
|
bool cheat_enabled;
|
2020-04-09 17:11:55 +00:00
|
|
|
|
size_t cheat_count;
|
|
|
|
|
GB_cheat_t **cheats;
|
|
|
|
|
GB_cheat_hash_t *cheat_hash[256];
|
2017-04-17 17:16:17 +00:00
|
|
|
|
|
|
|
|
|
/* Misc */
|
|
|
|
|
bool turbo;
|
|
|
|
|
bool turbo_dont_skip;
|
|
|
|
|
bool disable_rendering;
|
|
|
|
|
uint8_t boot_rom[0x900];
|
|
|
|
|
bool vblank_just_occured; // For slow operations involving syscalls; these should only run once per vblank
|
2018-02-20 19:17:12 +00:00
|
|
|
|
uint8_t cycles_since_run; // How many cycles have passed since the last call to GB_run(), in 8MHz units
|
2018-02-10 21:30:30 +00:00
|
|
|
|
double clock_multiplier;
|
2020-04-29 13:50:31 +00:00
|
|
|
|
GB_rumble_mode_t rumble_mode;
|
2019-10-19 16:26:04 +00:00
|
|
|
|
uint32_t rumble_on_cycles;
|
|
|
|
|
uint32_t rumble_off_cycles;
|
2020-02-26 22:12:42 +00:00
|
|
|
|
|
|
|
|
|
/* Temporary state */
|
|
|
|
|
bool wx_just_changed;
|
2020-11-20 14:24:16 +00:00
|
|
|
|
bool tile_sel_glitch;
|
2021-04-02 16:08:03 +00:00
|
|
|
|
|
|
|
|
|
GB_gbs_header_t gbs_header;
|
2017-04-17 17:16:17 +00:00
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
#ifndef GB_INTERNAL
|
|
|
|
|
struct GB_gameboy_s {
|
|
|
|
|
char __internal[sizeof(struct GB_gameboy_internal_s)];
|
|
|
|
|
};
|
|
|
|
|
#endif
|
2016-06-11 11:52:09 +00:00
|
|
|
|
|
2016-03-30 20:07:55 +00:00
|
|
|
|
|
|
|
|
|
#ifndef __printflike
|
|
|
|
|
/* Missing from Linux headers. */
|
|
|
|
|
#define __printflike(fmtarg, firstvararg) \
|
|
|
|
|
__attribute__((__format__ (__printf__, fmtarg, firstvararg)))
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-06-16 10:59:33 +00:00
|
|
|
|
void GB_init(GB_gameboy_t *gb, GB_model_t model);
|
2017-04-19 18:55:58 +00:00
|
|
|
|
bool GB_is_inited(GB_gameboy_t *gb);
|
2017-04-19 20:26:39 +00:00
|
|
|
|
bool GB_is_cgb(GB_gameboy_t *gb);
|
2019-07-15 17:47:16 +00:00
|
|
|
|
bool GB_is_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2
|
|
|
|
|
bool GB_is_hle_sgb(GB_gameboy_t *gb); // Returns true if the model is SGB or SGB2 and the SFC/SNES side is HLE'd
|
2018-06-16 10:59:33 +00:00
|
|
|
|
GB_model_t GB_get_model(GB_gameboy_t *gb);
|
2016-06-18 17:29:11 +00:00
|
|
|
|
void GB_free(GB_gameboy_t *gb);
|
2017-04-17 17:16:17 +00:00
|
|
|
|
void GB_reset(GB_gameboy_t *gb);
|
2018-06-16 10:59:33 +00:00
|
|
|
|
void GB_switch_model_and_reset(GB_gameboy_t *gb, GB_model_t model);
|
2018-01-31 13:18:04 +00:00
|
|
|
|
|
2019-07-13 17:29:11 +00:00
|
|
|
|
/* Returns the time passed, in 8MHz ticks. */
|
2018-01-31 13:18:04 +00:00
|
|
|
|
uint8_t GB_run(GB_gameboy_t *gb);
|
2017-04-24 21:19:10 +00:00
|
|
|
|
/* Returns the time passed since the last frame, in nanoseconds */
|
|
|
|
|
uint64_t GB_run_frame(GB_gameboy_t *gb);
|
2017-04-19 18:55:58 +00:00
|
|
|
|
|
2017-04-19 20:26:39 +00:00
|
|
|
|
typedef enum {
|
|
|
|
|
GB_DIRECT_ACCESS_ROM,
|
|
|
|
|
GB_DIRECT_ACCESS_RAM,
|
|
|
|
|
GB_DIRECT_ACCESS_CART_RAM,
|
|
|
|
|
GB_DIRECT_ACCESS_VRAM,
|
|
|
|
|
GB_DIRECT_ACCESS_HRAM,
|
|
|
|
|
GB_DIRECT_ACCESS_IO, /* Warning: Some registers can only be read/written correctly via GB_memory_read/write. */
|
|
|
|
|
GB_DIRECT_ACCESS_BOOTROM,
|
|
|
|
|
GB_DIRECT_ACCESS_OAM,
|
|
|
|
|
GB_DIRECT_ACCESS_BGP,
|
|
|
|
|
GB_DIRECT_ACCESS_OBP,
|
2017-10-12 19:49:39 +00:00
|
|
|
|
GB_DIRECT_ACCESS_IE,
|
2017-04-19 20:26:39 +00:00
|
|
|
|
} GB_direct_access_t;
|
|
|
|
|
|
|
|
|
|
/* Returns a mutable pointer to various hardware memories. If that memory is banked, the current bank
|
|
|
|
|
is returned at *bank, even if only a portion of the memory is banked. */
|
|
|
|
|
void *GB_get_direct_access(GB_gameboy_t *gb, GB_direct_access_t access, size_t *size, uint16_t *bank);
|
|
|
|
|
|
2017-04-19 18:55:58 +00:00
|
|
|
|
void *GB_get_user_data(GB_gameboy_t *gb);
|
|
|
|
|
void GB_set_user_data(GB_gameboy_t *gb, void *data);
|
|
|
|
|
|
2017-10-12 19:06:01 +00:00
|
|
|
|
|
2017-04-23 08:50:07 +00:00
|
|
|
|
|
2016-06-18 17:29:11 +00:00
|
|
|
|
int GB_load_boot_rom(GB_gameboy_t *gb, const char *path);
|
2017-10-12 19:06:01 +00:00
|
|
|
|
void GB_load_boot_rom_from_buffer(GB_gameboy_t *gb, const unsigned char *buffer, size_t size);
|
2016-06-18 17:29:11 +00:00
|
|
|
|
int GB_load_rom(GB_gameboy_t *gb, const char *path);
|
2019-07-16 18:04:29 +00:00
|
|
|
|
void GB_load_rom_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size);
|
2020-04-25 19:48:48 +00:00
|
|
|
|
int GB_load_isx(GB_gameboy_t *gb, const char *path);
|
2021-04-02 16:08:03 +00:00
|
|
|
|
int GB_load_gbs(GB_gameboy_t *gb, const char *path, GB_gbs_info_t *info);
|
|
|
|
|
void GB_gbs_switch_track(GB_gameboy_t *gb, uint8_t track);
|
|
|
|
|
|
2019-08-16 14:38:43 +00:00
|
|
|
|
int GB_save_battery_size(GB_gameboy_t *gb);
|
|
|
|
|
int GB_save_battery_to_buffer(GB_gameboy_t *gb, uint8_t *buffer, size_t size);
|
2016-06-18 17:29:11 +00:00
|
|
|
|
int GB_save_battery(GB_gameboy_t *gb, const char *path);
|
2019-08-16 14:38:43 +00:00
|
|
|
|
|
|
|
|
|
void GB_load_battery_from_buffer(GB_gameboy_t *gb, const uint8_t *buffer, size_t size);
|
2016-06-18 17:29:11 +00:00
|
|
|
|
void GB_load_battery(GB_gameboy_t *gb, const char *path);
|
2017-04-19 18:55:58 +00:00
|
|
|
|
|
|
|
|
|
void GB_set_turbo_mode(GB_gameboy_t *gb, bool on, bool no_frame_skip);
|
|
|
|
|
void GB_set_rendering_disabled(GB_gameboy_t *gb, bool disabled);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
2016-06-18 17:29:11 +00:00
|
|
|
|
void GB_set_pixels_output(GB_gameboy_t *gb, uint32_t *output);
|
2020-02-08 11:28:46 +00:00
|
|
|
|
void GB_set_border_mode(GB_gameboy_t *gb, GB_border_mode_t border_mode);
|
|
|
|
|
|
2017-04-19 18:55:58 +00:00
|
|
|
|
void GB_set_infrared_input(GB_gameboy_t *gb, bool state);
|
|
|
|
|
|
2016-06-18 17:29:11 +00:00
|
|
|
|
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_set_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback);
|
2016-07-17 21:39:43 +00:00
|
|
|
|
void GB_set_async_input_callback(GB_gameboy_t *gb, GB_input_callback_t callback);
|
2016-06-18 17:29:11 +00:00
|
|
|
|
void GB_set_rgb_encode_callback(GB_gameboy_t *gb, GB_rgb_encode_callback_t callback);
|
2016-07-18 19:05:11 +00:00
|
|
|
|
void GB_set_infrared_callback(GB_gameboy_t *gb, GB_infrared_callback_t callback);
|
2016-10-22 12:37:03 +00:00
|
|
|
|
void GB_set_rumble_callback(GB_gameboy_t *gb, GB_rumble_callback_t callback);
|
2019-06-07 15:27:25 +00:00
|
|
|
|
void GB_set_update_input_hint_callback(GB_gameboy_t *gb, GB_update_input_hint_callback_t callback);
|
2020-01-29 18:29:30 +00:00
|
|
|
|
/* Called when a new boot ROM is needed. The callback should call GB_load_boot_rom or GB_load_boot_rom_from_buffer */
|
|
|
|
|
void GB_set_boot_rom_load_callback(GB_gameboy_t *gb, GB_boot_rom_load_callback_t callback);
|
|
|
|
|
|
2020-01-29 12:19:11 +00:00
|
|
|
|
void GB_set_palette(GB_gameboy_t *gb, const GB_palette_t *palette);
|
2016-11-11 23:58:53 +00:00
|
|
|
|
|
|
|
|
|
/* These APIs are used when using internal clock */
|
2019-03-15 12:36:10 +00:00
|
|
|
|
void GB_set_serial_transfer_bit_start_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_start_callback_t callback);
|
|
|
|
|
void GB_set_serial_transfer_bit_end_callback(GB_gameboy_t *gb, GB_serial_transfer_bit_end_callback_t callback);
|
2016-11-11 23:58:53 +00:00
|
|
|
|
|
|
|
|
|
/* These APIs are used when using external clock */
|
2019-03-15 12:36:10 +00:00
|
|
|
|
bool GB_serial_get_data_bit(GB_gameboy_t *gb);
|
|
|
|
|
void GB_serial_set_data_bit(GB_gameboy_t *gb, bool data);
|
2017-04-19 18:55:58 +00:00
|
|
|
|
|
2017-01-13 19:27:37 +00:00
|
|
|
|
void GB_disconnect_serial(GB_gameboy_t *gb);
|
2019-07-15 19:01:41 +00:00
|
|
|
|
|
2020-05-23 11:50:54 +00:00
|
|
|
|
/* For cartridges with an alarm clock */
|
|
|
|
|
unsigned GB_time_to_alarm(GB_gameboy_t *gb); // 0 if no alarm
|
|
|
|
|
|
2021-02-25 20:12:14 +00:00
|
|
|
|
/* RTC emulation mode */
|
|
|
|
|
void GB_set_rtc_mode(GB_gameboy_t *gb, GB_rtc_mode_t mode);
|
|
|
|
|
|
2019-07-15 19:01:41 +00:00
|
|
|
|
/* For integration with SFC/SNES emulators */
|
|
|
|
|
void GB_set_joyp_write_callback(GB_gameboy_t *gb, GB_joyp_write_callback_t callback);
|
2019-07-16 17:44:27 +00:00
|
|
|
|
void GB_set_icd_pixel_callback(GB_gameboy_t *gb, GB_icd_pixel_callback_t callback);
|
|
|
|
|
void GB_set_icd_hreset_callback(GB_gameboy_t *gb, GB_icd_hreset_callback_t callback);
|
2019-07-15 20:02:58 +00:00
|
|
|
|
void GB_set_icd_vreset_callback(GB_gameboy_t *gb, GB_icd_vreset_callback_t callback);
|
|
|
|
|
|
2018-02-10 21:30:30 +00:00
|
|
|
|
uint32_t GB_get_clock_rate(GB_gameboy_t *gb);
|
2021-02-25 20:12:14 +00:00
|
|
|
|
uint32_t GB_get_unmultiplied_clock_rate(GB_gameboy_t *gb);
|
2018-02-10 21:30:30 +00:00
|
|
|
|
void GB_set_clock_multiplier(GB_gameboy_t *gb, double multiplier);
|
2018-11-14 22:21:21 +00:00
|
|
|
|
|
2019-05-18 15:45:31 +00:00
|
|
|
|
unsigned GB_get_screen_width(GB_gameboy_t *gb);
|
|
|
|
|
unsigned GB_get_screen_height(GB_gameboy_t *gb);
|
2019-06-19 20:49:43 +00:00
|
|
|
|
double GB_get_usual_frame_rate(GB_gameboy_t *gb);
|
2018-12-15 16:55:41 +00:00
|
|
|
|
unsigned GB_get_player_count(GB_gameboy_t *gb);
|
|
|
|
|
|
2016-06-18 17:29:11 +00:00
|
|
|
|
#endif /* GB_h */
|