Shared RAM on simulated netboard is now double-buffered; Spikeout Final Edition no longer requires a hack to work.

Preparing to enable simulated netboard to run in its own thread
This commit is contained in:
Matthew Daniels 2021-11-05 00:23:29 +00:00
parent b62110617b
commit 50465f9a5a
6 changed files with 116 additions and 57 deletions

View file

@ -1011,8 +1011,7 @@ UINT8 CModel3::Read8(UINT32 addr)
switch ((addr & 0x3ffff) >> 16) switch ((addr & 0x3ffff) >> 16)
{ {
case 0: case 0:
//printf("R8 netbuffer @%x=%x\n", (addr & 0xFFFF), netBuffer[(addr & 0xFFFF)]); return NetBoard->ReadCommRAM8((addr & 0xFFFF) ^ 2);
return netBuffer[(addr & 0xFFFF) ^ 2];
case 1: // ioreg 32bits access in 16bits environment case 1: // ioreg 32bits access in 16bits environment
if (addr > 0xc00101ff) if (addr > 0xc00101ff)
@ -1020,22 +1019,11 @@ UINT8 CModel3::Read8(UINT32 addr)
printf("R8 ATTENTION OUT OF RANGE\n"); printf("R8 ATTENTION OUT OF RANGE\n");
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Info", "Out of Range", NULL); SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Info", "Out of Range", NULL);
} }
//printf("R8 ioreg @%x=%x\n", (addr & 0x1FF), netBuffer[0x10000 + ((addr & 0x1FF) / 2)]);
//return netBuffer[0x10000 + ((addr & 0x1FF) / 2)];
return (UINT8)NetBoard->ReadIORegister((addr & 0x1FF) / 2); return (UINT8)NetBoard->ReadIORegister((addr & 0x1FF) / 2);
case 2: case 2:
case 3: case 3:
if (addr > 0xc002ffff)
{
printf("R8 ATTENTION OUT OF RANGE\n");
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Info", "Out of Range", NULL);
}
//printf("R8 netram @%x=%x\n", (addr & 0x1FFFF), netRAM[addr & 0x1ffff]);
return netRAM[((addr & 0x1FFFF) / 2)]; return netRAM[((addr & 0x1FFFF) / 2)];
/*case 3:
//printf("R8 netram @%x=%x\n", (addr & 0x1FFFF), netRAM[addr & 0x1ffff]);
return netRAM[((addr & 0x1FFFF) / 2)];*/
default: default:
printf("R8 ATTENTION OUT OF RANGE\n"); printf("R8 ATTENTION OUT OF RANGE\n");
@ -1152,8 +1140,7 @@ UINT16 CModel3::Read16(UINT32 addr)
switch ((addr & 0x3ffff) >> 16) switch ((addr & 0x3ffff) >> 16)
{ {
case 0: case 0:
//printf("R16 netbuffer @%x=%x\n", (addr & 0xFFFF), FLIPENDIAN16(*(UINT16 *)&netBuffer[(addr & 0xFFFF)])); result = NetBoard->ReadCommRAM16((addr & 0xFFFF) ^ 2);
result = *(UINT16 *)&netBuffer[(addr & 0xFFFF) ^ 2];
return FLIPENDIAN16(result); // result return FLIPENDIAN16(result); // result
default: default:
printf("CMODEL3 : unknown R16 : %x (C0)\n", addr); printf("CMODEL3 : unknown R16 : %x (C0)\n", addr);
@ -1317,7 +1304,7 @@ UINT32 CModel3::Read32(UINT32 addr)
switch ((addr & 0x3ffff) >> 16) switch ((addr & 0x3ffff) >> 16)
{ {
case 0: case 0:
result = *(UINT32 *)&netBuffer[(addr & 0xFFFF)]; result = NetBoard->ReadCommRAM32(addr & 0xFFFF);
result = FLIPENDIAN32(result); result = FLIPENDIAN32(result);
return ((result << 16) | (result >> 16)); return ((result << 16) | (result >> 16));
@ -1332,11 +1319,6 @@ UINT32 CModel3::Read32(UINT32 addr)
case 2: case 2:
case 3: case 3:
if (addr > 0xc003ffff)
{
printf("R32 ATTENTION OUT OF RANGE\n");
}
result = (*(UINT32 *)&netRAM[((addr & 0x1FFFF) / 2)]) & 0x0000ffff; result = (*(UINT32 *)&netRAM[((addr & 0x1FFFF) / 2)]) & 0x0000ffff;
return FLIPENDIAN32(result); // result return FLIPENDIAN32(result); // result
@ -1479,7 +1461,7 @@ void CModel3::Write8(UINT32 addr, UINT8 data)
switch ((addr & 0x3ffff) >> 16) switch ((addr & 0x3ffff) >> 16)
{ {
case 0: case 0:
*(UINT8 *)&netBuffer[(addr & 0xFFFF) ^ 2] = data; NetBoard->WriteCommRAM8((addr & 0xFFFF) ^ 2, data);
break; break;
case 1: // ioreg 32bits access to 16bits range case 1: // ioreg 32bits access to 16bits range
@ -1493,11 +1475,6 @@ void CModel3::Write8(UINT32 addr, UINT8 data)
case 2: case 2:
case 3: case 3:
if (addr > 0xc002ffff)
{
printf("W8 ATTENTION OUT OF RANGE\n");
}
*(UINT8 *)&netRAM[(addr & 0x1FFFF)/2] = data; *(UINT8 *)&netRAM[(addr & 0x1FFFF)/2] = data;
break; break;
@ -1600,7 +1577,7 @@ void CModel3::Write16(UINT32 addr, UINT16 data)
switch ((addr & 0x3ffff) >> 16) switch ((addr & 0x3ffff) >> 16)
{ {
case 0: case 0:
*(UINT16 *)&netBuffer[(addr & 0xFFFF) ^ 2] = FLIPENDIAN16(data); NetBoard->WriteCommRAM16((addr & 0xFFFF) ^ 2, FLIPENDIAN16(data));
break; break;
default: default:
@ -1806,7 +1783,7 @@ void CModel3::Write32(UINT32 addr, UINT32 data)
{ {
case 0: case 0:
temp = FLIPENDIAN32(data); temp = FLIPENDIAN32(data);
*(UINT32 *)&netBuffer[(addr & 0xFFFF)] = (temp << 16) | (temp >> 16); NetBoard->WriteCommRAM32(addr & 0xFFFF, (temp << 16) | (temp >> 16));
break; break;
case 1: // ioreg 32bits access to 16bits range case 1: // ioreg 32bits access to 16bits range
@ -1820,11 +1797,6 @@ void CModel3::Write32(UINT32 addr, UINT32 data)
case 2: case 2:
case 3: case 3:
if (addr > 0xc003ffff)
{
printf("W32 ATTENTION OUT OF RANGE\n");
}
*(UINT16 *)&netRAM[((addr & 0x1FFFF) / 2)] = FLIPENDIAN16(data >> 16); *(UINT16 *)&netRAM[((addr & 0x1FFFF) / 2)] = FLIPENDIAN16(data >> 16);
break; break;

View file

@ -43,6 +43,14 @@ public:
virtual void GetGame(Game) = 0; virtual void GetGame(Game) = 0;
virtual UINT8 ReadCommRAM8(unsigned addr) = 0;
virtual UINT16 ReadCommRAM16(unsigned addr) = 0;
virtual UINT32 ReadCommRAM32(unsigned addr) = 0;
virtual void WriteCommRAM8(unsigned addr, UINT8 data) = 0;
virtual void WriteCommRAM16(unsigned addr, UINT16 data) = 0;
virtual void WriteCommRAM32(unsigned addr, UINT32 data) = 0;
virtual UINT16 ReadIORegister(unsigned reg) = 0; virtual UINT16 ReadIORegister(unsigned reg) = 0;
virtual void WriteIORegister(unsigned reg, UINT16 data) = 0; virtual void WriteIORegister(unsigned reg, UINT16 data) = 0;
}; };

View file

@ -1314,6 +1314,36 @@ void CNetBoard::GetGame(Game gameinfo)
Gameinfo = gameinfo; Gameinfo = gameinfo;
} }
UINT8 CNetBoard::ReadCommRAM8(unsigned addr)
{
return CommRAM[addr];
}
UINT16 CNetBoard::ReadCommRAM16(unsigned addr)
{
return *(UINT16*)&CommRAM[addr];
}
UINT32 CNetBoard::ReadCommRAM32(unsigned addr)
{
return *(UINT32*)&CommRAM[addr];
}
void CNetBoard::WriteCommRAM8(unsigned addr, UINT8 data)
{
CommRAM[addr] = data;
}
void CNetBoard::WriteCommRAM16(unsigned addr, UINT16 data)
{
*(UINT16*)&CommRAM[addr] = data;
}
void CNetBoard::WriteCommRAM32(unsigned addr, UINT32 data)
{
*(UINT32*)&CommRAM[addr] = data;
}
UINT16 CNetBoard::ReadIORegister(unsigned reg) UINT16 CNetBoard::ReadIORegister(unsigned reg)
{ {
if (!IsRunning()) if (!IsRunning())

View file

@ -61,6 +61,14 @@ public:
void GetGame(Game); void GetGame(Game);
UINT8 ReadCommRAM8(unsigned addr);
UINT16 ReadCommRAM16(unsigned addr);
UINT32 ReadCommRAM32(unsigned addr);
void WriteCommRAM8(unsigned addr, UINT8 data);
void WriteCommRAM16(unsigned addr, UINT16 data);
void WriteCommRAM32(unsigned addr, UINT32 data);
UINT16 ReadIORegister(unsigned reg); UINT16 ReadIORegister(unsigned reg);
void WriteIORegister(unsigned reg, UINT16 data); void WriteIORegister(unsigned reg, UINT16 data);

View file

@ -61,7 +61,10 @@ void CSimNetBoard::LoadState(CBlockFile* SaveState)
bool CSimNetBoard::Init(uint8_t* netRAMPtr, uint8_t* netBufferPtr) bool CSimNetBoard::Init(uint8_t* netRAMPtr, uint8_t* netBufferPtr)
{ {
RAM = netRAMPtr; RAM = netRAMPtr;
CommRAM = netBufferPtr; Buffer = netBufferPtr;
CommRAM = Buffer;
externalCommRAM = Buffer + 0x10000;
m_attached = m_gameInfo.netboard_present && m_config["Network"].ValueAs<bool>(); m_attached = m_gameInfo.netboard_present && m_config["Network"].ValueAs<bool>();
@ -105,7 +108,7 @@ void CSimNetBoard::RunFrame(void)
break; break;
case State::init: case State::init:
memset(CommRAM, 0, 0x10000); memset(CommRAM, 0, 0x20000);
if (m_gameType == GameType::one) if (m_gameType == GameType::one)
{ {
if (m_status0 & 0x8000) // has main board changed this register? if (m_status0 & 0x8000) // has main board changed this register?
@ -454,39 +457,36 @@ void CSimNetBoard::RunFrame(void)
m_counter++; m_counter++;
CommRAM16[0x6] = FLIPENDIAN16(m_counter); CommRAM16[0x6] = FLIPENDIAN16(m_counter);
if (IsGame("spikeofe")) // temporary hack for spikeout final edition (avoids comm error) // we only send what we need to; helps cut down on bandwidth
// each machine has to receive back its own data (TODO: copy this data manually?)
for (int i = 0; i < m_numMachines; i++)
{ {
nets->Send(CommRAM + 0x100, m_segmentSize * m_numMachines); nets->Send(CommRAM + 0x100 + i * m_segmentSize, m_segmentSize);
auto& recv_data = netr->Receive(); auto& recv_data = netr->Receive();
if (recv_data.size() == 0) if (recv_data.size() == 0)
{ {
// link broken - send an "empty" packet to alert other machines // link broken - send an "empty" packet to alert other machines
nets->Send(nullptr, 0); nets->Send(nullptr, 0);
m_state = State::error; m_state = State::error;
m_status1 = 0x40; // send "link broken" message to mainboard if (m_gameType == GameType::one)
m_status1 = 0x40; // send "link broken" message to mainboard
break; break;
} }
memcpy(CommRAM + 0x100 + m_segmentSize, recv_data.data(), recv_data.size()); memcpy(CommRAM + 0x100 + (i + 1) * m_segmentSize, recv_data.data(), recv_data.size());
}
// swap CommRAM banks
if (m_commbank)
{
m_commbank = false;
CommRAM = Buffer;
externalCommRAM = Buffer + 0x10000;
} }
else else
{ {
// we only send what we need to; helps cut down on bandwidth m_commbank = true;
// each machine has to receive back its own data (TODO: copy this data manually?) CommRAM = Buffer + 0x10000;
for (int i = 0; i < m_numMachines; i++) externalCommRAM = Buffer;
{
nets->Send(CommRAM + 0x100 + i * m_segmentSize, m_segmentSize);
auto& recv_data = netr->Receive();
if (recv_data.size() == 0)
{
// link broken - send an "empty" packet to alert other machines
nets->Send(nullptr, 0);
m_state = State::error;
if (m_gameType == GameType::one)
m_status1 = 0x40; // send "link broken" message to mainboard
break;
}
memcpy(CommRAM + 0x100 + (i + 1) * m_segmentSize, recv_data.data(), recv_data.size());
}
} }
break; break;
@ -554,6 +554,36 @@ void CSimNetBoard::ConnectProc(void)
m_connected = true; m_connected = true;
} }
uint8_t CSimNetBoard::ReadCommRAM8(unsigned addr)
{
return externalCommRAM[addr];
}
uint16_t CSimNetBoard::ReadCommRAM16(unsigned addr)
{
return *(uint16_t*)&externalCommRAM[addr];
}
uint32_t CSimNetBoard::ReadCommRAM32(unsigned addr)
{
return *(uint32_t*)&externalCommRAM[addr];
}
void CSimNetBoard::WriteCommRAM8(unsigned addr, uint8_t data)
{
externalCommRAM[addr] = data;
}
void CSimNetBoard::WriteCommRAM16(unsigned addr, uint16_t data)
{
*(uint16_t*)&externalCommRAM[addr] = data;
}
void CSimNetBoard::WriteCommRAM32(unsigned addr, uint32_t data)
{
*(uint32_t*)&externalCommRAM[addr] = data;
}
uint16_t CSimNetBoard::ReadIORegister(unsigned reg) uint16_t CSimNetBoard::ReadIORegister(unsigned reg)
{ {
if (!IsRunning()) if (!IsRunning())

View file

@ -62,6 +62,14 @@ public:
void GetGame(Game gameInfo); void GetGame(Game gameInfo);
uint8_t ReadCommRAM8(unsigned addr);
uint16_t ReadCommRAM16(unsigned addr);
uint32_t ReadCommRAM32(unsigned addr);
void WriteCommRAM8(unsigned addr, uint8_t data);
void WriteCommRAM16(unsigned addr, uint16_t data);
void WriteCommRAM32(unsigned addr, uint32_t data);
uint16_t ReadIORegister(unsigned reg); uint16_t ReadIORegister(unsigned reg);
void WriteIORegister(unsigned reg, uint16_t data); void WriteIORegister(unsigned reg, uint16_t data);
@ -70,7 +78,9 @@ private:
const Util::Config::Node& m_config; const Util::Config::Node& m_config;
uint8_t* RAM = nullptr; uint8_t* RAM = nullptr;
uint8_t* Buffer = nullptr;
uint8_t* CommRAM = nullptr; uint8_t* CommRAM = nullptr;
uint8_t* externalCommRAM = nullptr;
// netsock // netsock
uint16_t port_in = 0; uint16_t port_in = 0;
@ -98,6 +108,7 @@ private:
uint16_t m_IRQ2ack = 0; uint16_t m_IRQ2ack = 0;
uint16_t m_status0 = 0; // ioreg 0x88 uint16_t m_status0 = 0; // ioreg 0x88
uint16_t m_status1 = 0; // ioreg 0x8a uint16_t m_status1 = 0; // ioreg 0x8a
bool m_commbank = false;
inline bool IsGame(const char* gameName); inline bool IsGame(const char* gameName);
void ConnectProc(void); void ConnectProc(void);