dolphin/Source/UnitTests/Core/DSP/DSPAcceleratorTest.cpp

188 lines
5.5 KiB
C++

// Copyright 2017 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include <gtest/gtest.h>
#include "Common/CommonTypes.h"
#include "Core/DSP/DSPAccelerator.h"
// Simulated DSP accelerator.
class TestAccelerator : public DSP::Accelerator
{
public:
// For convenience.
u16 TestRead()
{
std::array<s16, 16> coefs{};
m_accov_raised = false;
return Read(coefs.data());
}
bool EndExceptionRaised() const { return m_accov_raised; }
protected:
void OnEndException() override
{
EXPECT_TRUE(m_reads_stopped);
m_accov_raised = true;
}
u8 ReadMemory(u32 address) override { return 0; }
void WriteMemory(u32 address, u8 value) override {}
bool m_accov_raised = false;
};
TEST(DSPAccelerator, Initialization)
{
TestAccelerator accelerator;
accelerator.SetCurrentAddress(0x00000000);
accelerator.SetStartAddress(0x00000000);
accelerator.SetEndAddress(0x00001000);
EXPECT_EQ(accelerator.GetStartAddress(), 0x00000000u);
EXPECT_EQ(accelerator.GetCurrentAddress(), 0x00000000u);
EXPECT_EQ(accelerator.GetEndAddress(), 0x00001000u);
}
TEST(DSPAccelerator, SimpleReads)
{
TestAccelerator accelerator;
accelerator.SetCurrentAddress(0x00000000);
accelerator.SetStartAddress(0x00000000);
accelerator.SetEndAddress(0x00001000);
for (size_t i = 1; i <= 0xf; ++i)
{
accelerator.TestRead();
EXPECT_FALSE(accelerator.EndExceptionRaised());
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress() + i);
}
}
TEST(DSPAccelerator, AddressMasking)
{
TestAccelerator accelerator;
accelerator.SetCurrentAddress(0x48000000);
accelerator.SetStartAddress(0x48000000);
accelerator.SetEndAddress(0x48001000);
EXPECT_EQ(accelerator.GetStartAddress(), 0x08000000u);
EXPECT_EQ(accelerator.GetCurrentAddress(), 0x08000000u);
EXPECT_EQ(accelerator.GetEndAddress(), 0x08001000u);
accelerator.SetCurrentAddress(0xffffffff);
accelerator.SetStartAddress(0xffffffff);
accelerator.SetEndAddress(0xffffffff);
EXPECT_EQ(accelerator.GetStartAddress(), 0x3fffffffu);
EXPECT_EQ(accelerator.GetCurrentAddress(), 0xbfffffffu);
EXPECT_EQ(accelerator.GetEndAddress(), 0x3fffffffu);
}
TEST(DSPAccelerator, PredScaleRegisterMasking)
{
TestAccelerator accelerator;
accelerator.SetPredScale(0xbbbb);
EXPECT_EQ(accelerator.GetPredScale(), 0x3bu);
accelerator.SetPredScale(0xcccc);
EXPECT_EQ(accelerator.GetPredScale(), 0x4cu);
accelerator.SetPredScale(0xffff);
EXPECT_EQ(accelerator.GetPredScale(), 0x7fu);
}
TEST(DSPAccelerator, OverflowBehaviour)
{
TestAccelerator accelerator;
accelerator.SetCurrentAddress(0x00000000);
accelerator.SetStartAddress(0x00000000);
accelerator.SetEndAddress(0x0000000f);
for (size_t i = 1; i <= 0xf; ++i)
{
accelerator.TestRead();
EXPECT_FALSE(accelerator.EndExceptionRaised());
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress() + i);
}
accelerator.TestRead();
EXPECT_TRUE(accelerator.EndExceptionRaised());
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress());
// Since an ACCOV has fired, reads are stopped (until the YN2 register is reset),
// so the current address shouldn't be updated for this read.
accelerator.TestRead();
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress());
// Simulate a write to YN2, which internally resets the "reads stopped" flag.
// After resetting it, reads should work once again.
accelerator.SetYn2(0);
for (size_t i = 1; i <= 0xf; ++i)
{
accelerator.TestRead();
EXPECT_FALSE(accelerator.EndExceptionRaised());
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress() + i);
}
}
TEST(DSPAccelerator, OverflowFor16ByteAlignedAddresses)
{
TestAccelerator accelerator;
accelerator.SetCurrentAddress(0x00000000);
accelerator.SetStartAddress(0x00000000);
accelerator.SetEndAddress(0x00000010);
for (size_t i = 1; i <= 0xf; ++i)
{
accelerator.TestRead();
EXPECT_FALSE(accelerator.EndExceptionRaised());
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress() + i);
}
accelerator.TestRead();
EXPECT_FALSE(accelerator.EndExceptionRaised());
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress() + 1);
accelerator.TestRead();
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress() + 2);
}
TEST(DSPAccelerator, OverflowForXXXXXXX1Addresses)
{
TestAccelerator accelerator;
accelerator.SetCurrentAddress(0x00000000);
accelerator.SetStartAddress(0x00000000);
accelerator.SetEndAddress(0x00000011);
for (size_t i = 1; i <= 0xf; ++i)
{
accelerator.TestRead();
EXPECT_FALSE(accelerator.EndExceptionRaised());
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress() + i);
}
accelerator.TestRead();
EXPECT_FALSE(accelerator.EndExceptionRaised());
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress());
accelerator.TestRead();
EXPECT_EQ(accelerator.GetCurrentAddress(), accelerator.GetStartAddress() + 1);
}
TEST(DSPAccelerator, CurrentAddressSkips)
{
TestAccelerator accelerator;
accelerator.SetCurrentAddress(0x00000000);
accelerator.SetStartAddress(0x00000000);
accelerator.SetEndAddress(0x00001000);
for (size_t j = 1; j <= 0xf; ++j)
accelerator.TestRead();
EXPECT_EQ(accelerator.GetCurrentAddress(), 0x0000000fu);
accelerator.TestRead();
EXPECT_EQ(accelerator.GetCurrentAddress(), 0x00000012u);
accelerator.TestRead();
EXPECT_EQ(accelerator.GetCurrentAddress(), 0x00000013u);
}