public Run6502FunctionalTest( //ILogger<Run6502FunctionalTest> logger, FunctionalTestCompiler functionalTestCompiler) { //_logger = logger; _functionalTestCompiler = functionalTestCompiler; }
public void Can_Run_6502_Functional_Test_Program_With_Decimal_Mode_Disabled_Successfully() { // Arrange var functionalTestCompiler = new FunctionalTestCompiler(NullLogger <FunctionalTestCompiler> .Instance); var functionalTestBinary = functionalTestCompiler.Get6502FunctionalTestBinary(disableDecimalTests: true); // There is no 2 byte header in the 6502_functional_test.bin file. // It's supposed to be loaded to memory at 0x0000, and started at 0x0400 ushort loadAddress = 0x000A; ushort startAddress = 0x0400; var mem = BinaryLoader.Load( functionalTestBinary, out ushort loadedAtAddress, out int fileLength, forceLoadAddress: loadAddress); _output.WriteLine($"Data & code load address: {loadAddress.ToHex(), 10} ({loadAddress})"); _output.WriteLine($"Code+data length (bytes): 0x{fileLength, -8:X8} ({fileLength})"); _output.WriteLine($"Code start address: {startAddress.ToHex(), 10} ({startAddress})"); var computerBuilder = new ComputerBuilder(); computerBuilder .WithCPU() .WithStartAddress(startAddress) .WithMemory(mem) .WithExecOptions(options => { // A successful run has about 26765880 instructions (the version that was run 2021-02-06, that may change) // We increase to almost double, and will exit if not finished then. options.MaxNumberOfInstructions = 50000000; options.ExecuteUntilExecutedInstructionAtPC = 0x336d; options.UnknownInstructionThrowsException = false; }); var computer = computerBuilder.Build(); var execOptions = computer.DefaultExecOptions; _output.WriteLine($"If test logic succeeds, the test program will reach a specific memory location: {execOptions.ExecuteUntilExecutedInstructionAtPC.Value.ToHex()}, and the emulator will then stop processing."); _output.WriteLine($"If test logic fails, the test program will loop forever at the location the error was found. The emulator will try executing a maximum #instructions {execOptions.MaxNumberOfInstructions.Value} before giving up."); _output.WriteLine($"If unknown opcode is found, it's logged and ignored, and processing continues on next instruction."); // Act computer.Run(); // Assert var cpu = computer.CPU; var execState = cpu.ExecState; _output.WriteLine($"CPU last PC: {cpu.PC.ToHex()}"); _output.WriteLine($"CPU last opcode: {execState.LastOpCode.Value.ToOpCodeId()} ({execState.LastOpCode.Value.ToHex()})"); _output.WriteLine($"Total # CPU instructions executed: {execState.InstructionsExecutionCount}"); _output.WriteLine($"Total # CPU cycles consumed: {execState.CyclesConsumed}"); if (cpu.PC == computer.DefaultExecOptions.ExecuteUntilExecutedInstructionAtPC.Value) { _output.WriteLine($"Success. PC reached expected success memory location: {computer.DefaultExecOptions.ExecuteUntilExecutedInstructionAtPC.Value.ToHex()}"); Assert.True(true); } else { _output.WriteLine($"Probably failure. The emulator executer a maximum #instructions {computer.DefaultExecOptions.MaxNumberOfInstructions.Value}, and did not manage to get PC to the configured success location: {computer.DefaultExecOptions.ExecuteUntilExecutedInstructionAtPC.Value.ToHex()}"); _output.WriteLine($"The functional test program would end in a forever-loop on the same memory location if it fails."); _output.WriteLine($"Verify the last PC location against the functional test program's .lst file to find out which logic test failed."); Assert.True(false); } }