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_ram.fill(static_cast<u8>(0));
m_MEMCTRL.exp1_base = 0x1F000000; m_MEMCTRL.exp1_base = 0x1F000000;
m_MEMCTRL.exp2_base = 0x1F802000; m_MEMCTRL.exp2_base = 0x1F802000;
m_MEMCTRL.exp1_delay_size = 0x0013243F; m_MEMCTRL.exp1_delay_size.bits = 0x0013243F;
m_MEMCTRL.exp3_delay_size = 0x00003022; m_MEMCTRL.exp3_delay_size.bits = 0x00003022;
m_MEMCTRL.bios_delay_size = 0x0013243F; m_MEMCTRL.bios_delay_size.bits = 0x0013243F;
m_MEMCTRL.spu_delay_size = 0x200931E1; m_MEMCTRL.spu_delay_size.bits = 0x200931E1;
m_MEMCTRL.cdrom_delay_size = 0x00020843; m_MEMCTRL.cdrom_delay_size.bits = 0x00020843;
m_MEMCTRL.exp2_delay_size = 0x00070777; m_MEMCTRL.exp2_delay_size.bits = 0x00070777;
m_MEMCTRL.common_delay_size = 0x00031125; m_MEMCTRL.common_delay.bits = 0x00031125;
m_ram_size_reg = UINT32_C(0x00000B88); m_ram_size_reg = UINT32_C(0x00000B88);
RecalculateMemoryTimings();
} }
bool Bus::DoState(StateWrapper& sw) bool Bus::DoState(StateWrapper& sw)
@ -167,6 +168,61 @@ bool Bus::LoadBIOS()
return true; 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) bool Bus::DoInvalidAccess(MemoryAccessType type, MemoryAccessSize size, PhysicalMemoryAddress address, u32& value)
{ {
SmallString str; SmallString str;
@ -292,7 +348,16 @@ bool Bus::DoReadMemoryControl(MemoryAccessSize size, u32 offset, u32& value)
bool Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value) bool Bus::DoWriteMemoryControl(MemoryAccessSize size, u32 offset, u32 value)
{ {
FixupUnalignedWordAccessW32(offset, 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; return true;
} }
@ -455,10 +520,10 @@ bool Bus::DoReadDMA(MemoryAccessSize size, u32 offset, u32& value)
{ {
case MemoryAccessSize::Byte: case MemoryAccessSize::Byte:
case MemoryAccessSize::HalfWord: case MemoryAccessSize::HalfWord:
{ {
if ((offset & u32(0xF0)) >= 7 || (offset & u32(0x0F)) != 0x4) if ((offset & u32(0xF0)) >= 7 || (offset & u32(0x0F)) != 0x4)
FixupUnalignedWordAccessW32(offset, value); FixupUnalignedWordAccessW32(offset, value);
} }
default: default:
break; break;

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "YBaseLib/String.h" #include "YBaseLib/String.h"
#include "common/bitfield.h"
#include "types.h" #include "types.h"
#include <array> #include <array>
@ -95,6 +96,34 @@ private:
MEMCTRL_REG_COUNT = 9 MEMCTRL_REG_COUNT = 9
}; };
union MEMDELAY
{
u32 bits;
BitField<u32, u8, 4, 4> access_time; // cycles
BitField<u32, bool, 8, 1> use_com0_time;
BitField<u32, bool, 9, 1> use_com1_time;
BitField<u32, bool, 10, 1> use_com2_time;
BitField<u32, bool, 11, 1> use_com3_time;
BitField<u32, bool, 12, 1> data_bus_16bit;
BitField<u32, u8, 16, 5> memory_window_size;
static constexpr u32 WRITE_MASK = 0b10101111'00011111'11111111'11111111;
};
union COMDELAY
{
u32 bits;
BitField<u32, u8, 0, 4> com0;
BitField<u32, u8, 4, 4> com1;
BitField<u32, u8, 8, 4> com2;
BitField<u32, u8, 12, 4> com3;
BitField<u32, u8, 16, 2> comunk;
static constexpr u32 WRITE_MASK = 0b00000000'00000011'11111111'11111111;
};
union MEMCTRL union MEMCTRL
{ {
u32 regs[MEMCTRL_REG_COUNT]; u32 regs[MEMCTRL_REG_COUNT];
@ -103,18 +132,21 @@ private:
{ {
u32 exp1_base; u32 exp1_base;
u32 exp2_base; u32 exp2_base;
u32 exp1_delay_size; MEMDELAY exp1_delay_size;
u32 exp3_delay_size; MEMDELAY exp3_delay_size;
u32 bios_delay_size; MEMDELAY bios_delay_size;
u32 spu_delay_size; MEMDELAY spu_delay_size;
u32 cdrom_delay_size; MEMDELAY cdrom_delay_size;
u32 exp2_delay_size; MEMDELAY exp2_delay_size;
u32 common_delay_size; COMDELAY common_delay;
}; };
}; };
bool LoadBIOS(); bool LoadBIOS();
static std::tuple<TickCount, TickCount, TickCount> CalculateMemoryTiming(MEMDELAY mem_delay, COMDELAY common_delay);
void RecalculateMemoryTimings();
template<MemoryAccessType type, MemoryAccessSize size> template<MemoryAccessType type, MemoryAccessSize size>
bool DoRAMAccess(u32 offset, u32& value); bool DoRAMAccess(u32 offset, u32& value);
@ -172,6 +204,10 @@ private:
SPU* m_spu = nullptr; SPU* m_spu = nullptr;
MDEC* m_mdec = nullptr; MDEC* m_mdec = nullptr;
std::array<TickCount, 3> m_bios_access_time = {};
std::array<TickCount, 3> m_cdrom_access_time = {};
std::array<TickCount, 3> m_spu_access_time = {};
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; std::vector<u8> m_exp1_rom;