def setup(self): """Init state.""" self.registers = RegisterMemory() register_names = {"R1": "R1", "R2": "R2", "FLAGS": "FLAGS", "S": "S", "RES": "R1", "ADDR": "ADDR", "PC":"PC"} self.alu = ArithmeticLogicUnit(self.registers, register_names, BYTE_SIZE, WORD_SIZE) self.max_int = 2 ** (self.alu.operand_size - 1) self.min_int = -2 ** (self.alu.operand_size - 1) assert self.alu.registers is self.registers assert self.alu.operand_size == BYTE_SIZE assert self.alu.address_size == WORD_SIZE
def setup(self): """Init state.""" self.registers = RegisterMemory() self.registers.add_register('R1', WORD_SIZE) assert 'R1' in self.registers assert self.registers.fetch('R1', WORD_SIZE) == 0 self.registers.add_register('R2', WORD_SIZE) assert 'R2' in self.registers assert self.registers.fetch('R2', WORD_SIZE) == 0 self.registers.add_register('S', WORD_SIZE) assert 'S' in self.registers assert self.registers.fetch('S', WORD_SIZE) == 0 assert 'R3' not in self.registers assert 'R4' not in self.registers assert 0 not in self.registers
class TestArithmeticLogicUnit: """Test case for arithmetic logic unit.""" registers = None alu = None max_int, min_int = None, None def setup(self): """Init state.""" self.registers = RegisterMemory() register_names = {"R1": "R1", "R2": "R2", "FLAGS": "FLAGS", "S": "S", "RES": "R1", "ADDR": "ADDR", "PC":"PC"} self.alu = ArithmeticLogicUnit(self.registers, register_names, BYTE_SIZE, WORD_SIZE) self.max_int = 2 ** (self.alu.operand_size - 1) self.min_int = -2 ** (self.alu.operand_size - 1) assert self.alu.registers is self.registers assert self.alu.operand_size == BYTE_SIZE assert self.alu.address_size == WORD_SIZE def test_set_flags_negative(self): """Test set flags register algorithm with negative numbers.""" for i in range(4 * self.min_int, 0): self.registers.put('S', i % 2 ** BYTE_SIZE, BYTE_SIZE) self.alu.set_flags(i, i) if i == 4 * self.min_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF | ZF if 4 * self.min_int < i < 3 * self.min_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF if i == 3 * self.min_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF | SF if 3 * self.min_int < i < 2 * self.min_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF | SF if i == 2 * self.min_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF | ZF if 2 * self.min_int < i < self.min_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF if self.min_int <= i < 0: assert self.registers.fetch('FLAGS', BYTE_SIZE) == SF | CF def test_set_flags_positive(self): """Test set flags register algorithm with positive numbers.""" for i in range(0, 4 * self.max_int): self.registers.put('S', i % 2 ** BYTE_SIZE, BYTE_SIZE) self.alu.set_flags(i, i) if i == 0: assert self.registers.fetch('FLAGS', BYTE_SIZE) == ZF if 0 < i < self.max_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == 0 if self.max_int <= i < self.max_int * 2: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | SF if i == 2 * self.max_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF | ZF if 2 * self.max_int < i < 3 * self.max_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF if 3 * self.max_int <= i < 4 * self.max_int: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF | SF def test_get_ops(self): """Test interaction with registers.""" for i in range(self.min_int, self.max_int): self.registers.put('R1', i % 2 ** BYTE_SIZE, BYTE_SIZE) self.registers.put('R2', (-i - 1) % 2 ** BYTE_SIZE, BYTE_SIZE) signed = (Integer(i, BYTE_SIZE, True), Integer(-i-1, BYTE_SIZE, True)) unsigned = (Integer(i % 2 ** BYTE_SIZE, BYTE_SIZE, False), Integer((-i-1) % 2 ** BYTE_SIZE, BYTE_SIZE, False)) assert self.alu.get_signed_ops() == signed assert self.alu.get_unsigned_ops() == unsigned def test_add(self): """Add must set flags and calc right result.""" self.registers.put('R1', 0, BYTE_SIZE) self.registers.put('R2', 0, BYTE_SIZE) self.alu.add() assert self.registers.fetch('S', BYTE_SIZE) == 0 assert self.registers.fetch('FLAGS', BYTE_SIZE) == ZF for i in range(1, self.max_int): self.registers.put('R1', i, BYTE_SIZE) self.registers.put('R2', -i % 2 ** BYTE_SIZE, BYTE_SIZE) self.alu.add() assert self.registers.fetch('S', BYTE_SIZE) == 0 assert self.registers.fetch('FLAGS', BYTE_SIZE) == ZF | CF self.registers.put('R1', i, BYTE_SIZE) self.registers.put('R2', 10, BYTE_SIZE) self.alu.add() assert self.registers.fetch('S', BYTE_SIZE) == i + 10 if i < self.max_int - 10: assert self.registers.fetch('FLAGS', BYTE_SIZE) == 0 else: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | SF self.registers.put('R1', -i % 2 ** BYTE_SIZE, BYTE_SIZE) self.registers.put('R2', -10 % 2 ** BYTE_SIZE, BYTE_SIZE) self.alu.add() assert self.registers.fetch('S', BYTE_SIZE) == (-i - 10) % 2 ** BYTE_SIZE if -i >= self.min_int + 10: assert self.registers.fetch('FLAGS', BYTE_SIZE) == SF | CF else: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF def test_sub(self): """Substraction test.""" self.registers.put('R1', 0, BYTE_SIZE) self.registers.put('R2', 0, BYTE_SIZE) self.alu.sub() assert self.registers.fetch('S', BYTE_SIZE) == 0 assert self.registers.fetch('FLAGS', BYTE_SIZE) == ZF for i in range(1, self.max_int): self.registers.put('R1', i, BYTE_SIZE) self.registers.put('R2', i, BYTE_SIZE) self.alu.sub() assert self.registers.fetch('S', BYTE_SIZE) == 0 assert self.registers.fetch('FLAGS', BYTE_SIZE) == ZF self.registers.put('R1', i, BYTE_SIZE) self.registers.put('R2', 10, BYTE_SIZE) self.alu.sub() assert self.registers.fetch('S', BYTE_SIZE) == (i - 10) % 2 ** BYTE_SIZE if i < 10: assert self.registers.fetch('FLAGS', BYTE_SIZE) == CF | SF elif i == 10: assert self.registers.fetch('FLAGS', BYTE_SIZE) == ZF else: assert self.registers.fetch('FLAGS', BYTE_SIZE) == 0 self.registers.put('R1', -i % 2 ** BYTE_SIZE, BYTE_SIZE) self.registers.put('R2', 10, BYTE_SIZE) self.alu.sub() assert self.registers.fetch('S', BYTE_SIZE) == (-i - 10) % 2 ** BYTE_SIZE if -i >= self.min_int + 10: assert self.registers.fetch('FLAGS', BYTE_SIZE) == SF else: assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF def test_mul(self): """Multiplication test.""" self.registers.put('R1', 10, BYTE_SIZE) self.registers.put('R2', 15, BYTE_SIZE) self.alu.umul() assert self.registers.fetch('S', BYTE_SIZE) == 150 assert self.registers.fetch('FLAGS', BYTE_SIZE) == SF | OF self.alu.smul() assert self.registers.fetch('S', BYTE_SIZE) == 150 assert self.registers.fetch('FLAGS', BYTE_SIZE) == SF | OF self.registers.put('R1', 25, BYTE_SIZE) self.alu.umul() assert self.registers.fetch('S', BYTE_SIZE) == (25 * 15) % 2 ** BYTE_SIZE assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF self.registers.put('R1', -2 % 2 ** BYTE_SIZE, BYTE_SIZE) self.alu.smul() assert self.registers.fetch('S', BYTE_SIZE) == -30 % 2 ** BYTE_SIZE assert self.registers.fetch('FLAGS', BYTE_SIZE) == SF | CF self.registers.put('R1', -10 % 2 ** BYTE_SIZE, BYTE_SIZE) self.alu.smul() assert self.registers.fetch('S', BYTE_SIZE) == -150 % 2 ** BYTE_SIZE assert self.registers.fetch('FLAGS', BYTE_SIZE) == OF | CF def test_move(self): """Test move command.""" self.registers.put("R1", 10, BYTE_SIZE) self.alu.move() assert self.registers.fetch("S", BYTE_SIZE) == 10 def test_swap(self): """Test move command.""" self.registers.put("S", 20, BYTE_SIZE) self.registers.put("R1", 10, BYTE_SIZE) self.alu.swap() assert self.registers.fetch("S", BYTE_SIZE) == 10 assert self.registers.fetch("R1", BYTE_SIZE) == 20 def test_divmod(self): """Division test.""" first, second = 27, 5 div, mod = first // second, first % second self.registers.put('R1', first, BYTE_SIZE) self.registers.put('R2', second, BYTE_SIZE) self.alu.udiv() assert self.registers.fetch('S', BYTE_SIZE) == div assert self.registers.fetch('FLAGS', BYTE_SIZE) == 0 self.alu.umod() assert self.registers.fetch('S', BYTE_SIZE) == mod assert self.registers.fetch('FLAGS', BYTE_SIZE) == 0 self.alu.sdiv() assert self.registers.fetch('S', BYTE_SIZE) == div assert self.registers.fetch('FLAGS', BYTE_SIZE) == 0 self.alu.smod() assert self.registers.fetch('S', BYTE_SIZE) == mod assert self.registers.fetch('FLAGS', BYTE_SIZE) == 0 self.alu.sdivmod() assert self.registers.fetch('S', BYTE_SIZE) == div assert self.registers.fetch('R1', BYTE_SIZE) == mod assert self.registers.fetch('FLAGS', BYTE_SIZE) == 0 self.registers.put('R1', first, BYTE_SIZE) self.alu.udivmod() assert self.registers.fetch('S', BYTE_SIZE) == div assert self.registers.fetch('R1', BYTE_SIZE) == mod assert self.registers.fetch('FLAGS', BYTE_SIZE) == 0 first = -27 % 2 ** BYTE_SIZE div, mod = -5 % 2 ** BYTE_SIZE, -2 % 2 ** BYTE_SIZE self.registers.put('R1', first, BYTE_SIZE) self.alu.sdiv() assert self.registers.fetch('S', BYTE_SIZE) == div assert self.registers.fetch('FLAGS', BYTE_SIZE) == SF | CF self.alu.smod() assert self.registers.fetch('S', BYTE_SIZE) == mod assert self.registers.fetch('FLAGS', BYTE_SIZE) == SF | CF self.alu.sdivmod() assert self.registers.fetch('S', BYTE_SIZE) == div assert self.registers.fetch('R1', BYTE_SIZE) == mod assert self.registers.fetch('FLAGS', BYTE_SIZE) == SF | CF def test_jump(self): """Test jump instruction.""" self.registers.put("ADDR", 15, WORD_SIZE) self.alu.jump() assert self.registers.fetch("ADDR", WORD_SIZE) == 15 def run_cond_jump(self, should_jump, first, second, *vargs, **kvargs): """Run one conditional jump test.""" self.registers.put("R1", first % 2 ** BYTE_SIZE, BYTE_SIZE) self.registers.put("R2", second % 2 ** BYTE_SIZE, BYTE_SIZE) self.alu.sub() self.registers.put("PC", 1, WORD_SIZE) self.registers.put("ADDR", 2, WORD_SIZE) self.alu.cond_jump(*vargs, **kvargs) if should_jump: assert self.registers.fetch("PC", WORD_SIZE) == 2 else: assert self.registers.fetch("PC", WORD_SIZE) == 1 def test_cond_jump(self): """Test for conditional jumps.""" for signed in (False, True): self.run_cond_jump(False, 5, 10, signed, EQUAL, equal=True) self.run_cond_jump(True, 10, 10, signed, EQUAL, equal=True) self.run_cond_jump(False, 15, 10, signed, EQUAL, equal=True) self.run_cond_jump(True, 5, 10, signed, EQUAL, equal=False) self.run_cond_jump(False, 10, 10, signed, EQUAL, equal=False) self.run_cond_jump(True, 15, 10, signed, EQUAL, equal=False) self.run_cond_jump(True, 5, 10, signed, LESS, equal=False) self.run_cond_jump(False, 10, 10, signed, LESS, equal=False) self.run_cond_jump(False, 15, 10, signed, LESS, equal=False) self.run_cond_jump(True, 5, 10, signed, LESS, equal=True) self.run_cond_jump(True, 10, 10, signed, LESS, equal=True) self.run_cond_jump(False, 15, 10, signed, LESS, equal=True) self.run_cond_jump(False, 5, 10, signed, GREATER, equal=False) self.run_cond_jump(False, 10, 10, signed, GREATER, equal=False) self.run_cond_jump(True, 15, 10, signed, GREATER, equal=False) self.run_cond_jump(False, 5, 10, signed, GREATER, equal=True) self.run_cond_jump(True, 10, 10, signed, GREATER, equal=True) self.run_cond_jump(True, 15, 10, signed, GREATER, equal=True) self.run_cond_jump(False, -10, 10, False, LESS, equal=False) self.run_cond_jump(False, -10, 10, False, LESS, equal=True) self.run_cond_jump(True, -10, 10, True, LESS, equal=False) self.run_cond_jump(True, -10, 10, True, LESS, equal=True) self.run_cond_jump(True, 10, -10, False, LESS, equal=False) self.run_cond_jump(True, 10, -10, False, LESS, equal=True) self.run_cond_jump(False, 10, -10, True, LESS, equal=False) self.run_cond_jump(False, 10, -10, True, LESS, equal=True) self.run_cond_jump(True, -10, 10, False, GREATER, equal=False) self.run_cond_jump(True, -10, 10, False, GREATER, equal=True) self.run_cond_jump(False, -10, 10, True, GREATER, equal=False) self.run_cond_jump(False, -10, 10, True, GREATER, equal=True) self.run_cond_jump(False, 10, -10, False, GREATER, equal=False) self.run_cond_jump(False, 10, -10, False, GREATER, equal=True) self.run_cond_jump(True, 10, -10, True, GREATER, equal=False) self.run_cond_jump(True, 10, -10, True, GREATER, equal=True) def test_halt(self): """Very easy and important test.""" assert self.registers.fetch('FLAGS', BYTE_SIZE) & HALT == 0 self.alu.halt() assert self.registers.fetch('FLAGS', BYTE_SIZE) & HALT != 0
class TestRegisterMemory: """Test case for RegisterMemory.""" registers = None def setup(self): """Init state.""" self.registers = RegisterMemory() self.registers.add_register('R1', WORD_SIZE) assert 'R1' in self.registers assert self.registers.fetch('R1', WORD_SIZE) == 0 self.registers.add_register('R2', WORD_SIZE) assert 'R2' in self.registers assert self.registers.fetch('R2', WORD_SIZE) == 0 self.registers.add_register('S', WORD_SIZE) assert 'S' in self.registers assert self.registers.fetch('S', WORD_SIZE) == 0 assert 'R3' not in self.registers assert 'R4' not in self.registers assert 0 not in self.registers def test_check_address(self): """Should raise an error for undefined registers.""" self.registers.check_address('R1') self.registers.check_address('R2') self.registers.check_address('S') with raises(KeyError): self.registers.check_address('R3') with raises(KeyError): self.registers.check_address('R4') with raises(KeyError): self.registers.check_address(0) def test_add_register(self): """Register with exist name should be addable.""" self.registers.put('R1', 10, WORD_SIZE) self.registers.add_register('R1', WORD_SIZE) assert self.registers.fetch('R1', WORD_SIZE) == 10 with raises(KeyError): self.registers.add_register('R1', WORD_SIZE + 1) with raises(KeyError): self.registers.fetch('R3', WORD_SIZE) self.registers.add_register('R3', WORD_SIZE) assert self.registers.fetch('R3', WORD_SIZE) == 0 self.registers.put('R3', 10, WORD_SIZE) assert self.registers.fetch('R3', WORD_SIZE) == 10 def test_setitem(self): """Setitem can raise an error.""" with raises(KeyError): self.registers[0] = 5 with raises(KeyError): self.registers.__getitem__(0) with raises(KeyError): self.registers['R3'] = 5 with raises(KeyError): self.registers.__getitem__('R3') self.registers['R1'] = 5 assert self.registers['R1'] == 5 with raises(ValueError): self.registers['R2'] = 2 ** self.registers.word_size assert self.registers['R2'] == 0 def test_fetch_and_put(self): """Test main method to read and write.""" with raises(KeyError): self.registers.fetch(0, WORD_SIZE) with raises(KeyError): self.registers.put('R3', 5, WORD_SIZE + 1) self.registers.put('R1', 5, WORD_SIZE) assert self.registers.fetch('R1', WORD_SIZE) == 5 with raises(ValueError): self.registers.put('R2', 2 ** WORD_SIZE, WORD_SIZE) with raises(ValueError): self.registers.put('R2', -10, WORD_SIZE) assert self.registers.fetch('R2', WORD_SIZE) == 0 with raises(KeyError): self.registers.fetch('R1', WORD_SIZE + 1) with raises(KeyError): self.registers.fetch('R1', WORD_SIZE * 2)