Ejemplo n.º 1
0
        public void TestJumpAfterInstruction()
        {
            // We need to add the position at which
            // the program will be loaded in memory.
            // This will give us an absolute
            // address to work with.
            const int address =
                (
                    sizeof(OpCode) * 2 +
                    sizeof(Registers) +
                    sizeof(int) +
                    Compiler.InitialAddress
                );

            var program = new []
            {
                new CompilerIns(OpCode.JNE_REG,
                                new object[] { Registers.R1, 0 },
                                new AsmLabel("A", 1)),
                new CompilerIns(OpCode.NOP),
                new CompilerIns(OpCode.LABEL, new object[] { "A" }),
                new CompilerIns(OpCode.NOP),
            };

            Vm.LoadAndInitialize(QuickCompile.RawCompile(program));

            var ins = Vm.Cpu.Step();

            if (ins is null)
            {
                Assert.Fail();
            }

            Assert.IsTrue(address == (int)ins.Args[1].Value);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Run a set of tests within a given virtual machine
        /// instance for a given opcode.
        /// </summary>
        /// <param name="aVm">
        /// The virtual machine instance in which the tests should be run.
        /// </param>
        /// <param name="aTests">An array of the tests to be run.</param>
        /// <param name="aOp">The opcode to be tested.</param>
        /// <param name="aReg">
        /// The register to be used when checking the result.
        /// Defaults to the accumulator (AC).
        /// </param>
        public static void RunTests(VirtualMachine aVm,
                                    BitTestResult[] aTests,
                                    OpCode aOp,
                                    Registers aReg = Registers.AC)
        {
            for (var i = 0; i < aTests.Length; i++)
            {
                var entry = aTests[i];

                var program = TestUtilities.Generate(aOp, entry.Values);

                aVm.Run(QuickCompile.RawCompile(program));

                var success = entry.Type switch
                {
                    ResultTypes.EQUAL => aVm.Cpu.Registers[aReg] == entry.Result,
                    _ => false
                };

                Assert.IsTrue
                (
                    success,
                    $"Value of register '{aReg}' for test " +
                    $"{i} is incorrect. Expected {entry.Result}, " +
                    $"got {aVm.Cpu.Registers[aReg]}."
                );
            }
        }
    }
Ejemplo n.º 3
0
        public void TestModuloExceptions()
        {
            var table = new []
            {
                new [] { 0, 0 },
                new [] { 2, 0 },
            };

            for (var i = 0; i < table.Length; i++)
            {
                var entry = table[i];

                var program = new []
                {
                    new CompilerIns(OpCode.MOV_LIT_REG,
                                    new object[] { entry[0], (byte)Registers.R1 }),
                    new CompilerIns(OpCode.MOD_LIT_REG,
                                    new object[] { entry[1], (byte)Registers.R1 }),
                };

                Assert.ThrowsException <DivideByZeroException>
                (
                    () => Vm.Run(QuickCompile.RawCompile(program)),
                    $"Expected exception of type DivideByZeroException for test {i}."
                );
            }
        }
Ejemplo n.º 4
0
        public static void ExecutionOrderTest(VirtualMachine aVm,
                                              OpCode[] aOpCodes,
                                              string[] aProgram)
        {
            var pStr = string.Join(Environment.NewLine, aProgram);

            var program =
                AsmParser.Parse(pStr).CodeSectionData.ToArray();

            aVm.LoadAndInitialize(QuickCompile.RawCompile(program));

            var i   = 0;
            var ins = aVm.Cpu.Step();

            while (!(ins is null))
            {
                Assert.IsTrue
                (
                    ins.OpCode == aOpCodes[i],
                    $"OpCode at position {i} mismatched. " +
                    $"Expected {ins.OpCode}, got {aOpCodes[i]}."
                );

                ins = aVm.Cpu.Step();
                ++i;
            }
        }
