From fd1c4f1457e594d4f59795c4de61039036ebee6e Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Fri, 4 Oct 2019 19:41:18 +1000 Subject: [PATCH] Bus: Calculation of memory timings for external devices --- src/core/bus.cpp | 89 +++++++++++++++++++++++++++++++++++++++++------- src/core/bus.h | 50 +++++++++++++++++++++++---- 2 files changed, 120 insertions(+), 19 deletions(-) diff --git a/src/core/bus.cpp b/src/core/bus.cpp index 44aeb08a1..db51ecd05 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -51,14 +51,15 @@ void Bus::Reset() m_ram.fill(static_cast(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 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; diff --git a/src/core/bus.h b/src/core/bus.h index 328288840..c21541924 100644 --- a/src/core/bus.h +++ b/src/core/bus.h @@ -1,6 +1,7 @@ #pragma once #include "YBaseLib/String.h" +#include "common/bitfield.h" #include "types.h" #include @@ -95,6 +96,34 @@ private: MEMCTRL_REG_COUNT = 9 }; + union MEMDELAY + { + u32 bits; + + BitField access_time; // cycles + BitField use_com0_time; + BitField use_com1_time; + BitField use_com2_time; + BitField use_com3_time; + BitField data_bus_16bit; + BitField memory_window_size; + + static constexpr u32 WRITE_MASK = 0b10101111'00011111'11111111'11111111; + }; + + union COMDELAY + { + u32 bits; + + BitField com0; + BitField com1; + BitField com2; + BitField com3; + BitField comunk; + + static constexpr u32 WRITE_MASK = 0b00000000'00000011'11111111'11111111; + }; + union MEMCTRL { u32 regs[MEMCTRL_REG_COUNT]; @@ -103,18 +132,21 @@ private: { u32 exp1_base; u32 exp2_base; - u32 exp1_delay_size; - u32 exp3_delay_size; - u32 bios_delay_size; - u32 spu_delay_size; - u32 cdrom_delay_size; - u32 exp2_delay_size; - u32 common_delay_size; + MEMDELAY exp1_delay_size; + MEMDELAY exp3_delay_size; + MEMDELAY bios_delay_size; + MEMDELAY spu_delay_size; + MEMDELAY cdrom_delay_size; + MEMDELAY exp2_delay_size; + COMDELAY common_delay; }; }; bool LoadBIOS(); + static std::tuple CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay); + void RecalculateMemoryTimings(); + template bool DoRAMAccess(u32 offset, u32& value); @@ -172,6 +204,10 @@ private: SPU* m_spu = nullptr; MDEC* m_mdec = nullptr; + std::array m_bios_access_time = {}; + std::array m_cdrom_access_time = {}; + std::array m_spu_access_time = {}; + std::array m_ram{}; // 2MB RAM std::array m_bios{}; // 512K BIOS ROM std::vector m_exp1_rom;