Example #1
0
        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, });
        }
Example #2
0
        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());
        }
Example #3
0
        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;
                }
            }
        }
Example #4
0
        //[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.");
            }
        }
Example #5
0
        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));
        }