New JTAG patch for Sega Rally 2; linked mode now fully working.

Few other minor changes
This commit is contained in:
Matthew Daniels 2021-10-30 23:00:49 +00:00
parent 94d8a1b22d
commit b62110617b
8 changed files with 120 additions and 79 deletions

View file

@ -1899,10 +1899,18 @@
</hardware>
<roms>
<patches>
<!-- Unemulated JTAG stuff -->
<!-- Old patch to bypass JTAG checks, breaks linked mode -->
<!--
<patch region="crom" bits="32" offset="0x7c0c4" value="0x60000000" />
<patch region="crom" bits="32" offset="0x7c0c8" value="0x60000000" />
<patch region="crom" bits="32" offset="0x7c0cc" value="0x60000000" />
-->
<!-- New patch to bypass JTAG checks -->
<patch region="crom" bits="32" offset="0x7b348" value="0x60000000" />
<patch region="crom" bits="32" offset="0x7b568" value="0x60000000" />
<patch region="crom" bits="32" offset="0x7b6b4" value="0x60000000" />
<patch region="crom" bits="32" offset="0x7b7b0" value="0x60000000" />
<patch region="crom" bits="32" offset="0x7b8a8" value="0x60000000" />
</patches>
<region name="crom" stride="8" chunk_size="2" byte_swap="true">
<file offset="0" name="epr-20635.20" crc32="0x7937473F" />

View file

