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)
|
||||
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:
|
||||
gcc -c sdl/pixbuf.c -o sdl/pixbuf.o $(CFLAGS)
|
||||
|
@ -18,11 +18,5 @@ io/mbc2.o:
|
|||
io/joypad.o:
|
||||
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:
|
||||
rm sdl/*.o && rm io/*.o
|
||||
|
|
84
include/gb.h
84
include/gb.h
|
@ -1,16 +1,12 @@
|
|||
#ifndef GB_H
|
||||
#define GB_H
|
||||
#include <ragb_sdl.h>
|
||||
#include <r_io.h>
|
||||
#include <r_arch.h>
|
||||
#include <r_esil.h>
|
||||
|
||||
enum {
|
||||
GB_TIMERS_DIV = 0,
|
||||
GB_TIMERS_TIMA,
|
||||
GB_TIMERS_TMA,
|
||||
GB_TIMERS_TAC,
|
||||
GB_TIMERS_N_REGS,
|
||||
};
|
||||
|
||||
typedef struct gb_timers_t {
|
||||
|
@ -51,7 +47,6 @@ 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;
|
||||
|
@ -65,88 +60,11 @@ typedef struct gb_dma_t {
|
|||
#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);
|
||||
GBDMA *gb_dma_open(RIO *io, bool cgb);
|
||||
void gb_dma_update(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,
|
||||
};
|
||||
|
||||
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_mbc1;
|
||||
extern RIOPlugin r_io_plugin_gb_mbc2;
|
||||
|
|
45
io/dma.c
45
io/dma.c
|
@ -1,5 +1,4 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <gb.h>
|
||||
#include <r_io.h>
|
||||
#include <r_util.h>
|
||||
|
@ -19,7 +18,7 @@ static ut64 __bus_lseek(RIO* io, RIODesc *desc, ut64 offset, int whence) {
|
|||
break;
|
||||
case R_IO_SEEK_END:
|
||||
seek = 0xff80;
|
||||
break;
|
||||
break
|
||||
}
|
||||
dma->seek = (dma->seek & (~0xffff)) | 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) {
|
||||
GBDMA *dma = desc->data;
|
||||
ut64 seek = dma->seek & 0xffff;
|
||||
if (dma->seek > 0xff7f || len < 1) {
|
||||
if (timers->seek > 0xff7f || len < 1) {
|
||||
return 0;
|
||||
}
|
||||
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 (len != _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
|
||||
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) {
|
||||
GBDMA *dma = desc->data;
|
||||
ut64 seek = dma->seek & 0xffff;
|
||||
if (dma->seek > 0xff7f || len < 1) {
|
||||
if (timers->seek > 0xff7f || len < 1) {
|
||||
return 0;
|
||||
}
|
||||
len = R_MIN (len, 0xff80 - seek);
|
||||
int _len = R_MIN (len, 0xa0 - ((ut32)dma->dst + (st32)dma->frontrun));
|
||||
// memcpy (buf, &dma->buf[dma->dst + dma->frontrun], _len);
|
||||
dma->frontrun += _len;
|
||||
#if 1
|
||||
#if 0
|
||||
if (len != _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
|
||||
seek += len;
|
||||
|
@ -172,13 +171,13 @@ RIOPlugin r_io_plugin_gb_dma = {
|
|||
.write = __write,
|
||||
};
|
||||
|
||||
GBDMA *gb_dma_open (RIO *io) {
|
||||
GBDMA *gb_dma_open (RIO *io, bool cgb) {
|
||||
GBDMA *dma = R_NEW0 (GBDMA);
|
||||
if (!dma) {
|
||||
return NULL;
|
||||
}
|
||||
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) {
|
||||
free (dma);
|
||||
return NULL;
|
||||
|
@ -189,20 +188,12 @@ GBDMA *gb_dma_open (RIO *io) {
|
|||
return NULL;
|
||||
}
|
||||
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];
|
||||
memset (uri, 0x00, sizeof (char) * 64);
|
||||
sprintf (uri, "gb_dma://%p", dma);
|
||||
RIODesc *desc = r_io_desc_open_plugin (io, &r_io_plugin_gb_dma,
|
||||
uri, R_PERM_RWX, 0);
|
||||
if (!desc) {
|
||||
r_io_fd_close (io, dma->oam_fd);
|
||||
r_io_bank_free (bank);
|
||||
free (dma);
|
||||
return NULL;
|
||||
|
@ -211,8 +202,7 @@ GBDMA *gb_dma_open (RIO *io) {
|
|||
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);
|
||||
if (!desc) {
|
||||
r_io_fd_close (io, dma->oam_fd);
|
||||
r_io_fd_close (io, dma->dma_fd);
|
||||
r_io_fd_close (dma->dma_fd);
|
||||
r_io_bank_free (bank);
|
||||
free (dma);
|
||||
return NULL;
|
||||
|
@ -246,13 +236,8 @@ void gb_dma_update (GBDMA *dma, RIO *io, ut32 cycles, bool pre_exec) {
|
|||
dma->frontrun = ((st32)cycles) * (-1);
|
||||
}
|
||||
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,
|
||||
&dma->buf[dma->dst], cycles);
|
||||
#endif
|
||||
dma->dst += cycles;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
joypad->data = buf[0] & 0xf;
|
||||
#else
|
||||
buf[0] = joypad->data & 0x3f;
|
||||
#endif
|
||||
buf[0] = joypad->data & 0x3f
|
||||
joypad->odata |= 0x40;
|
||||
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