GB: Simplistic SIO implementation
Jeffrey Pfau jeffrey@endrift.com
Fri, 26 Aug 2016 14:45:43 -0700
5 files changed,
106 insertions(+),
4 deletions(-)
M
src/gb/gb.c
→
src/gb/gb.c
@@ -54,6 +54,9 @@
gb->audio.p = gb; GBAudioInit(&gb->audio, 2048, &gb->memory.io[REG_NR52], GB_AUDIO_DMG); // TODO: Remove magic constant + gb->sio.p = gb; + GBSIOInit(&gb->sio); + gb->timer.p = gb; gb->biosVf = 0;@@ -163,6 +166,8 @@ void GBDestroy(struct GB* gb) {
GBUnloadROM(gb); GBMemoryDeinit(gb); + GBVideoDeinit(&gb->video); + GBSIODeinit(&gb->sio); } void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {@@ -256,6 +261,7 @@ GBVideoReset(&gb->video);
GBTimerReset(&gb->timer); GBIOReset(gb); GBAudioReset(&gb->audio); + GBSIOReset(&gb->sio); } void GBUpdateIRQs(struct GB* gb) {@@ -328,6 +334,11 @@ }
} testEvent = GBTimerProcessEvents(&gb->timer, cycles); + if (testEvent < nextEvent) { + nextEvent = testEvent; + } + + testEvent = GBSIOProcessEvents(&gb->sio, cycles); if (testEvent < nextEvent) { nextEvent = testEvent; }
M
src/gb/gb.h
→
src/gb/gb.h
@@ -15,6 +15,7 @@
#include "gb/audio.h" #include "gb/interface.h" #include "gb/memory.h" +#include "gb/sio.h" #include "gb/timer.h" #include "gb/video.h"@@ -51,6 +52,7 @@ struct GBMemory memory;
struct GBVideo video; struct GBTimer timer; struct GBAudio audio; + struct GBSIO sio; enum GBModel model; struct mCoreSync* sync;
M
src/gb/io.c
→
src/gb/io.c
@@ -6,6 +6,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "io.h" #include "gb/gb.h" +#include "gb/sio.h" #include "gb/serialize.h" mLOG_DEFINE_CATEGORY(GB_IO, "GB I/O");@@ -157,6 +158,9 @@ }
void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { switch (address) { + case REG_SC: + GBSIOWriteSC(&gb->sio, value); + break; case REG_DIV: GBTimerDivReset(&gb->timer); return;@@ -334,6 +338,7 @@ gb->audio.ch3.wavedata8[gb->audio.ch3.window >> 1] = value;
} break; case REG_JOYP: + case REG_SB: case REG_TIMA: case REG_TMA: case REG_LYC:@@ -461,10 +466,6 @@ uint8_t GBIORead(struct GB* gb, unsigned address) {
switch (address) { case REG_JOYP: return _readKeys(gb); - case REG_SB: - case REG_SC: - // TODO - break; case REG_IE: return gb->memory.ie; case REG_WAVE_0:@@ -493,6 +494,8 @@ } else {
return gb->audio.ch3.wavedata8[address - REG_WAVE_0]; } break; + case REG_SB: + case REG_SC: case REG_IF: case REG_NR10: case REG_NR11:
A
src/gb/sio.c
@@ -0,0 +1,53 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "sio.h" + +#include "gb/gb.h" +#include "gb/io.h" +#include "gb/serialize.h" + +void GBSIOInit(struct GBSIO* sio) { + sio->pendingSB = 0xFF; +} + +void GBSIOReset(struct GBSIO* sio) { + sio->nextEvent = INT_MAX; + sio->remainingBits = 0; +} + +void GBSIODeinit(struct GBSIO* sio) { + UNUSED(sio); + // Nothing to do yet +} + +int32_t GBSIOProcessEvents(struct GBSIO* sio, int32_t cycles) { + if (sio->nextEvent != INT_MAX) { + sio->nextEvent -= cycles; + } + if (sio->nextEvent <= 0) { + --sio->remainingBits; + sio->p->memory.io[REG_SB] &= ~(8 >> sio->remainingBits); + sio->p->memory.io[REG_SB] |= sio->pendingSB & ~(8 >> sio->remainingBits); + if (!sio->remainingBits) { + sio->p->memory.io[REG_IF] |= (1 << GB_IRQ_SIO); + sio->p->memory.io[REG_SC] = GBRegisterSCClearEnable(sio->p->memory.io[REG_SC]); + GBUpdateIRQs(sio->p); + sio->nextEvent = INT_MAX; + } else { + sio->nextEvent += sio->period; + } + } + return sio->nextEvent; +} + +void GBSIOWriteSC(struct GBSIO* sio, uint8_t sc) { + sio->period = 0x1000; // TODO Shift Clock + if (GBRegisterSCIsEnable(sc)) { + sio->nextEvent = sio->p->cpu->cycles + sio->period; + sio->remainingBits = 8; + } +} +
A
src/gb/sio.h
@@ -0,0 +1,33 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_SIO_H +#define GB_SIO_H + +#include "util/common.h" + +struct GB; +struct GBSIO { + struct GB* p; + + int32_t nextEvent; + int32_t period; + int remainingBits; + + uint8_t pendingSB; +}; + +DECL_BITFIELD(GBRegisterSC, uint8_t); +DECL_BIT(GBRegisterSC, ShiftClock, 0); +DECL_BIT(GBRegisterSC, ClockSpeed, 1); +DECL_BIT(GBRegisterSC, Enable, 7); + +void GBSIOInit(struct GBSIO* sio); +void GBSIOReset(struct GBSIO* sio); +void GBSIODeinit(struct GBSIO* sio); +int32_t GBSIOProcessEvents(struct GBSIO* sio, int32_t cycles); +void GBSIOWriteSC(struct GBSIO* sio, uint8_t sc); + +#endif