DS Video: VRAM configuration

This commit is contained in:
Vicki Pfau 2017-02-16 00:46:01 -08:00
parent bb83e78af9
commit 9b86abec09
6 changed files with 207 additions and 10 deletions

View File

@ -65,7 +65,8 @@ enum {
enum { enum {
DS_OFFSET_MASK = 0x00FFFFFF, DS_OFFSET_MASK = 0x00FFFFFF,
DS_BASE_OFFSET = 24 DS_BASE_OFFSET = 24,
DS_VRAM_OFFSET = 14
}; };
mLOG_DECLARE_CATEGORY(DS_MEM); mLOG_DECLARE_CATEGORY(DS_MEM);
@ -82,6 +83,10 @@ struct DSMemory {
uint16_t io7[DS7_REG_MAX >> 1]; uint16_t io7[DS7_REG_MAX >> 1];
uint16_t io9[DS9_REG_MAX >> 1]; uint16_t io9[DS9_REG_MAX >> 1];
uint16_t vramMirror[9][0x40];
uint16_t vramMode[9][8];
uint16_t* vramBank[9];
size_t romSize; size_t romSize;
size_t wramSize7; size_t wramSize7;
size_t wramSize9; size_t wramSize9;

View File

@ -52,6 +52,9 @@ void DSVideoDeinit(struct DSVideo* video);
struct DSCommon; struct DSCommon;
void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value); void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value);
struct DSMemory;
void DSVideoConfigureVRAM(struct DSMemory* memory, int index, uint8_t value);
CXX_GUARD_START CXX_GUARD_START
#endif #endif

View File

