Compare commits

..

No commits in common. "3436097c6d4927b87130176f2412c82ed29613c0" and "fe0a183ae5d8cea5eb4b97555b0f9bcd9ec6c5eb" have entirely different histories.

5 changed files with 13 additions and 347 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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
View File

@ -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);
}