Skip to content

Commit

Permalink
Revert "DSP: ARAM cleanup experiments"
Browse files Browse the repository at this point in the history
  • Loading branch information
JMC47 committed Sep 2, 2019
1 parent 03ea0eb commit c144cde
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 135 deletions.
250 changes: 117 additions & 133 deletions Source/Core/Core/HW/DSP.cpp
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@


#include "Core/HW/DSP.h" #include "Core/HW/DSP.h"


#include <algorithm>
#include <memory> #include <memory>


#include "AudioCommon/AudioCommon.h" #include "AudioCommon/AudioCommon.h"
Expand All @@ -34,7 +33,7 @@
#include "Core/ConfigManager.h" #include "Core/ConfigManager.h"
#include "Core/CoreTiming.h" #include "Core/CoreTiming.h"
#include "Core/DSPEmulator.h" #include "Core/DSPEmulator.h"
#include "Core/HW/AddressSpace.h"
#include "Core/HW/MMIO.h" #include "Core/HW/MMIO.h"
#include "Core/HW/Memmap.h" #include "Core/HW/Memmap.h"
#include "Core/HW/ProcessorInterface.h" #include "Core/HW/ProcessorInterface.h"
Expand Down Expand Up @@ -120,22 +119,12 @@ union ARAM_Info
u16 Hex = 0; u16 Hex = 0;
struct struct
{ {
u16 base_size : 3; u16 size : 6;
u16 expansion_size : 3;
u16 unk : 1; u16 unk : 1;
u16 : 9; u16 : 9;
}; };
}; };


enum
{
ARAM_SIZE_02MB = 0b000,
ARAM_SIZE_04MB = 0b001,
ARAM_SIZE_08MB = 0b010,
ARAM_SIZE_16MB = 0b011,
ARAM_SIZE_32MB = 0b100,
};

// STATE_TO_SAVE // STATE_TO_SAVE
static ARAMInfo s_ARAM; static ARAMInfo s_ARAM;
static AudioDMA s_audioDMA; static AudioDMA s_audioDMA;
Expand Down Expand Up @@ -176,19 +165,12 @@ static void Do_ARAM_DMA();
static void GenerateDSPInterrupt(u64 DSPIntType, s64 cyclesLate = 0); static void GenerateDSPInterrupt(u64 DSPIntType, s64 cyclesLate = 0);


static CoreTiming::EventType* s_et_GenerateDSPInterrupt; static CoreTiming::EventType* s_et_GenerateDSPInterrupt;
static CoreTiming::EventType* s_et_ContinueARAM; static CoreTiming::EventType* s_et_CompleteARAM;


static void ContinueARAM(u64 userdata, s64 cyclesLate) static void CompleteARAM(u64 userdata, s64 cyclesLate)
{ {
if (s_arDMA.Cnt.count == 0) s_dspState.DMAState = 0;
{ GenerateDSPInterrupt(INT_ARAM);
s_dspState.DMAState = 0;
GenerateDSPInterrupt(INT_ARAM);
}
else
{
Do_ARAM_DMA();
}
} }


DSPEmulator* GetDSPEmulator() DSPEmulator* GetDSPEmulator()
Expand All @@ -200,7 +182,7 @@ void Init(bool hle)
{ {
Reinit(hle); Reinit(hle);
s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt); s_et_GenerateDSPInterrupt = CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt);
s_et_ContinueARAM = CoreTiming::RegisterEvent("ARAMint", ContinueARAM); s_et_CompleteARAM = CoreTiming::RegisterEvent("ARAMint", CompleteARAM);
} }


