GB: Implement sprites, SRAM

This commit is contained in:
Jeffrey Pfau 2016-01-21 19:30:51 -08:00
parent 5cd84799be
commit 8750f78808
6 changed files with 210 additions and 16 deletions

View File

@ -57,6 +57,9 @@ void GBMemoryDeinit(struct GB* gb) {
if (gb->memory.rom) { if (gb->memory.rom) {
mappedMemoryFree(gb->memory.rom, gb->memory.romSize); mappedMemoryFree(gb->memory.rom, gb->memory.romSize);
} }
if (gb->memory.sram) {
mappedMemoryFree(gb->memory.sram, 0x8000);
}
} }
void GBMemoryReset(struct GB* gb) { void GBMemoryReset(struct GB* gb) {
@ -67,6 +70,10 @@ void GBMemoryReset(struct GB* gb) {
gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0]; gb->memory.wramBank = &gb->memory.wram[GB_SIZE_WORKING_RAM_BANK0];
gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0]; gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
gb->memory.currentBank = 1; gb->memory.currentBank = 1;
gb->memory.sram = anonymousMemoryMap(0x8000); // TODO: Persist
gb->memory.sramCurrentBank = 0;
memset(&gb->video.oam, 0, sizeof(gb->video.oam));
const struct GBCartridge* cart = &gb->memory.rom[0x100]; const struct GBCartridge* cart = &gb->memory.rom[0x100];
switch (cart->type) { switch (cart->type) {
@ -138,8 +145,10 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
return gb->video.vram[address & (GB_SIZE_VRAM - 1)]; return gb->video.vram[address & (GB_SIZE_VRAM - 1)];
case GB_REGION_EXTERNAL_RAM: case GB_REGION_EXTERNAL_RAM:
case GB_REGION_EXTERNAL_RAM + 1: case GB_REGION_EXTERNAL_RAM + 1:
// TODO if (memory->sramAccess) {
return 0; return gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
}
return 0xFF;
case GB_REGION_WORKING_RAM_BANK0: case GB_REGION_WORKING_RAM_BANK0:
case GB_REGION_WORKING_RAM_BANK0 + 2: case GB_REGION_WORKING_RAM_BANK0 + 2:
return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
@ -149,9 +158,14 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
if (address < GB_BASE_OAM) { if (address < GB_BASE_OAM) {
return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)]; return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
} }
if (address < GB_BASE_UNUSABLE) {
if (gb->video.mode < 2) {
return gb->video.oam.raw[address & 0xFF];
}
return 0xFF;
}
if (address < GB_BASE_IO) { if (address < GB_BASE_IO) {
// TODO return 0xFF;
return 0;
} }
if (address < GB_BASE_HRAM) { if (address < GB_BASE_HRAM) {
return GBIORead(gb, address & (GB_SIZE_IO - 1)); return GBIORead(gb, address & (GB_SIZE_IO - 1));
@ -185,7 +199,9 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
return; return;
case GB_REGION_EXTERNAL_RAM: case GB_REGION_EXTERNAL_RAM:
case GB_REGION_EXTERNAL_RAM + 1: case GB_REGION_EXTERNAL_RAM + 1:
// TODO if (memory->sramAccess) {
gb->memory.sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
}
return; return;
case GB_REGION_WORKING_RAM_BANK0: case GB_REGION_WORKING_RAM_BANK0:
case GB_REGION_WORKING_RAM_BANK0 + 2: case GB_REGION_WORKING_RAM_BANK0 + 2:
@ -197,8 +213,13 @@ void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
default: default:
if (address < GB_BASE_OAM) { if (address < GB_BASE_OAM) {
memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value; memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
} else if (address < GB_BASE_UNUSABLE) {
if (gb->video.mode < 2) {
gb->video.oam.raw[address & 0xFF] = value;
gb->video.renderer->writeOAM(gb->video.renderer, address & 0xFF);
}
} else if (address < GB_BASE_IO) { } else if (address < GB_BASE_IO) {
// TODO // TODO: Log
} else if (address < GB_BASE_HRAM) { } else if (address < GB_BASE_HRAM) {
GBIOWrite(gb, address & (GB_SIZE_IO - 1), value); GBIOWrite(gb, address & (GB_SIZE_IO - 1), value);
} else if (address < GB_BASE_IE) { } else if (address < GB_BASE_IE) {
@ -282,12 +303,30 @@ static void _switchBank(struct GBMemory* memory, int bank) {
memory->currentBank = bank; memory->currentBank = bank;
} }
static void _switchSramBank(struct GBMemory* memory, int bank) {
size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
memory->sramBank = &memory->sram[bankStart];
memory->sramCurrentBank = bank;
}
void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) { void _GBMBC1(struct GBMemory* memory, uint16_t address, uint8_t value) {
int bank = value & 0x1F; int bank = value & 0x1F;
switch (address >> 13) { switch (address >> 13) {
case 0x0: case 0x0:
switch (value) {
case 0:
memory->sramAccess = false;
break;
case 0xA:
memory->sramAccess = true;
_switchSramBank(memory, memory->sramCurrentBank);
break;
default:
// TODO // TODO
break; break;
}
break;
break;
case 0x1: case 0x1:
if (!bank) { if (!bank) {
++bank; ++bank;
@ -305,14 +344,30 @@ void _GBMBC3(struct GBMemory* memory, uint16_t address, uint8_t value) {
int bank = value & 0x7F; int bank = value & 0x7F;
switch (address >> 13) { switch (address >> 13) {
case 0x0: case 0x0:
switch (value) {
case 0:
memory->sramAccess = false;
break;
case 0xA:
memory->sramAccess = true;
_switchSramBank(memory, memory->sramCurrentBank);
break;
default:
// TODO // TODO
break; break;
}
break;
case 0x1: case 0x1:
if (!bank) { if (!bank) {
++bank; ++bank;
} }
_switchBank(memory, bank); _switchBank(memory, bank);
break; break;
case 0x2:
if (value < 4) {
_switchSramBank(memory, value);
}
break;
} }
} }
@ -324,8 +379,20 @@ void _GBMBC5(struct GBMemory* memory, uint16_t address, uint8_t value) {
int bank = value & 0x7F; int bank = value & 0x7F;
switch (address >> 13) { switch (address >> 13) {
case 0x0: case 0x0:
switch (value) {
case 0:
memory->sramAccess = false;
break;
case 0xA:
memory->sramAccess = true;
_switchSramBank(memory, memory->sramCurrentBank);
break;
default:
// TODO // TODO
break; break;
}
break;
break;
case 0x1: case 0x1:
_switchBank(memory, bank); _switchBank(memory, bank);
break; break;

View File

@ -20,6 +20,7 @@ enum {
GB_BASE_WORKING_RAM_BANK0 = 0xC000, GB_BASE_WORKING_RAM_BANK0 = 0xC000,
GB_BASE_WORKING_RAM_BANK1 = 0xD000, GB_BASE_WORKING_RAM_BANK1 = 0xD000,
GB_BASE_OAM = 0xFE00, GB_BASE_OAM = 0xFE00,
GB_BASE_UNUSABLE = 0xFEA0,
GB_BASE_IO = 0xFF00, GB_BASE_IO = 0xFF00,
GB_BASE_HRAM = 0xFF80, GB_BASE_HRAM = 0xFF80,
GB_BASE_IE = 0xFFFF GB_BASE_IE = 0xFFFF

View File

@ -12,6 +12,7 @@ static void GBVideoSoftwareRendererInit(struct GBVideoRenderer* renderer);
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer); static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer);
static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer); static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer);
static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address); static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, uint8_t oam);
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y); static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y);
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer); static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer);
@ -19,6 +20,9 @@ static void GBVideoSoftwareRendererGetPixels(struct GBVideoRenderer* renderer, u
static void GBVideoSoftwareRendererPutPixels(struct GBVideoRenderer* renderer, unsigned stride, void* pixels); static void GBVideoSoftwareRendererPutPixels(struct GBVideoRenderer* renderer, unsigned stride, void* pixels);
static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int x, int y, int sx, int sy); static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer* renderer, uint8_t* maps, int x, int y, int sx, int sy);
static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int y);
static void _cleanOAM(struct GBVideoSoftwareRenderer* renderer);
#ifdef COLOR_16_BIT #ifdef COLOR_16_BIT
#ifdef COLOR_5_6_5 #ifdef COLOR_5_6_5
@ -36,6 +40,7 @@ void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer* renderer) {
renderer->d.deinit = GBVideoSoftwareRendererDeinit; renderer->d.deinit = GBVideoSoftwareRendererDeinit;
renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister; renderer->d.writeVideoRegister = GBVideoSoftwareRendererWriteVideoRegister;
renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM; renderer->d.writeVRAM = GBVideoSoftwareRendererWriteVRAM;
renderer->d.writeOAM = GBVideoSoftwareRendererWriteOAM;
renderer->d.drawScanline = GBVideoSoftwareRendererDrawScanline; renderer->d.drawScanline = GBVideoSoftwareRendererDrawScanline;
renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame; renderer->d.finishFrame = GBVideoSoftwareRendererFinishFrame;
renderer->d.getPixels = 0; renderer->d.getPixels = 0;
@ -65,6 +70,8 @@ static void GBVideoSoftwareRendererReset(struct GBVideoRenderer* renderer) {
softwareRenderer->scx = 0; softwareRenderer->scx = 0;
softwareRenderer->wy = 0; softwareRenderer->wy = 0;
softwareRenderer->wx = 0; softwareRenderer->wx = 0;
softwareRenderer->oamMax = 0;
softwareRenderer->oamDirty = false;
} }
static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) { static void GBVideoSoftwareRendererDeinit(struct GBVideoRenderer* renderer) {
@ -76,6 +83,13 @@ static void GBVideoSoftwareRendererWriteVRAM(struct GBVideoRenderer* renderer, u
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
// TODO // TODO
} }
static void GBVideoSoftwareRendererWriteOAM(struct GBVideoRenderer* renderer, uint8_t oam) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
UNUSED(oam);
softwareRenderer->oamDirty = true;
}
static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) { static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
switch (address) { switch (address) {
@ -119,7 +133,14 @@ static uint8_t GBVideoSoftwareRendererWriteVideoRegister(struct GBVideoRenderer*
static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y) { static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y]; size_t x;
for (x = 0; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
softwareRenderer->row[x] = GB_PALETTE[0];
}
if (softwareRenderer->oamDirty) {
_cleanOAM(softwareRenderer);
}
uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP]; uint8_t* maps = &softwareRenderer->d.vram[GB_BASE_MAP];
if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) { if (GBRegisterLCDCIsTileMap(softwareRenderer->lcdc)) {
@ -127,15 +148,27 @@ static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer
} }
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, 0, y, softwareRenderer->scx, softwareRenderer->scy); GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, 0, y, softwareRenderer->scx, softwareRenderer->scy);
if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc)) { if (GBRegisterLCDCIsWindow(softwareRenderer->lcdc) && softwareRenderer->wy < GB_VIDEO_VERTICAL_PIXELS) {
maps = &softwareRenderer->d.vram[GB_BASE_MAP]; maps = &softwareRenderer->d.vram[GB_BASE_MAP];
if (GBRegisterLCDCIsWindowTileMap(softwareRenderer->lcdc)) { if (GBRegisterLCDCIsWindowTileMap(softwareRenderer->lcdc)) {
maps += GB_SIZE_MAP; maps += GB_SIZE_MAP;
} }
GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, -7, y, softwareRenderer->wx - 7, softwareRenderer->wy); GBVideoSoftwareRendererDrawBackground(softwareRenderer, maps, 0, y, 7 - softwareRenderer->wx, -softwareRenderer->wy);
} }
size_t x; int spriteHeight = 8;
if (GBRegisterLCDCIsObjSize(softwareRenderer->lcdc)) {
spriteHeight = 16;
}
int i;
for (i = 0; i < softwareRenderer->oamMax; ++i) {
// TODO: Sprite sizes
if (y >= softwareRenderer->obj[i]->y - 16 && y < softwareRenderer->obj[i]->y - 16 + spriteHeight) {
GBVideoSoftwareRendererDrawObj(softwareRenderer, softwareRenderer->obj[i], y);
}
}
color_t* row = &softwareRenderer->outputBuffer[softwareRenderer->outputBufferStride * y];
#ifdef COLOR_16_BIT #ifdef COLOR_16_BIT
#if defined(__ARM_NEON) && !defined(__APPLE__) #if defined(__ARM_NEON) && !defined(__APPLE__)
_to16Bit(row, softwareRenderer->row, GB_VIDEO_HORIZONTAL_PIXELS); _to16Bit(row, softwareRenderer->row, GB_VIDEO_HORIZONTAL_PIXELS);
@ -149,6 +182,24 @@ static void GBVideoSoftwareRendererDrawScanline(struct GBVideoRenderer* renderer
#endif #endif
} }
static void _cleanOAM(struct GBVideoSoftwareRenderer* renderer) {
// TODO: GBC differences
renderer->oamMax = 0;
int o = 0;
int i;
for (i = 0; i < 40; ++i) {
uint8_t y = renderer->d.oam->obj[i].y;
if (y < 16 || y >= GB_VIDEO_VERTICAL_PIXELS + 16) {
continue;
}
// TODO: Sort
renderer->obj[o] = &renderer->d.oam->obj[i];
++o;
}
renderer->oamMax = o;
renderer->oamDirty = false;
}
static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) { static void GBVideoSoftwareRendererFinishFrame(struct GBVideoRenderer* renderer) {
struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer; struct GBVideoSoftwareRenderer* softwareRenderer = (struct GBVideoSoftwareRenderer*) renderer;
@ -165,9 +216,6 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
} }
int topY = (((y + sy) >> 3) & 0x1F) * 0x20; int topY = (((y + sy) >> 3) & 0x1F) * 0x20;
int bottomY = (y + sy) & 7; int bottomY = (y + sy) & 7;
if (x < 0) {
x = 0;
}
for (; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) { for (; x < GB_VIDEO_HORIZONTAL_PIXELS; ++x) {
int topX = ((x + sx) >> 3) & 0x1F; int topX = ((x + sx) >> 3) & 0x1F;
int bottomX = 7 - ((x + sx) & 7); int bottomX = 7 - ((x + sx) & 7);
@ -184,3 +232,45 @@ static void GBVideoSoftwareRendererDrawBackground(struct GBVideoSoftwareRenderer
renderer->row[x] = renderer->bgPalette[((tileDataUpper & 1) << 1) | (tileDataLower & 1)]; renderer->row[x] = renderer->bgPalette[((tileDataUpper & 1) << 1) | (tileDataLower & 1)];
} }
} }
static void GBVideoSoftwareRendererDrawObj(struct GBVideoSoftwareRenderer* renderer, struct GBObj* obj, int y) {
uint8_t* data = renderer->d.vram;
int tileOffset = 0;
int bottomY;
if (GBObjAttributesIsYFlip(obj->attr)) {
bottomY = 7 - ((y - obj->y - 16) & 7);
if (y - obj->y < -8) {
++tileOffset;
}
} else {
bottomY = (y - obj->y - 16) & 7;
if (y - obj->y >= -8) {
++tileOffset;
}
}
int end = GB_VIDEO_HORIZONTAL_PIXELS;
if (obj->x < end) {
end = obj->x;
}
int x = obj->x - 8;
if (x < 0) {
x = 0;
}
for (; x < end; ++x) {
int bottomX;
if (GBObjAttributesIsXFlip(obj->attr)) {
bottomX = (x - obj->x) & 7;
} else {
bottomX = 7 - ((x - obj->x) & 7);
}
int objTile = obj->tile + tileOffset;
uint8_t tileDataLower = data[(objTile * 8 + bottomY) * 2];
uint8_t tileDataUpper = data[(objTile * 8 + bottomY) * 2 + 1];
tileDataUpper >>= bottomX;
tileDataLower >>= bottomX;
color_t current = renderer->row[x];
if (((tileDataUpper | tileDataLower) & 1) && (!GBObjAttributesIsPriority(obj->attr) || current == GB_PALETTE[0])) {
renderer->row[x] = renderer->bgPalette[((tileDataUpper & 1) << 1) | (tileDataLower & 1)];
}
}
}

