268 lines
6.0 KiB
C
268 lines
6.0 KiB
C
#ifndef GB_H
|
|
#define GB_H
|
|
#include <ragb_sdl.h>
|
|
#include <r_io.h>
|
|
#include <r_arch.h>
|
|
#include <r_esil.h>
|
|
#include <r_anal.h>
|
|
#include <r_reg.h>
|
|
|
|
#define WHITE 0x86c06c
|
|
#define LIGHT_GRAY 0xe0f8cf
|
|
#define DARK_GRAY 0
|
|
#define BLACK 0
|
|
|
|
enum {
|
|
GB_TIMERS_DIV = 0,
|
|
GB_TIMERS_TIMA,
|
|
GB_TIMERS_TMA,
|
|
GB_TIMERS_TAC,
|
|
GB_TIMERS_N_REGS,
|
|
};
|
|
|
|
typedef struct gb_timers_t {
|
|
ut64 seek;
|
|
ut32 fd;
|
|
ut16 odiv;
|
|
ut16 div;
|
|
ut8 buf[4];
|
|
ut8 otma;
|
|
st8 tima_wait;
|
|
bool check_fedge;
|
|
} GBTimers;
|
|
|
|
bool gb_timers_init(GBTimers *timers, RIO *io);
|
|
void gb_timers_reset_div(GBTimers *timers);
|
|
void gb_timers_fini(GBTimers *timers, RIO *io);
|
|
|
|
typedef struct gb_joypad_t {
|
|
ut8 *keys;
|
|
int fd;
|
|
ut16 up;
|
|
ut16 down;
|
|
ut16 left;
|
|
ut16 right;
|
|
ut16 a;
|
|
ut16 b;
|
|
ut16 start;
|
|
ut16 select;
|
|
ut8 data;
|
|
ut8 odata;
|
|
} GBJoypad;
|
|
|
|
bool gb_joypad_init(GBJoypad *joypad, RIO *io);
|
|
void gb_joypad_fini(GBJoypad *joypad, RIO *io);
|
|
|
|
typedef struct gb_interrupts_t {
|
|
RRegItem *ime;
|
|
int fd;
|
|
ut32 flags;
|
|
} GBInterrupts;
|
|
|
|
enum {
|
|
GB_INTERRUPT_VBLANK = 0,
|
|
GB_INTERRUPT_STAT,
|
|
GB_INTERRUPT_TIMER,
|
|
GB_INTERRUPT_SERIAL,
|
|
GB_INTERRUPT_JOYPAD,
|
|
GB_INTERRUPT_N, //number of interrupts
|
|
GB_INTERRUPT_VBLANK_ENABLED = GB_INTERRUPT_N,
|
|
GB_INTERRUPT_STAT_ENABLED,
|
|
GB_INTERRUPT_TIMER_ENABLED,
|
|
GB_INTERRUPT_SERIAL_ENABLED,
|
|
GB_INTERRUPT_JOYPAD_ENABLED,
|
|
GB_INTERRUPT_ENABLED, //general enable of all interrupts
|
|
GB_INTERRUPT_ENABLE_WAIT, //wait 1 instruction befor enabling interrupts
|
|
GB_INTERRUPT_DEC_RET, //decrement return address when entering interrupt handler
|
|
//to honor halt instruction bug
|
|
GB_INTERRUPT_WAIT_TRIGGER, //gb was put in wait state on previous call
|
|
GB_INTERRUPT_SEEK, //2 bits for seek
|
|
GB_INTERRUPT_PENDING = GB_INTERRUPT_SEEK + 2, //3 bits for pending interrupt
|
|
};
|
|
|
|
bool gb_interrupts_init(GBInterrupts *ints, RIO *io, RReg *reg);
|
|
void gb_interrupts_fini(GBInterrupts *ints, RIO *io);
|
|
|
|
typedef struct gb_dma_t {
|
|
ut64 seek; //17 bit seek and some flags
|
|
int dma_fd; //fd representing the dma register
|
|
int dma_bus_fd; //fd representing the memory bus while dma occupies it
|
|
int oam_fd; //fd representing oam
|
|
ut32 oam_mapid;
|
|
ut32 dma_bank_id;
|
|
ut32 default_bank_id;
|
|
// ut16 bus_occupancy_size;
|
|
ut8 buf[0xa0];
|
|
ut8 dst; //current dst addr low byte
|
|
// ut8 todo; //cycles todo
|
|
st8 frontrun; //cycles that read/write ops had frontrun the dma copy
|
|
ut8 val;
|
|
} GBDMA;
|
|
|
|
#define GB_DMA_LAUNCH 0x20000
|
|
#define GB_DMA_RUNNING 0x40000
|
|
#define GB_DMA_ACTIVE 0x60000
|
|
#define GB_DMA_CGB_MODE 0x80000
|
|
|
|
bool gb_dma_init(GBDMA *dma, RIO *io);
|
|
//void gb_dma_enable_cgb(GBDMA *dma);
|
|
void gb_dma_continue(GBDMA *dma, RIO *io, ut32 cycles, bool pre_exec);
|
|
void gb_dma_fini(GBDMA *dma, RIO *io);
|
|
|
|
enum {
|
|
GB_PPU_LCDC = 0, //0xff40
|
|
GB_PPU_STAT, //0xff41
|
|
GB_PPU_SCY, //0xff42
|
|
GB_PPU_SCX, //0xff43
|
|
GB_PPU_LY, //0xff44
|
|
GB_PPU_LYC, //0xff45
|
|
GB_PPU_BGP, //0xff47
|
|
GB_PPU_OBP0, //0xff48
|
|
GB_PPU_OBP1, //0xff49
|
|
GB_PPU_WY, //0xff4a
|
|
GB_PPU_WX, //0xff4b
|
|
GB_PPU_N_REGS,
|
|
};
|
|
|
|
#define GB_PPU_LCDC_BGW_ENABLE 0x1
|
|
#define GB_PPU_LCDC_OBJ_ENABLE 0x2
|
|
#define GB_PPU_LCDC_BIG_OBJ 0x4
|
|
#define GB_PPU_LCDC_BG_TILE_MAP 0x8
|
|
#define GB_PPU_LCDC_TILE_BASE 0x10
|
|
#define GB_PPU_LCDC_WIN_ENABLE 0x20
|
|
#define GB_PPU_LCDC_WIN_TILE_MAP 0x40
|
|
#define GB_PPU_LCDC_ENABLE 0x80
|
|
|
|
enum {
|
|
GB_PPU_STAT_MODE_HBLANK = 0,
|
|
GB_PPU_STAT_MODE_VBLANK,
|
|
GB_PPU_STAT_MODE_OAM_SCAN,
|
|
GB_PPU_STAT_MODE_RENDER,
|
|
};
|
|
|
|
#define GB_PPU_STAT_MODE_MASK 0x3
|
|
|
|
#define GB_PPU_STAT_INTR_HBLANK 0x8
|
|
#define GB_PPU_STAT_INTR_VBLANK 0x10
|
|
#define GB_PPU_STAT_INTR_OAM 0x20
|
|
#define GB_PPU_STAT_INTR_LYC 0x40
|
|
|
|
typedef struct oam_scan_table {
|
|
ut32 data[10];
|
|
//low byte is x coordinate of sprite;
|
|
//second lowest byte is y coordinate
|
|
//second highest byte is addr of entry (0xffe0 + addr)
|
|
//highest byte is used for attributes, which is read by the fetcher, not during oam scan
|
|
ut8 n_entries; //max 10
|
|
ut8 addr;
|
|
} OAMScanTable;
|
|
|
|
typedef struct pixel_fifo_fetcher_t {
|
|
ut32 fetched;
|
|
ut16 addr;
|
|
ut8 data[2];
|
|
ut8 state_ctr;
|
|
} PixelFifoFetcher;
|
|
|
|
// flags
|
|
#define GB_PIXEL_FIFO_FETCH_OBJECT 0x10
|
|
#define GB_PIXEL_FIFO_FETCH_WINDOW 0x20
|
|
#define GB_PIXEL_FIFO_FETCH_READY 0x40
|
|
//specifies if scx & 0x7 and wy are copied into fifo
|
|
#define GB_PIXEL_FIFO_REG_DATA_LOADED 0x80
|
|
|
|
//flags1
|
|
//window x condition triggered
|
|
#define GB_PIXEL_FIFO_WXC_TRIGGERED 0x8
|
|
//indicates that LCDC_ENABLE bit was fliped
|
|
#define GB_PIXEL_FIFO_LCDC_SWITCH 0x10
|
|
|
|
#define GB_OAM_PALLET 0x10
|
|
#define GB_OAM_FLIP_X 0x20
|
|
#define GB_OAM_FLIP_Y 0x40
|
|
#define GB_OAM_PRIORITY 0x80
|
|
|
|
#define GB_FIFO_OAM_PALLET (GB_OAM_PALLET << 24)
|
|
#define GB_FIFO_OAM_FLIP_X (GB_OAM_FLIP_X << 24)
|
|
#define GB_FIFO_OAM_FLIP_Y (GB_OAM_FLIP_Y << 24)
|
|
#define GB_FIFO_OAM_PRIORITY (GB_OAM_PRIORITY << 24)
|
|
|
|
|
|
typedef struct pixel_fifo_t {
|
|
ut64 data;
|
|
PixelFifoFetcher fetcher[2];
|
|
ut32 remaining_cycles;
|
|
ut32 obj; //object
|
|
union {
|
|
ut8 shift_out; //lower nibble is sourch info, pallet, color
|
|
// 0b....spcc
|
|
#if 0
|
|
bg - 00
|
|
win - 01
|
|
obj p0 - 10
|
|
obj p1 - 11
|
|
#endif
|
|
ut8 flags;
|
|
};
|
|
ut8 n_fpixel; //number of pixel that are currently in the fifo
|
|
ut8 x;
|
|
ut8 wy;
|
|
union {
|
|
ut8 dx; //discard x
|
|
ut8 flags1;
|
|
};
|
|
} PixelFifo;
|
|
|
|
typedef struct gb_dmg_ppu_t {
|
|
GBPixBuf *pixbuf;
|
|
ut64 seek;
|
|
ut8 buf[GB_PPU_N_REGS];
|
|
OAMScanTable ost;
|
|
PixelFifo fifo;
|
|
int reg_fd;
|
|
int vram_fd;
|
|
ut32 vram_mapid;
|
|
} GBPPU;
|
|
|
|
enum {
|
|
GB_MODE_STOP,
|
|
GB_MODE_HALT_ENTER,
|
|
GB_MODE_HALT,
|
|
GB_MODE_HALT_DOUBLE_BYTE_FETCH,
|
|
};
|
|
|
|
typedef struct gameboy_t {
|
|
RIO *io;
|
|
RArch *arch;
|
|
RAnal *anal;
|
|
REsil *esil;
|
|
GBTimers timers;
|
|
GBJoypad joypad;
|
|
GBInterrupts interrupts;
|
|
GBDMA dma;
|
|
GBPPU *ppu;
|
|
ut64 addr;
|
|
int cartrigde_fd;
|
|
ut32 pause_cycles;
|
|
ut32 mode;
|
|
// bool double_speed;
|
|
} GB;
|
|
|
|
void gb_interrupts_request(GB *gb, int interrupt);
|
|
void gb_interrupts_continue(GB *gb);
|
|
void gb_timers_continue(GB *gb, ut32 cycles);
|
|
void gb_joypad_continue(GB *gb);
|
|
|
|
GBPPU *gb_ppu_open (RIO *io, SDL_Renderer *renderer);
|
|
void gb_ppu_continue (GB *gb, ut32 cycles);
|
|
void gb_ppu_close (GBPPU *ppu, RIO *io);
|
|
|
|
extern RIOPlugin r_io_plugin_gb_timers;
|
|
extern RIOPlugin r_io_plugin_gb_mbc1;
|
|
extern RIOPlugin r_io_plugin_gb_mbc2;
|
|
extern RIOPlugin r_io_plugin_gb_joypad;
|
|
|
|
bool gb_esil_setup (GB *gb);
|
|
|
|
#endif
|