Ejemplo n.º 5
0
        public void TestUserAssemblyWriteWithPositiveOffset()
        {
            const Registers r1 = Registers.R1;
            const Registers r2 = Registers.R2;
            const Registers r3 = Registers.R3;

            const int address  = 0x15;
            const int expected = 0x12;

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { expected, r1 }), // mov $0x12, R1
                new CompilerIns(OpCode.MOV_REG_MEM,
                                new object[] { r1, address }),  // mov R1, $0x15
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { address, r2 }),  // mov $0x15, R2
                new CompilerIns(OpCode.MOV_REG_PTR_REG,
                                new object[] { r2, r3 })        // mov *R2, R3
            };

            Vm.Run(QuickCompile.RawCompile(program));

            Assert.IsTrue(Vm.Cpu.Registers[r3] == expected);
        }
Ejemplo n.º 6
0
        public void TestPopIntegerValueToRegister()
        {
            var program = new CompilerIns[10];

            // Push the values to the stack.
            for (var i = 0; i < 5; i++)
            {
                program[i] =
                    new CompilerIns(OpCode.PSH_LIT,
                                    new object[] { i + 1 });
            }

            // Push the values to the registers in
            // reverse order so that they align.
            for (int j = 0, r = 4; j < 5; j++, r--)
            {
                program[j + 5] =
                    new CompilerIns(OpCode.POP,
                                    new object[] { (Registers)r });
            }

            Vm.Run(QuickCompile.RawCompile(program));

            Assert.IsTrue(Vm.Memory.StackTypes.Count == 0);

            var sp = Vm.Cpu.Registers[(Registers.SP, SystemCtx)];
Ejemplo n.º 7
0
        public void TestUserAssemblyInvalidReturn()
        {
            var program = new []
            {
                new CompilerIns(OpCode.RET)
            };

            Vm.Run(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 8
0
        public void TestCopyRegisterToInvalidMemory()
        {
            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_MEM,
                                new object[] { 0x00, int.MaxValue }),
            };

            Vm.Run(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 9
0
        public void TestCopyInvalidMemoryToRegister()
        {
            var program = new []
            {
                new CompilerIns(OpCode.MOV_MEM_REG,
                                new object[] { int.MaxValue, Registers.R1 }),
            };

            Vm.Run(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 10
0
        public void TestDuplicateLabelNames()
        {
            var program = new []
            {
                new CompilerIns(OpCode.LABEL, new object[] { "A" }),
                new CompilerIns(OpCode.LABEL, new object[] { "A" }),
                new CompilerIns(OpCode.NOP),
            };

            Vm.LoadAndInitialize(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 11
0
        public void TestJumpNoDestination()
        {
            var program = new []
            {
                new CompilerIns(OpCode.JNE_REG,
                                new object[] { Registers.R1, 0 },
                                new AsmLabel("A", 1)),
            };

            Vm.LoadAndInitialize(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 12
0
        public void TestUserAssemblyInvalidLabel()
        {
            var program = new []
            {
                new CompilerIns(OpCode.CAL_LIT,
                                new object[] { 0 },
                                new AsmLabel("GOOD", 0)),
            };

            Vm.Run(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 13
0
        public void TestBitTest()
        {
            var table = new []
            {
                #region TESTS
                // Note that these are little endian so the
                // least significant byte is first and the
                // most significant byte is last.
                // As 32-bit integers are 4 bytes in size that
                // means that the layout will be like this:
                // byte 4 (last 8 bits),
                // byte 3 (next 8 bits),
                // byte 2 (next 8 bits),
                // byte 1 (next 8 bits).
                // For ease of reference I have added
                // the binary representations to the
                // right of the test case.

                new object[] { 0, 0, true },           // 0b00000000_00000000_00000000_00000000
                new object[] { 0, 4, true },           // 0b00000000_00000000_00000000_00000100
                new object[] { 0, 5, false },          // 0b00000000_00000000_00000000_00000101
                new object[] { 1, 5, true },           // 0b00000000_00000000_00000000_00000101
                new object[] { 1, 6, false },          // 0b00000000_00000000_00000000_00000111
                new object[] { 0, -1, false },         // 0b11111111_11111111_11111111_11111111
                new object[] { 0, 2147473160, true },  // 0b‭01111111_11111111_11010111_00001000
                new object[] { 3, 2147473160, false }, // 0b‭01111111_11111111_11010111_00001000
                new object[] { 13, 2147473160, true }, // 0b‭01111111_11111111_11010111_00001000
                #endregion
            };

            for (var i = 0; i < table.Length; i++)
            {
                var entry = table[i];

                var program = new []
                {
                    new CompilerIns(OpCode.MOV_LIT_REG,
                                    new object[] { (int)entry[1], Registers.R1 }),
                    new CompilerIns(OpCode.BIT,
                                    new object[] { (int)entry[0], Registers.R1 }),
                };

                Vm.Run(QuickCompile.RawCompile(program));

                var success =
                    Vm.Cpu.IsFlagSet(CpuFlags.Z) == (bool)entry[2];

                Assert.IsTrue(success,
                              $"Zero flag for test {i} is incorrect. " +
                              $"Expected {(bool)entry[2]}, got " +
                              $"{Vm.Cpu.IsFlagSet(CpuFlags.Z)}.");
            }
        }
Ejemplo n.º 14
0
        public void TestUserAssemblyWriteProtectedRegister()
        {
            var program = new []
            {
                // Attempt to write a value to a protected write register.
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { 0x0, VMCore.VM.Core.Register.Registers.TESTER })
            };

            // This should fail with a RegisterAccessViolationException.
            _vm.Run(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 15
0
        public void TestLabelInvalidArgumentBind()
        {
            var program = new []
            {
                new CompilerIns(OpCode.LABEL, new object[] { "A" }),
                new CompilerIns(OpCode.JNE_REG,
                                new object[] { Registers.R1, 0 },
                                new AsmLabel("A", 0)),
            };

            Vm.LoadAndInitialize(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 16
0
        public void TestUserAssemblyReturn()
        {
            // Ensure that the stack is clean
            // before running each test.
            Vm.Memory.ClearStack();

            const Registers r1 = Registers.R1;
            const Registers ac = Registers.AC;

            #region Program

            var lines = new[]
            {
                ".section text",
                "push $0xAAA",  // Should remain in place once the stack is restored
                "push $0xC",    // TESTER Argument 3
                "push $0xB",    // TESTER Argument 2
                "push $0xA",    // TESTER Argument 1
                "push $3",      // The number of arguments for the subroutine
                "call !TESTER",
                "mov $0x123, R1",
                "hlt",

                "TESTER:",
                "mov $0x34, &FP, R3",
                "mov $0x30, &FP, R2",
                "mov $0x2C, &FP, R1",
                "add R1, R2",
                "add R3, AC",
                "ret",
            };

            #endregion // Program

            var pStr = string.Join(Environment.NewLine, lines);

            var program =
                _p.Parse(pStr).CodeSectionData.ToArray();

            Vm.Run(QuickCompile.RawCompile(program));

            // 0xAAA should be at the top of the stack.
            Assert.IsTrue(Vm.Memory.StackPopInt() == 0xAAA);
            Assert.IsTrue(Vm.Memory.StackPointer == Vm.Memory.StackEnd);

            // Ensure that the execution returns to the correct place
            // after the subroutine returns.
            Assert.IsTrue(Vm.Cpu.Registers[r1] == 0x123);

            // Ensure that the subroutine executed correctly.
            Assert.IsTrue(Vm.Cpu.Registers[ac] == 0x21);
        }
Ejemplo n.º 17
0
        public void TestCpuHaltState()
        {
            var program = new []
            {
                // Attempt to write a value to a protected write register.
                new CompilerIns(OpCode.HLT)
            };

            Vm.Run(QuickCompile.RawCompile(program));

            // Check if the halted state is set.
            Assert.IsTrue(Vm.Cpu.IsHalted);
        }
Ejemplo n.º 18
0
        public void TestCopyRegisterToInvalidMemory()
        {
            const int expected = 0x123;

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { expected, Registers.R1 }),
                new CompilerIns(OpCode.MOV_REG_MEM,
                                new object[] { Registers.R1, int.MaxValue }),
            };

            Vm.Run(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 19
0
        private void RunInvalidJumpDestinationProgram(OpCode aOp,
                                                      JumpType aType)
        {
            const Registers r1 = Registers.R1;

            // Calculate the value required value to ensure
            // that the jump condition is or isn't taken.
            var value = aType switch
            {
                JumpType.EQ => 1,
                JumpType.NEQ => 0,
                JumpType.LT => 1,
                JumpType.GT => - 1,
                JumpType.LTE => 2,
                JumpType.GTE => - 2,
                _ => 0
            };

            var program = new List <CompilerIns>();

            object arg;
            var    argTypes = _instructionCache[aOp].ArgumentTypes;

            if (argTypes[0] == typeof(Registers))
            {
                // Set the register to the required value.
                program.Add
                (
                    new CompilerIns(OpCode.MOV_LIT_REG,
                                    new object[] { value, r1 })
                );

                // This will become the jump instruction
                // condition argument below.
                arg = r1;
            }
            else
            {
                // This will become the jump instruction
                // condition argument below.
                arg = value;
            }

            program.Add(new CompilerIns(aOp,
                                        new [] { arg, -2 }));

            Vm.Run(QuickCompile.RawCompile(program.ToArray()));

            Vm.Cpu.FetchExecuteNextInstruction();
        }
Ejemplo n.º 20
0
        private void RunInvalidLabelBindProgram(OpCode aOp)
        {
            const Registers r1 = Registers.R1;

            var program = new[]
            {
                new CompilerIns(aOp,
                                new object[] { r1, 0 },
                                new AsmLabel("A", 0)),
                new CompilerIns(OpCode.LABEL, new object[] { "A" }),
            };

            Vm.Run(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 21
0
        public void TestJumpBeforeInstruction()
        {
            // We need to add the position at which
            // the program will be loaded in memory.
            // This will give us an absolute
            // address to work with.
            const int address =
                (
                    sizeof(OpCode) * 2 +
                    sizeof(Registers) +
                    sizeof(int) +
                    Compiler.InitialAddress
                );

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { 0, Registers.R1 }),
                new CompilerIns(OpCode.NOP),
                new CompilerIns(OpCode.LABEL, new object[] { "AAA" }),
                new CompilerIns(OpCode.NOP),

                new CompilerIns(OpCode.JNE_REG,
                                new object[] { Registers.R1, 0 },
                                new [] { new AsmLabel("AAA", 1) }),
            };

            Vm.LoadAndInitialize(QuickCompile.RawCompile(program));

            var ins = new InstructionData()
            {
                OpCode = OpCode.NOP
            };

            var i = 0;

            while (i < 4)
            {
                ins = Vm.Cpu.Step();
                i++;
            }

            if (ins is null)
            {
                Assert.Fail("Expected an instruction but none was returned.");
            }

            Assert.IsTrue(address == (int)ins.Args[1].Value);
        }
Ejemplo n.º 22
0
        public void TestUserAssemblyWriteWithNetSignedOffset()
        {
            const Registers r1 = Registers.R1;
            const Registers r2 = Registers.R2;

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { 0, r1 }),       // mov $0, R1
                new CompilerIns(OpCode.MOV_LIT_OFF_REG,
                                new object[] { -0x1, r1, r2 }) // mov [-$1 + R1], R2
            };

            Vm.Run(QuickCompile.RawCompile(program));
        }
Ejemplo n.º 23
0
        public void TestUserAssemblyWriteToRegister()
        {
            const Registers register = Registers.R1;
            const int       expected = 0x123;

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { expected, register }),
            };


            Vm.Run(QuickCompile.RawCompile(program));

            Assert.IsTrue(Vm.Cpu.Registers[register] == expected);
        }
Ejemplo n.º 24
0
        public void TestPushLiteralToStack()
        {
            var program = new CompilerIns[10];

            for (var i = 0; i < 10; i++)
            {
                program[i] =
                    new CompilerIns(OpCode.PSH_LIT,
                                    new object[] { i });
            }

            Vm.Run(QuickCompile.RawCompile(program));

            Assert.IsTrue(Vm.Memory.StackTypes.Count == 10);

            var sp = Vm.Cpu.Registers[(Registers.SP, SystemCtx)];
Ejemplo n.º 25
0
        public void TestUserAssemblyCopyValid()
        {
            const int expected = 0x12;

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { expected, Registers.R1 }),
                new CompilerIns(OpCode.MOV_REG_REG,
                                new object[] { Registers.R1, Registers.R2 }),
            };

            Vm.Run(QuickCompile.RawCompile(program));

            Assert.IsTrue(Vm.Cpu.Registers[Registers.R2] == expected);
        }
Ejemplo n.º 26
0
        public void TestCopyValidMemoryToRegister()
        {
            const int expected = 0x123;

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_MEM,
                                new object[] { expected, 0x0 }),
                new CompilerIns(OpCode.MOV_MEM_REG,
                                new object[] { 0x0, Registers.R1 }),
            };

            Vm.Run(QuickCompile.RawCompile(program));

            Assert.IsTrue(Vm.Cpu.Registers[Registers.R1] == expected);
        }
Ejemplo n.º 27
0
        /// <summary>
        /// Run a set of tests within a given virtual machine
        /// instance for a given opcode.
        /// </summary>
        /// <param name="aVm">
        /// The virtual machine instance in which the tests should be run.
        /// </param>
        /// <param name="aTests">An array of the tests to be run.</param>
        /// <param name="aOp">The opcode to be tested.</param>
        /// <param name="aReg">
        /// The register to be used when checking the result.
        /// Defaults to the accumulator (AC).
        /// </param>
        public static void RunTests(VirtualMachine aVm,
                                    IntegerTestResult[] aTests,
                                    OpCode aOp,
                                    Registers aReg = Registers.AC)
        {
            for (var i = 0; i < aTests.Length; i++)
            {
                var entry = aTests[i];

                var program = TestUtilities.Generate(aOp, entry.Values);

                aVm.Run(QuickCompile.RawCompile(program));

                var success = entry.Type switch
                {
                    ResultTypes.EQUAL
                    => aVm.Cpu.Registers[aReg] == entry.Result,
                    _
                    => false
                };

                Assert.IsTrue(success,
                              $"Value of register '{aReg}' for " +
                              $"test {i} is incorrect. " +
                              $"Expected {entry.Result}, got " +
                              $"{aVm.Cpu.Registers[aReg]}.");

                Assert.IsTrue(aVm.Cpu.IsFlagSet(CpuFlags.S) == entry.SignFlag,
                              "Sign flag not correctly set " +
                              $"for test {i}. " +
                              $"Expected {entry.SignFlag}.");

                Assert.IsTrue(aVm.Cpu.IsFlagSet(CpuFlags.Z) == entry.ZeroFlag,
                              "Zero flag not correctly " +
                              $"set for test {i}. " +
                              $"Expected {entry.ZeroFlag}.");

                Assert.IsTrue(aVm.Cpu.IsFlagSet(CpuFlags.O) == entry.OverflowFlag,
                              $"Overflow flag not correctly set " +
                              $"for test {i}. Expected {entry.OverflowFlag}.");
            }
        }
    }
Ejemplo n.º 28
0
        public void TestCopyRegisterToValidMemory()
        {
            const int expected = 0x123;

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_MEM,
                                new object[] { expected, 0x0 }),
            };

            Vm.Run(QuickCompile.RawCompile(program));

            // Extract the value type from memory.
            var intOut =
                Vm.Memory.GetInt(0x0,
                                 SecurityContext.System,
                                 false);

            Assert.IsTrue(intOut == expected);
        }
Ejemplo n.º 29
0
        public void TestUserAssemblyWriteWithNetSignedOffset()
        {
            const Registers r1 = Registers.R1;
            const Registers r2 = Registers.R2;
            const Registers r3 = Registers.R3;

            const int expected = 0x12;

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { -0x1, r1 }), // mov $-0x1, R1
                new CompilerIns(OpCode.MOV_REG_PTR_REG,
                                new object[] { r1, r2 })    // mov *R1, R2
            };


            Vm.Run(QuickCompile.RawCompile(program));

            Assert.IsTrue(Vm.Cpu.Registers[r3] == expected);
        }
Ejemplo n.º 30
0
        public void TestCpuIsHalted()
        {
            const int expected = 0x123;

            var program = new []
            {
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { expected, (byte)Registers.R1 }),
                new CompilerIns(OpCode.HLT),
                // This statement should never execute.
                new CompilerIns(OpCode.MOV_LIT_REG,
                                new object[] { 0xABC, (byte)Registers.R1 })
            };

            Vm.Run(QuickCompile.RawCompile(program));

            // If the CPU halted after executing the HLT instruction
            // then the register R1 should still be set to the value
            // of "expected". The last statement should not have executed.
            Assert.IsTrue(Vm.Cpu.Registers[Registers.R1] == expected);
        }