using NUnit.Framework; using VMdemo.Core; using VMdemo.Simulation; namespace VMdemo.Tests.EditMode { public class Step2AddressSplitTests { [TestCase(8)] [TestCase(16)] [TestCase(24)] public void AddressGenerator_NextVirtualAddress_StaysWithinRange(int vaBits) { var generator = new AddressGenerator(vaBits, seed: 7); for (var i = 0; i < 1000; i++) { var va = generator.NextVirtualAddress(); Assert.That(va, Is.LessThanOrEqualTo(generator.MaxVirtualAddress)); } } [Test] public void AddressGenerator_SameSeed_GeneratesDeterministicSequence() { var a = new AddressGenerator(24, seed: 99); var b = new AddressGenerator(24, seed: 99); for (var i = 0; i < 20; i++) { Assert.That(a.NextVirtualAddress(), Is.EqualTo(b.NextVirtualAddress())); } } [Test] public void AddressGenerator_DifferentSeed_GeneratesDifferentSequence() { var a = new AddressGenerator(24, seed: 99); var b = new AddressGenerator(24, seed: 100); var hasDifference = false; for (var i = 0; i < 20; i++) { if (a.NextVirtualAddress() != b.NextVirtualAddress()) { hasDifference = true; break; } } Assert.IsTrue(hasDifference); } [TestCase(0xAFUL, 8, 4, 0xAUL, 0xFUL, 0x2UL, 0x2UL)] [TestCase(0xABCDUL, 16, 8, 0xABUL, 0xCDUL, 0xAUL, 0xBUL)] [TestCase(0x123456UL, 24, 8, 0x1234UL, 0x56UL, 0x12UL, 0x34UL)] public void SplitVirtualAddress_SupportedVaBits_ReturnsExpectedParts( ulong va, int vaBits, int offsetBits, ulong expectedVpn, ulong expectedOffset, ulong expectedL1, ulong expectedL2) { var parts = AddressTranslatorUtils.SplitVirtualAddress(va, vaBits, offsetBits); TestContext.WriteLine(AddressTranslatorUtils.FormatSplitResult(va, vaBits, offsetBits, parts)); Assert.That(parts.Vpn, Is.EqualTo(expectedVpn)); Assert.That(parts.Offset, Is.EqualTo(expectedOffset)); Assert.That(parts.L1Index, Is.EqualTo(expectedL1)); Assert.That(parts.L2Index, Is.EqualTo(expectedL2)); } [Test] public void SplitVirtualAddress_OddVpnBits_UsesCeilFloorBitSplit() { const int vaBits = 24; const int offsetBits = 5; const ulong va = 0xABCDEFUL; var parts = AddressTranslatorUtils.SplitVirtualAddress(va, vaBits, offsetBits); AddressTranslatorUtils.GetPageTableBitLayout(vaBits - offsetBits, out var l1Bits, out var l2Bits); Assert.That(l1Bits, Is.EqualTo(10)); Assert.That(l2Bits, Is.EqualTo(9)); Assert.That(parts.Vpn, Is.EqualTo(0x55E6FUL)); Assert.That(parts.Offset, Is.EqualTo(0xFUL)); Assert.That(parts.L1Index, Is.EqualTo(0x2AFUL)); Assert.That(parts.L2Index, Is.EqualTo(0x6FUL)); } [Test] public void GetPageTableBitLayout_AlwaysSumsToVpnBits() { for (var vpnBits = 1; vpnBits <= 63; vpnBits++) { AddressTranslatorUtils.GetPageTableBitLayout(vpnBits, out var l1Bits, out var l2Bits); Assert.That(l1Bits + l2Bits, Is.EqualTo(vpnBits)); Assert.That(l1Bits, Is.GreaterThanOrEqualTo(l2Bits)); Assert.That(l1Bits - l2Bits, Is.LessThanOrEqualTo(1)); } } [Test] public void SplitVirtualAddress_AddressOutOfRange_Throws() { Assert.Throws(() => AddressTranslatorUtils.SplitVirtualAddress(0x1_000000UL, 24, 8)); } [Test] public void AddressGenerator_SequentialArrayLoop_FollowsClassicForLoopOrderAndWraps() { var generator = new AddressGenerator( vaBits: 16, seed: 7, mode: AddressGenerationMode.SequentialArrayLoop, arrayLengthBytes: 16, arrayElementBytes: 4, arrayBaseAddress: 0x20); Assert.That(generator.NextVirtualAddress(), Is.EqualTo(0x20UL)); Assert.That(generator.NextVirtualAddress(), Is.EqualTo(0x24UL)); Assert.That(generator.NextVirtualAddress(), Is.EqualTo(0x28UL)); Assert.That(generator.NextVirtualAddress(), Is.EqualTo(0x2CUL)); Assert.That(generator.NextVirtualAddress(), Is.EqualTo(0x20UL)); } } }