Huge progress on ppu

This commit is contained in:
condret 2024-11-14 03:52:55 +01:00
parent e94520f6cd
commit f8d11cacc9
4 changed files with 117 additions and 5 deletions

View File

@ -127,6 +127,7 @@ enum {
#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,
@ -169,6 +170,8 @@ typedef struct pixel_fifo_fetcher_t {
//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

View File

@ -8,14 +8,16 @@ typedef struct gb_pixel_buffer_t {
SDL_Texture *texture;
ut8 *buf; //buffer containing pixeldata
ut32 color[4]; //rgb colors
ut32 clear_color;
ut16 w; //x size in pixel
ut16 h; //y size in pixel
// ut16 xsf; //x scale factor for projecting onto the texture
// ut16 ysf; //y scale factor for projecting onto the texture
} GBPixBuf;
GBPixBuf *gb_pix_buf_new(SDL_Renderer *renderer, ut16 w, ut16 h);
GBPixBuf *gb_pix_buf_new(SDL_Renderer *renderer, ut16 w, ut16 h, ut32 clear_color);
void gb_pix_buf_free(GBPixBuf *pb);
void gb_pix_buf_set_pixel(GBPixBuf *pb, ut16 x, ut16 y, ut8 pixval);
void gb_pix_buf_set_color(GBPixBuf *pb, ut8 color_idx, ut32 rgb);
void gb_pix_buf_clear(GBPixBuf *pb);
#endif

100
io/ppu.c
View File

@ -53,9 +53,15 @@ static int __write(RIO *io, RIODesc *desc, const ut8 *buf, int len) {
for (i = 0; i < len; i++) {
switch (seek) {
case GB_PPU_STAT:
ppu->buf[GB_PPU_STAT] = (buf[i] & 0xf8) | (ppu->buf[GB_PPU_STAT] & 0x7);
ppu->buf[GB_PPU_STAT] = (buf[i] & 0xf8) |
(ppu->buf[GB_PPU_STAT] & 0x7);
case GB_PPU_LY:
break;
case GB_PPU_LCDC:
if ((ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_ENABLE) !=
(buf[i] & GB_PPU_LCDC_ENABLE)) {
ppu->fifo.flags1 |= GB_PIXEL_FIFO_LCDC_SWITCH;
}
default:
ppu->buf[seek] = buf[i];
break;
@ -114,7 +120,8 @@ GBPPU *gb_ppu_open (RIO *io, SDL_Renderer *renderer) {
return NULL;
}
ppu->reg_fd = desc->fd;
ppu->pixbuf = gb_pix_buf_new (renderer, 160, 144);
//TODO: use proper clear color
ppu->pixbuf = gb_pix_buf_new (renderer, 160, 144, 0xabcdef);
if (!ppu->pixbuf) {
r_io_desc_close (desc);
r_io_fd_close (io, ppu->vram_fd);
@ -480,14 +487,70 @@ static ut32 gb_ppu_render_continue (GB *gb, ut32 cycles) {
}
static ut32 gb_ppu_hblank_continue (GB *gb, ut32 cycles) {
if (cycles >= gb->ppu->fifo.remaining_cycles) {
gb->ppu->buf[GB_PPU_LY]++;
gb->ppu->buf[GB_PPU_STAT] &= ~GB_PPU_STAT_MODE_MASK;
if (gb->ppu->buf[GB_PPU_LY] == 144) {
//launch vblank
gb->ppu->buf[GB_PPU_STAT] |= GB_PPU_STAT_MODE_VBLANK;
return cycles - gb->ppu->fifo.remaining_cycles;
}
//launch oam scan
gb->ppu->buf[GB_PPU_STAT] |= GB_PPU_STAT_MODE_OAM_SCAN;
return cycles - gb->ppu->fifo.remaining_cycles;
}
gb->ppu->fifo.remaining_cycles -= cycles;
return 0;
}
static ut32 gb_ppu_vblank_continue (GB *gb, ut32 cycles) {
const ut32 m = gb->ppu->fifo.remaining_cycles % 456;
if (m && m < cycles) {
gb->ppu->buf[GB_PPU_LY]++;
if (gb->ppu->buf[GB_PPU_LY] == 156) {
gb->ppu->buf[GB_PPU_STAT] &= ~GB_PPU_STAT_MODE_MASK;
gb->ppu->buf[GB_PPU_STAT] |= GB_PPU_STAT_MODE_OAM_SCAN;
return cycles - gb->ppu->fifo.remaining_cycles;
}
}
gb->ppu->fifo.remaining_cycles -= cycles;
return 0;
}
void gb_ppu_continue (GB *gb, ut32 cycles) {
if (gb->ppu->fifo.flags1 & GB_PIXEL_FIFO_LCDC_SWITCH) {
gb->ppu->fifo.flags1 ^= GB_PIXEL_FIFO_LCDC_SWITCH;
RIOMap *map = r_io_map_get (gb->io, gb->ppu->oam_mapid);
if (gb->ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_ENABLE) {
//lcd was switched on
//launch oam scan
gb->ppu->buf[GB_PPU_LY] = 0;
//disable oam access
map->perm = 0;
gb->ppu->buf[GB_PPU_STAT] &= ~GB_PPU_STAT_MODE_MASK;
gb->ppu->buf[GB_PPU_STAT] |= GB_PPU_STAT_MODE_OAM_SCAN;
if (gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_INTR_OAM) {
gb_interrupts_request (gb, GB_INTERRUPT_STAT);
}
} else {
//lcd was switched off
//enable oam and vram access
map->perm = R_PERM_RWX;
map = r_io_map_get (gb->io, gb->ppu->vram_mapid);
map->perm = R_PERM_RWX;
//clear screen
gb_pix_buf_clear (gb->ppu->pixbuf);
return;
}
}
if (!(gb->ppu->buf[GB_PPU_LCDC] & GB_PPU_LCDC_ENABLE)) {
return;
}
if (gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_INTR_LYC) {
if (gb->ppu->buf[GB_PPU_LY] == gb->ppu->buf[GB_PPU_LYC]) {
gb_interrupts_request (gb, GB_INTERRUPT_STAT);
}
}
while (cycles) {
switch (gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_MODE_MASK) {
case GB_PPU_STAT_MODE_OAM_SCAN:
@ -498,16 +561,47 @@ void gb_ppu_continue (GB *gb, ut32 cycles) {
break;
case GB_PPU_STAT_MODE_RENDER:
cycles = gb_ppu_render_continue (gb, cycles);
if ((gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_MODE_MASK) == GB_PPU_STAT_MODE_HBLANK) {
RIOMap *map = r_io_map_get (gb->io, gb->ppu->oam_mapid);
map->perm = R_PERM_RWX;
map = r_io_map_get (gb->io, gb->ppu->vram_mapid);
map->perm = R_PERM_RWX;
}
break;
case GB_PPU_STAT_MODE_HBLANK:
cycles = gb_ppu_hblank_continue (gb, cycles);
if ((gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_MODE_MASK) == GB_PPU_STAT_MODE_OAM_SCAN) {
RIOMap *oam = r_io_map_get (gb->io, gb->ppu->oam_mapid);
oam->perm = 0;
if (gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_INTR_OAM) {
gb_interrupts_request (gb, GB_INTERRUPT_STAT);
}
} else if ((gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_MODE_MASK) == GB_PPU_STAT_MODE_VBLANK) {
if (gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_INTR_VBLANK) {
gb_interrupts_request (gb, GB_INTERRUPT_STAT);
}
gb_interrupts_request (gb, GB_INTERRUPT_VBLANK);
gb->ppu->fifo.remaining_cycles = 4560;
}
break;
case GB_PPU_STAT_MODE_VBLANK:
cycles = gb_ppu_vblank_continue (gb, cycles);
if ((gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_MODE_MASK) == GB_PPU_STAT_MODE_OAM_SCAN) {
gb->ppu->buf[GB_PPU_LY] = 0;
RIOMap *oam = r_io_map_get (gb->io, gb->ppu->oam_mapid);
oam->perm = 0;
if (gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_INTR_OAM) {
gb_interrupts_request (gb, GB_INTERRUPT_STAT);
}
}
break;
}
}
//TODO
if (gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_INTR_LYC) {
if (gb->ppu->buf[GB_PPU_LY] == gb->ppu->buf[GB_PPU_LYC]) {
gb_interrupts_request (gb, GB_INTERRUPT_STAT);
}
}
}
void gb_ppu_close (GBPPU *ppu, RIO *io) {

View File

@ -2,7 +2,7 @@
#include <r_util.h>
#include <SDL2/SDL.h>
GBPixBuf *gb_pix_buf_new (SDL_Renderer *renderer, ut16 w, ut16 h) {
GBPixBuf *gb_pix_buf_new (SDL_Renderer *renderer, ut16 w, ut16 h, ut32 clear_color) {
if (!renderer || !w || !h) {
return NULL;
}
@ -26,6 +26,7 @@ GBPixBuf *gb_pix_buf_new (SDL_Renderer *renderer, ut16 w, ut16 h) {
}
pb->w = w;
pb->h = h;
pb->clear_color = clear_color;
return pb;
}
@ -62,3 +63,15 @@ void gb_pix_buf_set_color (GBPixBuf *pb, ut8 color_idx, ut32 rgb) {
}
pb->color[color_idx & 0x3] = rgb;
}
void gb_pix_buf_clear (GBPixBuf *pb) {
if (!pb) {
return;
}
SDL_Texture *target = SDL_GetRenderTarget (pb->renderer);
SDL_SetRenderTarget (pb->renderer, pb->texture);
SDL_SetRenderDrawColor (pb->renderer, (pb->clear_color >> 16) & 0xff,
(pb->clear_color >> 8) & 0xff, pb->clear_color & 0xff, 0xff);
SDL_RenderClear (pb->renderer);
SDL_SetRenderTarget (pb->renderer, target);
}