From 8608f11154ec861b81c0bb2f165a9880b59911a0 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Wed, 17 Feb 2016 01:18:41 -0800 Subject: [PATCH] GB: Add double speed --- src/gb/audio.c | 48 +++++++++++++---------------------- src/gb/gb.c | 36 +++++++++++++++++--------- src/gb/gb.h | 1 + src/gb/io.c | 6 +++++ src/gb/video.c | 8 +++--- src/lr35902/emitter-lr35902.h | 2 +- src/lr35902/isa-lr35902.c | 10 +++++++- src/lr35902/lr35902.h | 2 +- 8 files changed, 63 insertions(+), 50 deletions(-) diff --git a/src/gb/audio.c b/src/gb/audio.c index ef2030c24..2f9133346 100644 --- a/src/gb/audio.c +++ b/src/gb/audio.c @@ -27,6 +27,7 @@ static int32_t _updateChannel2(struct GBAudioChannel2* ch); static int32_t _updateChannel3(struct GBAudioChannel3* ch, enum GBAudioStyle style); static int32_t _updateChannel4(struct GBAudioChannel4* ch); static void _sample(struct GBAudio* audio, int32_t cycles); +static void _scheduleEvent(struct GBAudio* audio); void GBAudioInit(struct GBAudio* audio, size_t samples, uint8_t* nr52, enum GBAudioStyle style) { audio->samples = samples; @@ -158,13 +159,7 @@ void GBAudioWriteNR14(struct GBAudio* audio, uint8_t value) { --audio->ch1.control.length; } } - // TODO: Don't need p - if (audio->p) { - audio->nextEvent = audio->p->cpu->cycles; - audio->p->cpu->nextEvent = audio->nextEvent; - } else { - audio->nextEvent = 0; - } + _scheduleEvent(audio); } *audio->nr52 &= ~0x0001; *audio->nr52 |= audio->playingCh1; @@ -216,13 +211,7 @@ void GBAudioWriteNR24(struct GBAudio* audio, uint8_t value) { --audio->ch2.control.length; } } - // TODO: Don't need p - if (audio->p) { - audio->nextEvent = audio->p->cpu->cycles; - audio->p->cpu->nextEvent = audio->nextEvent; - } else { - audio->nextEvent = 0; - } + _scheduleEvent(audio); } *audio->nr52 &= ~0x0002; *audio->nr52 |= audio->playingCh2 << 1; @@ -287,16 +276,9 @@ void GBAudioWriteNR34(struct GBAudio* audio, uint8_t value) { audio->eventDiff = 0; } audio->ch3.readable = audio->style != GB_AUDIO_DMG; - // TODO: Don't need p - if (audio->p) { - // TODO: Where does this cycle delay come from? - audio->nextCh3 = audio->eventDiff + audio->p->cpu->cycles + 4 + 2 * (2048 - audio->ch3.rate); - audio->nextEvent = audio->p->cpu->cycles; - audio->p->cpu->nextEvent = audio->nextEvent; - } else { - audio->nextCh3 = audio->eventDiff + 4 + 2 * (2048 - audio->ch3.rate); - audio->nextEvent = 0; - } + _scheduleEvent(audio); + // TODO: Where does this cycle delay come from? + audio->nextCh3 = audio->eventDiff + audio->nextEvent + 4 + 2 * (2048 - audio->ch3.rate); } *audio->nr52 &= ~0x0004; *audio->nr52 |= audio->playingCh3 << 2; @@ -352,13 +334,7 @@ void GBAudioWriteNR44(struct GBAudio* audio, uint8_t value) { --audio->ch4.length; } } - // TODO: Don't need p - if (audio->p) { - audio->nextEvent = audio->p->cpu->cycles; - audio->p->cpu->nextEvent = audio->nextEvent; - } else { - audio->nextEvent = 0; - } + _scheduleEvent(audio); } *audio->nr52 &= ~0x0008; *audio->nr52 |= audio->playingCh4 << 3; @@ -865,3 +841,13 @@ static int32_t _updateChannel4(struct GBAudioChannel4* ch) { timing *= 8; return timing; } + +void _scheduleEvent(struct GBAudio* audio) { + // TODO: Don't need p + if (audio->p) { + audio->nextEvent = audio->p->cpu->cycles >> audio->p->doubleSpeed; + audio->p->cpu->nextEvent = audio->nextEvent; + } else { + audio->nextEvent = 0; + } +} diff --git a/src/gb/gb.c b/src/gb/gb.c index 519971303..65c4375a3 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -62,6 +62,7 @@ static void GBInit(void* cpu, struct mCPUComponent* component) { gb->yankedRomSize = 0; gb->eiPending = false; + gb->doubleSpeed = 0; } bool GBLoadROM(struct GB* gb, struct VFile* vf) { @@ -160,7 +161,7 @@ void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) { irqh->processEvents = GBProcessEvents; irqh->setInterrupts = GBSetInterrupts; irqh->hitIllegal = GBIllegal; - irqh->hitStub = GBHitStub; + irqh->stop = GBStop; irqh->halt = GBHalt; } @@ -253,14 +254,20 @@ void GBProcessEvents(struct LR35902Core* cpu) { } } - testEvent = GBVideoProcessEvents(&gb->video, cycles); - if (testEvent < nextEvent) { - nextEvent = testEvent; + testEvent = GBVideoProcessEvents(&gb->video, cycles >> gb->doubleSpeed); + if (testEvent != INT_MAX) { + testEvent <<= gb->doubleSpeed; + if (testEvent < nextEvent) { + nextEvent = testEvent; + } } - testEvent = GBAudioProcessEvents(&gb->audio, cycles); - if (testEvent < nextEvent) { - nextEvent = testEvent; + testEvent = GBAudioProcessEvents(&gb->audio, cycles >> gb->doubleSpeed); + if (testEvent != INT_MAX) { + testEvent <<= gb->doubleSpeed; + if (testEvent < nextEvent) { + nextEvent = testEvent; + } } testEvent = GBTimerProcessEvents(&gb->timer, cycles); @@ -301,16 +308,21 @@ void GBHalt(struct LR35902Core* cpu) { cpu->halted = true; } +void GBStop(struct LR35902Core* cpu) { + struct GB* gb = (struct GB*) cpu->master; + if (gb->memory.io[REG_KEY1] & 1) { + gb->doubleSpeed ^= 1; + gb->memory.io[REG_KEY1] &= 1; + gb->memory.io[REG_KEY1] |= gb->doubleSpeed << 7; + } + // TODO: Actually stop +} + void GBIllegal(struct LR35902Core* cpu) { // TODO mLOG(GB, GAME_ERROR, "Hit illegal opcode at address %04X:%02X\n", cpu->pc, cpu->bus); } -void GBHitStub(struct LR35902Core* cpu) { - // TODO - mLOG(GB, STUB, "Hit stub at address %04X:%02X\n", cpu->pc, cpu->bus); -} - bool GBIsROM(struct VFile* vf) { vf->seek(vf, 0x104, SEEK_SET); uint8_t header[4]; diff --git a/src/gb/gb.h b/src/gb/gb.h index 8f29389ac..085384fd7 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -67,6 +67,7 @@ struct GB { struct mAVStream* stream; int32_t eiPending; + unsigned doubleSpeed; }; struct GBCartridge { diff --git a/src/gb/io.c b/src/gb/io.c index b392c7d52..bafccc14c 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -35,6 +35,7 @@ const static uint8_t _registerMask[] = { [REG_NR51] = 0x00, [REG_NR52] = 0x70, [REG_STAT] = 0x80, + [REG_KEY1] = 0x7E, [REG_VBK] = 0xFE, [REG_OCPS] = 0x40, [REG_BCPS] = 0x40, @@ -308,6 +309,10 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { default: if (gb->model >= GB_MODEL_CGB) { switch (address) { + case REG_KEY1: + value &= 0x1; + value |= gb->memory.io[address] & 0x80; + break; case REG_VBK: GBVideoSwitchBank(&gb->video, value); break; @@ -455,6 +460,7 @@ uint8_t GBIORead(struct GB* gb, unsigned address) { case REG_HDMA4: case REG_HDMA5: case REG_SVBK: + case REG_KEY1: // Handled transparently by the registers goto success; default: diff --git a/src/gb/video.c b/src/gb/video.c index 375152664..b11ef2c6a 100644 --- a/src/gb/video.c +++ b/src/gb/video.c @@ -221,7 +221,7 @@ void GBVideoProcessDots(struct GBVideo* video) { return; } int oldX = video->x; - video->x = video->dotCounter + video->eventDiff + video->p->cpu->cycles; + video->x = video->dotCounter + video->eventDiff + (video->p->cpu->cycles >> video->p->doubleSpeed); if (video->x > GB_VIDEO_HORIZONTAL_PIXELS) { video->x = GB_VIDEO_HORIZONTAL_PIXELS; } @@ -238,15 +238,15 @@ void GBVideoWriteLCDC(struct GBVideo* video, GBRegisterLCDC value) { video->mode = 2; video->nextMode = GB_VIDEO_MODE_2_LENGTH - 5; // TODO: Why is this fudge factor needed? Might be related to T-cycles for load/store differing video->nextEvent = video->nextMode; - video->eventDiff = -video->p->cpu->cycles; + video->eventDiff = -video->p->cpu->cycles >> video->p->doubleSpeed; // TODO: Does this read as 0 for 4 T-cycles? video->stat = GBRegisterSTATSetMode(video->stat, 2); video->p->memory.io[REG_STAT] = video->stat; video->ly = 0; video->p->memory.io[REG_LY] = 0; - if (video->p->cpu->cycles + video->nextEvent < video->p->cpu->nextEvent) { - video->p->cpu->nextEvent = video->p->cpu->cycles + video->nextEvent; + if (video->p->cpu->cycles + (video->nextEvent << video->p->doubleSpeed) < video->p->cpu->nextEvent) { + video->p->cpu->nextEvent = video->p->cpu->cycles + (video->nextEvent << video->p->doubleSpeed); } return; } diff --git a/src/lr35902/emitter-lr35902.h b/src/lr35902/emitter-lr35902.h index 07f68ba73..5f0013c66 100644 --- a/src/lr35902/emitter-lr35902.h +++ b/src/lr35902/emitter-lr35902.h @@ -26,7 +26,7 @@ DECLARE_INSTRUCTION_LR35902(EMITTER, DECC), \ DECLARE_INSTRUCTION_LR35902(EMITTER, LDC_), \ DECLARE_INSTRUCTION_LR35902(EMITTER, RRCA_), \ - DECLARE_INSTRUCTION_LR35902(EMITTER, STUB), \ + DECLARE_INSTRUCTION_LR35902(EMITTER, STOP), \ DECLARE_INSTRUCTION_LR35902(EMITTER, LDDE), \ DECLARE_INSTRUCTION_LR35902(EMITTER, LDDE_A), \ DECLARE_INSTRUCTION_LR35902(EMITTER, INCDE), \ diff --git a/src/lr35902/isa-lr35902.c b/src/lr35902/isa-lr35902.c index 6634c33af..ef731e1e5 100644 --- a/src/lr35902/isa-lr35902.c +++ b/src/lr35902/isa-lr35902.c @@ -767,7 +767,15 @@ DEFINE_RST_INSTRUCTION_LR35902(30); DEFINE_RST_INSTRUCTION_LR35902(38); DEFINE_INSTRUCTION_LR35902(ILL, cpu->irqh.hitIllegal(cpu)); -DEFINE_INSTRUCTION_LR35902(STUB, cpu->irqh.hitStub(cpu)); + +DEFINE_INSTRUCTION_LR35902(STOP2, + if (!cpu->bus) { + cpu->irqh.stop(cpu); + }); + +DEFINE_INSTRUCTION_LR35902(STOP, \ + cpu->executionState = LR35902_CORE_READ_PC; \ + cpu->instruction = _LR35902InstructionSTOP2;) static const LR35902Instruction _lr35902CBInstructionTable[0x100] = { DECLARE_LR35902_CB_EMITTER_BLOCK(_LR35902Instruction) diff --git a/src/lr35902/lr35902.h b/src/lr35902/lr35902.h index 93c8c8613..85c428d58 100644 --- a/src/lr35902/lr35902.h +++ b/src/lr35902/lr35902.h @@ -63,9 +63,9 @@ struct LR35902InterruptHandler { void (*processEvents)(struct LR35902Core* cpu); void (*setInterrupts)(struct LR35902Core* cpu, bool enable); void (*halt)(struct LR35902Core* cpu); + void (*stop)(struct LR35902Core* cpu); void (*hitIllegal)(struct LR35902Core* cpu); - void (*hitStub)(struct LR35902Core* cpu); }; struct LR35902Core {