def setup(self): """Init state.""" super().setup() self.ram = RandomAccessMemory(BYTE_SIZE, 256, 'big', is_protected=True) self.control_unit = ControlUnitV(WORD_SIZE, BYTE_SIZE, self.registers, self.ram, self.alu, WORD_SIZE) assert self.control_unit.opcodes == {0x00, 0x01, 0x02, 0x03, 0x04, 0x13, 0x14, 0x05, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x93, 0x94, 0x95, 0x96, 0x99}
class TestControlUnitV(TBCU2): """Test case for Model Machine Variable Control Unit.""" def setup(self): """Init state.""" super().setup() self.ram = RandomAccessMemory(BYTE_SIZE, 256, 'big', is_protected=True) self.control_unit = ControlUnitV(WORD_SIZE, BYTE_SIZE, self.registers, self.ram, self.alu, WORD_SIZE) assert self.control_unit.opcodes == {0x00, 0x01, 0x02, 0x03, 0x04, 0x13, 0x14, 0x05, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x93, 0x94, 0x95, 0x96, 0x99} def test_fetch_and_decode(self): """Right fetch and decode is a half of business.""" for opcode in set(range(2 ** BYTE_SIZE)) - self.control_unit.opcodes: with raises(ValueError): self.run_fetch(opcode, opcode, BYTE_SIZE) for opcode in ARITHMETIC_OPCODES | {OP_COMP, OP_MOVE}: self.control_unit.address1, self.control_unit.address2 = None, None self.run_fetch(opcode << 16 | 0x0203, opcode, 24) assert self.control_unit.address1 == 0x02 assert self.control_unit.address2 == 0x03 for opcode in CONDJUMP_OPCODES | {OP_JUMP}: self.control_unit.address1, self.control_unit.address2 = None, None self.run_fetch(opcode << 8 | 0x02, opcode, 16) assert self.control_unit.address1 == 0x02 assert self.control_unit.address2 is None for opcode in {OP_HALT}: self.control_unit.address1, self.control_unit.address2 = None, None self.run_fetch(opcode, opcode, 8) assert self.control_unit.address1 is None assert self.control_unit.address2 is None def test_load(self): """R1 := [A1], R2 := [A2].""" addr1, val1 = 5, 123456 addr2, val2 = 10, 654321 self.ram.put(addr1, val1, WORD_SIZE) self.ram.put(addr2, val2, WORD_SIZE) self.control_unit.address1 = addr1 self.control_unit.address2 = addr2 for opcode in ARITHMETIC_OPCODES | {OP_COMP}: self.registers.put.reset_mock() self.control_unit.opcode = opcode self.control_unit.load() self.registers.put.assert_has_calls([call("R1", val1, WORD_SIZE), call("R2", val2, WORD_SIZE)]) for opcode in {OP_MOVE}: self.registers.put.reset_mock() self.control_unit.opcode = opcode self.control_unit.load() self.registers.put.assert_called_once_with("R1", val2, WORD_SIZE) for opcode in CONDJUMP_OPCODES | {OP_JUMP}: self.registers.put.reset_mock() self.control_unit.opcode = opcode self.control_unit.load() self.registers.put.assert_called_once_with("ADDR", addr1, BYTE_SIZE) for opcode in {OP_HALT}: self.registers.put.reset_mock() self.control_unit.opcode = opcode self.control_unit.load() assert not self.registers.put.called def test_step(self): """Test step cycle.""" self.control_unit.registers = self.registers = RegisterMemory() self.registers.add_register('RI', WORD_SIZE) self.alu = ArithmeticLogicUnit(self.registers, self.control_unit.register_names, WORD_SIZE, BYTE_SIZE) self.control_unit.alu = self.alu self.ram.put(0x00, 0x01080c, 3 * BYTE_SIZE) self.ram.put(0x03, 0x050310, 3 * BYTE_SIZE) self.ram.put(0x06, 0x8614, 2 * BYTE_SIZE) self.ram.put(0x08, 12, WORD_SIZE) self.ram.put(0x0c, 10, WORD_SIZE) self.ram.put(0x10, 20, WORD_SIZE) self.ram.put(0x14, 0x99, BYTE_SIZE) self.registers.put("PC", 0, BYTE_SIZE) self.control_unit.step() assert self.ram.fetch(0x08, WORD_SIZE) == 22 assert self.registers.fetch("PC", BYTE_SIZE) == 0x03 assert self.control_unit.get_status() == RUNNING self.control_unit.step() assert self.ram.fetch(0x08, WORD_SIZE) == 22 assert self.registers.fetch("PC", BYTE_SIZE) == 0x06 assert self.control_unit.get_status() == RUNNING self.control_unit.step() assert self.registers.fetch("PC", BYTE_SIZE) == 0x14 assert self.control_unit.get_status() == RUNNING self.control_unit.step() assert self.registers.fetch("PC", BYTE_SIZE) == 0x15 assert self.control_unit.get_status() == HALTED def test_run(self): """Very simple program.""" self.control_unit.registers = self.registers = RegisterMemory() self.registers.add_register('RI', WORD_SIZE) self.alu = ArithmeticLogicUnit(self.registers, self.control_unit.register_names, WORD_SIZE, BYTE_SIZE) self.control_unit.alu = self.alu self.ram.put(0x00, 0x01080c, 3 * BYTE_SIZE) self.ram.put(0x03, 0x050310, 3 * BYTE_SIZE) self.ram.put(0x06, 0x8614, 2 * BYTE_SIZE) self.ram.put(0x08, 12, WORD_SIZE) self.ram.put(0x0c, 10, WORD_SIZE) self.ram.put(0x10, 20, WORD_SIZE) self.ram.put(0x14, 0x99, BYTE_SIZE) self.registers.put("PC", 0, BYTE_SIZE) self.control_unit.run() assert self.ram.fetch(0x08, WORD_SIZE) == 22 assert self.registers.fetch("PC", BYTE_SIZE) == 0x15 assert self.control_unit.get_status() == HALTED def test_minimal_run(self): """Minimal program.""" self.control_unit.registers = self.registers = RegisterMemory() self.registers.add_register('RI', WORD_SIZE) self.alu = ArithmeticLogicUnit(self.registers, self.control_unit.register_names, WORD_SIZE, BYTE_SIZE) self.control_unit.alu = self.alu self.ram.put(0x00, 0x99, BYTE_SIZE) self.registers.put("PC", 0, BYTE_SIZE) self.control_unit.run() assert self.registers.fetch("PC", BYTE_SIZE) == 0x01 assert self.control_unit.get_status() == HALTED