DS Video: Start hooking up software renderer

This commit is contained in:
Vicki Pfau 2017-02-21 16:11:32 -08:00
parent 9f31a1cc2c
commit 5ad7092567
5 changed files with 135 additions and 62 deletions

View File

@ -12,6 +12,7 @@ CXX_GUARD_START
#include <mgba/core/log.h>
#include <mgba/core/timing.h>
#include <mgba/internal/gba/video.h>
mLOG_DECLARE_CATEGORY(DS_VIDEO);
@ -29,6 +30,11 @@ enum {
DS_VIDEO_TOTAL_LENGTH = DS_VIDEO_HORIZONTAL_LENGTH * DS_VIDEO_VERTICAL_TOTAL_PIXELS,
};
union DSOAM {
union GBAOAM oam[2];
uint16_t raw[1024];
};
struct DSVideoRenderer {
void (*init)(struct DSVideoRenderer* renderer);
void (*reset)(struct DSVideoRenderer* renderer);
@ -41,7 +47,9 @@ struct DSVideoRenderer {
void (*getPixels)(struct DSVideoRenderer* renderer, size_t* stride, const void** pixels);
void (*putPixels)(struct DSVideoRenderer* renderer, size_t stride, const void* pixels);
uint16_t* palette;
uint16_t* vram;
union DSOAM* oam;
};
struct DS;
@ -54,7 +62,9 @@ struct DSVideo {
// VCOUNT
int vcount;
uint16_t palette[1024];
uint16_t* vram;
union DSOAM oam;
int32_t frameCounter;
int frameskip;

View File

@ -386,71 +386,77 @@ void DS9IOInit(struct DS* ds) {
}
void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
switch (address) {
// VRAM control
case DS9_REG_VRAMCNT_A:
case DS9_REG_VRAMCNT_C:
case DS9_REG_VRAMCNT_E:
value &= 0x9F9F;
DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A, value & 0xFF);
DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A + 1, value >> 8);
break;
case DS9_REG_VRAMCNT_G:
value &= 0x9F03;
DSVideoConfigureVRAM(&ds->memory, 6, value & 0xFF);
DSConfigureWRAM(&ds->memory, value >> 8);
break;
case DS9_REG_VRAMCNT_H:
value &= 0x9F9F;
DSVideoConfigureVRAM(&ds->memory, 7, value & 0xFF);
DSVideoConfigureVRAM(&ds->memory, 8, value >> 8);
break;
if (address <= DS9_REG_A_BLDY && (address > DS_REG_VCOUNT || address == DS9_REG_A_DISPCNT_LO || address == DS9_REG_B_DISPCNT_LO)) {
value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value);
} else if (address >= DS9_REG_B_DISPCNT_LO && address <= DS9_REG_B_BLDY && (address == DS9_REG_B_DISPCNT_LO || address == DS9_REG_B_DISPCNT_LO)) {
value = ds->video.renderer->writeVideoRegister(ds->video.renderer, address, value);
} else {
switch (address) {
// VRAM control
case DS9_REG_VRAMCNT_A:
case DS9_REG_VRAMCNT_C:
case DS9_REG_VRAMCNT_E:
value &= 0x9F9F;
DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A, value & 0xFF);
DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A + 1, value >> 8);
break;
case DS9_REG_VRAMCNT_G:
value &= 0x9F03;
DSVideoConfigureVRAM(&ds->memory, 6, value & 0xFF);
DSConfigureWRAM(&ds->memory, value >> 8);
break;
case DS9_REG_VRAMCNT_H:
value &= 0x9F9F;
DSVideoConfigureVRAM(&ds->memory, 7, value & 0xFF);
DSVideoConfigureVRAM(&ds->memory, 8, value >> 8);
break;
case DS9_REG_EXMEMCNT:
value &= 0xE8FF;
DSConfigureExternalMemory(ds, value);
break;
case DS9_REG_EXMEMCNT:
value &= 0xE8FF;
DSConfigureExternalMemory(ds, value);
break;
// Math
case DS9_REG_DIVCNT:
value = _scheduleDiv(ds, value);
break;
case DS9_REG_DIV_NUMER_0:
case DS9_REG_DIV_NUMER_1:
case DS9_REG_DIV_NUMER_2:
case DS9_REG_DIV_NUMER_3:
case DS9_REG_DIV_DENOM_0:
case DS9_REG_DIV_DENOM_1:
case DS9_REG_DIV_DENOM_2:
case DS9_REG_DIV_DENOM_3:
ds->memory.io9[DS9_REG_DIVCNT >> 1] = _scheduleDiv(ds, ds->memory.io9[DS9_REG_DIVCNT >> 1]);
break;
case DS9_REG_SQRTCNT:
value = _scheduleSqrt(ds, value);
break;
case DS9_REG_SQRT_PARAM_0:
case DS9_REG_SQRT_PARAM_1:
case DS9_REG_SQRT_PARAM_2:
case DS9_REG_SQRT_PARAM_3:
ds->memory.io9[DS9_REG_SQRTCNT >> 1] = _scheduleSqrt(ds, ds->memory.io9[DS9_REG_SQRTCNT >> 1]);
break;
// Math
case DS9_REG_DIVCNT:
value = _scheduleDiv(ds, value);
break;
case DS9_REG_DIV_NUMER_0:
case DS9_REG_DIV_NUMER_1:
case DS9_REG_DIV_NUMER_2:
case DS9_REG_DIV_NUMER_3:
case DS9_REG_DIV_DENOM_0:
case DS9_REG_DIV_DENOM_1:
case DS9_REG_DIV_DENOM_2:
case DS9_REG_DIV_DENOM_3:
ds->memory.io9[DS9_REG_DIVCNT >> 1] = _scheduleDiv(ds, ds->memory.io9[DS9_REG_DIVCNT >> 1]);
break;
case DS9_REG_SQRTCNT:
value = _scheduleSqrt(ds, value);
break;
case DS9_REG_SQRT_PARAM_0:
case DS9_REG_SQRT_PARAM_1:
case DS9_REG_SQRT_PARAM_2:
case DS9_REG_SQRT_PARAM_3:
ds->memory.io9[DS9_REG_SQRTCNT >> 1] = _scheduleSqrt(ds, ds->memory.io9[DS9_REG_SQRTCNT >> 1]);
break;
default:
{
uint32_t v2 = DSIOWrite(&ds->ds9, address, value);
if (v2 & 0x10000) {
value = v2;
break;
} else if (v2 & 0x20000) {
default:
{
uint32_t v2 = DSIOWrite(&ds->ds9, address, value);
if (v2 & 0x10000) {
value = v2;
break;
} else if (v2 & 0x20000) {
return;
}
}
mLOG(DS_IO, STUB, "Stub DS9 I/O register write: %06X:%04X", address, value);
if (address >= DS7_REG_MAX) {
mLOG(DS_IO, GAME_ERROR, "Write to unused DS9 I/O register: %06X:%04X", address, value);
return;
}
break;
}
mLOG(DS_IO, STUB, "Stub DS9 I/O register write: %06X:%04X", address, value);
if (address >= DS7_REG_MAX) {
mLOG(DS_IO, GAME_ERROR, "Write to unused DS9 I/O register: %06X:%04X", address, value);
return;
}
break;
}
ds->memory.io9[address >> 1] = value;
}