@ -1021,7 +1021,8 @@ UINT8 CModel3::Read8(UINT32 addr)
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 netBuffer[0x10000 + ((addr & 0x1FF) / 2)];
return (UINT8)NetBoard->ReadIORegister((addr & 0x1FF) / 2);
case 2:
case 3:
@ -1316,43 +1317,28 @@ UINT32 CModel3::Read32(UINT32 addr)
switch ((addr & 0x3ffff) >> 16)
{
case 0:
//printf("R32 netbuffer @%x=%x\n", (addr & 0xFFFF), FLIPENDIAN32(*(UINT32 *)&netBuffer[(addr & 0xFFFF)]));
result = *(UINT32 *)&netBuffer[(addr & 0xFFFF)];
result = FLIPENDIAN32(result);
return ((result << 16) | (result >> 16));
//return FLIPENDIAN32(result); // result
case 1: // ioreg 32bits access to 16bits range
//printf("R32 ioreg @%x=%x\n", (addr & 0x1FF), FLIPENDIAN32(*(UINT32 *)&netBuffer[0x10000 + ((addr & 0x1FF) / 2)]));
if (addr > 0xc00101ff)
{
printf("R32 ATTENTION OUT OF RANGE\n");
}
UINT32 test;
test = (*(UINT32 *)&netBuffer[0x10000 + ((addr & 0x1FF) / 2)]);
/*if (((FLIPENDIAN32(test) & 0x00ff0000) != 0x00900000) && ((FLIPENDIAN32(test) & 0x00ff0000) != 0x00a00000) && ((FLIPENDIAN32(test) & 0x00ff0000) != 0x00b00000) && ((FLIPENDIAN32(test) & 0x00ff0000) != 0x00800000) && ((FLIPENDIAN32(test) & 0x00ff0000) != 0x00f00000))
{
printf("R32 ioreg @%x=%04x\n", (addr), FLIPENDIAN32(test) >> 16);
}*/
result = (*(UINT32 *)&netBuffer[0x10000 + ((addr & 0x1FF) / 2)]) & 0x0000ffff;
result = NetBoard->ReadIORegister((addr & 0x1FF) / 2);
return FLIPENDIAN32(result);
case 2:
case 3:
//printf("R32 netram @%x=%x\n", (addr & 0x1FFFF), FLIPENDIAN32(*(UINT32 *)&netBuffer[(addr & 0x1FFFF)]));
if (addr > 0xc002ffff)
if (addr > 0xc003ffff)
{
printf("R32 ATTENTION OUT OF RANGE\n");
}
result = (*(UINT32 *)&netRAM[((addr & 0x1FFFF) / 2)]) & 0x0000ffff;
return FLIPENDIAN32(result); // result
/*case 3:
//printf("R32 netram @%x=%x\n", (addr & 0x1FFFF), FLIPENDIAN32(*(UINT32 *)&netBuffer[(addr & 0x1FFFF)]));
result = (*(UINT32 *)&netRAM[((addr & 0x1FFFF) / 2)]) & 0x0000ffff;
return FLIPENDIAN32(result); // result*/
default:
printf("R32 ATTENTION OUT OF RANGE\n");
@ -1493,7 +1479,6 @@ void CModel3::Write8(UINT32 addr, UINT8 data)
switch ((addr & 0x3ffff) >> 16)
{
case 0:
//printf("W8 netbuffer @%x<-%x\n", (addr & 0xFFFF), data);
*(UINT8 *)&netBuffer[(addr & 0xFFFF) ^ 2] = data;
break;
@ -1503,10 +1488,7 @@ void CModel3::Write8(UINT32 addr, UINT8 data)
printf("W8 ATTENTION OUT OF RANGE\n");
}
//printf("W8 ioreg @%x<-%x\n", (addr & 0x1FF), data);
if (((addr & 0x1FF) == 0x180) && (data == 0x00))
NetBoard->Reset();
*(UINT8 *)&netBuffer[0x10000 + ((addr & 0x1FF) / 2)] = data;
NetBoard->WriteIORegister((addr & 0x1FF) / 2, data);
break;
case 2:
@ -1516,13 +1498,8 @@ void CModel3::Write8(UINT32 addr, UINT8 data)
printf("W8 ATTENTION OUT OF RANGE\n");
}
//printf("W8 netram @%x<-%x\n", (addr & 0x1FFFF), data);
*(UINT8 *)&netRAM[(addr & 0x1FFFF)/2] = data;
break;
/*case 3:
//printf("W8 netram @%x<-%x\n", (addr & 0x1FFFF), data);
*(UINT8 *)&netRAM[(addr & 0x1FFFF) / 2] = data;
break;*/
default:
printf("W8 ATTENTION OUT OF RANGE\n");
@ -1623,7 +1600,6 @@ void CModel3::Write16(UINT32 addr, UINT16 data)
switch ((addr & 0x3ffff) >> 16)
{
case 0:
//printf("W16 netbuffer @%x<-%x\n", (addr & 0xFFFF), data);
*(UINT16 *)&netBuffer[(addr & 0xFFFF) ^ 2] = FLIPENDIAN16(data);
break;
@ -1829,8 +1805,6 @@ void CModel3::Write32(UINT32 addr, UINT32 data)
switch ((addr & 0x3ffff) >> 16)
{
case 0:
//printf("W32 netbuffer @%x<-%x\n", (addr & 0xFFFF), data);
//*(UINT32 *)&netBuffer[(addr & 0xFFFF)] = FLIPENDIAN32(data);
temp = FLIPENDIAN32(data);
*(UINT32 *)&netBuffer[(addr & 0xFFFF)] = (temp << 16) | (temp >> 16);
break;
@ -1841,26 +1815,19 @@ void CModel3::Write32(UINT32 addr, UINT32 data)
printf("W32 ATTENTION OUT OF RANGE\n");
}
//printf("W32 ioreg @%x<-%04x\n", (addr /*& 0x1FF*/), data>>16);
if (((addr & 0x1FF) == 0x180) && ((data >> 16) == 0x0000))
NetBoard->Reset();
*(UINT16 *)&netBuffer[0x10000 + ((addr & 0x1FF) / 2)] = FLIPENDIAN16(data >> 16);
NetBoard->WriteIORegister((addr & 0x1FF) / 2, FLIPENDIAN16(data >> 16));
break;
case 2:
case 3:
if (addr > 0xc002ffff)
if (addr > 0xc003ffff)
{
printf("W32 ATTENTION OUT OF RANGE\n");
}
//printf("W32 netram @%x<-%x\n", (addr & 0x1FFFF), data);
*(UINT16 *)&netRAM[((addr & 0x1FFFF) / 2)] = FLIPENDIAN16(data >> 16);
break;
/*case 3:
//printf("W32 netram @%x<-%x\n", (addr & 0x1FFFF), data);
*(UINT16 *)&netRAM[((addr & 0x1FFFF) / 2)] = FLIPENDIAN16(data >> 16);
break;*/
default:
printf("W32 ATTENTION OUT OF RANGE\n");
break;
@ -3153,7 +3120,7 @@ const static int DSBPROGROM_SIZE = 0x20000; //128KB
const static int DSBMPEGROM_SIZE = 0x1000000; //16MB
const static int DRIVEROM_SIZE = 0x10000; //64KB
const static int NETBUFFER_SIZE = 0x20000; //128KB
const static int NETRAM_SIZE = 0x20000; //128KB
const static int NETRAM_SIZE = 0x10000; //64KB
const static int MEM_POOL_SIZE = RAM_SIZE + CROM_SIZE +
CROMxx_SIZE + VROM_SIZE +

View file

@ -251,8 +251,8 @@ private:
UINT8 *backupRAM; // 128 KB Backup RAM (battery backed)
UINT8 *securityRAM; // 128 KB Security Board RAM
UINT8 *driveROM; // 32 KB drive board ROM (Z80 program) (optional)
UINT8 *netRAM; // 128KB RAM
UINT8 *netBuffer; // 128KB buffer
UINT8 *netRAM; // 64 KB RAM
UINT8 *netBuffer; // 128 KB buffer
// Banked CROM
UINT8 *cromBank; // currently mapped in CROM bank

View file

@ -42,6 +42,9 @@ public:
virtual bool Init(UINT8* netRAMPtr, UINT8* netBufferPtr) = 0;
virtual void GetGame(Game) = 0;
virtual UINT16 ReadIORegister(unsigned reg) = 0;
virtual void WriteIORegister(unsigned reg, UINT16 data) = 0;
};
#endif

