public override IEnumerable <object[]> GetData(MethodInfo testMethod) { var parameters = testMethod.GetParameters(); var parameterTypes = parameters.Select(x => x.ParameterType).ToArray(); if (!File.Exists(_filename)) { throw new Exception(); } var asm = File.ReadAllText(_filename); var assembler = new PatchAssembler(); var simulationMemory = assembler.Assemble(0, null, asm); yield return(new object[] { simulationMemory, }); }
public void LoadRegisters() { var assembler = new PatchAssembler(); var asm = @" .org $0000 lda #$31 ldx #$32 ldy #$33 loop: jmp loop .org $f000 rti .org $fffa nmi .addr $f000 .org $fffc reset .addr $0000 .org $fffe irq .addr $f000 ".Replace(".org", "* ="); var data = assembler.Assemble(0, null, asm); var simulator = new Simulator(new ArrayMemory(data)); simulator.Init(); simulator.RunStartProgram(); simulator.ExecuteCycles(20); Assert.Equal(0x31, simulator.ReadA()); Assert.Equal(0x32, simulator.ReadX()); Assert.Equal(0x33, simulator.ReadY()); }
public static void Main(string[] args) { var asm = @" vectors .macro * = $fff0 sed rti * = $fffa nmi .addr $fff0 reset .addr $0000 irq .addr $fff0 .endmacro init .macro ; Set the interrupt disable bit to prevent interrupts. sei ; Clear the decimal bit. Decimal mode is disabled in the NES so this should cause CPU emulators ; to mimic that behavior. cld ; Load 0xff into the stack register. ldx #$ff txs .endmacro done .macro ; Show that the test ran to the end by storing 0xa3 in 0xff00. lda #$a3 sta $ff00 doneLoop: jmp doneLoop .endmacro error .macro ; Show that the test ran to the end by storing 0xa3 in 0xff00. lda #$c9 sta $ff00 doneLoop: jmp doneLoop .endmacro * = $0000 .byte $00 ; Beginning of tests. * = $c000 .init ldx #$01 lda #$95 sta $5000,x lda #$00 asl $5000,x .done * = $fff0 rti * = $fffa nmiVector .addr $fff0 resetVector .addr $c000 irqVector .addr $fff0 "; var assembler = new PatchAssembler(); var simulationMemory = assembler.Assemble(0, null, asm); var memory = new ArrayMemory(simulationMemory); var simulator = new Simulator(memory); void WriteDataLine(int cycle) { Write($"{cycle:00000} {simulator.ReadAddressBus():x4} {simulator.ReadBits8("db"):x2} {simulator.ReadPC():x4} "); Write($"{simulator.ReadA():x2} {simulator.ReadX():x2} {simulator.ReadY():x2} {simulator.ReadS():x2} "); Write($"{simulator.ReadBits8("ir"):x2} {simulator.ReadBit("sync")} {simulator.ReadBit("rw")} "); Write($"{simulator.ReadBit("nmi")} {simulator.ReadPString()} "); WriteLine(); } WriteLine("cycle ab db pc a x y s ir sync rw nmi p"); var cycle = 1; simulator.Init(() => WriteDataLine(cycle++)); WriteLine("--------------"); cycle = 1; simulator.RunStartProgram(() => WriteDataLine(cycle++)); WriteLine("--------------"); cycle = 0; for (var i = 0; i < 1000; i++) { cycle++; if (cycle == 5) { //simulator.WriteBit("nmi", false); } simulator.Clock(); WriteDataLine(cycle); if (memory[0xff00] == 0xa3) { break; } } }
//[InlineData(12)] public void TestNmi(int cycleToSetNmiLow) { var asm = File.ReadAllText("Cpu/TestFiles/nmi.6502.asm"); var assembler = new PatchAssembler(); var memory = assembler.Assemble(0, null, asm); var simulatorMemory = new TrackedMemory(memory); var emulatorMemory = new TrackedMemory(memory); var simulator = new Simulator(simulatorMemory); simulator.Init(); var bus = new EmulatorBus(emulatorMemory); var cpu = new CentralProcessor.Cpu(bus); var simulatorLog = new StringBuilder(); var emulatorLog = new StringBuilder(); cpu.Init(); // Run the init programs. for (var i = 0; i < 9; i++) { cpu.Clock(); simulator.Clock(); } simulator.HalfClock(); // See notes in the simulation's start program code. // We only check the flags register the cycle after sync goes high. This variable // tracks the state of sync on the previous cycle. var previousSync = false; // Run the actual user code. for (var i = 0; i < 1000; i++) { if (i + 1 == cycleToSetNmiLow) { cpu.Nmi = true; simulator.WriteBit("nmi", false); } else { // For the simulator, we will only pull NMI low for a single cycle. This is // enough to set the NMI flipflop. For the emulator, the NMI flag represents // the flipfop so we don't need to touch that as it will be reset automatically // when the NMI routine finishes. simulator.WriteBit("nmi", true); } cpu.Clock(); simulator.Clock(); WriteDataLine(simulatorLog, i + 1, simulator); WriteDataLine(emulatorLog, i + 1, cpu); Assert.True(TrackedMemory.AreChangesEqual(simulatorMemory, emulatorMemory)); Assert.Equal(simulator.ReadPC(), cpu.CpuState.PC); Assert.Equal(simulator.ReadA(), cpu.CpuState.A); Assert.Equal(simulator.ReadX(), cpu.CpuState.X); Assert.Equal(simulator.ReadY(), cpu.CpuState.Y); // The S register reads funny during most of the execution of the JSR instruction. // Don't check S during execution of this operation. if (simulator.ReadBits8("ir") != (byte)Opcode.Jsr_Absolute) { Assert.Equal(simulator.ReadS(), cpu.CpuState.S); } // Because flags are set on very weird cycles for reasons I don't yet understand, // we will only check flags once we know for sure they will be set. if (previousSync) { Assert.Equal(simulator.ReadP(), (int)cpu.CpuState.P); } previousSync = simulator.ReadBit("sync") == 0 ? false : true; // When the test has completed successfully, it will write 0xa3 to memory location // 0xff00. if (simulatorMemory[0xff00] == 0xa3) { break; } else if (simulatorMemory[0xff00] == 0xc9) // A value of 0xc9 means we took the wrong code path. { throw new Exception("Hit an error."); } } // Make sure that after the test is ran we have the done marker set. If this isn't set // then the test was probably not given enough cycles to complete or it did something // wrong. if (simulatorMemory[0xff00] != 0xa3) { throw new Exception("Did not hit done."); } }
public static byte[] Assemble(BA origin, string name, string src) { PatchAssembler assembler = new PatchAssembler(); return(assembler.Assemble(origin.Addr, name, src, variables: Symbols.AsDictionaries.VariablesAndConstants, labels: Symbols.AsDictionaries.LabelsWithRunAddresses)); }