mirror of https://github.com/mgba-emu/mgba.git
GB Memory: Simplify DMA memory accesses
This commit is contained in:
parent
fcc8b5c805
commit
0b28dad51c
|
@ -168,9 +168,6 @@ uint8_t GBView8(struct LR35902Core* cpu, uint16_t address, int segment);
|
|||
void GBMemoryDMA(struct GB* gb, uint16_t base);
|
||||
void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value);
|
||||
|
||||
uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address);
|
||||
void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value);
|
||||
|
||||
void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old, int segment);
|
||||
|
||||
struct GBSerializedState;
|
||||
|
|
112
src/gb/memory.c
112
src/gb/memory.c
|
@ -16,6 +16,33 @@
|
|||
|
||||
mLOG_DEFINE_CATEGORY(GB_MEM, "GB Memory", "gb.memory");
|
||||
|
||||
struct OAMBlock {
|
||||
uint16_t low;
|
||||
uint16_t high;
|
||||
};
|
||||
|
||||
static const struct OAMBlock _oamBlockDMG[] = {
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0x8000, 0xA000 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
};
|
||||
|
||||
static const struct OAMBlock _oamBlockCGB[] = {
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0x8000, 0xA000 },
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0xC000, 0xFE00 },
|
||||
{ 0xA000, 0xC000 },
|
||||
};
|
||||
|
||||
static void _pristineCow(struct GB* gba);
|
||||
|
||||
static uint8_t GBFastLoad8(struct LR35902Core* cpu, uint16_t address) {
|
||||
|
@ -160,6 +187,16 @@ void GBMemorySwitchWramBank(struct GBMemory* memory, int bank) {
|
|||
uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
if (gb->memory.dmaRemaining) {
|
||||
const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB;
|
||||
block = &block[memory->dmaSource >> 13];
|
||||
if (address >= block->low && address < block->high) {
|
||||
return 0xFF;
|
||||
}
|
||||
if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {
|
||||
return 0xFF;
|
||||
}
|
||||
}
|
||||
switch (address >> 12) {
|
||||
case GB_REGION_CART_BANK0:
|
||||
case GB_REGION_CART_BANK0 + 1:
|
||||
|
@ -218,6 +255,16 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) {
|
|||
void GBStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
if (gb->memory.dmaRemaining) {
|
||||
const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB;
|
||||
block = &block[memory->dmaSource >> 13];
|
||||
if (address >= block->low && address < block->high) {
|
||||
return;
|
||||
}
|
||||
if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
switch (address >> 12) {
|
||||
case GB_REGION_CART_BANK0:
|
||||
case GB_REGION_CART_BANK0 + 1:
|
||||
|
@ -389,9 +436,6 @@ void GBMemoryDMA(struct GB* gb, uint16_t base) {
|
|||
if (base > 0xF100) {
|
||||
return;
|
||||
}
|
||||
gb->cpu->memory.store8 = GBDMAStore8;
|
||||
gb->cpu->memory.load8 = GBDMALoad8;
|
||||
gb->cpu->memory.cpuLoad8 = GBDMALoad8;
|
||||
mTimingSchedule(&gb->timing, &gb->memory.dmaEvent, 8);
|
||||
if (gb->cpu->cycles + 8 < gb->cpu->nextEvent) {
|
||||
gb->cpu->nextEvent = gb->cpu->cycles + 8;
|
||||
|
@ -425,18 +469,17 @@ void GBMemoryWriteHDMA5(struct GB* gb, uint8_t value) {
|
|||
|
||||
void _GBMemoryDMAService(struct mTiming* timing, void* context, uint32_t cyclesLate) {
|
||||
struct GB* gb = context;
|
||||
int dmaRemaining = gb->memory.dmaRemaining;
|
||||
gb->memory.dmaRemaining = 0;
|
||||
uint8_t b = GBLoad8(gb->cpu, gb->memory.dmaSource);
|
||||
// TODO: Can DMA write OAM during modes 2-3?
|
||||
gb->video.oam.raw[gb->memory.dmaDest] = b;
|
||||
gb->video.renderer->writeOAM(gb->video.renderer, gb->memory.dmaDest);
|
||||
++gb->memory.dmaSource;
|
||||
++gb->memory.dmaDest;
|
||||
--gb->memory.dmaRemaining;
|
||||
gb->memory.dmaRemaining = dmaRemaining - 1;
|
||||
if (gb->memory.dmaRemaining) {
|
||||
mTimingSchedule(timing, &gb->memory.dmaEvent, 4 - cyclesLate);
|
||||
} else {
|
||||
gb->cpu->memory.store8 = GBStore8;
|
||||
gb->cpu->memory.load8 = GBLoad8;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -468,61 +511,6 @@ void _GBMemoryHDMAService(struct mTiming* timing, void* context, uint32_t cycles
|
|||
}
|
||||
}
|
||||
|
||||
struct OAMBlock {
|
||||
uint16_t low;
|
||||
uint16_t high;
|
||||
};
|
||||
|
||||
static const struct OAMBlock _oamBlockDMG[] = {
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0x8000, 0xA000 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
{ 0xA000, 0xFE00 },
|
||||
};
|
||||
|
||||
static const struct OAMBlock _oamBlockCGB[] = {
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0x8000, 0xA000 },
|
||||
{ 0xA000, 0xC000 },
|
||||
{ 0xC000, 0xFE00 },
|
||||
{ 0xA000, 0xC000 },
|
||||
};
|
||||
|
||||
uint8_t GBDMALoad8(struct LR35902Core* cpu, uint16_t address) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB;
|
||||
block = &block[memory->dmaSource >> 13];
|
||||
if (address >= block->low && address < block->high) {
|
||||
return 0xFF;
|
||||
}
|
||||
if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {
|
||||
return 0xFF;
|
||||
}
|
||||
return GBLoad8(cpu, address);
|
||||
}
|
||||
|
||||
void GBDMAStore8(struct LR35902Core* cpu, uint16_t address, int8_t value) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
const struct OAMBlock* block = gb->model < GB_MODEL_CGB ? _oamBlockDMG : _oamBlockCGB;
|
||||
block = &block[memory->dmaSource >> 13];
|
||||
if (address >= block->low && address < block->high) {
|
||||
return;
|
||||
}
|
||||
if (address >= GB_BASE_OAM && address < GB_BASE_UNUSABLE) {
|
||||
return;
|
||||
}
|
||||
GBStore8(cpu, address, value);
|
||||
}
|
||||
|
||||
void GBPatch8(struct LR35902Core* cpu, uint16_t address, int8_t value, int8_t* old, int segment) {
|
||||
struct GB* gb = (struct GB*) cpu->master;
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
|
|
Loading…
Reference in New Issue