View file

@ -64,7 +64,7 @@
// Network=1
// PortIn = 1970
// PortOut = 1971
// addr_out = "127.0.0.1"
// AddressOut = "127.0.0.1"
//
// add for slave
// Network=1
@ -78,19 +78,19 @@
// Network=1
// PortIn = 1970
// PortOut = 1971
// addr_out = "127.0.0.1"
// AddressOut = "127.0.0.1"
//
// add for slave1
// Network=1
// PortIn = 1971
// PortOut = 1972
// addr_out = "127.0.0.1"
// AddressOut = "127.0.0.1"
//
// add for slave2
// Network=1
// PortIn = 1972
// PortOut = 1970
// addr_out = "127.0.0.1"
// AddressOut = "127.0.0.1"
//#define NET_DEBUG
@ -1306,7 +1306,7 @@ bool CNetBoard::IsAttached(void)
bool CNetBoard::IsRunning(void)
{
return m_attached && ((ioreg[0xc0] == 0xff) || (ioreg[0xc0] == 0x01));
return m_attached && (ioreg[0xc0] != 0);
}
void CNetBoard::GetGame(Game gameinfo)
@ -1314,3 +1314,18 @@ void CNetBoard::GetGame(Game gameinfo)
Gameinfo = gameinfo;
}
UINT16 CNetBoard::ReadIORegister(unsigned reg)
{
if (!IsRunning())
return 0;
return *(UINT16*)&ioreg[reg];
}
void CNetBoard::WriteIORegister(unsigned reg, UINT16 data)
{
if (reg == 0xc0 && !(data != 0 && IsRunning()))
Reset(); // don't reset if we are activating the netboard but it is already activated
*(UINT16*)&ioreg[reg] = data;
}

View file

@ -56,12 +56,14 @@ public:
M68KCtx *GetM68K(void);
bool IsAttached(void);
bool IsRunning(void);
bool CodeReady;
bool Init(UINT8 *netRAMPtr, UINT8 *netBufferPtr);
void GetGame(Game);
UINT16 ReadIORegister(unsigned reg);
void WriteIORegister(unsigned reg, UINT16 data);
CNetBoard(const Util::Config::Node &config);
~CNetBoard(void);
@ -72,7 +74,7 @@ private:
M68KCtx M68K;
// Sound board memory
UINT8 *netRAM; // 128Kb RAM (passed in from parent object)
UINT8 *netRAM; // 64Kb RAM (passed in from parent object)
UINT8 *netBuffer; // 128kb (passed in from parent object)
UINT8 *memoryPool; // single allocated region for all net board RAM
UINT8 *CommRAM;

View file

