Compare commits
No commits in common. "3436097c6d4927b87130176f2412c82ed29613c0" and "fe0a183ae5d8cea5eb4b97555b0f9bcd9ec6c5eb" have entirely different histories.
3436097c6d
...
fe0a183ae5
10
Makefile
10
Makefile
|
@ -1,7 +1,7 @@
|
||||||
LDFLAGS = $(shell pkg-config --libs sdl2 r_util r_io)
|
LDFLAGS = $(shell pkg-config --libs sdl2 r_util r_io)
|
||||||
CFLAGS = -Wall -I include/ $(shell pkg-config --cflags sdl2 r_util r_io r_arch r_esil)
|
CFLAGS = -Wall -I include/ $(shell pkg-config --cflags sdl2 r_util r_io)
|
||||||
|
|
||||||
all: sdl/pixbuf.o io/timers.o io/mbc1.o io/mbc2.o io/joypad.o io/dma.o io/ppu.o
|
all: sdl/pixbuf.o io/timers.o io/mbc1.o io/mbc2.o io/joypad.o
|
||||||
|
|
||||||
sdl/pixbuf.o:
|
sdl/pixbuf.o:
|
||||||
gcc -c sdl/pixbuf.c -o sdl/pixbuf.o $(CFLAGS)
|
gcc -c sdl/pixbuf.c -o sdl/pixbuf.o $(CFLAGS)
|
||||||
|
@ -18,11 +18,5 @@ io/mbc2.o:
|
||||||
io/joypad.o:
|
io/joypad.o:
|
||||||
gcc -c io/joypad.c -o io/joypad.o $(CFLAGS)
|
gcc -c io/joypad.c -o io/joypad.o $(CFLAGS)
|
||||||
|
|
||||||
io/dma.o:
|
|
||||||
gcc -c io/dma.c -o io/dma.o $(CFLAGS)
|
|
||||||
|
|
||||||
io/ppu.o:
|
|
||||||
gcc -c io/ppu.c -o io/ppu.o $(CFLAGS)
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm sdl/*.o && rm io/*.o
|
rm sdl/*.o && rm io/*.o
|
||||||
|
|
84
include/gb.h
84
include/gb.h
|
@ -1,16 +1,12 @@
|
||||||
#ifndef GB_H
|
#ifndef GB_H
|
||||||
#define GB_H
|
#define GB_H
|
||||||
#include <ragb_sdl.h>
|
|
||||||
#include <r_io.h>
|
#include <r_io.h>
|
||||||
#include <r_arch.h>
|
|
||||||
#include <r_esil.h>
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
GB_TIMERS_DIV = 0,
|
GB_TIMERS_DIV = 0,
|
||||||
GB_TIMERS_TIMA,
|
GB_TIMERS_TIMA,
|
||||||
GB_TIMERS_TMA,
|
GB_TIMERS_TMA,
|
||||||
GB_TIMERS_TAC,
|
GB_TIMERS_TAC,
|
||||||
GB_TIMERS_N_REGS,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct gb_timers_t {
|
typedef struct gb_timers_t {
|
||||||
|
@ -51,7 +47,6 @@ typedef struct gb_dma_t {
|
||||||
ut64 seek; //17 bit seek and some flags
|
ut64 seek; //17 bit seek and some flags
|
||||||
int dma_fd; //fd representing the dma register
|
int dma_fd; //fd representing the dma register
|
||||||
int dma_bus_fd; //fd representing the memory bus while dma occupies it
|
int dma_bus_fd; //fd representing the memory bus while dma occupies it
|
||||||
int oam_fd; //fd representing oam
|
|
||||||
ut32 dma_bank_id;
|
ut32 dma_bank_id;
|
||||||
ut32 default_bank_id;
|
ut32 default_bank_id;
|
||||||
// ut16 bus_occupancy_size;
|
// ut16 bus_occupancy_size;
|
||||||
|
@ -65,88 +60,11 @@ typedef struct gb_dma_t {
|
||||||
#define GB_DMA_LAUNCH 0x20000
|
#define GB_DMA_LAUNCH 0x20000
|
||||||
#define GB_DMA_RUNNING 0x40000
|
#define GB_DMA_RUNNING 0x40000
|
||||||
#define GB_DMA_ACTIVE 0x60000
|
#define GB_DMA_ACTIVE 0x60000
|
||||||
#define GB_DMA_CGB_MODE 0x80000
|
|
||||||
|
|
||||||
GBDMA *gb_dma_open(RIO *io);
|
GBDMA *gb_dma_open(RIO *io, bool cgb);
|
||||||
//void gb_dma_enable_cgb(GBDMA *dma);
|
|
||||||
void gb_dma_update(GBDMA *dma, RIO *io, ut32 cycles, bool pre_exec);
|
void gb_dma_update(GBDMA *dma, RIO *io, ut32 cycles, bool pre_exec);
|
||||||
void gb_dma_close(GBDMA *dma, RIO *io);
|
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
typedef struct oam_scan_table {
|
|
||||||
ut16 data[10]; //low byte is x coordinate of sprite; high byte is addr of entry (0xffe0 + high byte)
|
|
||||||
ut8 n_entries; //max 10
|
|
||||||
ut8 addr;
|
|
||||||
} OAMScanTable;
|
|
||||||
|
|
||||||
typedef struct pixel_fifo_t {
|
|
||||||
ut64 data;
|
|
||||||
ut32 fetch;
|
|
||||||
ut32 obj_fetch;
|
|
||||||
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 n_fpixel; //number of pixel that are currently in the upper half of the fifo - 1
|
|
||||||
ut8 x;
|
|
||||||
ut8 y;
|
|
||||||
} 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;
|
|
||||||
GBTimers *timers;
|
|
||||||
GBJoypad *joypad;
|
|
||||||
GBDMA *dma;
|
|
||||||
GBPPU *ppu;
|
|
||||||
ut64 addr;
|
|
||||||
int cartrigde_fd;
|
|
||||||
bool double_speed;
|
|
||||||
} GB;
|
|
||||||
|
|
||||||
GBPPU *gb_ppu_open (RIO *io, SDL_Renderer *renderer);
|
|
||||||
void gb_ppu_update (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_timers;
|
||||||
extern RIOPlugin r_io_plugin_gb_mbc1;
|
extern RIOPlugin r_io_plugin_gb_mbc1;
|
||||||
extern RIOPlugin r_io_plugin_gb_mbc2;
|
extern RIOPlugin r_io_plugin_gb_mbc2;
|
||||||
|
|
45
io/dma.c
45
io/dma.c
|
@ -1,5 +1,4 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
|
||||||
#include <gb.h>
|
#include <gb.h>
|
||||||
#include <r_io.h>
|
#include <r_io.h>
|
||||||
#include <r_util.h>
|
#include <r_util.h>
|
||||||
|
@ -19,7 +18,7 @@ static ut64 __bus_lseek(RIO* io, RIODesc *desc, ut64 offset, int whence) {
|
||||||
break;
|
break;
|
||||||
case R_IO_SEEK_END:
|
case R_IO_SEEK_END:
|
||||||
seek = 0xff80;
|
seek = 0xff80;
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
dma->seek = (dma->seek & (~0xffff)) | seek;
|
dma->seek = (dma->seek & (~0xffff)) | seek;
|
||||||
return seek;
|
return seek;
|
||||||
|
@ -32,7 +31,7 @@ static bool __bus_check(RIO *io, const char *pathname, bool many) {
|
||||||
static int __bus_read(RIO *io, RIODesc *desc, ut8 *buf, int len) {
|
static int __bus_read(RIO *io, RIODesc *desc, ut8 *buf, int len) {
|
||||||
GBDMA *dma = desc->data;
|
GBDMA *dma = desc->data;
|
||||||
ut64 seek = dma->seek & 0xffff;
|
ut64 seek = dma->seek & 0xffff;
|
||||||
if (dma->seek > 0xff7f || len < 1) {
|
if (timers->seek > 0xff7f || len < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
len = R_MIN (len, 0xff80 - seek);
|
len = R_MIN (len, 0xff80 - seek);
|
||||||
|
@ -42,7 +41,7 @@ static int __bus_read(RIO *io, RIODesc *desc, ut8 *buf, int len) {
|
||||||
#if 1
|
#if 1
|
||||||
if (len != _len) {
|
if (len != _len) {
|
||||||
ut64 vseek = r_io_p2v (io, seek + _len);
|
ut64 vseek = r_io_p2v (io, seek + _len);
|
||||||
r_io_bank_read_at (io, dma->default_bank_id, vseek, &buf[_len], len - _len);
|
r_io_bank_read_at (io, dma->default_bank_id, &buf[_len], len - _len)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
seek += len;
|
seek += len;
|
||||||
|
@ -53,17 +52,17 @@ static int __bus_read(RIO *io, RIODesc *desc, ut8 *buf, int len) {
|
||||||
static int __bus_write(RIO *io, RIODesc *desc, const ut8 *buf, int len) {
|
static int __bus_write(RIO *io, RIODesc *desc, const ut8 *buf, int len) {
|
||||||
GBDMA *dma = desc->data;
|
GBDMA *dma = desc->data;
|
||||||
ut64 seek = dma->seek & 0xffff;
|
ut64 seek = dma->seek & 0xffff;
|
||||||
if (dma->seek > 0xff7f || len < 1) {
|
if (timers->seek > 0xff7f || len < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
len = R_MIN (len, 0xff80 - seek);
|
len = R_MIN (len, 0xff80 - seek);
|
||||||
int _len = R_MIN (len, 0xa0 - ((ut32)dma->dst + (st32)dma->frontrun));
|
int _len = R_MIN (len, 0xa0 - ((ut32)dma->dst + (st32)dma->frontrun));
|
||||||
// memcpy (buf, &dma->buf[dma->dst + dma->frontrun], _len);
|
// memcpy (buf, &dma->buf[dma->dst + dma->frontrun], _len);
|
||||||
dma->frontrun += _len;
|
dma->frontrun += _len;
|
||||||
#if 1
|
#if 0
|
||||||
if (len != _len) {
|
if (len != _len) {
|
||||||
ut64 vseek = r_io_p2v (io, seek + _len);
|
ut64 vseek = r_io_p2v (io, seek + _len);
|
||||||
r_io_bank_write_at (io, dma->default_bank_id, vseek, &buf[_len], len - _len);
|
r_io_bank_write_at (io, dma->default_bank_id, &buf[_len], len - _len)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
seek += len;
|
seek += len;
|
||||||
|
@ -172,13 +171,13 @@ RIOPlugin r_io_plugin_gb_dma = {
|
||||||
.write = __write,
|
.write = __write,
|
||||||
};
|
};
|
||||||
|
|
||||||
GBDMA *gb_dma_open (RIO *io) {
|
GBDMA *gb_dma_open (RIO *io, bool cgb) {
|
||||||
GBDMA *dma = R_NEW0 (GBDMA);
|
GBDMA *dma = R_NEW0 (GBDMA);
|
||||||
if (!dma) {
|
if (!dma) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
dma->default_bank_id = io->bank;
|
dma->default_bank_id = io->bank;
|
||||||
RIOBank *bank = r_io_bank_new ("dma bus");
|
RIOBank *bank = r_io_bank_new (io, "dma bus");
|
||||||
if (!bank) {
|
if (!bank) {
|
||||||
free (dma);
|
free (dma);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -189,20 +188,12 @@ GBDMA *gb_dma_open (RIO *io) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
dma->dma_bank_id = bank->id;
|
dma->dma_bank_id = bank->id;
|
||||||
// strcpy (uri, "malloc://0xa0");
|
|
||||||
dma->oam_fd = r_io_fd_open (io, "malloc://0xa0", R_PERM_RWX, 0);
|
|
||||||
if (dma->oam_fd < 0) {
|
|
||||||
r_io_bank_free (bank);
|
|
||||||
free (dma);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
char uri[64];
|
char uri[64];
|
||||||
memset (uri, 0x00, sizeof (char) * 64);
|
memset (uri, 0x00, sizeof (char) * 64);
|
||||||
sprintf (uri, "gb_dma://%p", dma);
|
sprintf (uri, "gb_dma://%p", dma);
|
||||||
RIODesc *desc = r_io_desc_open_plugin (io, &r_io_plugin_gb_dma,
|
RIODesc *desc = r_io_desc_open_plugin (io, &r_io_plugin_gb_dma,
|
||||||
uri, R_PERM_RWX, 0);
|
uri, R_PERM_RWX, 0);
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
r_io_fd_close (io, dma->oam_fd);
|
|
||||||
r_io_bank_free (bank);
|
r_io_bank_free (bank);
|
||||||
free (dma);
|
free (dma);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -211,8 +202,7 @@ GBDMA *gb_dma_open (RIO *io) {
|
||||||
sprintf (uri, "gb_dma_bus://%p", dma);
|
sprintf (uri, "gb_dma_bus://%p", dma);
|
||||||
desc = r_io_desc_open_plugin (io, &r_io_plugin_gb_dma_bus, uri, R_PERM_RWX, 0);
|
desc = r_io_desc_open_plugin (io, &r_io_plugin_gb_dma_bus, uri, R_PERM_RWX, 0);
|
||||||
if (!desc) {
|
if (!desc) {
|
||||||
r_io_fd_close (io, dma->oam_fd);
|
r_io_fd_close (dma->dma_fd);
|
||||||
r_io_fd_close (io, dma->dma_fd);
|
|
||||||
r_io_bank_free (bank);
|
r_io_bank_free (bank);
|
||||||
free (dma);
|
free (dma);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -246,13 +236,8 @@ void gb_dma_update (GBDMA *dma, RIO *io, ut32 cycles, bool pre_exec) {
|
||||||
dma->frontrun = ((st32)cycles) * (-1);
|
dma->frontrun = ((st32)cycles) * (-1);
|
||||||
}
|
}
|
||||||
if (cycles) {
|
if (cycles) {
|
||||||
#if 1
|
|
||||||
r_io_fd_write_at (io, dma->oam_fd, (ut64)dma->dst,
|
|
||||||
&dma->buf[dma->dst], cycles);
|
|
||||||
#else
|
|
||||||
r_io_bank_write_at (io, dma->default_bank_id, 0xfe00 | dma->dst,
|
r_io_bank_write_at (io, dma->default_bank_id, 0xfe00 | dma->dst,
|
||||||
&dma->buf[dma->dst], cycles);
|
&dma->buf[dma->dst], cycles);
|
||||||
#endif
|
|
||||||
dma->dst += cycles;
|
dma->dst += cycles;
|
||||||
}
|
}
|
||||||
if (pre_exec) {
|
if (pre_exec) {
|
||||||
|
@ -263,15 +248,3 @@ void gb_dma_update (GBDMA *dma, RIO *io, ut32 cycles, bool pre_exec) {
|
||||||
dma->seek &= (~GB_DMA_ACTIVE);
|
dma->seek &= (~GB_DMA_ACTIVE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gb_dma_close (GBDMA *dma, RIO *io) {
|
|
||||||
if (!dma || !io) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
r_io_bank_use (io, dma->default_bank_id);
|
|
||||||
r_io_bank_del (io, dma->dma_bank_id);
|
|
||||||
r_io_fd_close (io, dma->dma_bus_fd);
|
|
||||||
r_io_fd_close (io, dma->dma_fd);
|
|
||||||
r_io_fd_close (io, dma->oam_fd);
|
|
||||||
free (dma);
|
|
||||||
}
|
|
||||||
|
|
|
@ -45,8 +45,7 @@ static int __read(RIO *io, RIODesc *desc, ut8 *buf, int len) {
|
||||||
#if 0
|
#if 0
|
||||||
joypad->data = buf[0] & 0xf;
|
joypad->data = buf[0] & 0xf;
|
||||||
#else
|
#else
|
||||||
buf[0] = joypad->data & 0x3f;
|
buf[0] = joypad->data & 0x3f
|
||||||
#endif
|
|
||||||
joypad->odata |= 0x40;
|
joypad->odata |= 0x40;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
218
io/ppu.c
218
io/ppu.c
|
@ -1,218 +0,0 @@
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <r_io.h>
|
|
||||||
#include <r_util.h>
|
|
||||||
#include <gb.h>
|
|
||||||
#include <ragb_sdl.h>
|
|
||||||
|
|
||||||
RIOPlugin r_io_plugin_gb_ppu;
|
|
||||||
|
|
||||||
static ut64 __lseek(RIO* io, RIODesc *desc, ut64 offset, int whence) {
|
|
||||||
GBPPU *ppu = desc->data;
|
|
||||||
ut64 seek = ppu->seek & 0xffff;
|
|
||||||
switch (whence) {
|
|
||||||
case R_IO_SEEK_SET:
|
|
||||||
seek = R_MIN (GB_PPU_N_REGS, offset);
|
|
||||||
break;
|
|
||||||
case R_IO_SEEK_CUR:
|
|
||||||
seek = R_MIN (GB_PPU_N_REGS, seek + offset);
|
|
||||||
break;
|
|
||||||
case R_IO_SEEK_END:
|
|
||||||
seek = GB_PPU_N_REGS;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
ppu->seek = (ppu->seek & (~0xffff)) | seek;
|
|
||||||
return seek;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool __check(RIO *io, const char *pathname, bool many) {
|
|
||||||
return r_str_startswith (pathname, "gb_ppu://");
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __read(RIO *io, RIODesc *desc, ut8 *buf, int len) {
|
|
||||||
GBPPU *ppu = desc->data;
|
|
||||||
ut64 seek = ppu->seek & 0xffff;
|
|
||||||
if (ppu->seek >= GB_PPU_N_REGS || len < 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
len = R_MIN (len, GB_PPU_N_REGS - seek);
|
|
||||||
memcpy (buf, &ppu->buf[ppu->seek], len);
|
|
||||||
seek += len;
|
|
||||||
ppu->seek = (ppu->seek & (~0xffff)) | seek;
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int __write(RIO *io, RIODesc *desc, const ut8 *buf, int len) {
|
|
||||||
GBPPU *ppu = desc->data;
|
|
||||||
ut64 seek = ppu->seek & 0xffff;
|
|
||||||
if (ppu->seek >= GB_PPU_N_REGS || len < 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
len = R_MIN (len, GB_PPU_N_REGS - seek);
|
|
||||||
ut32 i;
|
|
||||||
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);
|
|
||||||
case GB_PPU_LY:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ppu->buf[seek] = buf[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
seek++;
|
|
||||||
}
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool __close(RIODesc *desc) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static RIODesc *__open(RIO *io, const char *pathname, int rw, int mode) {
|
|
||||||
if (!r_str_startswith (pathname, "gb_ppu://")) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
GBPPU *ppu = NULL;
|
|
||||||
sscanf (pathname, "gb_ppu://%p", &ppu);
|
|
||||||
RIODesc *desc = r_io_desc_new (io, &r_io_plugin_gb_ppu, pathname,
|
|
||||||
R_PERM_RWX, mode, ppu);
|
|
||||||
return desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
RIOPlugin r_io_plugin_gb_ppu = {
|
|
||||||
.meta = {
|
|
||||||
.name = "gb_ppu",
|
|
||||||
.desc = "gb_ppu",
|
|
||||||
.license = "LGPL",
|
|
||||||
},
|
|
||||||
.uris = "gb_ppu://",
|
|
||||||
.open = __open,
|
|
||||||
.close = __close,
|
|
||||||
.read = __read,
|
|
||||||
.check = __check,
|
|
||||||
.seek = __lseek,
|
|
||||||
.write = __write,
|
|
||||||
};
|
|
||||||
|
|
||||||
GBPPU *gb_ppu_open (RIO *io, SDL_Renderer *renderer) {
|
|
||||||
GBPPU *ppu = R_NEW0 (GBPPU);
|
|
||||||
if (!ppu) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ppu->vram_fd = r_io_fd_open (io, "malloc//:0x2000", R_PERM_RWX, 0);
|
|
||||||
if (ppu->vram_fd < 0) {
|
|
||||||
free (ppu);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
char uri[64];
|
|
||||||
sprintf (uri, "gb_ppu://%p", ppu);
|
|
||||||
RIODesc *desc = r_io_desc_open_plugin (io, &r_io_plugin_gb_ppu, uri, R_PERM_RWX, 0);
|
|
||||||
if (!desc) {
|
|
||||||
r_io_fd_close (io, ppu->vram_fd);
|
|
||||||
free (ppu);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
ppu->reg_fd = desc->fd;
|
|
||||||
ppu->pixbuf = gb_pix_buf_new (renderer, 160, 144);
|
|
||||||
if (!ppu->pixbuf) {
|
|
||||||
r_io_desc_close (desc);
|
|
||||||
r_io_fd_close (io, ppu->vram_fd);
|
|
||||||
free (ppu);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return ppu;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ut32 gb_ppu_oam_scan_update (GB *gb, ut32 cycles) {
|
|
||||||
if (gb->ppu->ost.addr >= 0xa0) {
|
|
||||||
gb->ppu->ost.addr = 0;
|
|
||||||
gb->ppu->ost.n_entries = 0;
|
|
||||||
}
|
|
||||||
if (cycles & 0x1) {
|
|
||||||
R_LOG_WARN ("Odd amount of cycles");
|
|
||||||
}
|
|
||||||
if (gb->dma->seek & GB_DMA_ACTIVE) {
|
|
||||||
const ut8 running_cycles = R_MIN (cycles, (0xa0 - gb->ppu->ost.addr) >> 1);
|
|
||||||
//every oam entry costs 2 cycles
|
|
||||||
gb->ppu->ost.addr += running_cycles << 1;
|
|
||||||
cycles -= running_cycles;
|
|
||||||
goto beach;
|
|
||||||
}
|
|
||||||
const ut8 height = gb->ppu->buf[GB_PPU_LCDC] & 0x3? 16: 8;
|
|
||||||
const ut8 ly = gb->ppu->buf[GB_PPU_LY] + 16;
|
|
||||||
while (cycles && gb->ppu->ost.addr <= 0xa0) {
|
|
||||||
if (gb->ppu->ost.n_entries < 10) {
|
|
||||||
ut8 yx[2];
|
|
||||||
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.n_entries++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gb->ppu->ost.addr += 4;
|
|
||||||
cycles -= 2;
|
|
||||||
}
|
|
||||||
beach:
|
|
||||||
if (gb->ppu->ost.addr == 0xa0) {
|
|
||||||
//indicate next mode
|
|
||||||
gb->ppu->buf[GB_PPU_STAT] |= GB_PPU_STAT_MODE_RENDER;
|
|
||||||
RIOMap *vram = r_io_map_get (gb->io, gb->ppu->vram_mapid);
|
|
||||||
vram->perm = 0; //disable vram access for rendering
|
|
||||||
}
|
|
||||||
return cycles;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void gb_ppu_pixel_fifo_merge_opixels (PixelFifo *pxf, bool priority) {
|
|
||||||
ut32 pixels = pxf->data >> 32;
|
|
||||||
ut32 newpixels = 0;
|
|
||||||
ut32 i;
|
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
if (!(pixels & (0x3 << 28))) {
|
|
||||||
newpixels = (newpixels << 4) |
|
|
||||||
((pxf->obj_fetch & (0xf << ((i - 1) << 2))) >> ((i - 1) << 2));
|
|
||||||
pixels = pixels << 4;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static ut32 gb_ppu_render_update (GB *gb, ut32 cycles) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ut32 gb_ppu_hblank_update (GB *gb, ut32 cycles) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static ut32 gb_ppu_vblank_update (GB *gb, ut32 cycles) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void gb_ppu_update (GB *gb, ut32 cycles) {
|
|
||||||
while (cycles) {
|
|
||||||
switch (gb->ppu->buf[GB_PPU_STAT] & GB_PPU_STAT_MODE_MASK) {
|
|
||||||
case GB_PPU_STAT_MODE_OAM_SCAN:
|
|
||||||
cycles = gb_ppu_oam_scan_update (gb, cycles);
|
|
||||||
break;
|
|
||||||
case GB_PPU_STAT_MODE_RENDER:
|
|
||||||
cycles = gb_ppu_render_update (gb, cycles);
|
|
||||||
break;
|
|
||||||
case GB_PPU_STAT_MODE_HBLANK:
|
|
||||||
cycles = gb_ppu_hblank_update (gb, cycles);
|
|
||||||
break;
|
|
||||||
case GB_PPU_STAT_MODE_VBLANK:
|
|
||||||
cycles = gb_ppu_vblank_update (gb, cycles);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
void gb_ppu_close (GBPPU *ppu, RIO *io) {
|
|
||||||
r_io_fd_close (io, ppu->vram_fd);
|
|
||||||
r_io_fd_close (io, ppu->reg_fd);
|
|
||||||
gb_pix_buf_free (ppu->pixbuf);
|
|
||||||
free (ppu);
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user