mirror of https://github.com/mgba-emu/mgba.git
GB: Simplistic SIO implementation
This commit is contained in:
parent
488bc56d3c
commit
7bcda2daa9
11
src/gb/gb.c
11
src/gb/gb.c
|
@ -54,6 +54,9 @@ static void GBInit(void* cpu, struct mCPUComponent* component) {
|
||||||
gb->audio.p = gb;
|
gb->audio.p = gb;
|
||||||
GBAudioInit(&gb->audio, 2048, &gb->memory.io[REG_NR52], GB_AUDIO_DMG); // TODO: Remove magic constant
|
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->timer.p = gb;
|
||||||
|
|
||||||
gb->biosVf = 0;
|
gb->biosVf = 0;
|
||||||
|
@ -163,6 +166,8 @@ void GBDestroy(struct GB* gb) {
|
||||||
GBUnloadROM(gb);
|
GBUnloadROM(gb);
|
||||||
|
|
||||||
GBMemoryDeinit(gb);
|
GBMemoryDeinit(gb);
|
||||||
|
GBVideoDeinit(&gb->video);
|
||||||
|
GBSIODeinit(&gb->sio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
|
void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
|
||||||
|
@ -256,6 +261,7 @@ void GBReset(struct LR35902Core* cpu) {
|
||||||
GBTimerReset(&gb->timer);
|
GBTimerReset(&gb->timer);
|
||||||
GBIOReset(gb);
|
GBIOReset(gb);
|
||||||
GBAudioReset(&gb->audio);
|
GBAudioReset(&gb->audio);
|
||||||
|
GBSIOReset(&gb->sio);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GBUpdateIRQs(struct GB* gb) {
|
void GBUpdateIRQs(struct GB* gb) {
|
||||||
|
@ -332,6 +338,11 @@ void GBProcessEvents(struct LR35902Core* cpu) {
|
||||||
nextEvent = testEvent;
|
nextEvent = testEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
testEvent = GBSIOProcessEvents(&gb->sio, cycles);
|
||||||
|
if (testEvent < nextEvent) {
|
||||||
|
nextEvent = testEvent;
|
||||||
|
}
|
||||||
|
|
||||||
testEvent = GBMemoryProcessEvents(gb, cycles);
|
testEvent = GBMemoryProcessEvents(gb, cycles);
|
||||||
if (testEvent < nextEvent) {
|
if (testEvent < nextEvent) {
|
||||||
nextEvent = testEvent;
|
nextEvent = testEvent;
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "gb/audio.h"
|
#include "gb/audio.h"
|
||||||
#include "gb/interface.h"
|
#include "gb/interface.h"
|
||||||
#include "gb/memory.h"
|
#include "gb/memory.h"
|
||||||
|
#include "gb/sio.h"
|
||||||
#include "gb/timer.h"
|
#include "gb/timer.h"
|
||||||
#include "gb/video.h"
|
#include "gb/video.h"
|
||||||
|
|
||||||
|
@ -51,6 +52,7 @@ struct GB {
|
||||||
struct GBVideo video;
|
struct GBVideo video;
|
||||||
struct GBTimer timer;
|
struct GBTimer timer;
|
||||||
struct GBAudio audio;
|
struct GBAudio audio;
|
||||||
|
struct GBSIO sio;
|
||||||
enum GBModel model;
|
enum GBModel model;
|
||||||
|
|
||||||
struct mCoreSync* sync;
|
struct mCoreSync* sync;
|
||||||
|
|
11
src/gb/io.c
11
src/gb/io.c
|
@ -6,6 +6,7 @@
|
||||||
#include "io.h"
|
#include "io.h"
|
||||||
|
|
||||||
#include "gb/gb.h"
|
#include "gb/gb.h"
|
||||||
|
#include "gb/sio.h"
|
||||||
#include "gb/serialize.h"
|
#include "gb/serialize.h"
|
||||||
|
|
||||||
mLOG_DEFINE_CATEGORY(GB_IO, "GB I/O");
|
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) {
|
void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
|
||||||
switch (address) {
|
switch (address) {
|
||||||
|
case REG_SC:
|
||||||
|
GBSIOWriteSC(&gb->sio, value);
|
||||||
|
break;
|
||||||
case REG_DIV:
|
case REG_DIV:
|
||||||
GBTimerDivReset(&gb->timer);
|
GBTimerDivReset(&gb->timer);
|
||||||
return;
|
return;
|
||||||
|
@ -334,6 +338,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case REG_JOYP:
|
case REG_JOYP:
|
||||||
|
case REG_SB:
|
||||||
case REG_TIMA:
|
case REG_TIMA:
|
||||||
case REG_TMA:
|
case REG_TMA:
|
||||||
case REG_LYC:
|
case REG_LYC:
|
||||||
|
@ -461,10 +466,6 @@ uint8_t GBIORead(struct GB* gb, unsigned address) {
|
||||||
switch (address) {
|
switch (address) {
|
||||||
case REG_JOYP:
|
case REG_JOYP:
|
||||||
return _readKeys(gb);
|
return _readKeys(gb);
|
||||||
case REG_SB:
|
|
||||||
case REG_SC:
|
|
||||||
// TODO
|
|
||||||
break;
|
|
||||||
case REG_IE:
|
case REG_IE:
|
||||||
return gb->memory.ie;
|
return gb->memory.ie;
|
||||||
case REG_WAVE_0:
|
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];
|
return gb->audio.ch3.wavedata8[address - REG_WAVE_0];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case REG_SB:
|
||||||
|
case REG_SC:
|
||||||
case REG_IF:
|
case REG_IF:
|
||||||
case REG_NR10:
|
case REG_NR10:
|
||||||
case REG_NR11:
|
case REG_NR11:
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
Loading…
Reference in New Issue