Files
Yaroze.NET/tests/Yaroze.Tests/CPU/GteTests.cs
T
2026-01-24 17:23:50 +01:00

223 lines
6.2 KiB
C#

using Xunit;
using Yaroze.Core.CPU;
using Yaroze.Core.Memory;
namespace Yaroze.Tests.CPU;
public class GteTests
{
private readonly Cpu _cpu;
public GteTests()
{
var bus = new Bus();
_cpu = new Cpu(bus);
}
[Fact]
public void Gte_Reset_ClearsAllRegisters()
{
// Arrange
_cpu.Gte.WriteDataRegister(5, 0x12345678);
_cpu.Gte.WriteControlRegister(10, 0xABCDEF00);
// Act
_cpu.Gte.Reset();
// Assert
Assert.Equal(0u, _cpu.Gte.ReadDataRegister(5));
Assert.Equal(0u, _cpu.Gte.ReadControlRegister(10));
}
[Fact]
public void Gte_ReadWriteDataRegister_WorksCorrectly()
{
// Arrange
uint testValue = 0xDEADBEEF;
// Act
_cpu.Gte.WriteDataRegister(15, testValue);
uint result = _cpu.Gte.ReadDataRegister(15);
// Assert
Assert.Equal(testValue, result);
}
[Fact]
public void Gte_ReadWriteControlRegister_WorksCorrectly()
{
// Arrange
uint testValue = 0x12345678;
// Act
_cpu.Gte.WriteControlRegister(20, testValue);
uint result = _cpu.Gte.ReadControlRegister(20);
// Assert
Assert.Equal(testValue, result);
}
[Fact]
public void Gte_ReadInvalidRegister_ReturnsZero()
{
// Act & Assert
Assert.Equal(0u, _cpu.Gte.ReadDataRegister(100));
Assert.Equal(0u, _cpu.Gte.ReadControlRegister(100));
}
[Fact]
public void Gte_WriteInvalidRegister_DoesNotCrash()
{
// Act - should not throw
_cpu.Gte.WriteDataRegister(100, 0x12345678);
_cpu.Gte.WriteControlRegister(100, 0xABCDEF00);
}
[Fact]
public void MFC2_MovesFromGteDataRegister()
{
// Arrange - MFC2 $t1, $15 (0x48090000)
// Opcode: 0x12 (COP2), CopOp: 0x00 (MFC2), Rt: 9 ($t1), Rd: 15
_cpu.Gte.WriteDataRegister(15, 0xBAADF00D);
_cpu.Bus.Ram.Write32(0, 0x48090000 | (15 << 11));
// Act
_cpu.Step(); // MFC2
Assert.Equal(0u, _cpu.Registers.ReadGPR(9)); // Load delay
_cpu.Step(); // Delay slot (NOP)
// Assert
Assert.Equal(0xBAADF00Du, _cpu.Registers.ReadGPR(9));
}
[Fact]
public void MTC2_MovesToGteDataRegister()
{
// Arrange - MTC2 $t1, $15 (0x48890000)
// Opcode: 0x12 (COP2), CopOp: 0x04 (MTC2), Rt: 9 ($t1), Rd: 15
_cpu.Registers.WriteGPR(9, 0xCAFEBABE);
_cpu.Bus.Ram.Write32(0, 0x48890000 | (15 << 11));
// Act
_cpu.Step(); // MTC2
// Assert
Assert.Equal(0xCAFEBABEu, _cpu.Gte.ReadDataRegister(15));
}
[Fact]
public void CFC2_MovesFromGteControlRegister()
{
// Arrange - CFC2 $t1, $20 (0x484A0000)
// Opcode: 0x12 (COP2), CopOp: 0x02 (CFC2), Rt: 9 ($t1), Rd: 20
_cpu.Gte.WriteControlRegister(20, 0x11111111);
_cpu.Bus.Ram.Write32(0, 0x48490000 | (20 << 11));
// Act
_cpu.Step(); // CFC2
Assert.Equal(0u, _cpu.Registers.ReadGPR(9)); // Load delay
_cpu.Step(); // Delay slot (NOP)
// Assert
Assert.Equal(0x11111111u, _cpu.Registers.ReadGPR(9));
}
[Fact]
public void CTC2_MovesToGteControlRegister()
{
// Arrange - CTC2 $t1, $20 (0x48C90000)
// Opcode: 0x12 (COP2), CopOp: 0x06 (CTC2), Rt: 9 ($t1), Rd: 20
_cpu.Registers.WriteGPR(9, 0x22222222);
_cpu.Bus.Ram.Write32(0, 0x48C90000 | (20 << 11));
// Act
_cpu.Step(); // CTC2
// Assert
Assert.Equal(0x22222222u, _cpu.Gte.ReadControlRegister(20));
}
[Fact]
public void LWC2_LoadsWordToGteDataRegister()
{
// Arrange - LWC2 $15, 0x100($t0)
// Opcode: 0x32 (LWC2), Base: 8 ($t0), Rt: 15, Offset: 0x100
_cpu.Registers.WriteGPR(8, 0x00000000);
_cpu.Bus.Ram.Write32(0x100, 0x99999999);
_cpu.Bus.Ram.Write32(0, 0xC8080100); // LWC2
// Act
_cpu.Step();
// Assert
Assert.Equal(0x99999999u, _cpu.Gte.ReadDataRegister(15));
}
[Fact]
public void SWC2_StoresWordFromGteDataRegister()
{
// Arrange - SWC2 $15, 0x200($t0)
// Opcode: 0x3A (SWC2), Base: 8 ($t0), Rt: 15, Offset: 0x200
_cpu.Registers.WriteGPR(8, 0x00000000);
_cpu.Gte.WriteDataRegister(15, 0x88888888);
_cpu.Bus.Ram.Write32(0, 0xE8080200); // SWC2
// Act
_cpu.Step();
// Assert
Assert.Equal(0x88888888u, _cpu.Bus.Ram.Read32(0x200));
}
[Fact]
public void GteCommand_Executes_WithoutCrashing()
{
// Arrange - GTE RTPS command (0x4A180001) - Perspective Transformation
// Verifies that GTE commands execute without throwing exceptions
_cpu.Bus.Ram.Write32(0, 0x4A180001);
// Act - should not throw
_cpu.Step();
// Assert: Execution completes successfully
// Note: Full GTE calculations are not implemented, but command processing works
}
[Fact]
public void GteCommand_ClearsFlagRegister()
{
// Arrange
_cpu.Gte.WriteDataRegister(31, 0xFFFFFFFF); // Set FLAG register with errors
_cpu.Bus.Ram.Write32(0, 0x4A180001); // GTE command (RTPS)
// Act
_cpu.Step();
// Assert: FLAG register cleared to indicate successful execution
Assert.Equal(0u, _cpu.Gte.ReadDataRegister(31));
}
[Fact]
public void Gte_GetDataRegisterName_ReturnsCorrectNames()
{
// Test a few key register names
Assert.Equal("VXY0", Gte.GetDataRegisterName(0));
Assert.Equal("VZ0", Gte.GetDataRegisterName(1));
Assert.Equal("IR0", Gte.GetDataRegisterName(8));
Assert.Equal("SXY0", Gte.GetDataRegisterName(12));
Assert.Equal("MAC0", Gte.GetDataRegisterName(24));
Assert.Equal("LZCR", Gte.GetDataRegisterName(31));
}
[Fact]
public void Gte_GetControlRegisterName_ReturnsCorrectNames()
{
// Test a few key register names
Assert.Equal("R11R12", Gte.GetControlRegisterName(0));
Assert.Equal("TRX", Gte.GetControlRegisterName(5));
Assert.Equal("L11L12", Gte.GetControlRegisterName(8));
Assert.Equal("OFX", Gte.GetControlRegisterName(24));
Assert.Equal("FLAG", Gte.GetControlRegisterName(31));
}
}