From 7bcda2daa9cae93ec37e3806d22cb0fe1f259588 Mon Sep 17 00:00:00 2001 From: Jeffrey Pfau Date: Fri, 26 Aug 2016 14:45:43 -0700 Subject: [PATCH] GB: Simplistic SIO implementation --- src/gb/gb.c | 11 +++++++++++ src/gb/gb.h | 2 ++ src/gb/io.c | 11 +++++++---- src/gb/sio.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/gb/sio.h | 33 ++++++++++++++++++++++++++++++++ 5 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 src/gb/sio.c create mode 100644 src/gb/sio.h diff --git a/src/gb/gb.c b/src/gb/gb.c index 99a0f1b72..9800ec847 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -54,6 +54,9 @@ static void GBInit(void* cpu, struct mCPUComponent* component) { 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 @@ void GBReset(struct LR35902Core* cpu) { GBTimerReset(&gb->timer); GBIOReset(gb); GBAudioReset(&gb->audio); + GBSIOReset(&gb->sio); } void GBUpdateIRQs(struct GB* gb) { @@ -332,6 +338,11 @@ void GBProcessEvents(struct LR35902Core* cpu) { nextEvent = testEvent; } + testEvent = GBSIOProcessEvents(&gb->sio, cycles); + if (testEvent < nextEvent) { + nextEvent = testEvent; + } + testEvent = GBMemoryProcessEvents(gb, cycles); if (testEvent < nextEvent) { nextEvent = testEvent; diff --git a/src/gb/gb.h b/src/gb/gb.h index f803a68a5..6f28e66bd 100644 --- a/src/gb/gb.h +++ b/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 GB { struct GBVideo video; struct GBTimer timer; struct GBAudio audio; + struct GBSIO sio; enum GBModel model; struct mCoreSync* sync; diff --git a/src/gb/io.c b/src/gb/io.c index 3317acdf9..c6995c07a 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -6,6 +6,7 @@ #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 GBIOReset(struct GB* gb) { 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 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t 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 @@ uint8_t GBIORead(struct GB* gb, unsigned address) { 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: diff --git a/src/gb/sio.c b/src/gb/sio.c new file mode 100644 index 000000000..7e114b2e9 --- /dev/null +++ b/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; + } +} + diff --git a/src/gb/sio.h b/src/gb/sio.h new file mode 100644 index 000000000..8ff10265b --- /dev/null +++ b/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