mirror of
https://github.com/devinacker/bsnes-plus.git
synced 2025-04-02 10:52:46 -04:00
335 lines
7.9 KiB
C++
335 lines
7.9 KiB
C++
#ifdef BSX_CPP
|
|
|
|
BSXBase bsxbase;
|
|
|
|
void BSXBase::Enter() { bsxbase.enter(); }
|
|
|
|
void BSXBase::enter() {
|
|
while(true) {
|
|
scheduler.synchronize();
|
|
|
|
// buffer a packet for currently open streams
|
|
for(auto &stream : regs.stream) {
|
|
if(stream.queue) {
|
|
stream.queue--;
|
|
if(stream.pf_latch && stream.pf_queue < 0x80) stream.pf_queue++;
|
|
if(stream.dt_latch && stream.dt_queue < 0x80) stream.dt_queue++;
|
|
}
|
|
}
|
|
|
|
// time step based on BT.1126 layer 2
|
|
// simulate an estimated number of bits to buffer full link-layer packets:
|
|
// 30 bit header + 176 bit payload + 82 bit error correction/CRC per packet
|
|
// right now, act as if there are only ever two total channels in the broadcast,
|
|
// and that they're both using equal bandwidth, but in reality, there could be any
|
|
// arbitrary number of channels being broadcast asynchronously with each other in
|
|
// the same satellite data stream
|
|
step(288*2);
|
|
synchronize_cpu();
|
|
}
|
|
}
|
|
|
|
void BSXBase::init() {
|
|
}
|
|
|
|
void BSXBase::enable() {
|
|
memory::mmio.map(0x2188, 0x219f, *this);
|
|
}
|
|
|
|
void BSXBase::power() {
|
|
reset();
|
|
}
|
|
|
|
void BSXBase::reset() {
|
|
// data clock based on BT.1126 layer 1 (for NTSC mode B)
|
|
// 224 data bits and 48 16-bit stereo samples per (physical) frame
|
|
// 1000 frames per sec = 224kbit/s data and 48kHz audio
|
|
create(BSXBase::Enter, 224*1000);
|
|
|
|
memset(®s, 0x00, sizeof regs);
|
|
|
|
local_time = config().sat.local_time;
|
|
custom_time = config().sat.custom_time;
|
|
|
|
regs.r2196 = 0x10;
|
|
regs.r2197 = 0xFF;
|
|
regs.r2198 = 0x80;
|
|
regs.r2199 = 0x01;
|
|
regs.r219a = 0x10;
|
|
|
|
time(&start_time);
|
|
}
|
|
|
|
void BSXBase::unload() {
|
|
regs.stream[0].packets.close();
|
|
regs.stream[1].packets.close();
|
|
}
|
|
|
|
bool BSXBase::stream_fileload(BSXStream &stream)
|
|
{
|
|
//Make sure to close the file first
|
|
stream.packets.close();
|
|
char filename[256];
|
|
string filepath;
|
|
sprintf(filename, "BSX%04X-%d.bin", stream.channel, stream.count);
|
|
filepath << config().path.bsxdat << filename;
|
|
|
|
//Open Satellaview file
|
|
if (stream.packets.open(filepath, file::mode::read))
|
|
{
|
|
stream.first = true;
|
|
stream.loaded_channel = stream.channel;
|
|
stream.loaded_count = stream.count;
|
|
stream.queue = ceil(stream.packets.size() / 22.);
|
|
}
|
|
else
|
|
{
|
|
stream.loaded_channel = 0;
|
|
stream.prefix |= 0x0f;
|
|
}
|
|
|
|
return stream.packets.open();
|
|
}
|
|
|
|
uint8 BSXBase::get_time(BSXStream &stream)
|
|
{
|
|
if (stream.offset == 0) {
|
|
time_t rawtime;
|
|
tm *t;
|
|
|
|
time(&rawtime);
|
|
if (local_time) {
|
|
t = localtime(&rawtime);
|
|
} else {
|
|
rawtime -= start_time;
|
|
rawtime += custom_time;
|
|
t = gmtime(&rawtime);
|
|
}
|
|
|
|
// adjust time to BS-X value ranges
|
|
t->tm_wday++;
|
|
t->tm_mon++;
|
|
t->tm_year += 1900;
|
|
// store time for current stream
|
|
stream.time = *t;
|
|
}
|
|
|
|
switch(stream.offset) {
|
|
case 0: return 0x00; //Data Group ID / Repetition
|
|
case 1: return 0x00; //Data Group Link / Continuity
|
|
case 2: return 0x00; //Data Group Size (24-bit)
|
|
case 3: return 0x00;
|
|
case 4: return 0x10;
|
|
case 5: return 0x01; //Must be 0x01
|
|
case 6: return 0x01; //Amount of packets (1)
|
|
case 7: return 0x00; //Offset (24-bit)
|
|
case 8: return 0x00;
|
|
case 9: return 0x00;
|
|
case 10: return stream.time.tm_sec;
|
|
case 11: return stream.time.tm_min;
|
|
case 12: return stream.time.tm_hour;
|
|
case 13: return stream.time.tm_wday;
|
|
case 14: return stream.time.tm_mday;
|
|
case 15: return stream.time.tm_mon;
|
|
case 16: return stream.time.tm_year >> 0;
|
|
case 17: return stream.time.tm_year >> 8;
|
|
default: return 0x00;
|
|
}
|
|
}
|
|
|
|
uint8 BSXBase::mmio_read(unsigned addr) {
|
|
if(!Memory::debugger_access())
|
|
cpu.synchronize_coprocessor();
|
|
|
|
unsigned streamnum = addr >= 0x218e ? 1 : 0;
|
|
BSXStream &stream = regs.stream[streamnum];
|
|
|
|
switch(addr) {
|
|
//Stream 1 & 2
|
|
case 0x2188:
|
|
case 0x218e:
|
|
return stream.channel >> 0; //Logical Channel 1 + Data Structure
|
|
case 0x2189:
|
|
case 0x218f:
|
|
return stream.channel >> 8; //Logical Channel 2
|
|
|
|
case 0x218a:
|
|
case 0x2190: {
|
|
//Prefix Count
|
|
if (!stream.pf_latch || !stream.dt_latch)
|
|
{
|
|
//Stream Not Enabled
|
|
return 0;
|
|
}
|
|
|
|
if (!stream.pf_queue && !stream.dt_queue && !Memory::debugger_access())
|
|
{
|
|
//Queue is empty
|
|
stream.offset = 0;
|
|
if (stream.channel == 0)
|
|
{
|
|
//Time Channel, one packet
|
|
stream.first = true;
|
|
stream.loaded_channel = 0;
|
|
stream.queue = 1;
|
|
}
|
|
else if (!stream_fileload(stream) && stream.count > 0)
|
|
{
|
|
stream.count = 0;
|
|
stream_fileload(stream);
|
|
}
|
|
stream.count++;
|
|
}
|
|
|
|
return stream.pf_queue;
|
|
}
|
|
|
|
case 0x218b:
|
|
case 0x2191: {
|
|
//Prefix Data Latch
|
|
if (stream.pf_latch)
|
|
{
|
|
//Latch enabled
|
|
if(stream.pf_queue && !Memory::debugger_access())
|
|
{
|
|
stream.prefix = 0;
|
|
if (stream.first)
|
|
{
|
|
//First packet
|
|
stream.prefix |= 0x10;
|
|
stream.first = false;
|
|
}
|
|
|
|
stream.pf_queue--;
|
|
if (stream.queue == 0 && stream.pf_queue == 0)
|
|
{
|
|
//Last packet
|
|
stream.prefix |= 0x80;
|
|
}
|
|
}
|
|
|
|
if(!Memory::debugger_access())
|
|
stream.status |= stream.prefix;
|
|
|
|
return stream.prefix;
|
|
}
|
|
else
|
|
{
|
|
//Latch not enabled
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
case 0x218c:
|
|
case 0x2192: {
|
|
//Data Latch
|
|
if (stream.dt_latch)
|
|
{
|
|
if(stream.dt_queue && !Memory::debugger_access())
|
|
{
|
|
if (stream.channel == 0)
|
|
{
|
|
//Return Time
|
|
stream.data = get_time(stream);
|
|
}
|
|
else if (stream.packets.open())
|
|
{
|
|
//Get packet data
|
|
stream.data = stream.packets.read();
|
|
}
|
|
|
|
stream.offset++;
|
|
if(stream.offset % 22 == 0)
|
|
{
|
|
//finished reading current packet
|
|
stream.dt_queue--;
|
|
}
|
|
}
|
|
|
|
return stream.data;
|
|
}
|
|
else
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
case 0x218d:
|
|
case 0x2193: {
|
|
//Prefix Data OR Gate
|
|
uint8 temp = stream.status;
|
|
if((regs.r2194 & 1) && !Memory::debugger_access())
|
|
{
|
|
stream.status = 0;
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
//Other
|
|
case 0x2194: return regs.r2194; //Satellaview LED and Stream register
|
|
case 0x2195: return regs.r2195; //Unknown
|
|
case 0x2196: return regs.r2196; //Satellaview Status
|
|
case 0x2197: return regs.r2197; //Soundlink / EXT output
|
|
case 0x2198: return regs.r2198; //Serial I/O - Serial Number
|
|
case 0x2199: return regs.r2199; //Serial I/O - ???
|
|
case 0x219a: return regs.r219a; //Unknown
|
|
}
|
|
|
|
return 0x00;
|
|
}
|
|
|
|
void BSXBase::mmio_write(unsigned addr, uint8 data) {
|
|
if(!Memory::debugger_access())
|
|
cpu.synchronize_coprocessor();
|
|
|
|
unsigned streamnum = addr >= 0x218e ? 1 : 0;
|
|
BSXStream &stream = regs.stream[streamnum];
|
|
|
|
switch(addr) {
|
|
//Stream 1 & 2
|
|
case 0x2188:
|
|
case 0x218e: {
|
|
//Logical Channel 1 + Data Structure
|
|
if ((stream.channel & 0xff) != data)
|
|
stream.count = 0;
|
|
stream.channel = (stream.channel & 0x3f00) | data;
|
|
} break;
|
|
|
|
case 0x2189:
|
|
case 0x218f: {
|
|
//Logical Channel 2 (6bit)
|
|
if ((stream.channel >> 8) != (data & 0x3F))
|
|
stream.count = 0;
|
|
stream.channel = (stream.channel & 0xff) | (data << 8);
|
|
} break;
|
|
|
|
case 0x218b:
|
|
case 0x2191: {
|
|
//Prefix Data Latch
|
|
stream.pf_latch = (data != 0);
|
|
stream.pf_queue = 0;
|
|
} break;
|
|
|
|
case 0x218c:
|
|
case 0x2192: {
|
|
//Data Latch
|
|
stream.dt_latch = (data != 0);
|
|
stream.dt_queue = 0;
|
|
} break;
|
|
|
|
|
|
//Other
|
|
case 0x2194: {
|
|
//Satellaview LED and Stream enable (4bit)
|
|
regs.r2194 = data;
|
|
} break;
|
|
|
|
case 0x2197: {
|
|
//Soundlink / EXT output
|
|
regs.r2197 = data;
|
|
} break;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|