@ -224,9 +224,9 @@ void DS9Reset(struct ARMCore* cpu) {
struct DS* ds = (struct DS*) cpu->master; struct DS* ds = (struct DS*) cpu->master;
mTimingClear(&ds->ds9.timing); mTimingClear(&ds->ds9.timing);
CircleBufferInit(&ds->ds9.fifo, 64); CircleBufferInit(&ds->ds9.fifo, 64);
DSVideoReset(&ds->video);
DSDMAReset(&ds->ds9); DSDMAReset(&ds->ds9);
DS9IOInit(ds); DS9IOInit(ds);
DSVideoReset(&ds->video);
ds->activeCpu = cpu; ds->activeCpu = cpu;
mTimingSchedule(&ds->ds9.timing, &ds->slice, SLICE_CYCLES); mTimingSchedule(&ds->ds9.timing, &ds->slice, SLICE_CYCLES);

View File

@ -263,6 +263,15 @@ void DS9IOInit(struct DS* ds) {
void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) { void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
switch (address) { switch (address) {
case DS9_REG_VRAMCNT_A:
case DS9_REG_VRAMCNT_C:
case DS9_REG_VRAMCNT_E:
case DS9_REG_VRAMCNT_G:
DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A + 1, value & 0xFF);
// Fall through
case DS9_REG_VRAMCNT_I:
DSVideoConfigureVRAM(&ds->memory, address - DS9_REG_VRAMCNT_A, value >> 8);
break;
default: default:
{ {
uint32_t v2 = DSIOWrite(&ds->ds9, address, value); uint32_t v2 = DSIOWrite(&ds->ds9, address, value);

View File

@ -16,10 +16,24 @@ mLOG_DEFINE_CATEGORY(DS_MEM, "DS Memory");
static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb static uint32_t _deadbeef[1] = { 0xE710B710 }; // Illegal instruction on both ARM and Thumb
static const uint32_t _vramMask[9] = {
0x1FFFF,
0x1FFFF,
0x1FFFF,
0x1FFFF,
0x0FFFF,
0x03FFF,
0x03FFF,
0x07FFF,
0x03FFF
};
static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region); static void DS7SetActiveRegion(struct ARMCore* cpu, uint32_t region);
static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region); static void DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait); static int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait);
static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset);
static const char DS7_BASE_WAITSTATES[16] = { 0, 0, 8, 0, 0, 0, 0, 0 }; static const char DS7_BASE_WAITSTATES[16] = { 0, 0, 8, 0, 0, 0, 0, 0 };
static const char DS7_BASE_WAITSTATES_32[16] = { 0, 0, 9, 0, 0, 1, 1, 0 }; static const char DS7_BASE_WAITSTATES_32[16] = { 0, 0, 9, 0, 0, 1, 1, 0 };
static const char DS7_BASE_WAITSTATES_SEQ[16] = { 0, 0, 1, 0, 0, 0, 0, 0 }; static const char DS7_BASE_WAITSTATES_SEQ[16] = { 0, 0, 1, 0, 0, 0, 0, 0 };
@ -160,6 +174,16 @@ void DSMemoryReset(struct DS* ds) {
ds->memory.wramSize7 = 0x8000; ds->memory.wramSize7 = 0x8000;
ds->memory.wramSize9 = 0; ds->memory.wramSize9 = 0;
DSVideoConfigureVRAM(&ds->memory, 0, 0);
DSVideoConfigureVRAM(&ds->memory, 1, 0);
DSVideoConfigureVRAM(&ds->memory, 2, 0);
DSVideoConfigureVRAM(&ds->memory, 3, 0);
DSVideoConfigureVRAM(&ds->memory, 4, 0);
DSVideoConfigureVRAM(&ds->memory, 5, 0);
DSVideoConfigureVRAM(&ds->memory, 6, 0);
DSVideoConfigureVRAM(&ds->memory, 7, 0);
DSVideoConfigureVRAM(&ds->memory, 8, 0);
if (!ds->memory.wram || !ds->memory.wram7 || !ds->memory.ram || !ds->memory.itcm || !ds->memory.dtcm) { if (!ds->memory.wram || !ds->memory.wram7 || !ds->memory.ram || !ds->memory.itcm || !ds->memory.dtcm) {
DSMemoryDeinit(ds); DSMemoryDeinit(ds);
mLOG(DS_MEM, FATAL, "Could not map memory"); mLOG(DS_MEM, FATAL, "Could not map memory");
@ -277,7 +301,7 @@ uint32_t DS7Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
} }
mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address); mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
case DS_REGION_IO: case DS_REGION_IO:
value = DS7IORead(ds, address & 0x00FFFFFF); value = DS7IORead(ds, address & DS_OFFSET_MASK);
break; break;
default: default:
mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address); mLOG(DS_MEM, STUB, "Unimplemented DS7 Load16: %08X", address);
@ -346,7 +370,7 @@ void DS7Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle
mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value); mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
break; break;
case DS_REGION_IO: case DS_REGION_IO:
DS7IOWrite32(ds, address & 0x00FFFFFF, value); DS7IOWrite32(ds, address & DS_OFFSET_MASK, value);
break; break;
default: default:
mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value); mLOG(DS_MEM, STUB, "Unimplemented DS7 Store32: %08X:%08X", address, value);
@ -380,7 +404,7 @@ void DS7Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value); mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
break; break;
case DS_REGION_IO: case DS_REGION_IO:
DS7IOWrite(ds, address & 0x00FFFFFF, value); DS7IOWrite(ds, address & DS_OFFSET_MASK, value);
break; break;
default: default:
mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value); mLOG(DS_MEM, STUB, "Unimplemented DS7 Store16: %08X:%04X", address, value);
@ -413,7 +437,7 @@ void DS7Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
} }
mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value); mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
case DS_REGION_IO: case DS_REGION_IO:
DS7IOWrite8(ds, address & 0x00FFFFFF, value); DS7IOWrite8(ds, address & DS_OFFSET_MASK, value);
break; break;
default: default:
mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value); mLOG(DS_MEM, STUB, "Unimplemented DS7 Store8: %08X:%02X", address, value);
@ -690,6 +714,18 @@ uint32_t DS9Load32(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
case DS_REGION_IO: case DS_REGION_IO:
value = DS9IORead32(ds, address & 0x00FFFFFC); value = DS9IORead32(ds, address & 0x00FFFFFC);
break; break;
case DS_REGION_VRAM: {
unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
int i = 0;
for (i = 0; i < 9; ++i) {
if (mask & (1 << i)) {
uint32_t newValue;
LOAD_32(newValue, address & _vramMask[i], memory->vramBank[i]);
value |= newValue;
}
}
break;
}
case DS9_REGION_BIOS: case DS9_REGION_BIOS:
// TODO: Fix undersized BIOS // TODO: Fix undersized BIOS
// TODO: Fix masking // TODO: Fix masking
@ -739,8 +775,20 @@ uint32_t DS9Load16(struct ARMCore* cpu, uint32_t address, int* cycleCounter) {
} }
mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address); mLOG(DS_MEM, STUB, "Unimplemented DS9 Load16: %08X", address);
case DS_REGION_IO: case DS_REGION_IO:
value = DS9IORead(ds, address & 0x00FFFFFF); value = DS9IORead(ds, address & DS_OFFSET_MASK);
break; break;
case DS_REGION_VRAM: {
unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
int i = 0;
for (i = 0; i < 9; ++i) {
if (mask & (1 << i)) {
uint32_t newValue;
LOAD_16(newValue, address & _vramMask[i], memory->vramBank[i]);
value |= newValue;
}
}
break;
}
case DS9_REGION_BIOS: case DS9_REGION_BIOS:
// TODO: Fix undersized BIOS // TODO: Fix undersized BIOS
// TODO: Fix masking // TODO: Fix masking
@ -836,8 +884,18 @@ void DS9Store32(struct ARMCore* cpu, uint32_t address, int32_t value, int* cycle
mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value); mLOG(DS_MEM, STUB, "Unimplemented DS9 Store32: %08X:%08X", address, value);
break; break;
case DS_REGION_IO: case DS_REGION_IO:
DS9IOWrite32(ds, address & 0x00FFFFFF, value); DS9IOWrite32(ds, address & DS_OFFSET_MASK, value);
break; break;
case DS_REGION_VRAM: {
unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
int i = 0;
for (i = 0; i < 9; ++i) {
if (mask & (1 << i)) {
STORE_32(value, address & _vramMask[i], memory->vramBank[i]);
}
}
break;
}
default: default:
if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) { if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm); STORE_32(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
@ -879,8 +937,18 @@ void DS9Store16(struct ARMCore* cpu, uint32_t address, int16_t value, int* cycle
mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value); mLOG(DS_MEM, STUB, "Unimplemented DS9 Store16: %08X:%04X", address, value);
break; break;
case DS_REGION_IO: case DS_REGION_IO:
DS9IOWrite(ds, address & 0x00FFFFFF, value); DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
break; break;
case DS_REGION_VRAM: {
unsigned mask = _selectVRAM(memory, address >> DS_VRAM_OFFSET);
int i = 0;
for (i = 0; i < 9; ++i) {
if (mask & (1 << i)) {
STORE_16(value, address & _vramMask[i], memory->vramBank[i]);
}
}
break;
}
default: default:
if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) { if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm); STORE_16(value, address & (DS9_SIZE_DTCM - 1), memory->dtcm);
@ -921,7 +989,7 @@ void DS9Store8(struct ARMCore* cpu, uint32_t address, int8_t value, int* cycleCo
} }
mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value); mLOG(DS_MEM, STUB, "Unimplemented DS9 Store8: %08X:%02X", address, value);
case DS_REGION_IO: case DS_REGION_IO:
DS9IOWrite8(ds, address & 0x00FFFFFF, value); DS9IOWrite8(ds, address & DS_OFFSET_MASK, value);
break; break;
default: default:
if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) { if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
@ -1069,3 +1137,17 @@ int32_t DSMemoryStall(struct ARMCore* cpu, int32_t wait) {
return wait; return wait;
} }
static unsigned _selectVRAM(struct DSMemory* memory, uint32_t offset) {
unsigned mask = 0;
offset &= 0x3FF;
mask |= memory->vramMirror[0][offset & 0x3F] & memory->vramMode[0][offset >> 7];
mask |= memory->vramMirror[1][offset & 0x3F] & memory->vramMode[1][offset >> 7];
mask |= memory->vramMirror[2][offset & 0x3F] & memory->vramMode[2][offset >> 7];
mask |= memory->vramMirror[3][offset & 0x3F] & memory->vramMode[3][offset >> 7];
mask |= memory->vramMirror[4][offset & 0x3F] & memory->vramMode[4][offset >> 7];
mask |= memory->vramMirror[5][offset & 0x3F] & memory->vramMode[5][offset >> 7];
mask |= memory->vramMirror[6][offset & 0x3F] & memory->vramMode[6][offset >> 7];
mask |= memory->vramMirror[7][offset & 0x3F] & memory->vramMode[7][offset >> 7];
mask |= memory->vramMirror[8][offset & 0x3F] & memory->vramMode[8][offset >> 7];
return mask;
}