void Reinit(bool hle) void Reinit(bool hle)
Expand All @@ -211,9 +193,9 @@ void Reinit(bool hle)
if (SConfig::GetInstance().bWii) if (SConfig::GetInstance().bWii)
{ {
s_ARAM.wii_mode = true; s_ARAM.wii_mode = true;
s_ARAM.size = 0; s_ARAM.size = Memory::EXRAM_SIZE;
s_ARAM.mask = 0; s_ARAM.mask = Memory::EXRAM_MASK;
s_ARAM.ptr = nullptr; s_ARAM.ptr = Memory::m_pEXRAM;
} }
else else
{ {
Expand Down Expand Up @@ -318,7 +300,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
// Not really sure if this is correct, but it works... // Not really sure if this is correct, but it works...
// Kind of a hack because DSP_CONTROL_MASK should make this bit // Kind of a hack because DSP_CONTROL_MASK should make this bit
// only viewable to DSP emulator // only viewable to DSP emulator
if (val & 1) // DSPReset if (val & 1 /*DSPReset*/)
{ {
s_audioDMA.AudioDMAControl.Hex = 0; s_audioDMA.AudioDMAControl.Hex = 0;
} }
Expand Down Expand Up @@ -490,138 +472,140 @@ void UpdateAudioDMA()
} }
} }


