diff --git a/include/gb.h b/include/gb.h index fbc449a..1eb3efe 100644 --- a/include/gb.h +++ b/include/gb.h @@ -102,33 +102,54 @@ enum { #define GB_PPU_STAT_MODE_MASK 0x3 typedef struct oam_scan_table { - ut16 data[10]; //low byte is x coordinate of sprite; high byte is addr of entry (0xffe0 + high byte) + 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_fetch_t { +typedef struct pixel_fifo_fetcher_t { ut32 fetched; ut16 addr; ut8 data[2]; ut8 state_ctr; -} PixelFifoFetch; +} PixelFifoFetcher; -#define GB_PIXEL_FIFO_FETCH_SELECT 0x10 +#define GB_PIXEL_FIFO_FETCH_OBJECT 0x10 #define GB_PIXEL_FIFO_FETCH_WINDOW 0x20 +#define GB_PIXEL_FIFO_FETCH_READY 0x40 + +#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; - PixelFifoFetch fetch[2]; - ut8 shift_out; //lower nibble is sourch info, pallet, color - // 0b....spcc + 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 wy; ut8 x; } PixelFifo; diff --git a/io/ppu.c b/io/ppu.c index 6d4f8a9..0717448 100644 --- a/io/ppu.c +++ b/io/ppu.c @@ -147,7 +147,7 @@ static ut32 gb_ppu_oam_scan_update (GB *gb, ut32 cycles) { r_io_fd_read_at (gb->io, gb->dma->oam_fd, (ut64)gb->ppu->ost.addr, yx, 2); if ((yx[0] <= ly) && (ly < (yx[0] + height)) && yx[1]) { gb->ppu->ost.data[gb->ppu->ost.n_entries] = - (gb->ppu->ost.addr << 8) | yx[1]; + (gb->ppu->ost.addr << 16) | (yx[0] << 8) | yx[0]; gb->ppu->ost.n_entries++; } } @@ -164,24 +164,36 @@ beach: return cycles; } -static void read_tile_data (GB *gb, ut8 *tile) { - const bool use_window = !!(gb->ppu->fifo.shift_out & GB_PIXEL_FIFO_FETCH_WINDOW); +static void read_tile_data (GBPPU *ppu, RIO *io, ut8 *tile) { + const bool use_window = !!(ppu->fifo.flags & GB_PIXEL_FIFO_FETCH_WINDOW); ut64 addr; if (use_window) { - const ut8 x = ((gb->ppu->fifo.x + ((!!gb->ppu->fifo.n_fpixel) << 3)) - - gb->ppu->buf[GB_PPU_WX]) & 0xf8; + const ut8 x = ((ppu->fifo.x + ((!!ppu->fifo.n_fpixel) << 3)) - + ppu->buf[GB_PPU_WX]) & 0xf8; //maybe store this at begin of line - const ut8 y = (gb->ppu->buf[GB_PPU_LY] - gb->ppu->buf[GB_PPU_WY]) & 0xf8; - addr = ((gb->ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_WIN_TILE_MAP)? +#if 0 + const ut8 y = (ppu->buf[GB_PPU_LY] - ppu->buf[GB_PPU_WY]) & 0xf8; +#else + const ut8 y = (ppu->buf[GB_PPU_LY] - ppu->fifo.wy) & 0xf8; +#endif + addr = ((ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_WIN_TILE_MAP)? 0x1800: 0x1c00) + y * 32 + x; } else { - const ut8 x = (gb->ppu->fifo.x + gb->ppu->buf[GB_PPU_SCX] + - ((!!gb->ppu->fifo.n_fpixel) << 3)) & 0xf8; - const ut8 y = (gb->ppu->buf[GB_PPU_LY] + gb->ppu->buf[GB_PPU_SCY]) & 0xf8; - addr = ((gb->ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_BG_TILE_MAP)? + const ut8 x = (ppu->fifo.x + ppu->buf[GB_PPU_SCX] + + ((!!ppu->fifo.n_fpixel) << 3)) & 0xf8; + const ut8 y = (ppu->buf[GB_PPU_LY] + ppu->buf[GB_PPU_SCY]) & 0xf8; + addr = ((ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_BG_TILE_MAP)? 0x1800: 0x1c00) + y * 32 + x; } - r_io_fd_read_at (gb->io, gb->ppu->vram_fd, addr, tile, 1); + r_io_fd_read_at (io, ppu->vram_fd, addr, tile, 1); +} + +static void read_obj_data (GBPPU *ppu, RIO *io, ut8 *tile, int oam_fd) { + ut8 addr = (ppu->fifo.obj >> 16) & 0xff; + r_io_fd_read_at (io, oam_fd, (ut64)(addr + 2), tile, 1); + if (ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_BIG_OBJ) { + tile[0] &= 0xfe; + } } static void gb_ppu_pixel_fifo_merge_opixels (PixelFifo *pxf, bool priority) { @@ -191,7 +203,7 @@ static void gb_ppu_pixel_fifo_merge_opixels (PixelFifo *pxf, bool priority) { for (i = 0; i < 8; i++) { if (!(pixels & (0x3 << 28))) { //check for transparency newpixels = (newpixels << 4) | - ((pxf->fetch[1].fetched & (0xf << ((i - 1) << 2))) >> ((i - 1) << 2)); + ((pxf->fetcher[1].fetched & (0xf << (i << 2))) >> (i << 2)); pixels = pixels << 4; continue; } @@ -200,26 +212,108 @@ static void gb_ppu_pixel_fifo_merge_opixels (PixelFifo *pxf, bool priority) { static void gb_pixel_fifo_fetch_continue (GB *gb) { PixelFifo *fifo = &gb->ppu->fifo; - ut8 fetcher = !!(fifo->shift_out & GB_PIXEL_FIFO_FETCH_SELECT); + ut8 fetch_obj = !!(fifo->flags & GB_PIXEL_FIFO_FETCH_OBJECT); ut8 tile; - switch (fifo->fetch[fetcher].state_ctr) { + switch (fifo->fetcher[fetch_obj].state_ctr) { case 0: - read_tile_data (gb, &tile); - if (gb->ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_TILE_BASE) { - fifo->fetch[fetcher].addr = tile * 16; + if (!fetch_obj) { + read_tile_data (gb->ppu, gb->io, &tile); + if (gb->ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_TILE_BASE) { + fifo->fetcher[0].addr = tile * 16; + } else { + st8 s_tile = (st8)tile; + fifo->fetcher[0].addr = 0x1000 + s_tile * 16; + } + if (fifo->flags & GB_PIXEL_FIFO_FETCH_WINDOW) { + fifo->fetcher[0].addr += + ((gb->ppu->buf[GB_PPU_LY] - fifo->wy) & 0x7) * 2; + } else { + fifo->fetcher[0].addr += (gb->ppu->buf[GB_PPU_LY] & 0x7) * 2; + } } else { - st8 stile = (st8)tile; - fifo->fetch[fetcher].addr = 0x1000 + stile * 16; + read_obj_data (gb->ppu, gb->io, &tile, gb->dma->oam_fd); + fifo->fetcher[1].addr = tile; } case 1: break; case 2: - case 4: - break; + if (fetch_obj) { + ut8 addr = (fifo->obj >> 16) & 0xff; + //read object attributes + r_io_fd_read_at (gb->io, gb->dma->oam_fd, (ut64)(addr + 3), &tile, 1); + fifo->obj = (fifo->obj & 0xffffff) | (tile << 24); + //tile idx + tile = fifo->fetcher[1].addr & 0xff; + //object_y - line_y + addr = ((fifo->obj >> 8) & 0xff) - gb->ppu->buf[GB_PPU_LY]; + fifo->fetcher[1].addr = tile * 16; + if (fifo->obj & GB_FIFO_OAM_FLIP_Y) { + //perform y flip + addr ^= (gb->ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_BIG_OBJ)? 0xf: 0x7; + } + fifo->fetcher[1].addr += addr * 2; + } else { + r_io_fd_read_at (gb->io, gb->ppu->vram_fd, fifo->fetcher[0].addr, + &fifo->fetcher[0].data[0], 1); + fifo->fetcher[0].addr++; + } case 3: - fifo->fetch[fetcher].addr++; + break; + case 4: + r_io_fd_read_at (gb->io, gb->ppu->vram_fd, fifo->fetcher[fetch_obj].addr, + &fifo->fetcher[fetch_obj].data[!fetch_obj], 1); + fifo->fetcher[fetch_obj].addr++; + if (!fetch_obj) { + ut8 *p = &fifo->fetcher[0].data[0]; + fifo->fetcher[0].fetched = + ((p[1] & 0x80) << 22) | ((p[0] & 0x80) << 21) | + ((p[1] & 0x40) << 19) | ((p[0] & 0x40) << 18) | + ((p[1] & 0x20) << 16) | ((p[0] & 0x20) << 15) | + ((p[1] & 0x10) << 13) | ((p[0] & 0x10) << 12) | + ((p[1] & 0x8) << 10) | ((p[0] & 0x8) << 9) | + ((p[1] & 0x4) << 7) | ((p[0] & 0x4) << 6) | + ((p[1] & 0x2) << 4) | ((p[0] & 0x2) << 3) | + ((p[1] & 0x1) << 1) | (p[0] & 0x1); + if (fifo->flags & GB_PIXEL_FIFO_FETCH_WINDOW) { + fifo->fetcher[0].fetched |= 0x44444444; + } + } case 5: + break; + case 6: + if (fetch_obj) { + r_io_fd_read_at (gb->io, gb->ppu->vram_fd, fifo->fetcher[1].addr, + &fifo->fetcher[1].data[1], 1); + ut8 *p = &fifo->fetcher[1].data[0]; + if (fifo->obj & GB_FIFO_OAM_FLIP_X) { + fifo->fetcher[1].fetched = + ((p[1] & 0x80) >> 6) | ((p[0] & 0x80) >> 7) | + ((p[1] & 0x40) >> 1) | ((p[0] & 0x40) >> 2) | + ((p[1] & 0x20) << 4) | ((p[0] & 0x20) << 3) | + ((p[1] & 0x10) << 9) | ((p[0] & 0x10) << 8) | + ((p[1] & 0x8) << 14) | ((p[0] & 0x8) << 13) | + ((p[1] & 0x4) << 19) | ((p[0] & 0x4) << 18) | + ((p[1] & 0x2) << 24) | ((p[0] & 0x2) << 23) | + ((p[1] & 0x1) << 29) | ((p[0] & 0x1) << 28); + } else { + fifo->fetcher[1].fetched = + ((p[1] & 0x80) << 22) | ((p[0] & 0x80) << 21) | + ((p[1] & 0x40) << 19) | ((p[0] & 0x40) << 18) | + ((p[1] & 0x20) << 16) | ((p[0] & 0x20) << 15) | + ((p[1] & 0x10) << 13) | ((p[0] & 0x10) << 12) | + ((p[1] & 0x8) << 10) | ((p[0] & 0x8) << 9) | + ((p[1] & 0x4) << 7) | ((p[0] & 0x4) << 6) | + ((p[1] & 0x2) << 4) | ((p[0] & 0x2) << 3) | + ((p[1] & 0x1) << 1) | (p[0] & 0x1); + } + fifo->fetcher[1].fetched |= (fifo->obj & GB_FIFO_OAM_PALLET)? + 0xcccccccc: 0x88888888; + } + break; + case 7: + fifo->flags |= GB_PIXEL_FIFO_FETCH_READY; } + fifo->fetcher[fetch_obj].state_ctr = (fifo->fetcher[fetch_obj].state_ctr + 1) & 0x7; } static ut32 gb_ppu_render_update (GB *gb, ut32 cycles) {