mirror of https://github.com/mgba-emu/mgba.git
Use new bitfields for DMAs
This commit is contained in:
parent
7e4dc6c15c
commit
f4d27e5e40
|
@ -64,6 +64,7 @@
|
|||
#define MAKE_MASK(START, END) (((1 << ((END) - (START))) - 1) << (START))
|
||||
#define CHECK_BITS(SRC, START, END) ((SRC) & MAKE_MASK(START, END))
|
||||
#define EXT_BITS(SRC, START, END) (((SRC) >> (START)) & ((1 << ((END) - (START))) - 1))
|
||||
#define INS_BITS(SRC, START, END, BITS) (CLEAR_BITS(SRC, START, END) | (((BITS) << (START)) & MAKE_MASK(START, END)))
|
||||
#define CLEAR_BITS(SRC, START, END) ((SRC) & ~MAKE_MASK(START, END))
|
||||
#define FILL_BITS(SRC, START, END) ((SRC) | MAKE_MASK(START, END))
|
||||
|
||||
|
@ -81,6 +82,9 @@
|
|||
} \
|
||||
static inline TYPE TYPE ## Fill ## FIELD (TYPE src) { \
|
||||
return FILL_BITS(src, (START), (START) + (SIZE)); \
|
||||
} \
|
||||
static inline TYPE TYPE ## Set ## FIELD (TYPE src, TYPE bits) { \
|
||||
return INS_BITS(src, (START), (START) + (SIZE), bits); \
|
||||
}
|
||||
|
||||
#define DECL_BIT(TYPE, FIELD, BIT) DECL_BITS(TYPE, FIELD, BIT, 1)
|
||||
|
|
|
@ -253,7 +253,7 @@ void GBAAudioScheduleFifoDma(struct GBAAudio* audio, int number, struct GBADMA*
|
|||
GBALog(audio->p, GBA_LOG_GAME_ERROR, "Invalid FIFO destination: 0x%08X", info->dest);
|
||||
return;
|
||||
}
|
||||
info->dstControl = DMA_FIXED;
|
||||
info->reg = GBADMARegisterSetDestControl(info->reg, DMA_FIXED);
|
||||
}
|
||||
|
||||
void GBAAudioWriteSOUND1CNT_LO(struct GBAAudio* audio, uint16_t value) {
|
||||
|
|
|
@ -482,7 +482,7 @@ void GBAIODeserialize(struct GBA* gba, struct GBASerializedState* state) {
|
|||
gba->memory.dma[i].nextDest = state->dma[i].nextDest;
|
||||
gba->memory.dma[i].nextCount = state->dma[i].nextCount;
|
||||
gba->memory.dma[i].nextEvent = state->dma[i].nextEvent;
|
||||
if (gba->memory.dma[i].timing != DMA_TIMING_NOW) {
|
||||
if (GBADMARegisterGetTiming(gba->memory.dma[i].reg) != DMA_TIMING_NOW) {
|
||||
GBAMemoryScheduleDMA(gba, i, &gba->memory.dma[i]);
|
||||
}
|
||||
|
||||
|
|
|
@ -651,26 +651,26 @@ void GBAMemoryWriteDMACNT_LO(struct GBA* gba, int dma, uint16_t count) {
|
|||
uint16_t GBAMemoryWriteDMACNT_HI(struct GBA* gba, int dma, uint16_t control) {
|
||||
struct GBAMemory* memory = &gba->memory;
|
||||
struct GBADMA* currentDma = &memory->dma[dma];
|
||||
int wasEnabled = currentDma->enable;
|
||||
currentDma->packed = control;
|
||||
int wasEnabled = GBADMARegisterIsEnable(currentDma->reg);
|
||||
currentDma->reg = control;
|
||||
|
||||
if (currentDma->drq) {
|
||||
if (GBADMARegisterIsDRQ(currentDma->reg)) {
|
||||
GBALog(gba, GBA_LOG_STUB, "DRQ not implemented");
|
||||
}
|
||||
|
||||
if (!wasEnabled && currentDma->enable) {
|
||||
if (!wasEnabled && GBADMARegisterIsEnable(currentDma->reg)) {
|
||||
currentDma->nextSource = currentDma->source;
|
||||
currentDma->nextDest = currentDma->dest;
|
||||
currentDma->nextCount = currentDma->count;
|
||||
GBAMemoryScheduleDMA(gba, dma, currentDma);
|
||||
}
|
||||
// If the DMA has already occurred, this value might have changed since the function started
|
||||
return currentDma->packed;
|
||||
return currentDma->reg;
|
||||
};
|
||||
|
||||
void GBAMemoryScheduleDMA(struct GBA* gba, int number, struct GBADMA* info) {
|
||||
struct ARMCore* cpu = gba->cpu;
|
||||
switch (info->timing) {
|
||||
switch (GBADMARegisterGetTiming(info->reg)) {
|
||||
case DMA_TIMING_NOW:
|
||||
info->nextEvent = cpu->cycles;
|
||||
GBAMemoryUpdateDMAs(gba, 0);
|
||||
|
@ -706,7 +706,7 @@ void GBAMemoryRunHblankDMAs(struct GBA* gba, int32_t cycles) {
|
|||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
dma = &memory->dma[i];
|
||||
if (dma->enable && dma->timing == DMA_TIMING_HBLANK) {
|
||||
if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_HBLANK) {
|
||||
dma->nextEvent = cycles;
|
||||
}
|
||||
}
|
||||
|
@ -719,7 +719,7 @@ void GBAMemoryRunVblankDMAs(struct GBA* gba, int32_t cycles) {
|
|||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
dma = &memory->dma[i];
|
||||
if (dma->enable && dma->timing == DMA_TIMING_VBLANK) {
|
||||
if (GBADMARegisterIsEnable(dma->reg) && GBADMARegisterGetTiming(dma->reg) == DMA_TIMING_VBLANK) {
|
||||
dma->nextEvent = cycles;
|
||||
}
|
||||
}
|
||||
|
@ -752,7 +752,7 @@ void GBAMemoryUpdateDMAs(struct GBA* gba, int32_t cycles) {
|
|||
struct GBADMA* dma = &memory->dma[i];
|
||||
if (dma->nextEvent != INT_MAX) {
|
||||
dma->nextEvent -= cycles;
|
||||
if (dma->enable) {
|
||||
if (GBADMARegisterIsEnable(dma->reg)) {
|
||||
memory->activeDMA = i;
|
||||
memory->nextDMA = dma->nextEvent;
|
||||
}
|
||||
|
@ -766,9 +766,9 @@ void GBAMemoryUpdateDMAs(struct GBA* gba, int32_t cycles) {
|
|||
void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) {
|
||||
struct GBAMemory* memory = &gba->memory;
|
||||
struct ARMCore* cpu = gba->cpu;
|
||||
uint32_t width = info->width ? 4 : 2;
|
||||
int sourceOffset = DMA_OFFSET[info->srcControl] * width;
|
||||
int destOffset = DMA_OFFSET[info->dstControl] * width;
|
||||
uint32_t width = GBADMARegisterGetWidth(info->reg) ? 4 : 2;
|
||||
int sourceOffset = DMA_OFFSET[GBADMARegisterGetSrcControl(info->reg)] * width;
|
||||
int destOffset = DMA_OFFSET[GBADMARegisterGetDestControl(info->reg)] * width;
|
||||
int32_t wordsRemaining = info->nextCount;
|
||||
uint32_t source = info->nextSource;
|
||||
uint32_t dest = info->nextDest;
|
||||
|
@ -828,20 +828,20 @@ void GBAMemoryServiceDMA(struct GBA* gba, int number, struct GBADMA* info) {
|
|||
}
|
||||
|
||||
if (!wordsRemaining) {
|
||||
if (!info->repeat) {
|
||||
info->enable = 0;
|
||||
if (!GBADMARegisterIsRepeat(info->reg)) {
|
||||
info->reg = GBADMARegisterClearEnable(info->reg);
|
||||
info->nextEvent = INT_MAX;
|
||||
|
||||
// Clear the enable bit in memory
|
||||
memory->io[(REG_DMA0CNT_HI + number * (REG_DMA1CNT_HI - REG_DMA0CNT_HI)) >> 1] &= 0x7FE0;
|
||||
} else {
|
||||
info->nextCount = info->count;
|
||||
if (info->dstControl == DMA_INCREMENT_RELOAD) {
|
||||
if (GBADMARegisterGetDestControl(info->reg) == DMA_INCREMENT_RELOAD) {
|
||||
info->nextDest = info->dest;
|
||||
}
|
||||
GBAMemoryScheduleDMA(gba, number, info);
|
||||
}
|
||||
if (info->doIrq) {
|
||||
if (GBADMARegisterIsDoIRQ(info->reg)) {
|
||||
GBARaiseIRQ(gba, IRQ_DMA0 + number);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -80,21 +80,19 @@ enum DMATiming {
|
|||
DMA_TIMING_CUSTOM = 3
|
||||
};
|
||||
|
||||
|
||||
DECL_BITFIELD(GBADMARegister, uint16_t);
|
||||
DECL_BITS(GBADMARegister, DestControl, 5, 2);
|
||||
DECL_BITS(GBADMARegister, SrcControl, 7, 2);
|
||||
DECL_BIT(GBADMARegister, Repeat, 9);
|
||||
DECL_BIT(GBADMARegister, Width, 10);
|
||||
DECL_BIT(GBADMARegister, DRQ, 11);
|
||||
DECL_BITS(GBADMARegister, Timing, 12, 2);
|
||||
DECL_BIT(GBADMARegister, DoIRQ, 14);
|
||||
DECL_BIT(GBADMARegister, Enable, 15);
|
||||
|
||||
struct GBADMA {
|
||||
union {
|
||||
struct {
|
||||
int : 5;
|
||||
enum DMAControl dstControl : 2;
|
||||
enum DMAControl srcControl : 2;
|
||||
unsigned repeat : 1;
|
||||
unsigned width : 1;
|
||||
unsigned drq : 1;
|
||||
enum DMATiming timing : 2;
|
||||
unsigned doIrq : 1;
|
||||
unsigned enable : 1;
|
||||
};
|
||||
uint16_t packed;
|
||||
};
|
||||
GBADMARegister reg;
|
||||
|
||||
uint32_t source;
|
||||
uint32_t dest;
|
||||
|
|
Loading…
Reference in New Issue