diff --git a/include/mgba/internal/ds/video.h b/include/mgba/internal/ds/video.h index a02f5cbec..eecc67bd5 100644 --- a/include/mgba/internal/ds/video.h +++ b/include/mgba/internal/ds/video.h @@ -12,6 +12,7 @@ CXX_GUARD_START #include #include +#include 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; diff --git a/src/ds/io.c b/src/ds/io.c index d4eff69c0..3bd5b25b1 100644 --- a/src/ds/io.c +++ b/src/ds/io.c @@ -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; } diff --git a/src/ds/memory.c b/src/ds/memory.c index 905befee8..cd43d2a22 100644 --- a/src/ds/memory.c +++ b/src/ds/memory.c @@ -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); diff --git a/src/ds/renderers/software.c b/src/ds/renderers/software.c index e11788ef1..5baf94a84 100644 --- a/src/ds/renderers/software.c +++ b/src/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; } diff --git a/src/ds/video.c b/src/ds/video.c index f2fa114f9..9a5cd38f9 100644 --- a/src/ds/video.c +++ b/src/ds/video.c @@ -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); }