Use new bitfields for DMAs

This commit is contained in:
Jeffrey Pfau 2014-10-01 00:17:51 -07:00
parent 7e4dc6c15c
commit f4d27e5e40
5 changed files with 34 additions and 32 deletions

View File

@ -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)

View File

@ -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) {

View File

@ -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]);
}

View File

@ -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 {

View File

@ -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;