Permalink
Browse files

GB: Revamp IRQ handling based on new information

  • Loading branch information...
endrift committed Sep 26, 2017
1 parent 148e7cd commit a949fdfcedb5792685e485ee0ac68d6cc1a81d76
View
@@ -44,6 +44,7 @@ Bugfixes:
- GBA Video: Fix broken sprite blending hack (fixes mgba.io/i/532)
- GBA I/O: Fix reading from a few invalid I/O registers (fixes mgba.io/i/876)
- GBA Savedata: Fix size of SRAM saves (fixes mgba.io/i/883)
+ - GB: Revamp IRQ handling based on new information
Misc:
- GBA Timer: Use global cycles for timers
- GBA: Extend oddly-sized ROMs to full address space (fixes mgba.io/i/722)
@@ -42,7 +42,7 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* | 0x00036 - 0x00037: Index address
* | 0x00038: Bus value
* | 0x00039: Execution state
- * | 0x0003A - 0x0003B: IRQ vector
+ * | 0x0003A - 0x0003B: Reserved
* | 0x0003C - 0x0003F: EI pending cycles
* | 0x00040 - 0x00043: Reserved (DI pending cycles)
* | 0x00044 - 0x00047: Flags
@@ -287,7 +287,7 @@ struct GBSerializedState {
uint8_t bus;
uint8_t executionState;
- uint16_t irqVector;
+ uint16_t reserved;
uint32_t eiPending;
int32_t reservedDiPending;
@@ -66,6 +66,7 @@ struct LR35902InterruptHandler {
void (*reset)(struct LR35902Core* cpu);
void (*processEvents)(struct LR35902Core* cpu);
void (*setInterrupts)(struct LR35902Core* cpu, bool enable);
+ uint16_t (*irqVector)(struct LR35902Core* cpu);
void (*halt)(struct LR35902Core* cpu);
void (*stop)(struct LR35902Core* cpu);
@@ -118,7 +119,6 @@ struct LR35902Core {
LR35902Instruction instruction;
bool irqPending;
- uint16_t irqVector;
struct LR35902Memory memory;
struct LR35902InterruptHandler irqh;
@@ -136,7 +136,7 @@ void LR35902HotplugAttach(struct LR35902Core* cpu, size_t slot);
void LR35902HotplugDetach(struct LR35902Core* cpu, size_t slot);
void LR35902Reset(struct LR35902Core* cpu);
-void LR35902RaiseIRQ(struct LR35902Core* cpu, uint8_t vector);
+void LR35902RaiseIRQ(struct LR35902Core* cpu);
void LR35902Tick(struct LR35902Core* cpu);
void LR35902Run(struct LR35902Core* cpu);
View
@@ -39,6 +39,7 @@ static void GBDeinit(struct mCPUComponent* component);
static void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh);
static void GBProcessEvents(struct LR35902Core* cpu);
static void GBSetInterrupts(struct LR35902Core* cpu, bool enable);
+static uint16_t GBIRQVector(struct LR35902Core* cpu);
static void GBIllegal(struct LR35902Core* cpu);
static void GBStop(struct LR35902Core* cpu);
@@ -371,6 +372,7 @@ void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
irqh->reset = GBReset;
irqh->processEvents = GBProcessEvents;
irqh->setInterrupts = GBSetInterrupts;
+ irqh->irqVector = GBIRQVector;
irqh->hitIllegal = GBIllegal;
irqh->stop = GBStop;
irqh->halt = GBHalt;
@@ -596,31 +598,7 @@ void GBUpdateIRQs(struct GB* gb) {
if (!gb->memory.ime || gb->cpu->irqPending) {
return;
}
-
- if (irqs & (1 << GB_IRQ_VBLANK)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_VBLANK);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
- return;
- }
- if (irqs & (1 << GB_IRQ_LCDSTAT)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_LCDSTAT);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
- return;
- }
- if (irqs & (1 << GB_IRQ_TIMER)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_TIMER);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
- return;
- }
- if (irqs & (1 << GB_IRQ_SIO)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_SIO);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
- return;
- }
- if (irqs & (1 << GB_IRQ_KEYPAD)) {
- LR35902RaiseIRQ(gb->cpu, GB_VECTOR_KEYPAD);
- gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
- }
+ LR35902RaiseIRQ(gb->cpu);
}
void GBProcessEvents(struct LR35902Core* cpu) {
@@ -663,6 +641,33 @@ void GBSetInterrupts(struct LR35902Core* cpu, bool enable) {
}
}
+uint16_t GBIRQVector(struct LR35902Core* cpu) {
+ struct GB* gb = (struct GB*) cpu->master;
+ int irqs = gb->memory.ie & gb->memory.io[REG_IF];
+
+ if (irqs & (1 << GB_IRQ_VBLANK)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_VBLANK);
+ return GB_VECTOR_VBLANK;
+ }
+ if (irqs & (1 << GB_IRQ_LCDSTAT)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_LCDSTAT);
+ return GB_VECTOR_LCDSTAT;
+ }
+ if (irqs & (1 << GB_IRQ_TIMER)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_TIMER);
+ return GB_VECTOR_TIMER;
+ }
+ if (irqs & (1 << GB_IRQ_SIO)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_SIO);
+ return GB_VECTOR_SIO;
+ }
+ if (irqs & (1 << GB_IRQ_KEYPAD)) {
+ gb->memory.io[REG_IF] &= ~(1 << GB_IRQ_KEYPAD);
+ return GB_VECTOR_KEYPAD;
+ }
+ return 0;
+}
+
static void _enableInterrupts(struct mTiming* timing, void* user, uint32_t cyclesLate) {
UNUSED(timing);
UNUSED(cyclesLate);
View
@@ -47,7 +47,6 @@ void GBSerialize(struct GB* gb, struct GBSerializedState* state) {
STORE_16LE(gb->cpu->index, 0, &state->cpu.index);
state->cpu.bus = gb->cpu->bus;
state->cpu.executionState = gb->cpu->executionState;
- STORE_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
GBSerializedCpuFlags flags = 0;
flags = GBSerializedCpuFlagsSetCondition(flags, gb->cpu->condition);
@@ -154,7 +153,6 @@ bool GBDeserialize(struct GB* gb, const struct GBSerializedState* state) {
LOAD_16LE(gb->cpu->index, 0, &state->cpu.index);
gb->cpu->bus = state->cpu.bus;
gb->cpu->executionState = state->cpu.executionState;
- LOAD_16LE(gb->cpu->irqVector, 0, &state->cpu.irqVector);
GBSerializedCpuFlags flags;
LOAD_32LE(flags, 0, &state->cpu.flags);
View
@@ -70,9 +70,8 @@ void LR35902Reset(struct LR35902Core* cpu) {
cpu->irqh.reset(cpu);
}
-void LR35902RaiseIRQ(struct LR35902Core* cpu, uint8_t vector) {
+void LR35902RaiseIRQ(struct LR35902Core* cpu) {
cpu->irqPending = true;
- cpu->irqVector = vector;
}
static void _LR35902InstructionIRQStall(struct LR35902Core* cpu) {
@@ -85,18 +84,19 @@ static void _LR35902InstructionIRQFinish(struct LR35902Core* cpu) {
}
static void _LR35902InstructionIRQDelay(struct LR35902Core* cpu) {
- cpu->index = cpu->sp + 1;
- cpu->bus = cpu->pc >> 8;
+ --cpu->sp;
+ cpu->index = cpu->sp;
+ cpu->bus = cpu->pc;
cpu->executionState = LR35902_CORE_MEMORY_STORE;
cpu->instruction = _LR35902InstructionIRQFinish;
- cpu->pc = cpu->irqVector;
+ cpu->pc = cpu->irqh.irqVector(cpu);
cpu->memory.setActiveRegion(cpu, cpu->pc);
}
static void _LR35902InstructionIRQ(struct LR35902Core* cpu) {
- cpu->sp -= 2; /* TODO: Atomic incrementing? */
+ --cpu->sp;
cpu->index = cpu->sp;
- cpu->bus = cpu->pc;
+ cpu->bus = cpu->pc >> 8;
cpu->executionState = LR35902_CORE_MEMORY_STORE;
cpu->instruction = _LR35902InstructionIRQDelay;
}
Oops, something went wrong.

0 comments on commit a949fdf

Please sign in to comment.