View File

@ -7,6 +7,7 @@
#include <mgba/core/sync.h> #include <mgba/core/sync.h>
#include <mgba/internal/ds/ds.h> #include <mgba/internal/ds/ds.h>
#include <mgba/internal/ds/memory.h>
#include <mgba/internal/gba/video.h> #include <mgba/internal/gba/video.h>
#include <mgba-util/memory.h> #include <mgba-util/memory.h>
@ -18,6 +19,75 @@ static void _startHdraw7(struct mTiming*, void* context, uint32_t cyclesLate);
static void _startHblank9(struct mTiming*, void* context, uint32_t cyclesLate); static void _startHblank9(struct mTiming*, void* context, uint32_t cyclesLate);
static void _startHdraw9(struct mTiming*, void* context, uint32_t cyclesLate); static void _startHdraw9(struct mTiming*, void* context, uint32_t cyclesLate);
static const uint32_t _vramSize[9] = {
0x20000,
0x20000,
0x20000,
0x20000,
0x10000,
0x04000,
0x04000,
0x08000,
0x04000
};
const struct DSVRAMBankInfo {
int base;
uint32_t mirrorSize;
int mode;
int offset[4];
} _vramInfo[9][8] = {
{ // A
{ 0x000, 0x40, 4 }, // LCDC
{ 0x000, 0x20, 0, { 0x00, 0x08, 0x10, 0x18 } }, // A-BG
{ 0x000, 0x10, 2, { 0x00, 0x08, 0x80, 0x80 } }, // A-OBJ
},
{ // B
{ 0x008, 0x40, 4 }, // LCDC
{ 0x000, 0x20, 0, { 0x00, 0x08, 0x10, 0x18 } }, // A-BG
{ 0x000, 0x10, 2, { 0x00, 0x08, 0x80, 0x80 } }, // A-OBJ
},
{ // C
{ 0x010, 0x40, 4 }, // LCDC
{ 0x000, 0x20, 0, { 0x00, 0x08, 0x10, 0x18 } }, // A-BG
{},
{},
{ 0x000, 0x08, 1 }, // B-BG
},
{ // D
{ 0x018, 0x40, 4 }, // LCDC
{ 0x000, 0x20, 0, { 0x00, 0x08, 0x10, 0x18 } }, // A-BG
{},
{},
{ 0x000, 0x08, 3 }, // B-OBJ
},
{ // E
{ 0x020, 0x40, 4 }, // LCDC
{ 0x000, 0x20, 0 }, // A-BG
{ 0x000, 0x10, 2 }, // A-OBJ
},
{ // F
{ 0x024, 0x40, 4 }, // LCDC
{ 0x000, 0x20, 0, { 0x00, 0x01, 0x04, 0x05 } }, // A-BG
{ 0x000, 0x10, 2, { 0x00, 0x01, 0x04, 0x05 } }, // A-OBJ
},
{ // G
{ 0x025, 0x40, 4 }, // LCDC
{ 0x000, 0x20, 0 }, // A-BG
{ 0x000, 0x10, 2 }, // A-OBJ
},
{ // H
{ 0x026, 0x40, 4 }, // LCDC
{ 0x000, 0x04, 1 }, // B-BG
{ 0x000, 0x10, 2 }, // A-OBJ
},
{ // I
{ 0x028, 0x40, 4 }, // LCDC
{ 0x002, 0x04, 1 }, // B-BG
{ 0x000, 0x01, 3 }, // B-OBJ
},
};
void DSVideoInit(struct DSVideo* video) { void DSVideoInit(struct DSVideo* video) {
video->vram = NULL; video->vram = NULL;
video->frameskip = 0; video->frameskip = 0;
@ -48,6 +118,16 @@ void DSVideoReset(struct DSVideo* video) {
mappedMemoryFree(video->vram, DS_SIZE_VRAM); mappedMemoryFree(video->vram, DS_SIZE_VRAM);
} }
video->vram = anonymousMemoryMap(DS_SIZE_VRAM); video->vram = anonymousMemoryMap(DS_SIZE_VRAM);
video->p->memory.vramBank[0] = &video->vram[0x00000];
video->p->memory.vramBank[1] = &video->vram[0x10000];
video->p->memory.vramBank[2] = &video->vram[0x20000];
video->p->memory.vramBank[3] = &video->vram[0x30000];
video->p->memory.vramBank[4] = &video->vram[0x40000];
video->p->memory.vramBank[5] = &video->vram[0x48000];
video->p->memory.vramBank[6] = &video->vram[0x4A000];
video->p->memory.vramBank[7] = &video->vram[0x4C000];
video->p->memory.vramBank[8] = &video->vram[0x50000];
} }
void DSVideoDeinit(struct DSVideo* video) { void DSVideoDeinit(struct DSVideo* video) {
@ -174,3 +254,21 @@ void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value) {
dscore->memory.io[DS_REG_DISPSTAT >> 1] |= value; dscore->memory.io[DS_REG_DISPSTAT >> 1] |= value;
// TODO: Does a VCounter IRQ trigger on write? // TODO: Does a VCounter IRQ trigger on write?
} }
void DSVideoConfigureVRAM(struct DSMemory* memory, int index, uint8_t value) {
struct DSVRAMBankInfo info = _vramInfo[index][value & 0x7];
memset(&memory->vramMirror[index], 0, sizeof(memory->vramMirror[index]));
memset(&memory->vramMode[index], 0, sizeof(memory->vramMode[index]));
if (!(value & 0x80)) {
return;
}
uint32_t size = _vramSize[index] >> DS_VRAM_OFFSET;
memory->vramMode[index][info.mode] = 0xFFFF;
uint32_t offset = info.base + info.offset[(value >> 3) & 3];
uint32_t i, j;
for (j = offset; j < 0x40; j += info.mirrorSize) {
for (i = 0; i < size; ++i) {
memory->vramMirror[index][i + j] = 1 << index;
}
}
}