View File

@ -526,8 +526,6 @@ void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
} \
}
uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
struct DS* ds = (struct DS*) cpu->master;
struct DSMemory* memory = &ds->memory;
@ -590,7 +588,6 @@ uint32_t DS7LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum L
return address | addressMisalign;
}
uint32_t DS7StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum LSMDirection direction, int* cycleCounter) {
struct DS* ds = (struct DS*) cpu->master;
struct DSMemory* memory = &ds->memory;
@ -733,6 +730,9 @@ uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
case DS_REGION_IO:
value = DS9IORead32(ds, address & 0x00FFFFFC);
break;
case DS9_REGION_PALETTE_RAM:
LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
break;
case DS_REGION_VRAM: {
unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
int i = 0;
@ -745,6 +745,9 @@ uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
}
break;
}
case DS9_REGION_OAM:
LOAD_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
break;
case DS9_REGION_BIOS:
// TODO: Fix undersized BIOS
// TODO: Fix masking
@ -803,6 +806,9 @@ uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
case DS_REGION_IO:
value = DS9IORead(ds, address & DS_OFFSET_MASK);
break;
case DS9_REGION_PALETTE_RAM:
LOAD_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
break;
case DS_REGION_VRAM: {
unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
int i = 0;
@ -815,6 +821,9 @@ uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
}
break;
}
case DS9_REGION_OAM:
LOAD_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
break;
case DS9_REGION_BIOS:
// TODO: Fix undersized BIOS
// TODO: Fix masking
@ -929,6 +938,9 @@ void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle
case DS_REGION_IO:
DS9IOWrite32(ds, address & DS_OFFSET_MASK, value);
break;
case DS9_REGION_PALETTE_RAM:
STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 4), ds->video.palette);
break;
case DS_REGION_VRAM: {
unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
int i = 0;
@ -939,6 +951,9 @@ void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle
}
break;
}
case DS9_REGION_OAM:
STORE_32(value, address & (DS9_SIZE_OAM - 4), ds->video.oam.raw);
break;
default:
if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
STORE_32(value, address & (DS9_SIZE_DTCM - 4), memory->dtcm);
@ -989,6 +1004,9 @@ void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
case DS_REGION_IO:
DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
break;
case DS9_REGION_PALETTE_RAM:
STORE_16(value, address & (DS9_SIZE_PALETTE_RAM - 2), ds->video.palette);
break;
case DS_REGION_VRAM: {
unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
int i = 0;
@ -999,6 +1017,9 @@ void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
}
break;
}
case DS9_REGION_OAM:
STORE_16(value, address & (DS9_SIZE_OAM - 2), ds->video.oam.raw);
break;
default:
if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
@ -1114,6 +1135,9 @@ uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum L
case DS_REGION_IO:
LDM_LOOP(value = DS9IORead32(ds, address));
break;
case DS9_REGION_PALETTE_RAM:
LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette));
break;
case DS_REGION_VRAM:
LDM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
value = 0;
@ -1126,6 +1150,9 @@ uint32_t DS9LoadMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum L
}
});
break;
case DS9_REGION_OAM:
LDM_LOOP(LOAD_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw));
break;
default:
LDM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
LOAD_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
@ -1200,6 +1227,9 @@ uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum
mLOG(DS_MEM, STUB, "Unimplemented DS9 STM: %08X", address);
});
break;
case DS9_REGION_PALETTE_RAM:
STM_LOOP(STORE_32(value, address & (DS9_SIZE_PALETTE_RAM - 1), ds->video.palette));
break;
case DS_REGION_VRAM:
STM_LOOP(unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
int i = 0;
@ -1209,6 +1239,9 @@ uint32_t DS9StoreMultiple(struct ARMCore* cpu, uint32_t address, int mask, enum
}
});
break;
case DS9_REGION_OAM:
STM_LOOP(STORE_32(value, address & (DS9_SIZE_OAM - 1), ds->video.oam.raw));
break;
default:
STM_LOOP(if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);