static constexpr u32 ARAM_MEMORY_WRAP_MASK = 0x3ffffe0; static void Do_ARAM_DMA()
{
s_dspState.DMAState = 1;


// Used when converting from a smaller memory size to 16MB // ARAM DMA transfer rate has been measured on real hw
static constexpr u32 ARAM_UPPER_MASK1 = 0xfffffe00; int ticksToTransfer = (s_arDMA.Cnt.count / 32) * 246;
static constexpr u32 ARAM_LOWER_MASK1 = 0x000001ff; CoreTiming::ScheduleEvent(ticksToTransfer, s_et_CompleteARAM);


// Used when converting from a larger memory size to 16MB // Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
static constexpr u32 ARAM_UPPER_MASK2 = 0xff800000; if (s_arDMA.Cnt.dir)
static constexpr u32 ARAM_LOWER_MASK2 = 0x003fffff; {
// ARAM -> MRAM
DEBUG_LOG(DSPINTERFACE, "DMA %08x bytes from ARAM %08x to MRAM %08x PC: %08x",
s_arDMA.Cnt.count, s_arDMA.ARAddr, s_arDMA.MMAddr, PC);


// Depending on the size ARAM is configured as, the mapping to the underlying physical ARAM can // Outgoing data from ARAM is mirrored every 64MB (verified on real HW)
// change. These mappings have been confirmed on hardware. s_arDMA.ARAddr &= 0x3ffffff;
s_arDMA.MMAddr &= 0x3ffffff;


template <u32 MB_SIZE> if (s_arDMA.ARAddr < s_ARAM.size)
static std::optional<u32> ARAM_map_to_16MB(u32 address) {
{ while (s_arDMA.Cnt.count)
static_assert((MB_SIZE == 2) || (MB_SIZE == 4) || (MB_SIZE == 8) || (MB_SIZE == 16) || {
(MB_SIZE == 32)); // These are logically separated in code to show that a memory map has been set up
// See below in the write section for more information
if ((s_ARAM_Info.Hex & 0xf) == 3)
{
Memory::Write_U64_Swap(*(u64*)&s_ARAM.ptr[s_arDMA.ARAddr & s_ARAM.mask], s_arDMA.MMAddr);
}
else if ((s_ARAM_Info.Hex & 0xf) == 4)
{
Memory::Write_U64_Swap(*(u64*)&s_ARAM.ptr[s_arDMA.ARAddr & s_ARAM.mask], s_arDMA.MMAddr);
}
else
{
Memory::Write_U64_Swap(*(u64*)&s_ARAM.ptr[s_arDMA.ARAddr & s_ARAM.mask], s_arDMA.MMAddr);
}


address &= ARAM_MEMORY_WRAP_MASK; s_arDMA.MMAddr += 8;
if (address >= MB_SIZE * 1024 * 1024) s_arDMA.ARAddr += 8;
{ s_arDMA.Cnt.count -= 8;
return std::nullopt; }
} }
if constexpr (MB_SIZE < 16) else
{ {
return ((address & ARAM_UPPER_MASK1) << 1) | (address & ARAM_LOWER_MASK1); // Assuming no external ARAM installed; returns zeros on out of bounds reads (verified on real
} // HW)
else if constexpr (MB_SIZE > 16) while (s_arDMA.Cnt.count)
{ {
return ((address & ARAM_UPPER_MASK2) >> 1) | (address & ARAM_LOWER_MASK2); Memory::Write_U64(0, s_arDMA.MMAddr);
s_arDMA.MMAddr += 8;
s_arDMA.ARAddr += 8;
s_arDMA.Cnt.count -= 8;
}
}
} }
else else
{ {
return address; // MRAM -> ARAM
} DEBUG_LOG(DSPINTERFACE, "DMA %08x bytes from MRAM %08x to ARAM %08x PC: %08x",
} s_arDMA.Cnt.count, s_arDMA.MMAddr, s_arDMA.ARAddr, PC);

using ARAM_ADDRESS_CONVERSION_F = std::optional<u32> (*)(u32 address);
constexpr std::array<ARAM_ADDRESS_CONVERSION_F, 8> conversion_functions = {
&ARAM_map_to_16MB<2>, &ARAM_map_to_16MB<4>, &ARAM_map_to_16MB<8>, &ARAM_map_to_16MB<16>,
&ARAM_map_to_16MB<32>, &ARAM_map_to_16MB<32>, &ARAM_map_to_16MB<32>, &ARAM_map_to_16MB<32>,
};

enum
{
ARAM_DMA_DIR_TO_ARAM = 0,
ARAM_DMA_DIR_FROM_ARAM = 1,
};


// Size of the smallest unit of transfer to/from ARAM via DMA. // Incoming data into ARAM is mirrored every 64MB (verified on real HW)
constexpr u32 ARAM_LINE_SIZE = 0x20; s_arDMA.ARAddr &= 0x3ffffff;

s_arDMA.MMAddr &= 0x3ffffff;
// Maximum number of lines to transfer at a time via DMA.
constexpr u32 ARAM_MAX_TRANSFER_CHUNKING = 0x10;

// The number of clock ticks for each line to be transferred.
constexpr u32 TICKS_TO_TRANSFER_LINE = 246;

static void Do_ARAM_DMA()
{
constexpr std::array<const char*, 2> aram_transfer_direction = {"to", "from"};


s_dspState.DMAState = 1; if (s_arDMA.ARAddr < s_ARAM.size)
// ARAM is mirrored every 64MB (verified on real HW) - done in address conversion func
// Source/destination/count aligned to 32 bytes - done in MMIO handler

u32 lines_to_transfer = std::min(s_arDMA.Cnt.count / ARAM_LINE_SIZE, ARAM_MAX_TRANSFER_CHUNKING);
u32 ticks_to_transfer = lines_to_transfer * TICKS_TO_TRANSFER_LINE;
CoreTiming::ScheduleEvent(ticks_to_transfer, s_et_ContinueARAM);

DEBUG_LOG(DSPINTERFACE, "DMA %08x bytes %s ARAM %08x %s MRAM %08x PC: %08x", s_arDMA.Cnt.count,
aram_transfer_direction[s_arDMA.Cnt.dir], s_arDMA.ARAddr,
aram_transfer_direction[1 - s_arDMA.Cnt.dir], s_arDMA.MMAddr, PC);

if (s_ARAM.wii_mode)
{
// Wii has no physical ARAM
if (s_arDMA.Cnt.dir == ARAM_DMA_DIR_FROM_ARAM)
{ {
std::fill_n(Memory::GetPointer(s_arDMA.MMAddr), ARAM_LINE_SIZE * lines_to_transfer, 0); while (s_arDMA.Cnt.count)
} {
s_arDMA.MMAddr += ARAM_LINE_SIZE * lines_to_transfer; if ((s_ARAM_Info.Hex & 0xf) == 3)
s_arDMA.ARAddr += ARAM_LINE_SIZE * lines_to_transfer; {
s_arDMA.Cnt.count -= ARAM_LINE_SIZE * lines_to_transfer; *(u64*)&s_ARAM.ptr[s_arDMA.ARAddr & s_ARAM.mask] =
return; Common::swap64(Memory::Read_U64(s_arDMA.MMAddr));
} }
else if ((s_ARAM_Info.Hex & 0xf) == 4)
{
if (s_arDMA.ARAddr < 0x400000)
{
*(u64*)&s_ARAM.ptr[(s_arDMA.ARAddr + 0x400000) & s_ARAM.mask] =
Common::swap64(Memory::Read_U64(s_arDMA.MMAddr));
}
*(u64*)&s_ARAM.ptr[s_arDMA.ARAddr & s_ARAM.mask] =
Common::swap64(Memory::Read_U64(s_arDMA.MMAddr));
}
else
{
*(u64*)&s_ARAM.ptr[s_arDMA.ARAddr & s_ARAM.mask] =
Common::swap64(Memory::Read_U64(s_arDMA.MMAddr));
}


const ARAM_ADDRESS_CONVERSION_F convert_address = conversion_functions[s_ARAM_Info.base_size]; s_arDMA.MMAddr += 8;
for (u32 n = 0; n < lines_to_transfer; ++n) s_arDMA.ARAddr += 8;
{ s_arDMA.Cnt.count -= 8;
std::optional<u32> physical_aram_addr = convert_address(s_arDMA.ARAddr); }
if (physical_aram_addr)
{
u8* copy_pointers[2] = {Memory::GetPointer(s_arDMA.MMAddr), &s_ARAM.ptr[*physical_aram_addr]};
std::copy_n(copy_pointers[s_arDMA.Cnt.dir], ARAM_LINE_SIZE,
copy_pointers[1 - s_arDMA.Cnt.dir]);
} }
else if (s_arDMA.Cnt.dir == ARAM_DMA_DIR_FROM_ARAM) else
{ {
// ARAM returns zeros on out of bounds reads (verified on real HW) // Assuming no external ARAM installed; writes nothing to ARAM when out of bounds (verified on
// ARAM writes nothing on out of bounds writes (verified on real HW) // real HW)
std::fill_n(Memory::GetPointer(s_arDMA.MMAddr), ARAM_LINE_SIZE, 0); s_arDMA.MMAddr += s_arDMA.Cnt.count;
s_arDMA.ARAddr += s_arDMA.Cnt.count;
s_arDMA.Cnt.count = 0;
} }
s_arDMA.MMAddr += ARAM_LINE_SIZE;
s_arDMA.ARAddr += ARAM_LINE_SIZE;
} }
s_arDMA.Cnt.count -= ARAM_LINE_SIZE * lines_to_transfer; }
} // namespace DSP


