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(); }
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)); }
private void RunInvalidLabelProgram(OpCode aOp) { var argTypes = _instructionCache[aOp].ArgumentTypes; object arg; if (argTypes[0] == typeof(Registers)) { arg = Registers.R1; } else { arg = 0; } var program = new[] { new CompilerIns(aOp, new [] { arg, 0 }, new AsmLabel("A", 1)), }; Vm.Run(QuickCompile.RawCompile(program)); }
private void RunJumpTestProgram(OpCode aOp, JumpType aType, bool aInvert, bool aUseLabel) { const Registers ac = Registers.AC; const Registers r1 = Registers.R1; const Registers r2 = Registers.R2; var expected = aInvert ? 0x321 : 0x123; var program = new List <CompilerIns> { // Set the accumulator to be zero. // This isn't strictly required as it // will default to zero, but just to be // safe. new CompilerIns(OpCode.MOV_LIT_REG, new object[] { 0, ac }) }; // Calculate the value required value to ensure // that the jump condition is or isn't taken. var value = aType switch { JumpType.EQ => aInvert ? 1 : 0, JumpType.NEQ => aInvert ? 0 : 1, JumpType.LT => aInvert ? 1 : -1, JumpType.GT => aInvert ? -1 : 1, JumpType.LTE => aInvert ? 2 : -2, JumpType.GTE => aInvert ? -2 : 2, _ => 0 }; 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; } var labels = new AsmLabel[2]; if (aUseLabel) { labels[1] = new AsmLabel("GOOD", 1); } // If we are not using labels then we will go back and // update the jump position below. // Insert a placeholder value here for the time being. program.Add ( new CompilerIns(aOp, new [] { arg, 0 }, labels) ); // In the jump not taken (inverted) case // this should execute. program.Add ( new CompilerIns(OpCode.MOV_LIT_REG, new object[] { 0x321, r2 }) ); // Add a halt instruction to block execution // of the success instruction. program.Add(new CompilerIns(OpCode.HLT)); if (aUseLabel) { program.Add ( new CompilerIns(OpCode.LABEL, new object[] { "GOOD" }) ); } else { // Calculate the address of the current instruction. // This effectively acts as a label. var jumpAddress = CalculateDestinationAddress(program); // Go back and update the jump address in the instruction // from which the jump should or shouldn't occur. foreach (var entry in program) { if (entry.Op != aOp) { continue; } entry.Args[1] = jumpAddress; break; } } // In the jump is taken (normal) case this should execute. program.Add ( new CompilerIns(OpCode.MOV_LIT_REG, new object[] { 0x123, r2 }) ); // Run the test program. Vm.Run(QuickCompile.RawCompile(program.ToArray())); // Check the result. Assert.IsTrue ( Vm.Cpu.Registers[r2] == expected, $"Test OpCode '{aOp}'. " + $"Inverted = {aInvert}, Use Label = {aUseLabel} failed " + "to yield the correct result." ); }