#ifndef GB_H #define GB_H #include #include #include #include #include #include #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_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; ut16 flags; // ut16 pc; } 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_WAIT_TRIGGER, //gb was put in wait state on previous call GB_INTERRUPT_SEEK, //2 bits for seek }; 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 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 GBDMA *gb_dma_open(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_close(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 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 #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; ut32 oam_mapid; } GBPPU; 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; 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; #endif