// (shuffle2) I still don't believe that this hack is actually needed... :(
// Maybe the Wii Sports ucode is processed incorrectly?
// (LM) It just means that DSP reads via '0xffdd' on Wii can end up in EXRAM or main RAM
u8 ReadARAM(u32 address) u8 ReadARAM(u32 address)
{ {
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors( if (s_ARAM.wii_mode)
s_ARAM.wii_mode ? AddressSpace::Type::Physical : AddressSpace::Type::Auxiliary); {
return accessors->ReadU8(address); if (address & 0x10000000)
return s_ARAM.ptr[address & s_ARAM.mask];
else
return Memory::Read_U8(address & Memory::RAM_MASK);
}
else
{
return s_ARAM.ptr[address & s_ARAM.mask];
}
} }


void WriteARAM(u8 value, u32 address) void WriteARAM(u8 value, u32 address)
{ {
AddressSpace::Accessors* accessors = AddressSpace::GetAccessors( // TODO: verify this on Wii
s_ARAM.wii_mode ? AddressSpace::Type::Physical : AddressSpace::Type::Auxiliary); s_ARAM.ptr[address & s_ARAM.mask] = value;
accessors->WriteU8(address, value);
} }


u8* GetARAMPtr() u8* GetARAMPtr()
{ {
return s_ARAM.ptr; return s_ARAM.ptr;
} }


u32 GetARAMPhysicalSize()
{
return s_ARAM.size;
}

} // end of namespace DSP } // end of namespace DSP
3 changes: 1 addition & 2 deletions Source/Core/Core/HW/DSP.h
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ enum DSPInterruptType
enum enum
{ {
ARAM_SIZE = 0x01000000, // 16 MB ARAM_SIZE = 0x01000000, // 16 MB
// ARAM_SIZE is always a power-of-two, so (ARAM_SIZE-1) is the mask ARAM_MASK = 0x00FFFFFF,
ARAM_MASK = ARAM_SIZE - 1,
}; };


// UDSPControl // UDSPControl
Expand Down

0 comments on commit c144cde

Please sign in to comment.