@ -28,7 +28,6 @@
// these make 16-bit read/writes much neater
#define RAM16 *(uint16_t*)&RAM
#define CommRAM16 *(uint16_t*)&CommRAM
#define ioreg16 *(uint16_t*)&ioreg
static const uint64_t netGUID = 0x5bf177da34872;
@ -39,12 +38,11 @@ inline bool CSimNetBoard::IsGame(const char* gameName)
CSimNetBoard::CSimNetBoard(const Util::Config::Node& config) : m_config(config)
{
m_running = true;
}
CSimNetBoard::~CSimNetBoard(void)
{
m_running = false;
m_quit = true;
if (m_connectThread.joinable())
m_connectThread.join();
@ -64,7 +62,6 @@ bool CSimNetBoard::Init(uint8_t* netRAMPtr, uint8_t* netBufferPtr)
{
RAM = netRAMPtr;
CommRAM = netBufferPtr;
ioreg = netBufferPtr + 0x10000;
m_attached = m_gameInfo.netboard_present && m_config["Network"].ValueAs<bool>();
@ -102,8 +99,8 @@ void CSimNetBoard::RunFrame(void)
case State::start:
if (!m_connected && !m_connectThread.joinable())
m_connectThread = std::thread(&CSimNetBoard::ConnectProc, this);
ioreg16[0x88] = 0;
ioreg16[0x8a] = IsGame("dirtdvls") ? 0x4004 : 0xe000;
m_status0 = 0;
m_status1 = IsGame("dirtdvls") ? 0x4004 : 0xe000;
m_state = State::init;
break;
@ -111,23 +108,23 @@ void CSimNetBoard::RunFrame(void)
memset(CommRAM, 0, 0x10000);
if (m_gameType == GameType::one)
{
if (ioreg16[0x88] & 0x8000) // has main board changed this register?
if (m_status0 & 0x8000) // has main board changed this register?
{
ioreg[0] |= 0x01; // simulate IRQ 2 ack
if (ioreg16[0x88] == 0xf000)
m_IRQ2ack |= 0x01; // simulate IRQ 2 ack
if (m_status0 == 0xf000)
{
// initialization complete
ioreg16[0x8a] = 0;
m_status1 = 0;
CommRAM16[0x72] = FLIPENDIAN16(0x1); // is this necessary?
m_state = State::testing;
}
ioreg16[0x88] = 0; // 0 should work for all init subroutines
m_status0 = 0; // 0 should work for all init subroutines
}
}
else
{
// type 2 performs initialization on its own
ioreg16[0x8a] = 0;
m_status1 = 0;
m_state = State::testing;
m_counter = 0;
}
@ -136,7 +133,7 @@ void CSimNetBoard::RunFrame(void)
case State::testing:
if (m_gameType == GameType::one)
{
ioreg16[0x88] += 1; // type 1 games require this to be incremented every frame
m_status0 += 1; // type 1 games require this to be incremented every frame
if (!m_connected)
break;
@ -240,8 +237,8 @@ void CSimNetBoard::RunFrame(void)
m_numMachines = numMachines + 1;
ioreg16[0x88] = 0; // supposed to cycle between 0 and 1 (also 2 for Daytona 2); doesn't seem to matter
ioreg16[0x8a] = 0x2021 + (numMachines * 0x20) + machineIndex;
m_status0 = 0; // supposed to cycle between 0 and 1 (also 2 for Daytona 2); doesn't seem to matter
m_status1 = 0x2021 + (numMachines * 0x20) + machineIndex;
CommRAM16[0x0] = RAM16[0x400]; // 0 if master, 1 if slave
CommRAM16[0x2] = numMachines;
@ -421,18 +418,18 @@ void CSimNetBoard::RunFrame(void)
{
ErrorLog("no slave machines detected. Make sure only one machine is set to master!");
if (IsGame("dirtdvls"))
ioreg16[0x8a] = 0x8085; // seems like the netboard code writers really liked their CPU model numbers
m_status1 = 0x8085; // seems like the netboard code writers really liked their CPU model numbers
m_state = State::error;
break;
}
m_numMachines = numMachines.total + 1;
ioreg16[0x88] = 5; // probably not necessary
m_status0 = 5; // probably not necessary
if (IsGame("dirtdvls"))
ioreg16[0x8a] = (numMachines.playable << 4) | machineIndex.playable | 0x7400;
m_status1 = (numMachines.playable << 4) | machineIndex.playable | 0x7400;
else
ioreg16[0x8a] = (numMachines.playable << 8) | machineIndex.playable;
m_status1 = (numMachines.playable << 8) | machineIndex.playable;
CommRAM16[0x0] = RAM16[0x200]; // master/slave/relay status
CommRAM16[0x2] = (numMachines.playable << 8) | numMachines.total;
@ -466,7 +463,7 @@ void CSimNetBoard::RunFrame(void)
// link broken - send an "empty" packet to alert other machines
nets->Send(nullptr, 0);
m_state = State::error;
ioreg16[0x8a] = 0x40; // send "link broken" message to mainboard
m_status1 = 0x40; // send "link broken" message to mainboard
break;
}
memcpy(CommRAM + 0x100 + m_segmentSize, recv_data.data(), recv_data.size());
@ -485,7 +482,7 @@ void CSimNetBoard::RunFrame(void)
nets->Send(nullptr, 0);
m_state = State::error;
if (m_gameType == GameType::one)
ioreg16[0x8a] = 0x40; // send "link broken" message to mainboard
m_status1 = 0x40; // send "link broken" message to mainboard
break;
}
memcpy(CommRAM + 0x100 + (i + 1) * m_segmentSize, recv_data.data(), recv_data.size());
@ -509,7 +506,7 @@ void CSimNetBoard::Reset(void)
netr->Receive();
}
ioreg[0xc0] = 0;
m_running = false;
m_state = State::start;
}
@ -520,7 +517,7 @@ bool CSimNetBoard::IsAttached(void)
bool CSimNetBoard::IsRunning(void)
{
return (ioreg[0xc0] == 0xff) || (ioreg[0xc0] == 0x01); // there's probably a better way of checking
return m_attached && m_running;
}
void CSimNetBoard::GetGame(Game gameInfo)
@ -540,14 +537,14 @@ void CSimNetBoard::ConnectProc(void)
// wait until TCPSend has connected to the next machine
while (!nets->Connect())
{
if (!m_running)
if (m_quit)
return;
}
// wait until TCPReceive has accepted a connection from the previous machine
while (!netr->Connected())
{
if (!m_running)
if (m_quit)
return;
std::this_thread::sleep_for(1ms);
}
@ -555,4 +552,46 @@ void CSimNetBoard::ConnectProc(void)
printf("Successfully connected.\n");
m_connected = true;
}
uint16_t CSimNetBoard::ReadIORegister(unsigned reg)
{
if (!IsRunning())
return 0;
switch (reg)
{
case 0x00:
return m_IRQ2ack;
case 0x88:
return m_status0;
case 0x8a:
return m_status1;
default:
ErrorLog("read from unknown IO register 0x%02x", reg);
return 0;
}
}
void CSimNetBoard::WriteIORegister(unsigned reg, uint16_t data)
{
switch (reg)
{
case 0x00:
m_IRQ2ack = data;
break;
case 0x88:
m_status0 = data;
break;
case 0x8a:
m_status1 = data;
break;
case 0xc0:
if (data == 0)
Reset();
m_running = (data != 0);
break;
default:
ErrorLog("write to unknown IO register 0x%02x", reg);
}
}

View file

@ -62,20 +62,22 @@ public:
void GetGame(Game gameInfo);
uint16_t ReadIORegister(unsigned reg);
void WriteIORegister(unsigned reg, uint16_t data);
private:
// Config
const Util::Config::Node& m_config;
uint8_t* RAM = nullptr;
uint8_t* CommRAM = nullptr;
uint8_t* ioreg = nullptr;
// netsock
uint16_t port_in = 0;
uint16_t port_out = 0;
std::string addr_out = "";
std::thread m_connectThread;
std::atomic_bool m_running = false;
std::atomic_bool m_quit = false;
std::atomic_bool m_connected = false;
std::unique_ptr<TCPSend> nets = nullptr;
@ -91,6 +93,11 @@ private:
uint16_t m_segmentSize = 0;
bool m_attached = false;
bool m_running = false;
uint16_t m_IRQ2ack = 0;
uint16_t m_status0 = 0; // ioreg 0x88
uint16_t m_status1 = 0; // ioreg 0x8a
inline bool IsGame(const char* gameName);
void ConnectProc(void);