mirror of https://github.com/mgba-emu/mgba.git
DS Video: VRAM configuration
This commit is contained in:
parent
bb83e78af9
commit
9b86abec09
|
@ -65,7 +65,8 @@ enum {
|
|||
|
||||
enum {
|
||||
DS_OFFSET_MASK = 0x00FFFFFF,
|
||||
DS_BASE_OFFSET = 24
|
||||
DS_BASE_OFFSET = 24,
|
||||
DS_VRAM_OFFSET = 14
|
||||
};
|
||||
|
||||
mLOG_DECLARE_CATEGORY(DS_MEM);
|
||||
|
@ -82,6 +83,10 @@ struct DSMemory {
|
|||
uint16_t io7[DS7_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 wramSize7;
|
||||
size_t wramSize9;
|
||||
|
|
|
@ -52,6 +52,9 @@ void DSVideoDeinit(struct DSVideo* video);
|
|||
struct DSCommon;
|
||||
void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value);
|
||||
|
||||
struct DSMemory;
|
||||
void DSVideoConfigureVRAM(struct DSMemory* memory, int index, uint8_t value);
|
||||
|
||||
CXX_GUARD_START
|
||||
|
||||
#endif
|
||||
|
|
|
@ -224,9 +224,9 @@ void DS9Reset(struct ARMCore* cpu) {
|
|||
struct DS* ds = (struct DS*) cpu->master;
|
||||
mTimingClear(&ds->ds9.timing);
|
||||
CircleBufferInit(&ds->ds9.fifo, 64);
|
||||
DSVideoReset(&ds->video);
|
||||
DSDMAReset(&ds->ds9);
|
||||
DS9IOInit(ds);
|
||||
DSVideoReset(&ds->video);
|
||||
|
||||
ds->activeCpu = cpu;
|
||||
mTimingSchedule(&ds->ds9.timing, &ds->slice, SLICE_CYCLES);
|
||||
|
|
|
@ -263,6 +263,15 @@ void DS9IOInit(struct DS* ds) {
|
|||
|
||||
void DS9IOWrite(struct DS* ds, uint32_t address, uint16_t value) {
|
||||
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:
|
||||
{
|
||||
uint32_t v2 = DSIOWrite(&ds->ds9, address, value);
|
||||
|
|
|
@ -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 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 DS9SetActiveRegion(struct ARMCore* cpu, uint32_t region);
|
||||
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_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 };
|
||||
|
@ -160,6 +174,16 @@ void DSMemoryReset(struct DS* ds) {
|
|||
ds->memory.wramSize7 = 0x8000;
|
||||
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) {
|
||||
DSMemoryDeinit(ds);
|
||||
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);
|
||||
case DS_REGION_IO:
|
||||
value = DS7IORead(ds, address & 0x00FFFFFF);
|
||||
value = DS7IORead(ds, address & DS_OFFSET_MASK);
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
break;
|
||||
case DS_REGION_IO:
|
||||
DS7IOWrite32(ds, address & 0x00FFFFFF, value);
|
||||
DS7IOWrite32(ds, address & DS_OFFSET_MASK, value);
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
break;
|
||||
case DS_REGION_IO:
|
||||
DS7IOWrite(ds, address & 0x00FFFFFF, value);
|
||||
DS7IOWrite(ds, address & DS_OFFSET_MASK, value);
|
||||
break;
|
||||
default:
|
||||
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);
|
||||
case DS_REGION_IO:
|
||||
DS7IOWrite8(ds, address & 0x00FFFFFF, value);
|
||||
DS7IOWrite8(ds, address & DS_OFFSET_MASK, value);
|
||||
break;
|
||||
default:
|
||||
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:
|
||||
value = DS9IORead32(ds, address & 0x00FFFFFC);
|
||||
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:
|
||||
// TODO: Fix undersized BIOS
|
||||
// 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);
|
||||
case DS_REGION_IO:
|
||||
value = DS9IORead(ds, address & 0x00FFFFFF);
|
||||
value = DS9IORead(ds, address & DS_OFFSET_MASK);
|
||||
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:
|
||||
// TODO: Fix undersized BIOS
|
||||
// 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);
|
||||
break;
|
||||
case DS_REGION_IO:
|
||||
DS9IOWrite32(ds, address & 0x00FFFFFF, value);
|
||||
DS9IOWrite32(ds, address & DS_OFFSET_MASK, value);
|
||||
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:
|
||||
if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
|
||||
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);
|
||||
break;
|
||||
case DS_REGION_IO:
|
||||
DS9IOWrite(ds, address & 0x00FFFFFF, value);
|
||||
DS9IOWrite(ds, address & DS_OFFSET_MASK, value);
|
||||
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:
|
||||
if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
|
||||
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);
|
||||
case DS_REGION_IO:
|
||||
DS9IOWrite8(ds, address & 0x00FFFFFF, value);
|
||||
DS9IOWrite8(ds, address & DS_OFFSET_MASK, value);
|
||||
break;
|
||||
default:
|
||||
if ((address & ~(DS9_SIZE_DTCM - 1)) == memory->dtcmBase) {
|
||||
|
@ -1069,3 +1137,17 @@ int32_t DSMemoryStall(struct ARMCore* cpu, int32_t 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;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include <mgba/core/sync.h>
|
||||
#include <mgba/internal/ds/ds.h>
|
||||
#include <mgba/internal/ds/memory.h>
|
||||
#include <mgba/internal/gba/video.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 _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) {
|
||||
video->vram = NULL;
|
||||
video->frameskip = 0;
|
||||
|
@ -48,6 +118,16 @@ void DSVideoReset(struct DSVideo* video) {
|
|||
mappedMemoryFree(video->vram, 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) {
|
||||
|
@ -174,3 +254,21 @@ void DSVideoWriteDISPSTAT(struct DSCommon* dscore, uint16_t value) {
|
|||
dscore->memory.io[DS_REG_DISPSTAT >> 1] |= value;
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue