mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-26 15:45:42 +00:00
System: Support loading expansion ROMs
This commit is contained in:
parent
5d1c12c9ad
commit
20f14688ca
|
@ -42,6 +42,7 @@ static int Run(int argc, char* argv[])
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
const char* filename = nullptr;
|
const char* filename = nullptr;
|
||||||
|
const char* exp1_filename = nullptr;
|
||||||
TinyString state_filename;
|
TinyString state_filename;
|
||||||
for (int i = 1; i < argc; i++)
|
for (int i = 1; i < argc; i++)
|
||||||
{
|
{
|
||||||
|
@ -50,6 +51,8 @@ static int Run(int argc, char* argv[])
|
||||||
|
|
||||||
if (CHECK_ARG_PARAM("-state"))
|
if (CHECK_ARG_PARAM("-state"))
|
||||||
state_filename = SDLInterface::GetSaveStateFilename(std::strtoul(argv[++i], nullptr, 10));
|
state_filename = SDLInterface::GetSaveStateFilename(std::strtoul(argv[++i], nullptr, 10));
|
||||||
|
else if (CHECK_ARG_PARAM("-exp1"))
|
||||||
|
exp1_filename = argv[++i];
|
||||||
else
|
else
|
||||||
filename = argv[i];
|
filename = argv[i];
|
||||||
|
|
||||||
|
@ -58,7 +61,7 @@ static int Run(int argc, char* argv[])
|
||||||
}
|
}
|
||||||
|
|
||||||
// create system
|
// create system
|
||||||
if (!host_interface->InitializeSystem(filename, state_filename.IsEmpty() ? nullptr : state_filename.GetCharArray()))
|
if (!host_interface->InitializeSystem(filename, exp1_filename, state_filename.IsEmpty() ? nullptr : state_filename.GetCharArray()))
|
||||||
{
|
{
|
||||||
host_interface.reset();
|
host_interface.reset();
|
||||||
SDL_Quit();
|
SDL_Quit();
|
||||||
|
|
|
@ -112,6 +112,11 @@ void Bus::PatchBIOS(u32 address, u32 value, u32 mask /*= UINT32_C(0xFFFFFFFF)*/)
|
||||||
old_disasm.GetCharArray(), new_value, new_disasm.GetCharArray());
|
old_disasm.GetCharArray(), new_value, new_disasm.GetCharArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Bus::SetExpansionROM(std::vector<u8> data)
|
||||||
|
{
|
||||||
|
m_exp1_rom = std::move(data);
|
||||||
|
}
|
||||||
|
|
||||||
bool Bus::LoadBIOS()
|
bool Bus::LoadBIOS()
|
||||||
{
|
{
|
||||||
std::FILE* fp = std::fopen("SCPH1001.BIN", "rb");
|
std::FILE* fp = std::fopen("SCPH1001.BIN", "rb");
|
||||||
|
@ -175,7 +180,49 @@ bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, Physical
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bus::ReadExpansionRegion2(MemoryAccessSize size, u32 offset, u32& value)
|
bool Bus::DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value)
|
||||||
|
{
|
||||||
|
if (m_exp1_rom.empty())
|
||||||
|
return DoInvalidAccess(MemoryAccessType::Read, size, EXP1_BASE | offset, EXP1_BASE | offset, value);
|
||||||
|
|
||||||
|
if (offset == 0x20018)
|
||||||
|
{
|
||||||
|
// Bit 0 - Action Replay On/Off
|
||||||
|
return UINT32_C(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const u32 transfer_size = u32(1) << static_cast<u32>(size);
|
||||||
|
if ((offset + transfer_size) > m_exp1_rom.size())
|
||||||
|
{
|
||||||
|
value = UINT32_C(0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size == MemoryAccessSize::Byte)
|
||||||
|
{
|
||||||
|
value = ZeroExtend32(m_exp1_rom[offset]);
|
||||||
|
}
|
||||||
|
else if (size == MemoryAccessSize::HalfWord)
|
||||||
|
{
|
||||||
|
u16 halfword;
|
||||||
|
std::memcpy(&halfword, &m_exp1_rom[offset], sizeof(halfword));
|
||||||
|
value = ZeroExtend32(halfword);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::memcpy(&value, &m_exp1_rom[offset], sizeof(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Log_DevPrintf("EXP1 read: 0x%08X -> 0x%08X", EXP1_BASE | offset, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bus::DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value)
|
||||||
|
{
|
||||||
|
return DoInvalidAccess(MemoryAccessType::Write, size, EXP1_BASE | offset, EXP1_BASE | offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bus::DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value)
|
||||||
{
|
{
|
||||||
offset &= EXP2_MASK;
|
offset &= EXP2_MASK;
|
||||||
|
|
||||||
|
@ -189,7 +236,7 @@ bool Bus::ReadExpansionRegion2(MemoryAccessSize size, u32 offset, u32& value)
|
||||||
return DoInvalidAccess(MemoryAccessType::Read, size, EXP2_BASE | offset, EXP2_BASE | offset, value);
|
return DoInvalidAccess(MemoryAccessType::Read, size, EXP2_BASE | offset, EXP2_BASE | offset, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Bus::WriteExpansionRegion2(MemoryAccessSize size, u32 offset, u32 value)
|
bool Bus::DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value)
|
||||||
{
|
{
|
||||||
offset &= EXP2_MASK;
|
offset &= EXP2_MASK;
|
||||||
|
|
||||||
|
@ -233,6 +280,22 @@ bool Bus::DoWritePad(MemoryAccessSize size, u32 offset, u32 value)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Bus::DoReadSIO(MemoryAccessSize size, u32 offset, u32& value)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("SIO Read 0x%08X", offset);
|
||||||
|
value = 0;
|
||||||
|
if (offset == 0x04)
|
||||||
|
value = 0x5;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Bus::DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("SIO Write 0x%08X <- 0x%08X", offset, value);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Bus::DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value)
|
bool Bus::DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value)
|
||||||
{
|
{
|
||||||
// TODO: Splitting of half/word reads.
|
// TODO: Splitting of half/word reads.
|
||||||
|
|
|
@ -40,11 +40,18 @@ public:
|
||||||
bool DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32& value);
|
bool DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddress bus_address, u32& value);
|
||||||
|
|
||||||
void PatchBIOS(u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF));
|
void PatchBIOS(u32 address, u32 value, u32 mask = UINT32_C(0xFFFFFFFF));
|
||||||
|
void SetExpansionROM(std::vector<u8> data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static constexpr u32 EXP1_BASE = 0x1F000000;
|
||||||
|
static constexpr u32 EXP1_SIZE = 0x800000;
|
||||||
|
static constexpr u32 EXP1_MASK = EXP1_SIZE - 1;
|
||||||
static constexpr u32 PAD_BASE = 0x1F801040;
|
static constexpr u32 PAD_BASE = 0x1F801040;
|
||||||
static constexpr u32 PAD_SIZE = 0x10;
|
static constexpr u32 PAD_SIZE = 0x10;
|
||||||
static constexpr u32 PAD_MASK = PAD_SIZE - 1;
|
static constexpr u32 PAD_MASK = PAD_SIZE - 1;
|
||||||
|
static constexpr u32 SIO_BASE = 0x1F801050;
|
||||||
|
static constexpr u32 SIO_SIZE = 0x10;
|
||||||
|
static constexpr u32 SIO_MASK = SIO_SIZE - 1;
|
||||||
static constexpr u32 INTERRUPT_CONTROLLER_BASE = 0x1F801070;
|
static constexpr u32 INTERRUPT_CONTROLLER_BASE = 0x1F801070;
|
||||||
static constexpr u32 INTERRUPT_CONTROLLER_SIZE = 0x08;
|
static constexpr u32 INTERRUPT_CONTROLLER_SIZE = 0x08;
|
||||||
static constexpr u32 INTERRUPT_CONTROLLER_MASK = INTERRUPT_CONTROLLER_SIZE - 1;
|
static constexpr u32 INTERRUPT_CONTROLLER_MASK = INTERRUPT_CONTROLLER_SIZE - 1;
|
||||||
|
@ -80,12 +87,18 @@ private:
|
||||||
bool DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress cpu_address,
|
bool DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress cpu_address,
|
||||||
PhysicalMemoryAddress bus_address, u32& value);
|
PhysicalMemoryAddress bus_address, u32& value);
|
||||||
|
|
||||||
bool ReadExpansionRegion2(MemoryAccessSize size, u32 offset, u32& value);
|
bool DoReadEXP1(MemoryAccessSize size, u32 offset, u32& value);
|
||||||
bool WriteExpansionRegion2(MemoryAccessSize size, u32 offset, u32 value);
|
bool DoWriteEXP1(MemoryAccessSize size, u32 offset, u32 value);
|
||||||
|
|
||||||
|
bool DoReadEXP2(MemoryAccessSize size, u32 offset, u32& value);
|
||||||
|
bool DoWriteEXP2(MemoryAccessSize size, u32 offset, u32 value);
|
||||||
|
|
||||||
bool DoReadPad(MemoryAccessSize size, u32 offset, u32& value);
|
bool DoReadPad(MemoryAccessSize size, u32 offset, u32& value);
|
||||||
bool DoWritePad(MemoryAccessSize size, u32 offset, u32 value);
|
bool DoWritePad(MemoryAccessSize size, u32 offset, u32 value);
|
||||||
|
|
||||||
|
bool DoReadSIO(MemoryAccessSize size, u32 offset, u32& value);
|
||||||
|
bool DoWriteSIO(MemoryAccessSize size, u32 offset, u32 value);
|
||||||
|
|
||||||
bool DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value);
|
bool DoReadCDROM(MemoryAccessSize size, u32 offset, u32& value);
|
||||||
bool DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value);
|
bool DoWriteCDROM(MemoryAccessSize size, u32 offset, u32 value);
|
||||||
|
|
||||||
|
@ -114,6 +127,7 @@ private:
|
||||||
|
|
||||||
std::array<u8, 2097152> m_ram{}; // 2MB RAM
|
std::array<u8, 2097152> m_ram{}; // 2MB RAM
|
||||||
std::array<u8, 524288> m_bios{}; // 512K BIOS ROM
|
std::array<u8, 524288> m_bios{}; // 512K BIOS ROM
|
||||||
|
std::vector<u8> m_exp1_rom;
|
||||||
|
|
||||||
String m_tty_line_buffer;
|
String m_tty_line_buffer;
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,6 +80,15 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddres
|
||||||
{
|
{
|
||||||
return DoRAMAccess<type, size>(bus_address, value);
|
return DoRAMAccess<type, size>(bus_address, value);
|
||||||
}
|
}
|
||||||
|
else if (bus_address < EXP1_BASE)
|
||||||
|
{
|
||||||
|
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
|
||||||
|
}
|
||||||
|
else if (bus_address < (EXP1_BASE + EXP1_SIZE))
|
||||||
|
{
|
||||||
|
return (type == MemoryAccessType::Read) ? DoReadEXP1(size, bus_address & EXP1_MASK, value) :
|
||||||
|
DoWriteEXP1(size, bus_address & EXP1_MASK, value);
|
||||||
|
}
|
||||||
else if (bus_address < PAD_BASE)
|
else if (bus_address < PAD_BASE)
|
||||||
{
|
{
|
||||||
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
|
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
|
||||||
|
@ -89,6 +98,11 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddres
|
||||||
return (type == MemoryAccessType::Read) ? DoReadPad(size, bus_address & PAD_MASK, value) :
|
return (type == MemoryAccessType::Read) ? DoReadPad(size, bus_address & PAD_MASK, value) :
|
||||||
DoWritePad(size, bus_address & PAD_MASK, value);
|
DoWritePad(size, bus_address & PAD_MASK, value);
|
||||||
}
|
}
|
||||||
|
else if (bus_address < (SIO_BASE + SIO_SIZE))
|
||||||
|
{
|
||||||
|
return (type == MemoryAccessType::Read) ? DoReadSIO(size, bus_address & SIO_MASK, value) :
|
||||||
|
DoWriteSIO(size, bus_address & SIO_MASK, value);
|
||||||
|
}
|
||||||
else if (bus_address < INTERRUPT_CONTROLLER_BASE)
|
else if (bus_address < INTERRUPT_CONTROLLER_BASE)
|
||||||
{
|
{
|
||||||
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
|
return DoInvalidAccess(type, size, cpu_address, bus_address, value);
|
||||||
|
@ -150,8 +164,8 @@ bool Bus::DispatchAccess(PhysicalMemoryAddress cpu_address, PhysicalMemoryAddres
|
||||||
}
|
}
|
||||||
else if (bus_address < (EXP2_BASE + EXP2_SIZE))
|
else if (bus_address < (EXP2_BASE + EXP2_SIZE))
|
||||||
{
|
{
|
||||||
return (type == MemoryAccessType::Read) ? ReadExpansionRegion2(size, bus_address & EXP2_MASK, value) :
|
return (type == MemoryAccessType::Read) ? DoReadEXP2(size, bus_address & EXP2_MASK, value) :
|
||||||
WriteExpansionRegion2(size, bus_address & EXP2_MASK, value);
|
DoWriteEXP2(size, bus_address & EXP2_MASK, value);
|
||||||
}
|
}
|
||||||
else if (bus_address < BIOS_BASE)
|
else if (bus_address < BIOS_BASE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@ HostInterface::HostInterface() = default;
|
||||||
|
|
||||||
HostInterface::~HostInterface() = default;
|
HostInterface::~HostInterface() = default;
|
||||||
|
|
||||||
bool HostInterface::InitializeSystem(const char* filename, const char* save_state_filename)
|
bool HostInterface::InitializeSystem(const char* filename, const char* exp1_filename, const char* save_state_filename)
|
||||||
{
|
{
|
||||||
m_system = std::make_unique<System>(this);
|
m_system = std::make_unique<System>(this);
|
||||||
if (!m_system->Initialize())
|
if (!m_system->Initialize())
|
||||||
|
@ -42,6 +42,9 @@ bool HostInterface::InitializeSystem(const char* filename, const char* save_stat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (exp1_filename)
|
||||||
|
m_system->SetExpansionROM(exp1_filename);
|
||||||
|
|
||||||
if (save_state_filename)
|
if (save_state_filename)
|
||||||
LoadState(save_state_filename);
|
LoadState(save_state_filename);
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,7 @@ public:
|
||||||
HostInterface();
|
HostInterface();
|
||||||
virtual ~HostInterface();
|
virtual ~HostInterface();
|
||||||
|
|
||||||
bool InitializeSystem(const char* filename, const char* save_state_filename);
|
bool InitializeSystem(const char* filename, const char* exp1_filename, const char* save_state_filename);
|
||||||
|
|
||||||
virtual void SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height) = 0;
|
virtual void SetDisplayTexture(GL::Texture* texture, u32 offset_x, u32 offset_y, u32 width, u32 height) = 0;
|
||||||
virtual void ReportMessage(const char* message) = 0;
|
virtual void ReportMessage(const char* message) = 0;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "system.h"
|
#include "system.h"
|
||||||
#include "YBaseLib/ByteStream.h"
|
#include "YBaseLib/Log.h"
|
||||||
#include "bus.h"
|
#include "bus.h"
|
||||||
#include "cdrom.h"
|
#include "cdrom.h"
|
||||||
#include "common/state_wrapper.h"
|
#include "common/state_wrapper.h"
|
||||||
|
@ -10,6 +10,8 @@
|
||||||
#include "pad.h"
|
#include "pad.h"
|
||||||
#include "pad_device.h"
|
#include "pad_device.h"
|
||||||
#include "timers.h"
|
#include "timers.h"
|
||||||
|
#include <cstdio>
|
||||||
|
Log_SetChannel(System);
|
||||||
|
|
||||||
System::System(HostInterface* host_interface) : m_host_interface(host_interface)
|
System::System(HostInterface* host_interface) : m_host_interface(host_interface)
|
||||||
{
|
{
|
||||||
|
@ -209,6 +211,34 @@ bool System::LoadEXE(const char* filename)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool System::SetExpansionROM(const char* filename)
|
||||||
|
{
|
||||||
|
std::FILE* fp = std::fopen(filename, "rb");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to open '%s'", filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fseek(fp, 0, SEEK_END);
|
||||||
|
const u32 size = static_cast<u32>(std::ftell(fp));
|
||||||
|
std::fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
|
std::vector<u8> data(size);
|
||||||
|
if (std::fread(data.data(), size, 1, fp) != 1)
|
||||||
|
{
|
||||||
|
Log_ErrorPrintf("Failed to read ROM data from '%s'", filename);
|
||||||
|
std::fclose(fp);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::fclose(fp);
|
||||||
|
|
||||||
|
Log_InfoPrintf("Loaded expansion ROM from '%s': %u bytes", filename, size);
|
||||||
|
m_bus->SetExpansionROM(std::move(data));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void System::Synchronize()
|
void System::Synchronize()
|
||||||
{
|
{
|
||||||
m_cpu->ResetDowncount();
|
m_cpu->ResetDowncount();
|
||||||
|
|
|
@ -41,6 +41,7 @@ public:
|
||||||
void RunFrame();
|
void RunFrame();
|
||||||
|
|
||||||
bool LoadEXE(const char* filename);
|
bool LoadEXE(const char* filename);
|
||||||
|
bool SetExpansionROM(const char* filename);
|
||||||
|
|
||||||
void SetDowncount(TickCount downcount);
|
void SetDowncount(TickCount downcount);
|
||||||
void Synchronize();
|
void Synchronize();
|
||||||
|
|
Loading…
Reference in a new issue