188 lines
5.5 KiB
C++
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);
|
|
}
|