// Copyright 2017 Dolphin Emulator Project // Licensed under GPLv2+ // Refer to the license.txt file included. #include #include #include "Common/CommonTypes.h" #include "Core/DSP/DSPAccelerator.h" // Simulated DSP accelerator. class TestAccelerator : public DSP::Accelerator { public: // For convenience. u16 TestRead() { std::array 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); }