forked from dolphin-emu/dolphin
		
	
		
			
	
	
		
			188 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			188 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|   | // Copyright 2017 Dolphin Emulator Project
 | ||
|  | // Licensed under GPLv2+
 | ||
|  | // Refer to the license.txt file included.
 | ||
|  | 
 | ||
|  | #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); | ||
|  | } |