2008-11-25 02:00:42 +00:00
|
|
|
#include "Iop_SubSystem.h"
|
2018-06-22 12:42:04 -04:00
|
|
|
#include "IopBios.h"
|
2018-07-20 12:51:04 -04:00
|
|
|
#include "GenericMipsExecutor.h"
|
2018-06-22 12:42:04 -04:00
|
|
|
#include "../psx/PsxBios.h"
|
2019-02-06 13:34:51 -05:00
|
|
|
#include "../states/MemoryStateFile.h"
|
2023-07-28 20:22:01 -04:00
|
|
|
#include "../states/RegisterStateFile.h"
|
2008-11-25 02:00:42 +00:00
|
|
|
#include "../Ps2Const.h"
|
2025-03-11 12:48:26 -04:00
|
|
|
#include "Log.h"
|
2008-12-24 01:39:03 +00:00
|
|
|
#include "placeholder_def.h"
|
2008-11-25 02:00:42 +00:00
|
|
|
|
|
|
|
using namespace Iop;
|
|
|
|
using namespace PS2;
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
#define LOG_NAME ("iop_subsystem")
|
2008-11-25 02:00:42 +00:00
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
#define STATE_CPU ("iop_cpu")
|
|
|
|
#define STATE_RAM ("iop_ram")
|
|
|
|
#define STATE_SCRATCH ("iop_scratch")
|
|
|
|
#define STATE_SPURAM ("iop_spuram")
|
2008-12-24 01:39:03 +00:00
|
|
|
|
2023-07-28 20:22:01 -04:00
|
|
|
#define STATE_TIMING ("iop_timing")
|
|
|
|
#define STATE_TIMING_DMA_UPDATE_TICKS ("dmaUpdateTicks")
|
|
|
|
#define STATE_TIMING_SPU_IRQ_UPDATE_TICKS ("spuIrqUpdateTicks")
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
CSubSystem::CSubSystem(bool ps2Mode)
|
2019-04-17 13:11:52 -04:00
|
|
|
: m_cpu(MEMORYMAP_ENDIAN_LSBF, true)
|
2023-05-02 08:56:25 -04:00
|
|
|
, m_cpuArch(MIPS_REGSIZE_32)
|
|
|
|
, m_copScu(MIPS_REGSIZE_32)
|
2018-04-30 21:01:23 +01:00
|
|
|
, m_ram(new uint8[IOP_RAM_SIZE])
|
|
|
|
, m_scratchPad(new uint8[IOP_SCRATCH_SIZE])
|
|
|
|
, m_spuRam(new uint8[SPU_RAM_SIZE])
|
|
|
|
, m_dmac(m_ram, m_intc)
|
|
|
|
, m_counters(ps2Mode ? IOP_CLOCK_OVER_FREQ : IOP_CLOCK_BASE_FREQ, m_intc)
|
2024-03-14 14:48:43 -04:00
|
|
|
, m_spuCore0(m_spuRam, SPU_RAM_SIZE, &m_spuSampleCache, &m_spuIrqWatcher, 0)
|
|
|
|
, m_spuCore1(m_spuRam, SPU_RAM_SIZE, &m_spuSampleCache, &m_spuIrqWatcher, 1)
|
2018-04-30 21:01:23 +01:00
|
|
|
, m_spu(m_spuCore0)
|
|
|
|
, m_spu2(m_spuCore0, m_spuCore1)
|
2012-09-24 02:37:03 +00:00
|
|
|
#ifdef _IOP_EMULATE_MODULES
|
2018-04-30 21:01:23 +01:00
|
|
|
, m_sio2(m_intc)
|
2012-09-24 02:37:03 +00:00
|
|
|
#endif
|
2021-02-15 20:08:31 -05:00
|
|
|
, m_speed(m_intc)
|
2022-03-08 17:50:17 -05:00
|
|
|
, m_ilink(m_intc)
|
2008-11-25 02:00:42 +00:00
|
|
|
{
|
2018-06-22 12:42:04 -04:00
|
|
|
if(ps2Mode)
|
|
|
|
{
|
2023-06-08 17:12:43 -04:00
|
|
|
m_bios = std::make_shared<CIopBios>(m_cpu, m_ram, m_scratchPad);
|
2018-06-22 12:42:04 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2023-06-08 17:12:43 -04:00
|
|
|
m_bios = std::make_shared<CPsxBios>(m_cpu, m_ram, PS2::IOP_BASE_RAM_SIZE);
|
2018-06-22 12:42:04 -04:00
|
|
|
}
|
|
|
|
|
2022-08-15 10:45:12 -04:00
|
|
|
m_cpu.m_executor = std::make_unique<CGenericMipsExecutor<BlockLookupOneWay>>(m_cpu, (IOP_RAM_SIZE * 4), BLOCK_CATEGORY_PS2_IOP);
|
2018-07-20 12:51:04 -04:00
|
|
|
|
2008-11-25 02:00:42 +00:00
|
|
|
//Read memory map
|
2018-04-30 21:01:23 +01:00
|
|
|
m_cpu.m_pMemoryMap->InsertReadMap((0 * IOP_RAM_SIZE), (0 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x01);
|
|
|
|
m_cpu.m_pMemoryMap->InsertReadMap((1 * IOP_RAM_SIZE), (1 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x02);
|
|
|
|
m_cpu.m_pMemoryMap->InsertReadMap((2 * IOP_RAM_SIZE), (2 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x03);
|
|
|
|
m_cpu.m_pMemoryMap->InsertReadMap((3 * IOP_RAM_SIZE), (3 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x04);
|
2021-01-22 19:18:47 -05:00
|
|
|
m_cpu.m_pMemoryMap->InsertReadMap(SPEED_REG_BEGIN, SPEED_REG_END, std::bind(&CSubSystem::ReadIoRegister, this, std::placeholders::_1), 0x05);
|
|
|
|
m_cpu.m_pMemoryMap->InsertReadMap(IOP_SCRATCH_ADDR, IOP_SCRATCH_ADDR + IOP_SCRATCH_SIZE - 1, m_scratchPad, 0x06);
|
|
|
|
m_cpu.m_pMemoryMap->InsertReadMap(HW_REG_BEGIN, HW_REG_END, std::bind(&CSubSystem::ReadIoRegister, this, std::placeholders::_1), 0x07);
|
2008-11-25 02:00:42 +00:00
|
|
|
|
|
|
|
//Write memory map
|
2018-04-30 21:01:23 +01:00
|
|
|
m_cpu.m_pMemoryMap->InsertWriteMap((0 * IOP_RAM_SIZE), (0 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x01);
|
|
|
|
m_cpu.m_pMemoryMap->InsertWriteMap((1 * IOP_RAM_SIZE), (1 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x02);
|
|
|
|
m_cpu.m_pMemoryMap->InsertWriteMap((2 * IOP_RAM_SIZE), (2 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x03);
|
|
|
|
m_cpu.m_pMemoryMap->InsertWriteMap((3 * IOP_RAM_SIZE), (3 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x04);
|
2021-01-22 19:18:47 -05:00
|
|
|
m_cpu.m_pMemoryMap->InsertWriteMap(SPEED_REG_BEGIN, SPEED_REG_END, std::bind(&CSubSystem::WriteIoRegister, this, std::placeholders::_1, std::placeholders::_2), 0x05);
|
|
|
|
m_cpu.m_pMemoryMap->InsertWriteMap(IOP_SCRATCH_ADDR, IOP_SCRATCH_ADDR + IOP_SCRATCH_SIZE - 1, m_scratchPad, 0x06);
|
|
|
|
m_cpu.m_pMemoryMap->InsertWriteMap(HW_REG_BEGIN, HW_REG_END, std::bind(&CSubSystem::WriteIoRegister, this, std::placeholders::_1, std::placeholders::_2), 0x07);
|
2008-11-25 02:00:42 +00:00
|
|
|
|
|
|
|
//Instruction memory map
|
2018-04-30 21:01:23 +01:00
|
|
|
m_cpu.m_pMemoryMap->InsertInstructionMap((0 * IOP_RAM_SIZE), (0 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x01);
|
|
|
|
m_cpu.m_pMemoryMap->InsertInstructionMap((1 * IOP_RAM_SIZE), (1 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x02);
|
|
|
|
m_cpu.m_pMemoryMap->InsertInstructionMap((2 * IOP_RAM_SIZE), (2 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x03);
|
|
|
|
m_cpu.m_pMemoryMap->InsertInstructionMap((3 * IOP_RAM_SIZE), (3 * IOP_RAM_SIZE) + IOP_RAM_SIZE - 1, m_ram, 0x04);
|
2008-11-25 02:00:42 +00:00
|
|
|
|
2009-03-30 04:57:52 +00:00
|
|
|
m_cpu.m_pArch = &m_cpuArch;
|
2011-06-06 00:18:33 +00:00
|
|
|
m_cpu.m_pCOP[0] = &m_copScu;
|
2008-11-25 02:00:42 +00:00
|
|
|
m_cpu.m_pAddrTranslator = &CMIPS::TranslateAddress64;
|
|
|
|
|
2021-04-01 17:22:33 -04:00
|
|
|
m_dmac.SetReceiveFunction(CDmac::CHANNEL_SPU0, std::bind(&CSpuBase::ReceiveDma, &m_spuCore0, PLACEHOLDER_1, PLACEHOLDER_2, PLACEHOLDER_3, PLACEHOLDER_4));
|
|
|
|
m_dmac.SetReceiveFunction(CDmac::CHANNEL_SPU1, std::bind(&CSpuBase::ReceiveDma, &m_spuCore1, PLACEHOLDER_1, PLACEHOLDER_2, PLACEHOLDER_3, PLACEHOLDER_4));
|
|
|
|
m_dmac.SetReceiveFunction(CDmac::CHANNEL_DEV9, std::bind(&CSpeed::ReceiveDma, &m_speed, PLACEHOLDER_1, PLACEHOLDER_2, PLACEHOLDER_3, PLACEHOLDER_4));
|
|
|
|
m_dmac.SetReceiveFunction(CDmac::CHANNEL_SIO2in, std::bind(&CSio2::ReceiveDmaIn, &m_sio2, PLACEHOLDER_1, PLACEHOLDER_2, PLACEHOLDER_3, PLACEHOLDER_4));
|
|
|
|
m_dmac.SetReceiveFunction(CDmac::CHANNEL_SIO2out, std::bind(&CSio2::ReceiveDmaOut, &m_sio2, PLACEHOLDER_1, PLACEHOLDER_2, PLACEHOLDER_3, PLACEHOLDER_4));
|
2019-04-17 13:11:52 -04:00
|
|
|
|
|
|
|
SetupPageTable();
|
2008-11-25 02:00:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CSubSystem::~CSubSystem()
|
|
|
|
{
|
2012-10-21 02:08:14 +00:00
|
|
|
m_bios.reset();
|
2018-04-30 21:01:23 +01:00
|
|
|
delete[] m_ram;
|
|
|
|
delete[] m_scratchPad;
|
|
|
|
delete[] m_spuRam;
|
2008-11-25 02:00:42 +00:00
|
|
|
}
|
|
|
|
|
2011-05-05 04:28:11 +00:00
|
|
|
void CSubSystem::NotifyVBlankStart()
|
|
|
|
{
|
|
|
|
m_bios->NotifyVBlankStart();
|
2011-11-06 21:37:50 +00:00
|
|
|
m_intc.AssertLine(Iop::CIntc::LINE_VBLANK);
|
2011-05-05 04:28:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CSubSystem::NotifyVBlankEnd()
|
|
|
|
{
|
|
|
|
m_bios->NotifyVBlankEnd();
|
2011-11-06 21:37:50 +00:00
|
|
|
m_intc.AssertLine(Iop::CIntc::LINE_EVBLANK);
|
2011-05-05 04:28:11 +00:00
|
|
|
}
|
|
|
|
|
2009-07-31 02:51:31 +00:00
|
|
|
void CSubSystem::SaveState(Framework::CZipArchiveWriter& archive)
|
2008-12-24 01:39:03 +00:00
|
|
|
{
|
2023-07-23 17:22:18 -04:00
|
|
|
archive.InsertFile(std::make_unique<CMemoryStateFile>(STATE_CPU, &m_cpu.m_State, sizeof(MIPSSTATE)));
|
|
|
|
archive.InsertFile(std::make_unique<CMemoryStateFile>(STATE_RAM, m_ram, IOP_RAM_SIZE));
|
|
|
|
archive.InsertFile(std::make_unique<CMemoryStateFile>(STATE_SCRATCH, m_scratchPad, IOP_SCRATCH_SIZE));
|
|
|
|
archive.InsertFile(std::make_unique<CMemoryStateFile>(STATE_SPURAM, m_spuRam, SPU_RAM_SIZE));
|
2013-03-05 05:42:20 +00:00
|
|
|
m_intc.SaveState(archive);
|
2017-02-11 15:00:24 -05:00
|
|
|
m_dmac.SaveState(archive);
|
2014-06-28 23:49:51 -04:00
|
|
|
m_counters.SaveState(archive);
|
2024-03-14 14:48:43 -04:00
|
|
|
m_spuIrqWatcher.SaveState(archive);
|
2013-03-05 05:42:20 +00:00
|
|
|
m_spuCore0.SaveState(archive);
|
|
|
|
m_spuCore1.SaveState(archive);
|
2022-03-09 10:50:08 -05:00
|
|
|
m_ilink.SaveState(archive);
|
2017-02-12 13:52:50 -05:00
|
|
|
#ifdef _IOP_EMULATE_MODULES
|
2017-02-09 22:36:01 -05:00
|
|
|
m_sio2.SaveState(archive);
|
2017-02-12 13:52:50 -05:00
|
|
|
#endif
|
2012-03-11 20:16:15 +00:00
|
|
|
m_bios->SaveState(archive);
|
2023-07-28 20:22:01 -04:00
|
|
|
|
|
|
|
//Save timing state
|
|
|
|
{
|
|
|
|
auto registerFile = std::make_unique<CRegisterStateFile>(STATE_TIMING);
|
|
|
|
registerFile->SetRegister32(STATE_TIMING_DMA_UPDATE_TICKS, m_dmaUpdateTicks);
|
|
|
|
registerFile->SetRegister32(STATE_TIMING_SPU_IRQ_UPDATE_TICKS, m_spuIrqUpdateTicks);
|
|
|
|
archive.InsertFile(std::move(registerFile));
|
|
|
|
}
|
2008-12-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2009-07-31 02:51:31 +00:00
|
|
|
void CSubSystem::LoadState(Framework::CZipArchiveReader& archive)
|
2008-12-24 01:39:03 +00:00
|
|
|
{
|
2024-08-07 13:00:19 -04:00
|
|
|
m_bios->PreLoadState();
|
|
|
|
|
2022-05-19 15:32:55 -04:00
|
|
|
//Read and check differences in memory to invalidate executor blocks only if necessary
|
|
|
|
{
|
|
|
|
auto stream = archive.BeginReadFile(STATE_RAM);
|
|
|
|
static const uint32 bufferSize = 0x1000;
|
|
|
|
uint8 buffer[bufferSize];
|
|
|
|
for(uint32 i = 0; i < IOP_RAM_SIZE; i += bufferSize)
|
|
|
|
{
|
|
|
|
stream->Read(buffer, bufferSize);
|
|
|
|
if(memcmp(m_ram + i, buffer, bufferSize))
|
|
|
|
{
|
|
|
|
m_cpu.m_executor->ClearActiveBlocksInRange(i, i + bufferSize, false);
|
|
|
|
}
|
|
|
|
memcpy(m_ram + i, buffer, bufferSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-30 21:01:23 +01:00
|
|
|
archive.BeginReadFile(STATE_CPU)->Read(&m_cpu.m_State, sizeof(MIPSSTATE));
|
|
|
|
archive.BeginReadFile(STATE_SCRATCH)->Read(m_scratchPad, IOP_SCRATCH_SIZE);
|
|
|
|
archive.BeginReadFile(STATE_SPURAM)->Read(m_spuRam, SPU_RAM_SIZE);
|
2013-03-05 05:42:20 +00:00
|
|
|
m_intc.LoadState(archive);
|
2017-02-11 15:00:24 -05:00
|
|
|
m_dmac.LoadState(archive);
|
2014-06-28 23:49:51 -04:00
|
|
|
m_counters.LoadState(archive);
|
2023-05-17 16:55:50 -04:00
|
|
|
m_spuSampleCache.Clear();
|
2024-03-14 14:48:43 -04:00
|
|
|
m_spuIrqWatcher.LoadState(archive);
|
2013-03-05 05:42:20 +00:00
|
|
|
m_spuCore0.LoadState(archive);
|
|
|
|
m_spuCore1.LoadState(archive);
|
2022-03-09 10:50:08 -05:00
|
|
|
m_ilink.LoadState(archive);
|
2017-02-12 13:52:50 -05:00
|
|
|
#ifdef _IOP_EMULATE_MODULES
|
2017-02-09 22:36:01 -05:00
|
|
|
m_sio2.LoadState(archive);
|
2017-02-12 13:52:50 -05:00
|
|
|
#endif
|
2012-03-11 20:16:15 +00:00
|
|
|
m_bios->LoadState(archive);
|
2023-07-31 10:53:56 -04:00
|
|
|
|
2023-07-28 20:22:01 -04:00
|
|
|
//Load timing state
|
|
|
|
{
|
|
|
|
CRegisterStateFile registerFile(*archive.BeginReadFile(STATE_TIMING));
|
|
|
|
m_dmaUpdateTicks = registerFile.GetRegister32(STATE_TIMING_DMA_UPDATE_TICKS);
|
|
|
|
m_spuIrqUpdateTicks = registerFile.GetRegister32(STATE_TIMING_SPU_IRQ_UPDATE_TICKS);
|
|
|
|
}
|
2008-12-24 01:39:03 +00:00
|
|
|
}
|
|
|
|
|
2008-11-25 02:00:42 +00:00
|
|
|
void CSubSystem::Reset()
|
|
|
|
{
|
2012-03-11 20:16:15 +00:00
|
|
|
memset(m_ram, 0, IOP_RAM_SIZE);
|
2008-11-25 02:00:42 +00:00
|
|
|
memset(m_scratchPad, 0, IOP_SCRATCH_SIZE);
|
|
|
|
memset(m_spuRam, 0, SPU_RAM_SIZE);
|
|
|
|
m_cpu.Reset();
|
2018-07-20 12:51:04 -04:00
|
|
|
m_cpu.m_executor->Reset();
|
2014-08-16 21:42:19 -04:00
|
|
|
m_cpu.m_analysis->Clear();
|
2023-05-17 16:55:50 -04:00
|
|
|
m_spuSampleCache.Clear();
|
2024-03-14 14:48:43 -04:00
|
|
|
m_spuIrqWatcher.Reset();
|
2008-11-25 02:00:42 +00:00
|
|
|
m_spuCore0.Reset();
|
|
|
|
m_spuCore1.Reset();
|
2012-03-11 20:16:15 +00:00
|
|
|
m_spu.Reset();
|
|
|
|
m_spu2.Reset();
|
2012-09-24 02:37:03 +00:00
|
|
|
#ifdef _IOP_EMULATE_MODULES
|
|
|
|
m_sio2.Reset();
|
|
|
|
#endif
|
2021-02-15 20:08:31 -05:00
|
|
|
m_speed.Reset();
|
2022-03-08 17:50:17 -05:00
|
|
|
m_ilink.Reset();
|
2008-11-25 02:00:42 +00:00
|
|
|
m_counters.Reset();
|
|
|
|
m_dmac.Reset();
|
|
|
|
m_intc.Reset();
|
2008-11-28 02:56:27 +00:00
|
|
|
|
2012-03-11 20:16:15 +00:00
|
|
|
m_cpu.m_Comments.RemoveTags();
|
|
|
|
m_cpu.m_Functions.RemoveTags();
|
2013-03-06 04:42:17 +00:00
|
|
|
|
|
|
|
m_dmaUpdateTicks = 0;
|
2022-02-05 18:25:15 -05:00
|
|
|
m_spuIrqUpdateTicks = 0;
|
2008-11-25 02:00:42 +00:00
|
|
|
}
|
|
|
|
|
2019-04-17 13:11:52 -04:00
|
|
|
void CSubSystem::SetupPageTable()
|
|
|
|
{
|
|
|
|
for(uint32 i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
uint32 addressBit = (i == 0) ? 0 : 0x80000000;
|
|
|
|
|
|
|
|
m_cpu.MapPages(addressBit | (PS2::IOP_RAM_SIZE * 0), PS2::IOP_RAM_SIZE, m_ram);
|
|
|
|
m_cpu.MapPages(addressBit | (PS2::IOP_RAM_SIZE * 1), PS2::IOP_RAM_SIZE, m_ram);
|
|
|
|
m_cpu.MapPages(addressBit | (PS2::IOP_RAM_SIZE * 2), PS2::IOP_RAM_SIZE, m_ram);
|
|
|
|
m_cpu.MapPages(addressBit | (PS2::IOP_RAM_SIZE * 3), PS2::IOP_RAM_SIZE, m_ram);
|
|
|
|
|
2019-05-25 11:28:31 -04:00
|
|
|
m_cpu.MapPages(addressBit | PS2::IOP_SCRATCH_ADDR, PS2::IOP_SCRATCH_SIZE, m_scratchPad);
|
2019-04-17 13:11:52 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-11-25 02:00:42 +00:00
|
|
|
uint32 CSubSystem::ReadIoRegister(uint32 address)
|
|
|
|
{
|
|
|
|
if(address == 0x1F801814)
|
|
|
|
{
|
|
|
|
return 0x14802000;
|
|
|
|
}
|
|
|
|
else if(address >= CSpu::SPU_BEGIN && address <= CSpu::SPU_END)
|
|
|
|
{
|
|
|
|
return m_spu.ReadRegister(address);
|
|
|
|
}
|
2020-07-13 20:15:31 +02:00
|
|
|
else if(
|
|
|
|
(address >= CDmac::DMAC_ZONE1_START && address <= CDmac::DMAC_ZONE1_END) ||
|
|
|
|
(address >= CDmac::DMAC_ZONE2_START && address <= CDmac::DMAC_ZONE2_END) ||
|
|
|
|
(address >= CDmac::DMAC_ZONE3_START && address <= CDmac::DMAC_ZONE3_END))
|
2008-11-25 02:00:42 +00:00
|
|
|
{
|
|
|
|
return m_dmac.ReadRegister(address);
|
|
|
|
}
|
|
|
|
else if(address >= CIntc::ADDR_BEGIN && address <= CIntc::ADDR_END)
|
|
|
|
{
|
|
|
|
return m_intc.ReadRegister(address);
|
|
|
|
}
|
2012-05-29 01:01:02 +00:00
|
|
|
else if(
|
2018-04-30 21:01:23 +01:00
|
|
|
(address >= CRootCounters::ADDR_BEGIN1 && address <= CRootCounters::ADDR_END1) ||
|
|
|
|
(address >= CRootCounters::ADDR_BEGIN2 && address <= CRootCounters::ADDR_END2))
|
2008-11-25 02:00:42 +00:00
|
|
|
{
|
|
|
|
return m_counters.ReadRegister(address);
|
|
|
|
}
|
2012-09-24 02:37:03 +00:00
|
|
|
#ifdef _IOP_EMULATE_MODULES
|
|
|
|
else if(address >= CSio2::ADDR_BEGIN && address <= CSio2::ADDR_END)
|
|
|
|
{
|
|
|
|
return m_sio2.ReadRegister(address);
|
|
|
|
}
|
|
|
|
#endif
|
2008-11-25 02:00:42 +00:00
|
|
|
else if(address >= CSpu2::REGS_BEGIN && address <= CSpu2::REGS_END)
|
|
|
|
{
|
|
|
|
return m_spu2.ReadRegister(address);
|
|
|
|
}
|
2020-11-06 09:59:37 +01:00
|
|
|
else if((address >= 0x1F801000 && address <= 0x1F801020) || (address >= 0x1F801400 && address <= 0x1F801420))
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Reading from SSBUS.\r\n");
|
|
|
|
}
|
2021-01-22 19:18:47 -05:00
|
|
|
else if(address >= CDev9::ADDR_BEGIN && address <= CDev9::ADDR_END)
|
|
|
|
{
|
|
|
|
return m_dev9.ReadRegister(address);
|
|
|
|
}
|
|
|
|
else if(address >= SPEED_REG_BEGIN && address <= SPEED_REG_END)
|
|
|
|
{
|
|
|
|
return m_speed.ReadRegister(address);
|
|
|
|
}
|
2022-03-08 10:11:19 -05:00
|
|
|
else if(address >= CIlink::ADDR_BEGIN && address <= CIlink::ADDR_END)
|
2012-04-21 21:20:14 +00:00
|
|
|
{
|
2022-03-08 10:11:19 -05:00
|
|
|
return m_ilink.ReadRegister(address);
|
2012-04-21 21:20:14 +00:00
|
|
|
}
|
2008-11-25 02:00:42 +00:00
|
|
|
else
|
|
|
|
{
|
2017-05-29 06:01:32 +01:00
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Reading an unknown hardware register (0x%08X).\r\n", address);
|
2008-11-25 02:00:42 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32 CSubSystem::WriteIoRegister(uint32 address, uint32 value)
|
|
|
|
{
|
2020-07-13 20:15:31 +02:00
|
|
|
if(address >= CSpu::SPU_BEGIN && address <= CSpu::SPU_END)
|
2008-11-25 02:00:42 +00:00
|
|
|
{
|
|
|
|
m_spu.WriteRegister(address, static_cast<uint16>(value));
|
|
|
|
}
|
2020-07-13 20:15:31 +02:00
|
|
|
else if(
|
|
|
|
(address >= CDmac::DMAC_ZONE1_START && address <= CDmac::DMAC_ZONE1_END) ||
|
|
|
|
(address >= CDmac::DMAC_ZONE2_START && address <= CDmac::DMAC_ZONE2_END) ||
|
|
|
|
(address >= CDmac::DMAC_ZONE3_START && address <= CDmac::DMAC_ZONE3_END))
|
2008-11-25 02:00:42 +00:00
|
|
|
{
|
|
|
|
m_dmac.WriteRegister(address, value);
|
|
|
|
}
|
|
|
|
else if(address >= CIntc::ADDR_BEGIN && address <= CIntc::ADDR_END)
|
|
|
|
{
|
|
|
|
m_intc.WriteRegister(address, value);
|
|
|
|
}
|
2012-05-29 01:01:02 +00:00
|
|
|
else if(
|
2018-04-30 21:01:23 +01:00
|
|
|
(address >= CRootCounters::ADDR_BEGIN1 && address <= CRootCounters::ADDR_END1) ||
|
|
|
|
(address >= CRootCounters::ADDR_BEGIN2 && address <= CRootCounters::ADDR_END2))
|
2008-11-25 02:00:42 +00:00
|
|
|
{
|
|
|
|
m_counters.WriteRegister(address, value);
|
|
|
|
}
|
2012-09-24 02:37:03 +00:00
|
|
|
#ifdef _IOP_EMULATE_MODULES
|
|
|
|
else if(address >= CSio2::ADDR_BEGIN && address <= CSio2::ADDR_END)
|
|
|
|
{
|
|
|
|
m_sio2.WriteRegister(address, value);
|
|
|
|
}
|
|
|
|
#endif
|
2008-11-25 02:00:42 +00:00
|
|
|
else if(address >= CSpu2::REGS_BEGIN && address <= CSpu2::REGS_END)
|
|
|
|
{
|
|
|
|
return m_spu2.WriteRegister(address, value);
|
|
|
|
}
|
2020-11-06 09:59:37 +01:00
|
|
|
else if((address >= 0x1F801000 && address <= 0x1F801020) || (address >= 0x1F801400 && address <= 0x1F801420))
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Print(LOG_NAME, "Writing to SSBUS (0x%08X).\r\n", value);
|
|
|
|
}
|
2021-01-22 19:18:47 -05:00
|
|
|
else if(address >= CDev9::ADDR_BEGIN && address <= CDev9::ADDR_END)
|
|
|
|
{
|
|
|
|
m_dev9.WriteRegister(address, value);
|
|
|
|
}
|
|
|
|
else if(address >= SPEED_REG_BEGIN && address <= SPEED_REG_END)
|
|
|
|
{
|
|
|
|
m_speed.WriteRegister(address, value);
|
|
|
|
}
|
2022-03-08 10:11:19 -05:00
|
|
|
else if(address >= CIlink::ADDR_BEGIN && address <= CIlink::ADDR_END)
|
|
|
|
{
|
|
|
|
m_ilink.WriteRegister(address, value);
|
|
|
|
}
|
2008-11-25 02:00:42 +00:00
|
|
|
else
|
|
|
|
{
|
2020-07-13 16:56:44 +02:00
|
|
|
CLog::GetInstance().Warn(LOG_NAME, "Writing to an unknown hardware register (0x%08X, 0x%08X).\r\n", address, value);
|
2008-11-25 02:00:42 +00:00
|
|
|
}
|
2017-04-22 21:16:52 -04:00
|
|
|
|
|
|
|
if(
|
2018-04-30 21:01:23 +01:00
|
|
|
m_intc.HasPendingInterrupt() &&
|
|
|
|
(m_cpu.m_State.nHasException == MIPS_EXCEPTION_NONE) &&
|
|
|
|
((m_cpu.m_State.nCOP0[CCOP_SCU::STATUS] & CMIPS::STATUS_IE) == CMIPS::STATUS_IE))
|
2017-04-22 21:16:52 -04:00
|
|
|
{
|
|
|
|
m_cpu.m_State.nHasException = MIPS_EXCEPTION_CHECKPENDINGINT;
|
|
|
|
}
|
|
|
|
|
2008-11-25 02:00:42 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-04-22 21:15:31 -04:00
|
|
|
void CSubSystem::CheckPendingInterrupts()
|
|
|
|
{
|
|
|
|
if(!m_cpu.m_State.nHasException)
|
|
|
|
{
|
|
|
|
if(m_intc.HasPendingInterrupt())
|
|
|
|
{
|
|
|
|
m_bios->HandleInterrupt();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-25 03:17:46 +00:00
|
|
|
bool CSubSystem::IsCpuIdle()
|
2008-11-25 02:00:42 +00:00
|
|
|
{
|
2017-06-25 15:49:51 -04:00
|
|
|
return m_bios->IsIdle();
|
2012-09-25 03:17:46 +00:00
|
|
|
}
|
2010-03-30 04:19:45 +00:00
|
|
|
|
2012-09-25 03:17:46 +00:00
|
|
|
void CSubSystem::CountTicks(int ticks)
|
|
|
|
{
|
2017-07-26 22:15:01 -04:00
|
|
|
static const int g_dmaUpdateDelay = 10000;
|
2021-01-21 09:27:33 -05:00
|
|
|
static const int g_spuIrqCheckDelay = 1000;
|
2012-09-25 03:17:46 +00:00
|
|
|
m_counters.Update(ticks);
|
2021-02-25 19:48:25 -05:00
|
|
|
m_speed.CountTicks(ticks);
|
2012-09-25 03:17:46 +00:00
|
|
|
m_bios->CountTicks(ticks);
|
2013-03-06 04:42:17 +00:00
|
|
|
m_dmaUpdateTicks += ticks;
|
2014-06-04 23:33:05 -04:00
|
|
|
if(m_dmaUpdateTicks >= g_dmaUpdateDelay)
|
2013-03-06 04:42:17 +00:00
|
|
|
{
|
2021-05-25 11:18:12 +02:00
|
|
|
m_dmac.ResumeDma(Iop::CDmac::CHANNEL_SPU0);
|
|
|
|
m_dmac.ResumeDma(Iop::CDmac::CHANNEL_SPU1);
|
2014-06-04 23:33:05 -04:00
|
|
|
m_dmaUpdateTicks -= g_dmaUpdateDelay;
|
2013-03-06 04:42:17 +00:00
|
|
|
}
|
2021-01-21 09:27:33 -05:00
|
|
|
m_spuIrqUpdateTicks += ticks;
|
|
|
|
if(m_spuIrqUpdateTicks >= g_spuIrqCheckDelay)
|
2015-02-08 17:18:41 -05:00
|
|
|
{
|
|
|
|
bool irqPending = false;
|
|
|
|
irqPending |= m_spuCore0.GetIrqPending();
|
|
|
|
irqPending |= m_spuCore1.GetIrqPending();
|
|
|
|
if(irqPending)
|
|
|
|
{
|
|
|
|
m_intc.AssertLine(CIntc::LINE_SPU2);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_intc.ClearLine(CIntc::LINE_SPU2);
|
|
|
|
}
|
2021-01-21 09:27:33 -05:00
|
|
|
m_spuIrqUpdateTicks -= g_spuIrqCheckDelay;
|
2015-02-08 17:18:41 -05:00
|
|
|
}
|
2012-09-25 03:17:46 +00:00
|
|
|
}
|
2010-03-30 04:19:45 +00:00
|
|
|
|
2012-09-25 03:17:46 +00:00
|
|
|
int CSubSystem::ExecuteCpu(int quota)
|
|
|
|
{
|
|
|
|
int executed = 0;
|
2017-04-22 21:15:31 -04:00
|
|
|
CheckPendingInterrupts();
|
2012-09-25 03:17:46 +00:00
|
|
|
if(!m_cpu.m_State.nHasException)
|
|
|
|
{
|
2018-07-20 12:51:04 -04:00
|
|
|
executed = (quota - m_cpu.m_executor->Execute(quota));
|
2012-09-25 03:17:46 +00:00
|
|
|
}
|
2008-11-25 02:00:42 +00:00
|
|
|
if(m_cpu.m_State.nHasException)
|
|
|
|
{
|
2017-04-22 21:16:52 -04:00
|
|
|
switch(m_cpu.m_State.nHasException)
|
|
|
|
{
|
|
|
|
case MIPS_EXCEPTION_SYSCALL:
|
|
|
|
m_bios->HandleException();
|
|
|
|
assert(m_cpu.m_State.nHasException == MIPS_EXCEPTION_NONE);
|
|
|
|
break;
|
|
|
|
case MIPS_EXCEPTION_CHECKPENDINGINT:
|
2018-04-30 21:01:23 +01:00
|
|
|
{
|
|
|
|
m_cpu.m_State.nHasException = MIPS_EXCEPTION_NONE;
|
|
|
|
CheckPendingInterrupts();
|
|
|
|
//Needs to be cleared again because exception flag might be set by BIOS interrupt handler
|
|
|
|
m_cpu.m_State.nHasException = MIPS_EXCEPTION_NONE;
|
|
|
|
}
|
|
|
|
break;
|
2017-04-22 21:16:52 -04:00
|
|
|
}
|
|
|
|
assert(m_cpu.m_State.nHasException == MIPS_EXCEPTION_NONE);
|
2008-11-25 02:00:42 +00:00
|
|
|
}
|
2012-09-25 03:17:46 +00:00
|
|
|
return executed;
|
2008-11-25 02:00:42 +00:00
|
|
|
}
|