Mesen-SX/Core/BsxSatellaview.cpp
2020-12-19 23:30:09 +03:00

163 lines
3.8 KiB
C++

#include "stdafx.h"
#include "BsxSatellaview.h"
#include "Console.h"
#include "MemoryManager.h"
#include "EmuSettings.h"
#include "../Utilities/Serializer.h"
BsxSatellaview::BsxSatellaview(Console* console, IMemoryHandler* bBusHandler) : IMemoryHandler(SnesMemoryType::Register)
{
_console = console;
_memoryManager = console->GetMemoryManager().get();
_customDate = console->GetSettings()->GetEmulationConfig().BsxCustomDate;
_bBusHandler = bBusHandler;
Reset();
}
void BsxSatellaview::Reset()
{
_prevMasterClock = 0;
_streamReg = 0;
_extOutput = 0xFF;
time_t resetDate;
if (_customDate >= 0)
{
resetDate = (time_t)_customDate;
}
else
{
//Use the current date/time as the BS-X date/time
time(&resetDate);
}
_stream[0].Reset(_console, resetDate);
_stream[1].Reset(_console, resetDate);
}
uint8_t BsxSatellaview::Read(uint32_t addr)
{
addr &= 0xFFFF;
if (addr >= 0x2188 && addr <= 0x219F)
{
//Handle BS-X $2188-219F registers
ProcessClocks();
switch (addr)
{
case 0x2188: return _stream[0].GetChannel() & 0xFF;
case 0x2189: return (_stream[0].GetChannel()) >> 8;
case 0x218A: return _stream[0].GetPrefixCount();
case 0x218B: return _stream[0].GetPrefix();
case 0x218C: return _stream[0].GetData();
case 0x218D: return _stream[0].GetStatus((_streamReg & 0x01) != 0);
case 0x218E: return _stream[1].GetChannel() & 0xFF;
case 0x218F: return (_stream[1].GetChannel()) >> 8;
case 0x2190: return _stream[1].GetPrefixCount();
case 0x2191: return _stream[1].GetPrefix();
case 0x2192: return _stream[1].GetData();
case 0x2193: return _stream[1].GetStatus((_streamReg & 0x01) != 0);
case 0x2194: return _streamReg; //LED and Stream register
case 0x2195: return 0; //Unknown
case 0x2196: return 0x10; //Satellaview status
case 0x2197: return _extOutput; //Soundlink / EXT output
case 0x2198: return 0x80; //Serial IO (Serial number)
case 0x2199: return 0x01; //Serial IO (???)
case 0x219A: return 0x10; //Unknown
}
}
//Use regular B-bus handler for everything else
return _bBusHandler->Read(addr);
}
void BsxSatellaview::Write(uint32_t addr, uint8_t value)
{
addr &= 0xFFFF;
if (addr >= 0x2188 && addr <= 0x219F)
{
//Handle BS-X register writes
ProcessClocks();
switch (addr)
{
case 0x2188: _stream[0].SetChannelLow(value);
break;
case 0x2189: _stream[0].SetChannelHigh(value);
break;
case 0x218B: _stream[0].SetPrefixLatch(value);
break;
case 0x218C: _stream[0].SetDataLatch(value);
break;
case 0x218E: _stream[1].SetChannelLow(value);
break;
case 0x218F: _stream[1].SetChannelHigh(value);
break;
case 0x2191: _stream[1].SetPrefixLatch(value);
break;
case 0x2192: _stream[1].SetDataLatch(value);
break;
case 0x2194: _streamReg = value;
break;
case 0x2197: _extOutput = value;
break;
}
}
else
{
//Regular B-bus handler
_bBusHandler->Write(addr, value);
}
}
void BsxSatellaview::ProcessClocks()
{
if (_stream[0].NeedUpdate() || _stream[1].NeedUpdate())
{
uint64_t gap = _memoryManager->GetMasterClock() - _prevMasterClock;
uint64_t clocksPerFrame = _console->GetMasterClockRate() / 1000; //1000 frames/sec (224kbits/sec)
while (gap >= clocksPerFrame)
{
bool needUpdate = _stream[0].FillQueues() || _stream[1].FillQueues();
if (!needUpdate)
{
gap = 0;
break;
}
gap -= clocksPerFrame;
}
_prevMasterClock = _memoryManager->GetMasterClock() - gap;
}
else
{
_prevMasterClock = _memoryManager->GetMasterClock();
}
}
uint8_t BsxSatellaview::Peek(uint32_t addr)
{
return 0;
}
void BsxSatellaview::PeekBlock(uint32_t addr, uint8_t* output)
{
memset(output, 0, 0x1000);
}
AddressInfo BsxSatellaview::GetAbsoluteAddress(uint32_t address)
{
return {-1, SnesMemoryType::Register};
}
void BsxSatellaview::Serialize(Serializer& s)
{
s.Stream(_extOutput, _streamReg, _customDate, _prevMasterClock);
s.Stream(&_stream[0]);
s.Stream(&_stream[1]);
}