Bus: Calculation of memory timings for external devices

This commit is contained in:
Connor McLaughlin
2019-10-04 19:41:18 +10:00
parent 0b46a8cfc4
commit fd1c4f1457
2 changed files with 120 additions and 19 deletions

View File

@ -51,14 +51,15 @@ void Bus::Reset()
m_ram.fill(static_cast<u8>(0));
m_MEMCTRL.exp1_base = 0x1F000000;
m_MEMCTRL.exp2_base = 0x1F802000;
m_MEMCTRL.exp1_delay_size = 0x0013243F;
m_MEMCTRL.exp3_delay_size = 0x00003022;
m_MEMCTRL.bios_delay_size = 0x0013243F;
m_MEMCTRL.spu_delay_size = 0x200931E1;
m_MEMCTRL.cdrom_delay_size = 0x00020843;
m_MEMCTRL.exp2_delay_size = 0x00070777;
m_MEMCTRL.common_delay_size = 0x00031125;
m_MEMCTRL.exp1_delay_size.bits = 0x0013243F;
m_MEMCTRL.exp3_delay_size.bits = 0x00003022;
m_MEMCTRL.bios_delay_size.bits = 0x0013243F;
m_MEMCTRL.spu_delay_size.bits = 0x200931E1;
m_MEMCTRL.cdrom_delay_size.bits = 0x00020843;
m_MEMCTRL.exp2_delay_size.bits = 0x00070777;
m_MEMCTRL.common_delay.bits = 0x00031125;
m_ram_size_reg = UINT32_C(0x00000B88);
RecalculateMemoryTimings();
}
bool Bus::DoState(StateWrapper& sw)
@ -167,6 +168,61 @@ bool Bus::LoadBIOS()
return true;
}
std::tuple<TickCount, TickCount, TickCount> Bus::CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay)
{
// from nocash spec
s32 first = 0, seq = 0, min = 0;
if (mem_delay.use_com0_time)
{
first += s32(common_delay.com0) - 1;
seq += s32(common_delay.com0) - 1;
}
if (mem_delay.use_com2_time)
{
first += s32(common_delay.com2);
seq += s32(common_delay.com2);
}
if (mem_delay.use_com3_time)
{
min = s32(common_delay.com3);
}
if (first < 6)
first++;
first = first + s32(mem_delay.access_time) + 2;
seq = seq + s32(mem_delay.access_time) + 2;
if (first < (min + 6))
first = min + 6;
if (seq < (min + 2))
seq = min + 2;
const TickCount byte_access_time = first;
const TickCount halfword_access_time = mem_delay.data_bus_16bit ? first : (first + seq);
const TickCount word_access_time = mem_delay.data_bus_16bit ? (first + seq) : (first + seq + seq + seq);
return std::tie(byte_access_time, halfword_access_time, word_access_time);
}
void Bus::RecalculateMemoryTimings()
{
std::tie(m_bios_access_time[0], m_bios_access_time[1], m_bios_access_time[2]) =
CalculateMemoryTiming(m_MEMCTRL.bios_delay_size, m_MEMCTRL.common_delay);
std::tie(m_cdrom_access_time[0], m_cdrom_access_time[1], m_cdrom_access_time[2]) =
CalculateMemoryTiming(m_MEMCTRL.cdrom_delay_size, m_MEMCTRL.common_delay);
std::tie(m_spu_access_time[0], m_spu_access_time[1], m_spu_access_time[2]) =
CalculateMemoryTiming(m_MEMCTRL.spu_delay_size, m_MEMCTRL.common_delay);
Log_DevPrintf("BIOS Memory Timing: %u bit bus, byte=%d, halfword=%d, word=%d",
m_MEMCTRL.bios_delay_size.data_bus_16bit ? 16 : 8, m_bios_access_time[0], m_bios_access_time[1],
m_bios_access_time[2]);
Log_DevPrintf("CDROM Memory Timing: %u bit bus, byte=%d, halfword=%d, word=%d",
m_MEMCTRL.cdrom_delay_size.data_bus_16bit ? 16 : 8, m_cdrom_access_time[0], m_cdrom_access_time[1],
m_cdrom_access_time[2]);
Log_DevPrintf("SPU Memory Timing: %u bit bus, byte=%d, halfword=%d, word=%d",
m_MEMCTRL.spu_delay_size.data_bus_16bit ? 16 : 8, m_spu_access_time[0], m_spu_access_time[1],
m_spu_access_time[2]);
}
bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value)
{
SmallString str;
@ -292,7 +348,16 @@ bool Bus::DoReadMemoryControl(MemoryAccessSize size, u32 offset, u32& value)
bool Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value)
{
FixupUnalignedWordAccessW32(offset, value);
m_MEMCTRL.regs[offset / 4] = value;
const u32 index = offset / 4;
const u32 write_mask = (index == 8) ? COMDELAY::WRITE_MASK : MEMDELAY::WRITE_MASK;
const u32 new_value = (m_MEMCTRL.regs[index] & ~write_mask) | (value & write_mask);
if (m_MEMCTRL.regs[index] != new_value)
{
m_MEMCTRL.regs[index] = new_value;
RecalculateMemoryTimings();
}
return true;
}
@ -455,10 +520,10 @@ bool Bus::DoReadDMA(MemoryAccessSize size, u32 offset, u32& value)
{
case MemoryAccessSize::Byte:
case MemoryAccessSize::HalfWord:
{
if ((offset & u32(0xF0)) >= 7 || (offset & u32(0x0F)) != 0x4)
FixupUnalignedWordAccessW32(offset, value);
}
{
if ((offset & u32(0xF0)) >= 7 || (offset & u32(0x0F)) != 0x4)
FixupUnalignedWordAccessW32(offset, value);
}
default:
break;