View File

@ -18,22 +18,44 @@ void DSVideoSoftwareRendererCreate(struct DSVideoSoftwareRenderer* renderer) {
renderer->d.init = DSVideoSoftwareRendererInit;
renderer->d.reset = DSVideoSoftwareRendererReset;
renderer->d.deinit = DSVideoSoftwareRendererDeinit;
renderer->d.writeVideoRegister = DSVideoSoftwareRendererWriteVideoRegister;
renderer->d.drawScanline = DSVideoSoftwareRendererDrawScanline;
renderer->d.finishFrame = DSVideoSoftwareRendererFinishFrame;
renderer->d.getPixels = DSVideoSoftwareRendererGetPixels;
renderer->d.putPixels = DSVideoSoftwareRendererPutPixels;
renderer->engA.d.cache = NULL;
GBAVideoSoftwareRendererCreate(&renderer->engA);
renderer->engB.d.cache = NULL;
GBAVideoSoftwareRendererCreate(&renderer->engB);
}
static void DSVideoSoftwareRendererInit(struct DSVideoRenderer* renderer) {
struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
softwareRenderer->engA.d.palette = &renderer->palette[0];
softwareRenderer->engA.d.oam = &renderer->oam->oam[0];
// TODO: VRAM
softwareRenderer->engB.d.palette = &renderer->palette[512];
softwareRenderer->engB.d.oam = &renderer->oam->oam[1];
// TODO: VRAM
DSVideoSoftwareRendererReset(renderer);
}
static void DSVideoSoftwareRendererReset(struct DSVideoRenderer* renderer) {
struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
softwareRenderer->engA.d.reset(&softwareRenderer->engA.d);
softwareRenderer->engB.d.reset(&softwareRenderer->engB.d);
}
static void DSVideoSoftwareRendererDeinit(struct DSVideoRenderer* renderer) {
struct DSVideoSoftwareRenderer* softwareRenderer = (struct DSVideoSoftwareRenderer*) renderer;
softwareRenderer->engA.d.deinit(&softwareRenderer->engA.d);
softwareRenderer->engB.d.deinit(&softwareRenderer->engB.d);
}
static uint16_t DSVideoSoftwareRendererWriteVideoRegister(struct DSVideoRenderer* renderer, uint32_t address, uint16_t value) {
mLOG(DS_VIDEO, STUB, "Stub video register write: %04X:%04X", address, value);
return value;
}

View File

@ -158,7 +158,9 @@ void DSVideoReset(struct DSVideo* video) {
void DSVideoAssociateRenderer(struct DSVideo* video, struct DSVideoRenderer* renderer) {
video->renderer->deinit(video->renderer);
video->renderer = renderer;
renderer->palette = video->palette;
renderer->vram = video->vram;
renderer->oam = &video->oam;
video->renderer->init(video->renderer);
}