From 1473d61331e7616bb7a197bcf628b31214ac5716 Mon Sep 17 00:00:00 2001 From: Ian Fisher Date: Thu, 3 Jan 2019 14:56:48 -0500 Subject: [PATCH] Simplify ternary op execution logic in virtual machine --- hera/utils.py | 1 + hera/vm.py | 83 ++-- test/test_op/test_arithmetic_logic.py | 597 ++++++-------------------- test/test_op/test_misc.py | 14 - 4 files changed, 150 insertions(+), 545 deletions(-) delete mode 100644 test/test_op/test_misc.py diff --git a/hera/utils.py b/hera/utils.py index b4526d0..81492ed 100644 --- a/hera/utils.py +++ b/hera/utils.py @@ -94,6 +94,7 @@ def is_symbol(s): RELATIVE_BRANCHES = set(b + "R" for b in REGISTER_BRANCHES) BRANCHES = REGISTER_BRANCHES | RELATIVE_BRANCHES DATA_STATEMENTS = set(["CONSTANT", "DLABEL", "INTEGER", "LP_STRING", "DSKIP"]) +TERNARY_OPS = set(["ADD", "SUB", "MUL", "AND", "OR", "XOR"]) def emit_error(msg, *, loc=None, exit=False): diff --git a/hera/vm.py b/hera/vm.py index 4a01252..17a03f0 100644 --- a/hera/vm.py +++ b/hera/vm.py @@ -15,29 +15,12 @@ REGISTER_BRANCHES, register_to_index, RELATIVE_BRANCHES, + TERNARY_OPS, to_u16, to_u32, ) -def ternary_op(f): - """A decorator for ternary HERA ops. It handles fetching the values of the - left and right registers, storing the result in the target register, - setting the zero and sign flags, and incrementing the program counter. - """ - - @functools.wraps(f) - def inner(self, target, left, right): - left = self.get_register(left) - right = self.get_register(right) - result = f(self, left, right) - self.store_register(target, result) - self.set_zero_and_sign(result) - self.pc += 1 - - return inner - - def binary_op(f): """A decorator for binary HERA ops. It handles fetching the value of the operand register, storing the result in the target register, setting the @@ -94,30 +77,33 @@ def exec_one(self, op): if op.name in BRANCHES: self.exec_branch(op) + elif op.name in TERNARY_OPS: + self.exec_ternary_op(op) else: - try: - handler = getattr(self, "exec_" + op.name.lower()) - except AttributeError: - raise RuntimeError('unknown instruction "{}"'.format(op.name)) from None - else: - handler(*op.args) + handler = getattr(self, "exec_" + op.name.lower()) + handler(*op.args) def exec_branch(self, op): name = op.name if op.name in REGISTER_BRANCHES else op.name[:-1] - try: - should_branch = getattr(self, "should_" + name)() - except AttributeError: - raise RuntimeError( - 'could not find branch handler for "{}"'.format(op.name) - ) from None - else: - if should_branch: - if op.name in REGISTER_BRANCHES: - self.pc = self.get_register(op.args[0]) - else: - self.pc += op.args[0] + should_branch = getattr(self, "should_" + name)() + if should_branch: + if op.name in REGISTER_BRANCHES: + self.pc = self.get_register(op.args[0]) else: - self.pc += 1 + self.pc += op.args[0] + else: + self.pc += 1 + + def exec_ternary_op(self, op): + left = self.get_register(op.args[1]) + right = self.get_register(op.args[2]) + + calculator = getattr(self, "calculate_" + op.name) + + result = calculator(left, right) + self.store_register(op.args[0], result) + self.set_zero_and_sign(result) + self.pc += 1 def exec_many(self, program, *, lines=None): """Execute a program (i.e., a list of operations), resetting the machine's @@ -180,9 +166,7 @@ def exec_sethi(self, target, value): self.store_register(target, (value << 8) + (self.get_register(target) & 0x00FF)) self.pc += 1 - @ternary_op - def exec_add(self, left, right): - """Execute the ADD instruction.""" + def calculate_ADD(self, left, right): carry = 1 if not self.flag_carry_block and self.flag_carry else 0 result = (left + right + carry) & 0xFFFF @@ -192,9 +176,7 @@ def exec_add(self, left, right): return result - @ternary_op - def exec_sub(self, left, right): - """Execute the SUB instruction.""" + def calculate_SUB(self, left, right): borrow = 1 if not self.flag_carry_block and not self.flag_carry else 0 # to_u16 is necessary because although left and right are necessarily @@ -208,8 +190,7 @@ def exec_sub(self, left, right): return result - @ternary_op - def exec_mul(self, left, right): + def calculate_MUL(self, left, right): """Execute the MUL instruction.""" if self.flag_sign and not self.flag_carry_block: # Take the high 16 bits. @@ -225,19 +206,13 @@ def exec_mul(self, left, right): return result - @ternary_op - def exec_and(self, left, right): - """Execute the AND instruction.""" + def calculate_AND(self, left, right): return left & right - @ternary_op - def exec_or(self, left, right): - """Execute the OR instruction.""" + def calculate_OR(self, left, right): return left | right - @ternary_op - def exec_xor(self, left, right): - """Execute the XOR instruction.""" + def calculate_XOR(self, left, right): return left ^ right def exec_inc(self, target, value): diff --git a/test/test_op/test_arithmetic_logic.py b/test/test_op/test_arithmetic_logic.py index c2f9604..c469082 100644 --- a/test/test_op/test_arithmetic_logic.py +++ b/test/test_op/test_arithmetic_logic.py @@ -11,675 +11,318 @@ def vm(): return VirtualMachine() -def test_exec_one_delegates_to_add(vm): - with patch("hera.vm.VirtualMachine.exec_add") as mock_exec_add: - vm.exec_one(Op("ADD", ["R1", "R2", "R3"])) - assert mock_exec_add.call_count == 1 - assert mock_exec_add.call_args == (("R1", "R2", "R3"), {}) +def test_exec_ternary_op_with_ADD(vm): + vm.registers[2] = to_u16(-1) + vm.registers[3] = 1 + vm.exec_ternary_op(Op("ADD", ["R1", "R2", "R3"])) -def test_add_small_numbers(vm): - vm.registers[2] = 20 - vm.registers[3] = 22 - vm.exec_add("R1", "R2", "R3") - assert vm.registers[1] == 42 + assert vm.registers[1] == 0 + assert not vm.flag_sign + assert vm.flag_zero -def test_add_increments_pc(vm): - vm.exec_add("R1", "R2", "R3") - assert vm.pc == 1 +def test_exec_ternary_op_with_SUB(vm): + vm.flag_carry_block = True + vm.registers[2] = 40 + vm.registers[3] = 100 + vm.exec_ternary_op(Op("SUB", ["R1", "R2", "R3"])) -def test_add_sets_flags(vm): - vm.registers[2] = 20 - vm.registers[3] = 22 - vm.exec_add("R1", "R2", "R3") - assert not vm.flag_sign + assert vm.registers[1] == to_u16(-60) + assert vm.flag_sign assert not vm.flag_zero + + +def test_calculate_ADD_small_numbers(vm): + assert vm.calculate_ADD(20, 22) == 42 assert not vm.flag_overflow assert not vm.flag_carry -def test_add_with_negative(vm): - vm.registers[2] = to_u16(-14) - vm.registers[3] = 8 - vm.exec_add("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-6) - assert vm.flag_sign - assert not vm.flag_zero +def test_calculate_ADD_with_negative(vm): + assert vm.calculate_ADD(to_u16(-14), 8) == to_u16(-6) -def test_add_with_zero(vm): - vm.registers[7] = to_u16(-4) - vm.registers[3] = 4 - vm.exec_add("R5", "R7", "R3") - assert vm.registers[5] == 0 - assert not vm.flag_sign - assert vm.flag_zero +def test_calculate_ADD_with_zero(vm): + assert vm.calculate_ADD(to_u16(-4), 4) == 0 -def test_add_with_overflow(vm): - vm.registers[9] = 32767 - vm.registers[2] = 1 - vm.exec_add("R7", "R9", "R2") - assert vm.registers[7] == to_u16(-32768) - assert vm.flag_sign +def test_calculate_ADD_with_overflow(vm): + assert vm.calculate_ADD(32767, 1) == to_u16(-32768) assert vm.flag_overflow assert not vm.flag_carry -def test_add_with_big_overflow(vm): - vm.registers[9] = 32767 - vm.registers[2] = 32767 - vm.exec_add("R7", "R9", "R2") - assert vm.registers[7] == to_u16(-2) - assert vm.flag_sign +def test_calculate_ADD_with_big_overflow(vm): + assert vm.calculate_ADD(32767, 32767) == to_u16(-2) assert vm.flag_overflow assert not vm.flag_carry -def test_add_with_negative_overflow(vm): - vm.registers[9] = to_u16(-32768) - vm.registers[2] = to_u16(-32768) - vm.exec_add("R7", "R9", "R2") - assert vm.registers[7] == 0 - assert vm.flag_zero +def test_calculate_ADD_with_negative_overflow(vm): + assert vm.calculate_ADD(to_u16(-32768), to_u16(-32768)) == 0 assert vm.flag_overflow assert vm.flag_carry -def test_add_with_carry(vm): - vm.registers[3] = 5 - vm.registers[5] = 3 +def test_calculate_ADD_with_carry(vm): vm.flag_carry = True - vm.exec_add("R7", "R3", "R5") - assert vm.registers[7] == 9 + assert vm.calculate_ADD(5, 3) == 9 assert not vm.flag_carry -def test_add_with_carry_and_block(vm): - vm.registers[3] = 5 - vm.registers[5] = 3 +def test_calculate_ADD_with_carry_and_block(vm): vm.flag_carry = True vm.flag_carry_block = True - vm.exec_add("R7", "R3", "R5") - assert vm.registers[7] == 8 + assert vm.calculate_ADD(5, 3) == 8 assert not vm.flag_carry assert vm.flag_carry_block -def test_add_with_overflow_from_carry(vm): - vm.registers[2] = 32760 - vm.registers[3] = 7 +def test_calculate_ADD_with_overflow_from_carry(vm): vm.flag_carry = True - vm.exec_add("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-32768) - assert vm.flag_sign + assert vm.calculate_ADD(32760, 7) == to_u16(-32768) assert vm.flag_overflow assert not vm.flag_carry -def test_add_does_not_change_R0(vm): - vm.registers[1] = 1 - vm.registers[2] = 1 - vm.exec_add("R0", "R1", "R2") - assert vm.registers[0] == 0 - - -def test_exec_one_delegates_to_sub(vm): - with patch("hera.vm.VirtualMachine.exec_sub") as mock_exec_sub: - vm.exec_one(Op("SUB", ["R1", "R2", "R3"])) - assert mock_exec_sub.call_count == 1 - assert mock_exec_sub.call_args == (("R1", "R2", "R3"), {}) - - -def test_sub_small_numbers(vm): - vm.registers[2] = 64 - vm.registers[3] = 22 +def test_calculate_SUB_small_numbers(vm): vm.flag_carry_block = True - vm.exec_sub("R1", "R2", "R3") - assert vm.registers[1] == 42 + assert vm.calculate_SUB(64, 22) == 42 -def test_sub_sets_flags(vm): - vm.registers[2] = 64 - vm.registers[3] = 22 +def test_calculate_SUB_sets_flags(vm): vm.flag_carry_block = True - vm.exec_sub("R1", "R2", "R3") - assert not vm.flag_sign - assert not vm.flag_zero + vm.calculate_SUB(64, 22) assert not vm.flag_overflow assert vm.flag_carry -def test_sub_increments_pc(vm): - vm.exec_sub("R1", "R2", "R3") - assert vm.pc == 1 - - -def test_sub_with_negative(vm): - vm.registers[2] = to_u16(-64) - vm.registers[3] = 22 +def test_calculate_SUB_with_negative(vm): vm.flag_carry_block = True - vm.exec_sub("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-86) - assert vm.flag_sign - assert not vm.flag_zero + assert vm.calculate_SUB(to_u16(-64), 22) == to_u16(-86) -def test_sub_with_zero(vm): - vm.registers[2] = to_u16(-37) - vm.registers[3] = to_u16(-37) +def test_calculate_SUB_with_zero(vm): vm.flag_carry_block = True - vm.exec_sub("R1", "R2", "R3") - assert vm.registers[1] == 0 - assert not vm.flag_sign - assert vm.flag_zero + assert vm.calculate_SUB(to_u16(-37), to_u16(-37)) == 0 -def test_sub_with_two_negatives(vm): - vm.registers[2] = to_u16(-20) - vm.registers[3] = to_u16(-40) +def test_calculate_SUB_with_two_negatives(vm): vm.flag_carry_block = True - vm.exec_sub("R1", "R2", "R3") - assert vm.registers[1] == 20 - assert not vm.flag_sign + assert vm.calculate_SUB(to_u16(-20), to_u16(-40)) == 20 assert vm.flag_carry assert not vm.flag_overflow -def test_sub_with_min_negative_overflow(vm): - vm.registers[1] = to_u16(-32768) - vm.registers[2] = 1 +def test_calculate_SUB_with_min_negative_overflow(vm): vm.flag_carry_block = True - vm.exec_sub("R3", "R1", "R2") - assert vm.registers[3] == 32767 - assert not vm.flag_sign + assert vm.calculate_SUB(to_u16(-32768), 1) == 32767 assert vm.flag_carry assert vm.flag_overflow -def test_sub_with_big_negative_overflow(vm): - vm.registers[1] = to_u16(-32000) - vm.registers[2] = 32000 +def test_calculate_SUB_with_big_negative_overflow(vm): vm.flag_carry_block = True - vm.exec_sub("R3", "R1", "R2") - assert vm.registers[3] == 1536 - assert not vm.flag_sign + assert vm.calculate_SUB(to_u16(-32000), 32000) == 1536 assert vm.flag_carry assert vm.flag_overflow -def test_sub_with_max_negative_overflow(vm): - vm.registers[1] = to_u16(-32768) - vm.registers[2] = 32767 +def test_calculate_SUB_with_max_negative_overflow(vm): vm.flag_carry_block = True - vm.exec_sub("R3", "R1", "R2") - assert vm.registers[3] == 1 - assert not vm.flag_sign + assert vm.calculate_SUB(to_u16(-32768), 32767) == 1 assert vm.flag_carry assert vm.flag_overflow -def test_sub_with_min_positive_overflow(vm): - vm.registers[4] = 32767 - vm.registers[5] = to_u16(-1) +def test_calculate_SUB_with_min_positive_overflow(vm): vm.flag_carry_block = True - vm.exec_sub("R6", "R4", "R5") - assert vm.registers[6] == to_u16(-32768) - assert vm.flag_sign + assert vm.calculate_SUB(32767, to_u16(-1)) == to_u16(-32768) assert not vm.flag_carry assert vm.flag_overflow -def test_sub_with_big_positive_overflow(vm): - vm.registers[4] = 27500 - vm.registers[5] = to_u16(-7040) +def test_calculate_SUB_with_big_positive_overflow(vm): vm.flag_carry_block = True - vm.exec_sub("R6", "R4", "R5") - assert vm.registers[6] == to_u16(-30996) - assert vm.flag_sign + assert vm.calculate_SUB(27500, to_u16(-7040)) == to_u16(-30996) assert not vm.flag_carry assert vm.flag_overflow -def test_sub_with_max_positive_overflow(vm): - vm.registers[4] = 32767 - vm.registers[5] = to_u16(-32768) +def test_calculate_SUB_with_max_positive_overflow(vm): vm.flag_carry_block = True - vm.exec_sub("R6", "R4", "R5") - assert vm.registers[6] == to_u16(-1) - assert vm.flag_sign + assert vm.calculate_SUB(32767, to_u16(-32768)) == to_u16(-1) assert not vm.flag_carry assert vm.flag_overflow -def test_sub_with_implicit_borrow(vm): - vm.registers[2] = 17 - vm.registers[3] = 5 - vm.exec_sub("R1", "R2", "R3") - assert vm.registers[1] == 11 +def test_calculate_SUB_with_implicit_borrow(vm): + assert vm.calculate_SUB(17, 5) == 11 -def test_sub_with_no_carry_block_and_no_borrow(vm): - vm.registers[2] = to_u16(-64) - vm.registers[3] = 22 +def test_calculate_SUB_with_no_carry_block_and_no_borrow(vm): vm.flag_carry = True - vm.exec_sub("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-86) + assert vm.calculate_SUB(to_u16(-64), 22) == to_u16(-86) assert vm.flag_carry -def test_sub_overflow_from_borrow(vm): - vm.registers[1] = to_u16(-32767) - vm.registers[2] = 1 - vm.exec_sub("R3", "R1", "R2") - assert vm.registers[3] == 32767 - assert not vm.flag_sign +def test_calculate_SUB_overflow_from_borrow(vm): + assert vm.calculate_SUB(to_u16(-32767), 1) == 32767 assert vm.flag_carry assert vm.flag_overflow -def test_sub_overflow_takes_borrow_into_account(vm): - vm.registers[1] = 10 - vm.registers[2] = 11 - vm.exec_sub("R0", "R1", "R2") +def test_calculate_SUB_overflow_takes_borrow_into_account(vm): + vm.calculate_SUB(10, 11) assert not vm.flag_overflow -def test_sub_sets_carry_for_equal_operands(vm): +def test_calculate_SUB_sets_carry_for_equal_operands(vm): vm.flag_carry = True - vm.registers[1] = 12 - vm.registers[2] = 12 - vm.exec_sub("R3", "R1", "R2") - assert vm.registers[3] == 0 + assert vm.calculate_SUB(12, 12) == 0 assert vm.flag_carry -def test_sub_does_not_affect_R0(vm): - vm.registers[1] = 4 - vm.registers[2] = 3 - vm.exec_sub("R0", "R1", "R2") - assert vm.registers[0] == 0 +def test_calculate_MUL_with_small_positives(vm): + assert vm.calculate_MUL(4, 2) == 8 -def test_exec_one_delegates_to_mul(vm): - with patch("hera.vm.VirtualMachine.exec_mul") as mock_exec_mul: - vm.exec_one(Op("MUL", ["R1", "R2", "R3"])) - assert mock_exec_mul.call_count == 1 - assert mock_exec_mul.call_args == (("R1", "R2", "R3"), {}) +def test_calculate_MUL_with_large_positives(vm): + assert vm.calculate_MUL(4500, 3) == 13500 -def test_mul_with_small_positives(vm): - vm.registers[2] = 4 - vm.registers[3] = 2 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 8 +def test_calculate_MUL_with_small_negatives(vm): + assert vm.calculate_MUL(to_u16(-5), 3) == to_u16(-15) -def test_mul_with_large_positives(vm): - vm.registers[2] = 4500 - vm.registers[3] = 3 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 13500 +def test_calculate_MUL_with_large_negatives(vm): + assert vm.calculate_MUL(7, to_u16(-3100)) == to_u16(-21700) -def test_mul_with_small_negatives(vm): - vm.registers[2] = to_u16(-5) - vm.registers[3] = 3 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-15) - - -def test_mul_with_large_negatives(vm): - vm.registers[2] = 7 - vm.registers[3] = to_u16(-3100) - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-21700) - - -def test_mul_sets_zero_flag(vm): - vm.registers[2] = 7 - vm.registers[3] = 0 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 0 - assert vm.flag_zero - assert not vm.flag_sign - - -def test_mul_sets_sign_flag(vm): - vm.registers[2] = to_u16(-1) - vm.registers[3] = 17 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-17) - assert not vm.flag_zero - assert vm.flag_sign - - -def test_mul_with_signed_positive_overflow(vm): - vm.registers[2] = 17000 - vm.registers[3] = 3 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-14536) +def test_calculate_MUL_with_signed_positive_overflow(vm): + assert vm.calculate_MUL(17000, 3) == to_u16(-14536) assert not vm.flag_carry assert vm.flag_overflow -def test_mul_with_unsigned_positive_overflow(vm): - vm.registers[2] = 128 - vm.registers[3] = 749 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 30336 +def test_calculate_MUL_with_unsigned_positive_overflow(vm): + assert vm.calculate_MUL(128, 749) == 30336 assert vm.flag_carry assert vm.flag_overflow -def test_mul_with_signed_negative_overflow(vm): - vm.registers[2] = to_u16(-400) - vm.registers[3] = to_u16(-200) - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 14464 +def test_calculate_MUL_with_signed_negative_overflow(vm): + assert vm.calculate_MUL(to_u16(-400), to_u16(-200)) == 14464 assert vm.flag_carry assert vm.flag_overflow -def test_mul_ignores_carry_when_blocked(vm): +def test_calculate_MUL_ignores_carry_when_blocked(vm): vm.flag_carry_block = True vm.flag_carry = True - vm.registers[2] = 4 - vm.registers[3] = 12 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 48 + assert vm.calculate_MUL(4, 12) == 48 assert not vm.flag_carry -def test_mul_ignores_carry_when_not_blocked(vm): +def test_calculate_MUL_ignores_carry_when_not_blocked(vm): vm.flag_carry = True - vm.registers[2] = 4 - vm.registers[3] = 12 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 48 + assert vm.calculate_MUL(4, 12) == 48 assert not vm.flag_carry -def test_mul_produces_high_bits_when_sign_flag_is_on(vm): +def test_calculate_MUL_produces_high_bits_when_sign_flag_is_on(vm): vm.flag_sign = True - vm.registers[2] = 20000 - vm.registers[3] = 200 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 0b111101 - assert not vm.flag_sign + assert vm.calculate_MUL(20000, 200) == 0b111101 # TODO: Find out how the carry and overflow flags should be set. -def test_mul_with_sign_flag_and_negative_result(vm): +def test_calculate_MUL_with_sign_flag_and_negative_result(vm): vm.flag_sign = True - vm.registers[2] = 20000 - vm.registers[3] = to_u16(-200) - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 0b1111111111000010 - assert vm.flag_sign + assert vm.calculate_MUL(20000, to_u16(-200)) == 0b1111111111000010 -def test_mul_with_sign_flag_zero_result(vm): - vm.flag_sign = True - vm.registers[2] = 47 - vm.registers[3] = 0 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 0 - assert not vm.flag_sign - assert vm.flag_zero - - -def test_mul_ignores_sign_flag_when_carry_is_blocked(vm): +def test_calculate_MUL_ignores_sign_flag_when_carry_is_blocked(vm): vm.flag_sign = True vm.flag_carry_block = True - vm.registers[2] = 20000 - vm.registers[3] = 200 - vm.exec_mul("R1", "R2", "R3") - assert vm.registers[1] == 2304 - assert not vm.flag_sign + assert vm.calculate_MUL(20000, 200) == 2304 assert vm.flag_carry -def test_mul_increments_pc(vm): - vm.exec_mul("R1", "R2", "R3") - assert vm.pc == 1 - - -def test_mul_does_not_affect_R0(vm): - vm.registers[1] = 4 - vm.registers[2] = 3 - vm.exec_mul("R0", "R1", "R2") - assert vm.registers[0] == 0 - - -def test_exec_one_delegates_to_and(vm): - with patch("hera.vm.VirtualMachine.exec_and") as mock_exec_and: - vm.exec_one(Op("AND", ["R1", "R2", "R3"])) - assert mock_exec_and.call_count == 1 - assert mock_exec_and.call_args == (("R1", "R2", "R3"), {}) - - -def test_and_same_numbers(vm): - vm.registers[2] = 27 - vm.registers[3] = 27 - vm.exec_and("R1", "R2", "R3") - assert vm.registers[1] == 27 +def test_calculate_AND_same_numbers(vm): + assert vm.calculate_AND(27, 27) == 27 -def test_and_different_numbers(vm): - vm.registers[2] = 3 # 011 - vm.registers[3] = 6 # 110 - vm.exec_and("R1", "R2", "R3") - assert vm.registers[1] == 2 +def test_calculate_AND_different_numbers(vm): + assert vm.calculate_AND(0b011, 0b110) == 0b010 -def test_and_increments_pc(vm): - vm.exec_and("R0", "R1", "R2") - assert vm.pc == 1 - - -def test_and_big_numbers(vm): - vm.registers[2] = 62434 - vm.registers[3] = 17589 - vm.exec_and("R1", "R2", "R3") - assert vm.registers[1] == 16544 - - -def test_and_sets_zero_flag(vm): - vm.registers[2] = 82 - vm.registers[3] = 0 - vm.exec_and("R1", "R2", "R3") - assert vm.registers[1] == 0 - assert vm.flag_zero - assert not vm.flag_sign +def test_calculate_AND_big_numbers(vm): + assert vm.calculate_AND(62434, 17589) == 16544 -def test_and_sets_sign_flag(vm): - vm.registers[2] = to_u16(-1) - vm.registers[3] = to_u16(-37) - vm.exec_and("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-37) - assert not vm.flag_zero - assert vm.flag_sign - - -def test_and_does_not_set_other_flags(vm): - vm.registers[2] = to_u16(-1) - vm.registers[3] = to_u16(-1) - vm.exec_and("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-1) +def test_calculate_AND_does_not_set_other_flags(vm): + assert vm.calculate_AND(to_u16(-1), to_u16(-1)) == to_u16(-1) assert not vm.flag_carry assert not vm.flag_overflow -def test_and_does_not_clear_other_flags(vm): - vm.registers[2] = to_u16(-1) - vm.registers[3] = to_u16(-1) +def test_calculate_AND_does_not_clear_other_flags(vm): vm.flag_carry = True vm.flag_overflow = True - vm.exec_and("R1", "R2", "R3") + vm.calculate_AND(to_u16(-1), to_u16(-1)) assert vm.flag_carry assert vm.flag_overflow -def test_and_does_not_affect_R0(vm): - vm.registers[1] = 1 - vm.registers[2] = 1 - vm.exec_and("R0", "R1", "R2") - assert vm.registers[0] == 0 - - -def test_exec_one_delegates_to_or(vm): - with patch("hera.vm.VirtualMachine.exec_or") as mock_exec_or: - vm.exec_one(Op("OR", ["R1", "R2", "R3"])) - assert mock_exec_or.call_count == 1 - assert mock_exec_or.call_args == (("R1", "R2", "R3"), {}) - - -def test_or_same_numbers(vm): - vm.registers[2] = 27 - vm.registers[3] = 27 - vm.exec_or("R1", "R2", "R3") - assert vm.registers[1] == 27 - - -def test_or_different_numbers(vm): - vm.registers[2] = 3 # 011 - vm.registers[3] = 6 # 110 - vm.exec_or("R1", "R2", "R3") - assert vm.registers[1] == 7 - +def test_calculate_OR_same_numbers(vm): + assert vm.calculate_OR(27, 27) == 27 -def test_or_increments_pc(vm): - vm.exec_or("R0", "R1", "R2") - assert vm.pc == 1 +def test_calculate_OR_different_numbers(vm): + assert vm.calculate_OR(0b011, 0b110) == 0b111 -def test_or_big_numbers(vm): - vm.registers[2] = 8199 - vm.registers[3] = 762 - vm.exec_or("R1", "R2", "R3") - assert vm.registers[1] == 8959 +def test_calculate_OR_big_numbers(vm): + assert vm.calculate_OR(8199, 762) == 8959 -def test_or_sets_zero_flag(vm): - vm.registers[2] = 0 - vm.registers[3] = 0 - vm.exec_or("R1", "R2", "R3") - assert vm.registers[1] == 0 - assert vm.flag_zero - assert not vm.flag_sign - - -def test_or_sets_sign_flag(vm): - vm.registers[2] = to_u16(-1) - vm.registers[3] = to_u16(-37) - vm.exec_or("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-1) - assert not vm.flag_zero - assert vm.flag_sign - -def test_or_does_not_set_other_flags(vm): - vm.registers[2] = to_u16(-1) - vm.registers[3] = to_u16(-1) - vm.exec_or("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-1) +def test_calculate_OR_does_not_set_other_flags(vm): + assert vm.calculate_OR(to_u16(-1), to_u16(-1)) == to_u16(-1) assert not vm.flag_carry assert not vm.flag_overflow -def test_or_does_not_clear_other_flags(vm): - vm.registers[2] = to_u16(-1) - vm.registers[3] = to_u16(-1) +def test_calculate_OR_does_not_clear_other_flags(vm): vm.flag_carry = True vm.flag_overflow = True - vm.exec_or("R1", "R2", "R3") + vm.calculate_OR(to_u16(-1), to_u16(-1)) assert vm.flag_carry assert vm.flag_overflow -def test_or_does_not_affect_R0(vm): - vm.registers[1] = 1 - vm.registers[2] = 1 - vm.exec_or("R0", "R1", "R2") - assert vm.registers[0] == 0 - +def test_calculate_XOR_same_numbers(vm): + assert vm.calculate_XOR(27, 27) == 0 -def test_exec_one_delegates_to_xor(vm): - with patch("hera.vm.VirtualMachine.exec_xor") as mock_exec_xor: - vm.exec_one(Op("XOR", ["R1", "R2", "R3"])) - assert mock_exec_xor.call_count == 1 - assert mock_exec_xor.call_args == (("R1", "R2", "R3"), {}) - - -def test_xor_same_numbers(vm): - vm.registers[2] = 27 - vm.registers[3] = 27 - vm.exec_xor("R1", "R2", "R3") - assert vm.registers[1] == 0 +def test_calculate_XOR_different_numbers(vm): + assert vm.calculate_XOR(0b011, 0b110) == 0b101 -def test_xor_different_numbers(vm): - vm.registers[2] = 3 # 011 - vm.registers[3] = 6 # 110 - vm.exec_xor("R1", "R2", "R3") - assert vm.registers[1] == 5 +def test_calculate_XOR_big_numbers(vm): + assert vm.calculate_XOR(8199, 762) == 8957 -def test_xor_increments_pc(vm): - vm.exec_xor("R0", "R1", "R2") - assert vm.pc == 1 - -def test_xor_big_numbers(vm): - vm.registers[2] = 8199 - vm.registers[3] = 762 - vm.exec_xor("R1", "R2", "R3") - assert vm.registers[1] == 8957 - - -def test_xor_sets_zero_flag(vm): - vm.registers[2] = 0 - vm.registers[3] = 0 - vm.exec_xor("R1", "R2", "R3") - assert vm.registers[1] == 0 - assert vm.flag_zero - assert not vm.flag_sign - - -def test_xor_sets_sign_flag(vm): - vm.registers[2] = 0 - vm.registers[3] = to_u16(-37) - vm.exec_xor("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-37) - assert not vm.flag_zero - assert vm.flag_sign - - -def test_xor_does_not_set_other_flags(vm): - vm.registers[2] = 0 - vm.registers[3] = to_u16(-37) - vm.exec_xor("R1", "R2", "R3") - assert vm.registers[1] == to_u16(-37) +def test_calculate_XOR_does_not_set_other_flags(vm): + assert vm.calculate_XOR(0, to_u16(-37)) == to_u16(-37) assert not vm.flag_carry assert not vm.flag_overflow -def test_xor_does_not_clear_other_flags(vm): - vm.registers[2] = 0 - vm.registers[3] = to_u16(-37) +def test_calculate_XOR_does_not_clear_other_flags(vm): vm.flag_carry = True vm.flag_overflow = True - vm.exec_xor("R1", "R2", "R3") + vm.calculate_XOR(0, to_u16(-37)) assert vm.flag_carry assert vm.flag_overflow - - -def test_xor_does_not_affect_R0(vm): - vm.registers[1] = 1 - vm.registers[2] = 0 - vm.exec_xor("R0", "R1", "R2") - assert vm.registers[0] == 0 diff --git a/test/test_op/test_misc.py b/test/test_op/test_misc.py deleted file mode 100644 index ef9975b..0000000 --- a/test/test_op/test_misc.py +++ /dev/null @@ -1,14 +0,0 @@ -import pytest - -from hera.data import Op -from hera.vm import VirtualMachine - - -@pytest.fixture -def vm(): - return VirtualMachine() - - -def test_execute_unknown_instruction(vm): - with pytest.raises(RuntimeError): - vm.exec_one(Op("whatever", []))