View File

@ -35,6 +35,10 @@ struct GBVideoSoftwareRenderer {
uint8_t wx; uint8_t wx;
GBRegisterLCDC lcdc; GBRegisterLCDC lcdc;
struct GBObj* obj[40];
int oamMax;
bool oamDirty;
}; };
void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*); void GBVideoSoftwareRendererCreate(struct GBVideoSoftwareRenderer*);

View File

@ -15,6 +15,7 @@ static void GBVideoDummyRendererReset(struct GBVideoRenderer* renderer);
static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer); static void GBVideoDummyRendererDeinit(struct GBVideoRenderer* renderer);
static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); static uint8_t GBVideoDummyRendererWriteVideoRegister(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address); static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint16_t address);
static void GBVideoDummyRendererWriteOAM(struct GBVideoRenderer* renderer, uint8_t oam);
static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y); static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y);
static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer); static void GBVideoDummyRendererFinishFrame(struct GBVideoRenderer* renderer);
static void GBVideoDummyRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels); static void GBVideoDummyRendererGetPixels(struct GBVideoRenderer* renderer, unsigned* stride, const void** pixels);
@ -25,6 +26,7 @@ static struct GBVideoRenderer dummyRenderer = {
.deinit = GBVideoDummyRendererDeinit, .deinit = GBVideoDummyRendererDeinit,
.writeVideoRegister = GBVideoDummyRendererWriteVideoRegister, .writeVideoRegister = GBVideoDummyRendererWriteVideoRegister,
.writeVRAM = GBVideoDummyRendererWriteVRAM, .writeVRAM = GBVideoDummyRendererWriteVRAM,
.writeOAM = GBVideoDummyRendererWriteOAM,
.drawScanline = GBVideoDummyRendererDrawScanline, .drawScanline = GBVideoDummyRendererDrawScanline,
.finishFrame = GBVideoDummyRendererFinishFrame, .finishFrame = GBVideoDummyRendererFinishFrame,
.getPixels = GBVideoDummyRendererGetPixels .getPixels = GBVideoDummyRendererGetPixels
@ -53,6 +55,8 @@ void GBVideoReset(struct GBVideo* video) {
} }
video->vram = anonymousMemoryMap(GB_SIZE_VRAM); video->vram = anonymousMemoryMap(GB_SIZE_VRAM);
video->renderer->vram = video->vram; video->renderer->vram = video->vram;
memset(&video->oam, 0, sizeof(video->oam));
video->renderer->oam = &video->oam;
video->renderer->deinit(video->renderer); video->renderer->deinit(video->renderer);
video->renderer->init(video->renderer); video->renderer->init(video->renderer);
@ -200,6 +204,12 @@ static void GBVideoDummyRendererWriteVRAM(struct GBVideoRenderer* renderer, uint
// Nothing to do // Nothing to do
} }
static void GBVideoDummyRendererWriteOAM(struct GBVideoRenderer* renderer, uint8_t oam) {
UNUSED(renderer);
UNUSED(oam);
// Nothing to do
}
static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y) { static void GBVideoDummyRendererDrawScanline(struct GBVideoRenderer* renderer, int y) {
UNUSED(renderer); UNUSED(renderer);
UNUSED(y); UNUSED(y);

View File

@ -29,6 +29,24 @@ enum {
GB_SIZE_MAP = 0x0400 GB_SIZE_MAP = 0x0400
}; };
DECL_BITFIELD(GBObjAttributes, uint8_t);
DECL_BIT(GBObjAttributes, Palette, 4);
DECL_BIT(GBObjAttributes, XFlip, 5);
DECL_BIT(GBObjAttributes, YFlip, 6);
DECL_BIT(GBObjAttributes, Priority, 7);
struct GBObj {
uint8_t y;
uint8_t x;
uint8_t tile;
GBObjAttributes attr;
};
union GBOAM {
struct GBObj obj[40];
uint8_t raw[160];
};
struct GBVideoRenderer { struct GBVideoRenderer {
void (*init)(struct GBVideoRenderer* renderer); void (*init)(struct GBVideoRenderer* renderer);
void (*reset)(struct GBVideoRenderer* renderer); void (*reset)(struct GBVideoRenderer* renderer);
@ -36,6 +54,7 @@ struct GBVideoRenderer {
uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value); uint8_t (*writeVideoRegister)(struct GBVideoRenderer* renderer, uint16_t address, uint8_t value);
void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address); void (*writeVRAM)(struct GBVideoRenderer* renderer, uint16_t address);
void (*writeOAM)(struct GBVideoRenderer* renderer, uint8_t oam);
void (*drawScanline)(struct GBVideoRenderer* renderer, int y); void (*drawScanline)(struct GBVideoRenderer* renderer, int y);
void (*finishFrame)(struct GBVideoRenderer* renderer); void (*finishFrame)(struct GBVideoRenderer* renderer);
@ -43,6 +62,7 @@ struct GBVideoRenderer {
void (*putPixels)(struct GBVideoRenderer* renderer, unsigned stride, void* pixels); void (*putPixels)(struct GBVideoRenderer* renderer, unsigned stride, void* pixels);
uint8_t* vram; uint8_t* vram;
union GBOAM* oam;
}; };
DECL_BITFIELD(GBRegisterLCDC, uint8_t); DECL_BITFIELD(GBRegisterLCDC, uint8_t);
@ -80,6 +100,8 @@ struct GBVideo {
uint8_t* vram; uint8_t* vram;
uint8_t* vramBank; uint8_t* vramBank;
union GBOAM oam;
int32_t frameCounter; int32_t frameCounter;
int frameskip; int frameskip;
int frameskipCounter; int frameskipCounter;