all repos — mgba @ 5ad70925670fcc5069eb093c264d62f45c6b7131

mGBA Game Boy Advance Emulator

DS Video: Start hooking up software renderer
Vicki Pfau vi@endrift.com
Tue, 21 Feb 2017 16:11:32 -0800
commit

5ad70925670fcc5069eb093c264d62f45c6b7131

parent

9f31a1cc2cdb2b88670d8e44d33d6a3cafbb50fc

5 files changed, 135 insertions(+), 62 deletions(-)

jump to
M include/mgba/internal/ds/video.hinclude/mgba/internal/ds/video.h

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

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

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

// VCOUNT int vcount; + uint16_t palette[1024]; uint16_t* vram; + union DSOAM oam; int32_t frameCounter; int frameskip;
M src/ds/io.csrc/ds/io.c

@@ -386,71 +386,77 @@ DS9IOWrite(ds, DS9_REG_VRAMCNT_G, 0x0300);

} 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; }
M src/ds/memory.csrc/ds/memory.c

@@ -526,8 +526,6 @@ address += 4; \

} \ } - - 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;

@@ -589,7 +587,6 @@ }

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;

@@ -733,6 +730,9 @@ break;

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

} 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 @@ mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);

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

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

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

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

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

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

@@ -1113,6 +1134,9 @@ });

break; 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);

@@ -1126,6 +1150,9 @@ value |= newValue;

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

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;

@@ -1208,6 +1238,9 @@ if (mask & (1 << i)) {

STORE_32(value, address & _vramMask[i], memory->vramBank[i]); } }); + 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) {
M src/ds/renderers/software.csrc/ds/renderers/software.c

@@ -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; }
M src/ds/video.csrc/ds/video.c

@@ -158,7 +158,9 @@

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