[TestCase((ushort)0x9037, typeof(ShlInstruction), "SHL")] // SHL X, 4
        public void BuildWhenCalledForRawInstructionBuildsExpectedInstructionInstance(
            ushort rawInstruction, Type expectedInstruction, string token)
        {
            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);
            var instruction = builder.Build(rawInstruction, null);

            Assert.That(instruction, Is.InstanceOf(expectedInstruction));
            Assert.That(instruction.Token, Is.EqualTo(token));
        }
        [TestCase((ushort)0x9037, typeof(ShlInstruction))] // SHL X, 4
        public void BuildWhenCalledForRawInstructionBuildsExpectedInstructionInstance(ushort rawInstruction, Type expectedInstruction)
        {
            var cpu = new Mock<ICpuStateOperations>();
            var operandFactory = new Mock<IInstructionOperandFactory>();

            operandFactory.Setup(m => m.Create(It.IsAny<ushort>())).Returns(new NullOperand());

            var builder = new InstructionBuilder(operandFactory.Object);

            var instruction = builder.Build(rawInstruction, cpu.Object);

            Assert.That(instruction, Is.InstanceOf(expectedInstruction));
        }
        public void ExecuteWhenCalledWithJsrSetsProgramCounterToOperandValue()
        {
            var reader = new StringReader("JSR 0x04");
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);
            var memory = new Memory();
            memory.LoadData(program);
            var cpu = new Cpu(builder) { Memory = memory };
            cpu.SetProgramCounter(0x10);
            var instruction = builder.Build(program.ToList()[0], cpu);
            instruction.Execute();

            Assert.That(cpu.ProgramCounter, Is.EqualTo(0x04));
        }
        public void ExecuteWhenCalledWithIfEqualsAndResultIsFalseSetsIgnoreNextInstruction()
        {
            var reader = new StringReader("IFE A, 1");
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);
            var memory = new Memory();
            memory.LoadData(program);
            var cpu = new Cpu(builder) { Memory = memory };
            var instruction = builder.Build(program.ToList()[0], cpu);
            instruction.Execute();

            Assert.That(cpu.IgnoreNextInstruction, Is.EqualTo(true));
        }
        public void ExecuteWhenCalledWithSubLiteralToRegisterValueSetsCorrectRegisterValue(
            string code, ushort registerAddress, int expectedValue)
        {
            var reader = new StringReader(code);
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);
            var memory = new Memory();
            memory.LoadData(program);
            var cpu = new Cpu(builder) { Memory = memory };
            var instruction1 = builder.Build(program.ToList()[0], cpu);
            var instruction2 = builder.Build(program.ToList()[1], cpu);
            instruction1.Execute();
            instruction2.Execute();

            Assert.That(cpu.ReadGeneralPursoseRegisterValue(registerAddress), Is.EqualTo(expectedValue));
        }
        public void ExecuteWhenCalledWithSetRegisterWithPopSetsCorrectRegistryValue()
        {
            const string Code = @"SET PUSH, 0x10
								  SET I, POP";

            var reader = new StringReader(Code);
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);
            var memory = new Memory();
            memory.LoadData(program);
            var cpu = new Cpu(builder) { Memory = memory };
            var instruction1 = builder.Build(program.ToList()[0], cpu);
            var instruction2 = builder.Build(program.ToList()[1], cpu);
            instruction1.Execute();
            instruction2.Execute();

            Assert.That(cpu.ReadGeneralPursoseRegisterValue((ushort)RegisterIdentifier.RegI), Is.EqualTo(0x10));
        }
        public void BuildWhenCalledForRawInstructionBuildsExpectedInstructionToken(
            string code)
        {
            var reader = new StringReader(code);
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);
            var memory = new Memory();
            memory.LoadData(program);
            var cpu = new Cpu(builder) { Memory = memory };

            var instruction = builder.Build(program.ToList()[0], cpu);

            Assert.That(instruction.Token, Is.EqualTo(code.Substring(0, 3)));
        }
        public void ExecuteWhenCalledWithSetPushWithLiteralSetsCorrectMemoryValue()
        {
            var reader = new StringReader("SET PUSH, 0x10");
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);
            var memory = new Memory();
            memory.LoadData(program);
            var cpu = new Cpu(builder) { Memory = memory };
            var instruction = builder.Build(program.ToList()[0], cpu);
            instruction.Execute();

            Assert.That(cpu.ReadMemoryValueAtAddress(cpu.StackPointer), Is.EqualTo(0x10));
        }
        public void ExecuteWhenCalledWithSetOffsetMemoryAddressWithNextWordSetsCorrectMemoryValue(
            string code, ushort memoryAddress, int expectedValue)
        {
            var reader = new StringReader(code);
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);
            var memory = new Memory();
            memory.LoadData(program);
            var cpu = new Cpu(builder) { Memory = memory };
            var instruction = builder.Build(program.ToList()[0], cpu);
            instruction.Execute();

            Assert.That(cpu.ReadMemoryValueAtAddress(memoryAddress), Is.EqualTo(expectedValue));
        }
        public void ExecuteWhenCalledWithPeekDoesNotChangeStackPointer()
        {
            const string Code = @"SET PUSH, 0x10
								  SET I, PEEK";

            var reader = new StringReader(Code);
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);
            var memory = new Memory();
            memory.LoadData(program);
            var cpu = new Cpu(builder) { Memory = memory };
            var instruction1 = builder.Build(program.ToList()[0], cpu);
            var instruction2 = builder.Build(program.ToList()[1], cpu);
            instruction1.Execute();
            instruction2.Execute();

            Assert.That(cpu.StackPointer, Is.EqualTo(ushort.MaxValue));
        }
        public void ExecuteWhenCalledAndOperationOverflowsSetsOverflowRegister(string code, int expectedValue)
        {
            var reader = new StringReader(code);
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var operandFactory = new InstructionOperandFactory();
            var builder = new InstructionBuilder(operandFactory);

            var memory = new Memory();
            memory.LoadData(program);
            var cpu = new Cpu(builder) { Memory = memory };
            var instruction1 = builder.Build(program.ToList()[0], cpu);
            var instruction2 = builder.Build(program.ToList()[1], cpu);
            instruction1.Execute();
            cpu.IncrementProgramCounter();
            instruction2.Execute();

            Assert.That(cpu.Overflow, Is.EqualTo(expectedValue));
        }
        public void InstructionBuilderWhenCalledWithNotchSampleGeneratesCorrectNumberOfInstructions()
        {
            const string Code =
                @"  ;Try some basic stuff
                                    SET A, 0x30              ; 7c01 0030
                                    SET [0x1000], 0x20       ; 7de1 1000 0020
                                    SUB A, [0x1000]          ; 7803 1000
                                    IFN A, 0x10              ; c00d
                                    SET PC, crash            ; 7dc1 001a [*]

                                    ; Do a loopy thing
                                    SET I, 10                ; a861
                                    SET A, 0x2000            ; 7c01 2000
                                    :loop         SET [0x2000+I], [A]      ; 2161 2000
                                    SUB I, 1                 ; 8463
                                    IFN I, 0                 ; 806d
                                    SET PC, loop             ; 7dc1 000d [*]

                                    ; Call a subroutine
                                    SET X, 0x4               ; 9031
                                    JSR testsub              ; 7c10 0018 [*]
                                    SET PC, crash            ; 7dc1 001a [*]

                                    :testsub      SHL X, 4   ; 9037
                                    SET PC, POP              ; 61c1

                                    ; Hang forever. X should now be 0x40 if everything went right.
                                    :crash        SET PC, crash            ; 7dc1 001a [*]";

            var reader = new StringReader(Code);
            var lexer = new CodeLexer(reader, this.matchers);
            var directOperandFactory = new DirectOperandFactory();
            var indirectOperandFactory = new IndirectOperandFactory();
            var parser = new Parser(lexer, directOperandFactory, indirectOperandFactory);

            var statments = parser.Parse();
            var assembler = new Assembler();
            var program = assembler.AssembleStatments(statments);

            var cpu = new Mock<ICpuStateOperations>();
            var operandFactory = new Mock<IInstructionOperandFactory>();
            var builder = new InstructionBuilder(operandFactory.Object);

            var instructions = program.Select(@ushort => builder.Build(@ushort, cpu.Object)).ToList();

            Assert.That(instructions.Count, Is.EqualTo(28));
        }