Beispiel #1
0
 def setup(self):
     """Init state."""
     self.ram = RandomAccessMemory(WORD_SIZE, 512, endianess='big')
     assert self.ram.word_size == WORD_SIZE
     assert self.ram.memory_size == 512
     assert len(self.ram) == 512
     assert self.ram.is_protected is True
Beispiel #2
0
    def test_fetch(self):
        """Fetch is basic operation of transfer data."""
        for i in range(5, 9):
            self.ram[i] = i
            assert self.ram.fetch(i, WORD_SIZE) == i
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                0x00000005000000060000000700000008)
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                big_endian_decode([5, 6, 7, 8], WORD_SIZE))

        self.ram[5] = 0
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                big_endian_decode([0, 6, 7, 8], WORD_SIZE))
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                0x00000000000000060000000700000008)

        with raises(KeyError):
            self.ram.fetch(5, 4 * WORD_SIZE - 1)
        with raises(KeyError):
            self.ram.fetch(4, 4 * WORD_SIZE)

        self.ram = RandomAccessMemory(WORD_SIZE, 512, endianess="little")
        for i in range(5, 9):
            self.ram[i] = i
            assert self.ram.fetch(i, WORD_SIZE) == i
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                0x00000008000000070000000600000005)
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                little_endian_decode([5, 6, 7, 8], WORD_SIZE))
Beispiel #3
0
 def test_not_protected_getitem(self):
     """Test if programmer can shut in his leg."""
     self.ram = RandomAccessMemory(WORD_SIZE, 512, 'big', is_protected=False)
     for i in range(len(self.ram)):
         assert self.ram[i] == 0
     for i in range(len(self.ram), 2 * len(self.ram)):
         with raises(KeyError):
             self.ram.__getitem__(i)
 def setup(self):
     """Init state."""
     self.ram = RandomAccessMemory(WORD_SIZE, 256, 'big')
     self.registers = create_autospec(RegisterMemory, True, True)
     self.alu = create_autospec(ArithmeticLogicUnit, True, True)
     self.control_unit = ControlUnit(WORD_SIZE,
                                     BYTE_SIZE,
                                     self.registers,
                                     self.ram,
                                     self.alu,
                                     WORD_SIZE)
     self.test_const()
 def setup(self):
     """Init state."""
     super().setup()
     self.ram = RandomAccessMemory(WORD_SIZE, 256, 'big')
     self.control_unit = ControlUnit3(WORD_SIZE,
                                      BYTE_SIZE,
                                      self.registers,
                                      self.ram,
                                      self.alu,
                                      WORD_SIZE)
     assert self.control_unit.opcodes == {0x00, 0x01, 0x02, 0x03, 0x04,
                                          0x13, 0x14,
                                          0x80, 0x81, 0x82,
                                          0x83, 0x84, 0x85, 0x86,
                                          0x93, 0x94, 0x95, 0x96,
                                          0x99}
Beispiel #6
0
    def test_put(self):
        """Test put operation."""
        value_list = [0, 6, 7, 0]
        value = big_endian_decode(value_list, WORD_SIZE)
        self.ram.put(5, value, 4 * WORD_SIZE)
        with raises(ValueError):
            self.ram.put(5, 2 ** WORD_SIZE, WORD_SIZE)
        self.ram.put(4, 4, WORD_SIZE)
        for i in range(5, 9):
            assert self.ram[i] == value_list[i - 5]

        self.ram = RandomAccessMemory(WORD_SIZE, 512, endianess="little")
        value = little_endian_decode(value_list, WORD_SIZE)
        self.ram.put(5, value, 4 * WORD_SIZE)
        for i in range(5, 9):
            assert self.ram[i] == value_list[i - 5]
 def setup(self):
     """Init state."""
     super().setup()
     self.ram = RandomAccessMemory(HALF_SIZE, 2 ** HALF_SIZE, 'big', is_protected=True)
     self.control_unit = ControlUnitM(WORD_SIZE,
                                      HALF_SIZE,
                                      self.registers,
                                      self.ram,
                                      self.alu,
                                      WORD_SIZE)
     self.operand_size = WORD_SIZE
     self.address_size = 2 * BYTE_SIZE
     assert self.control_unit.opcodes == {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
                                          0x10, 0x11, 0x13, 0x14,
                                          0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
                                          0x33, 0x34,
                                          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
class TestControlUnitM(TBCU2):

    """Test case for Address Modification Model Machine Control Unit."""

    def setup(self):
        """Init state."""
        super().setup()
        self.ram = RandomAccessMemory(HALF_SIZE, 2 ** HALF_SIZE, 'big', is_protected=True)
        self.control_unit = ControlUnitM(WORD_SIZE,
                                         HALF_SIZE,
                                         self.registers,
                                         self.ram,
                                         self.alu,
                                         WORD_SIZE)
        self.operand_size = WORD_SIZE
        self.address_size = 2 * BYTE_SIZE
        assert self.control_unit.opcodes == {0x00, 0x01, 0x02, 0x03, 0x04, 0x05,
                                             0x10, 0x11, 0x13, 0x14,
                                             0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
                                             0x33, 0x34,
                                             0x80, 0x81, 0x82,
                                             0x83, 0x84, 0x85, 0x86,
                                             0x93, 0x94, 0x95, 0x96,
                                             0x99}

    def test_const(self):
        super().test_const()
        assert self.control_unit.OPCODES["addr"] == OP_ADDR
        assert self.control_unit.OPCODES["rmove"] == OP_RMOVE
        assert self.control_unit.OPCODES["radd"] == OP_RADD
        assert self.control_unit.OPCODES["rsub"] == OP_RSUB
        assert self.control_unit.OPCODES["rsmul"] == OP_RSMUL
        assert self.control_unit.OPCODES["rsdivmod"] == OP_RSDIVMOD
        assert self.control_unit.OPCODES["rcomp"] == OP_RCOMP
        assert self.control_unit.OPCODES["rumul"] == OP_RUMUL
        assert self.control_unit.OPCODES["rudivmod"] == OP_RUDIVMOD

    def run_fetch(self, value, opcode, instruction_size, r2=True):
        """Run one fetch test."""
        address1 = 10
        address2 = 42
        self.ram.put(address1, value, instruction_size)
        increment = instruction_size // self.ram.word_size

        # pylint: disable=no-member
        self.registers.fetch.reset_mock()
        self.registers.put.reset_mock()

        def get_register(name, size):
            """Get PC."""
            if name == "PC":
                assert size == 2 * BYTE_SIZE
                return address1
            elif name == "R2":
                assert size == WORD_SIZE
                return address2
            else:
                raise KeyError()

        self.registers.fetch.side_effect = get_register

        self.control_unit.fetch_and_decode()
        if r2:
            self.registers.fetch.assert_has_calls([call("PC", 2 * BYTE_SIZE),
                                                   call("R2", WORD_SIZE)])
        else:
            self.registers.fetch.assert_any_call("PC", 2 * BYTE_SIZE)
        self.registers.put.assert_has_calls([call("RI", value, WORD_SIZE),
                                             call("PC", address1 + increment, 2 * BYTE_SIZE)])
        assert self.control_unit.opcode == opcode

    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 << BYTE_SIZE, opcode, 2 * BYTE_SIZE)

        for opcode in ARITHMETIC_OPCODES | JUMP_OPCODES | {OP_COMP, OP_LOAD, OP_ADDR, OP_STORE}:
            self.control_unit.register1 = None
            self.control_unit.register2 = None
            self.control_unit.address = None

            self.run_fetch(opcode << 24 | 0x120014, opcode, 32)

            assert self.control_unit.register1 == 'R1'
            assert self.control_unit.register2 is None
            assert self.control_unit.address == 0x14 + 42

        for opcode in REGISTER_OPCODES:
            self.control_unit.register1 = None
            self.control_unit.register2 = None
            self.control_unit.address = None

            self.run_fetch(opcode << 8 | 0x12, opcode, 16, r2=False)

            assert self.control_unit.register1 == 'R1'
            assert self.control_unit.register2 == 'R2'
            assert self.control_unit.address is None

        for opcode in {OP_HALT}:
            self.control_unit.register1 = None
            self.control_unit.register2 = None
            self.control_unit.address = None

            self.run_fetch(opcode << 8 | 0x12, opcode, 16, r2=False)


            assert self.control_unit.register1 is None
            assert self.control_unit.register2 is None
            assert self.control_unit.address is None

    def test_load(self):
        """R1 := [A1], R2 := [A2]."""
        register1, val1 = 'R3', 123456
        register2, val2 = 'R4', 654321
        address, val3 = 10, 111111

        def get_register(name, size):
            """Get PC."""
            assert size == WORD_SIZE
            if name == register1:
                return val1
            elif name == register2:
                return val2
            else:
                raise KeyError()

        self.registers.fetch.side_effect = get_register
        self.control_unit.address = address
        self.control_unit.register1 = register1
        self.control_unit.register2 = register2
        self.ram.put(address, val3, WORD_SIZE)

        # pylint: disable=no-member
        for opcode in ARITHMETIC_OPCODES | {OP_LOAD, OP_COMP}:
            self.registers.fetch.reset_mock()
            self.registers.put.reset_mock()

            self.control_unit.opcode = opcode
            self.control_unit.load()
            self.registers.fetch.assert_called_once_with(register1, WORD_SIZE)
            self.registers.put.assert_has_calls([call("S", val1, WORD_SIZE),
                                                 call("RZ", val3, WORD_SIZE)])

        for opcode in {OP_STORE}:
            self.registers.fetch.reset_mock()
            self.registers.put.reset_mock()

            self.control_unit.opcode = opcode
            self.control_unit.load()
            self.registers.fetch.assert_called_once_with(register1, WORD_SIZE)
            self.registers.put.assert_called_once_with("S", val1, WORD_SIZE)

        for opcode in REGISTER_OPCODES:
            self.registers.fetch.reset_mock()
            self.registers.put.reset_mock()

            self.control_unit.opcode = opcode
            self.control_unit.load()
            self.registers.fetch.assert_has_calls([call(register1, WORD_SIZE),
                                                   call(register2, WORD_SIZE)])
            self.registers.put.assert_has_calls([call("S", val1, WORD_SIZE),
                                                 call("RZ", val2, WORD_SIZE)])

        for opcode in {OP_ADDR}:
            self.registers.fetch.reset_mock()
            self.registers.put.reset_mock()

            self.control_unit.opcode = opcode
            self.control_unit.load()
            assert not self.registers.fetch.called
            self.registers.put.assert_called_once_with("S", address, WORD_SIZE)

        for opcode in CONDJUMP_OPCODES | {OP_JUMP}:
            self.registers.fetch.reset_mock()
            self.registers.put.reset_mock()

            self.control_unit.opcode = opcode
            self.control_unit.load()

            assert not self.registers.fetch.called
            self.registers.put.assert_called_once_with("ADDR", address, 2 * BYTE_SIZE)

        for opcode in {OP_HALT}:
            self.registers.fetch.reset_mock()
            self.registers.put.reset_mock()

            self.control_unit.opcode = opcode

            self.control_unit.load()
            assert not self.registers.fetch.called
            assert not self.registers.put.called

    def test_basic_execute(self, should_move=None):
        """Test basic operations."""
        super().test_basic_execute(should_move=should_move)

        # pylint: disable=no-member
        self.control_unit.opcode = OP_MOVE
        self.alu.move.reset_mock()
        self.control_unit.execute()
        self.alu.move.assert_called_once_with('R2', 'S')

        self.control_unit.opcode = OP_ADDR
        self.alu.move.reset_mock()
        self.control_unit.execute()
        assert not self.alu.move.called

    def run_write_back(self, should, opcode):
        """Run write back method for specific opcode."""

        print(hex(opcode), should)

        register1, next_register1, register2 = 'R5', 'R6', 'R8'
        res_register1, val1 = 'S', 123456
        res_register2, val2 = 'RZ', 654321
        address, canary = 10, 0

        def get_register(name, size):
            """Get PC."""
            assert size == self.operand_size
            if name == res_register1:
                return val1
            elif name == res_register2:
                return val2
            else:
                raise KeyError()

        self.registers.fetch.side_effect = get_register
        self.control_unit.address = address
        self.control_unit.register1 = register1
        self.control_unit.register2 = register2
        self.ram.put(address, canary, self.operand_size)

        # pylint: disable=no-member
        self.registers.fetch.reset_mock()
        self.registers.put.reset_mock()

        self.control_unit.opcode = opcode
        self.control_unit.write_back()

        if should == 'two_registers':
            self.registers.fetch.assert_has_calls([call(res_register1, self.operand_size),
                                                   call(res_register2, self.operand_size)])
            self.registers.put.assert_has_calls([call(register1, val1, self.operand_size),
                                                 call(next_register1, val2, self.operand_size)])
            assert self.ram.fetch(address, self.operand_size) == canary

        elif should == 'register':
            self.registers.fetch.assert_called_once_with(res_register1, self.operand_size)
            self.registers.put.assert_called_once_with(register1, val1, self.operand_size)
            assert self.ram.fetch(address, self.operand_size) == canary

        elif should == 'memory':
            self.registers.fetch.assert_called_once_with(res_register1, self.operand_size)
            assert not self.registers.put.called
            assert self.ram.fetch(address, self.operand_size) == val1

        else:
            assert not self.registers.fetch.called
            assert not self.registers.put.called
            assert self.ram.fetch(address, self.operand_size) == canary

    def test_write_back(self):
        """Test write back result to the memory."""
        for opcode in {OP_SDIVMOD, OP_UDIVMOD}:
            self.run_write_back('two_registers', opcode)

        for opcode in (ARITHMETIC_OPCODES | {OP_ADDR, OP_LOAD}) - \
                      {OP_SDIVMOD, OP_UDIVMOD}:
            self.run_write_back('register', opcode)

        for opcode in {OP_STORE}:
            self.run_write_back('memory', opcode)

        for opcode in (CONDJUMP_OPCODES |
                       {OP_HALT, OP_JUMP, OP_COMP}):
            self.run_write_back('nothing', opcode)

    def test_step(self):
        """Test step cycle."""
        self.control_unit.registers = self.registers = RegisterMemory()
        for register in {'RI', 'RZ', 'S', 'R0', 'R1', 'R2', 'R3', 'R4',
                         'R5', 'R6', 'R7', 'R8', 'R9', 'RA', 'RB', 'RC',
                         'RD', 'RE', 'RF'}:
            self.registers.add_register(register, self.operand_size)
        self.alu = ArithmeticLogicUnit(self.registers,
                                       self.control_unit.register_names,
                                       self.operand_size,
                                       self.address_size)
        self.control_unit.alu = self.alu

        canary = 0
        self.ram.put(0x0000, 0x00000100, WORD_SIZE)
        self.ram.put(0x0002, 0x0300000C, WORD_SIZE)
        self.ram.put(0x0004, 0x0400000E, WORD_SIZE)
        self.ram.put(0x0006, 0x02100102, WORD_SIZE)
        self.ram.put(0x0008, 0x2311, 2 * BYTE_SIZE)
        self.ram.put(0x0009, 0x10100104, WORD_SIZE)
        self.ram.put(0x000B, 0x9900, 2 * BYTE_SIZE)
        self.ram.put(0x000C, 0xffffffeb, WORD_SIZE)
        self.ram.put(0x000E, 0x00000032, WORD_SIZE)
        self.ram.put(0x0100, -123 % 2 ** WORD_SIZE, WORD_SIZE)
        self.ram.put(0x0102, 456, WORD_SIZE)
        self.ram.put(0x0104, canary, WORD_SIZE)
        self.registers.put("PC", 0, 2 * BYTE_SIZE)

        self.control_unit.step()
        assert self.registers.fetch("R0", WORD_SIZE) == -123 % 2 ** WORD_SIZE
        assert self.registers.fetch("R1", WORD_SIZE) == 0
        assert self.registers.fetch("PC", 2 * BYTE_SIZE) == 0x02
        assert self.ram.fetch(0x0104, WORD_SIZE) == canary
        assert self.control_unit.get_status() == RUNNING

        self.control_unit.step()
        assert self.registers.fetch("R0", WORD_SIZE) == (21 * 123)
        assert self.registers.fetch("R1", WORD_SIZE) == 0
        assert self.registers.fetch("PC", 2 * BYTE_SIZE) == 0x04
        assert self.ram.fetch(0x0104, WORD_SIZE) == canary
        assert self.control_unit.get_status() == RUNNING

        self.control_unit.step()
        assert self.registers.fetch("R0", WORD_SIZE) == (21 * 123) // 50
        x = 21 * 123 % 50
        assert self.registers.fetch("R1", WORD_SIZE) == x
        assert self.registers.fetch("PC", 2 * BYTE_SIZE) == 0x06
        assert self.ram.fetch(0x0104, WORD_SIZE) == canary
        assert self.control_unit.get_status() == RUNNING

        self.control_unit.step()
        assert self.registers.fetch("R0", WORD_SIZE) == (21 * 123) // 50
        assert self.registers.fetch("R1", WORD_SIZE) == (x - 456) % 2 ** WORD_SIZE
        assert self.registers.fetch("PC", 2 * BYTE_SIZE) == 0x08
        assert self.ram.fetch(0x0104, WORD_SIZE) == canary
        assert self.control_unit.get_status() == RUNNING

        self.control_unit.step()
        assert self.registers.fetch("R0", WORD_SIZE) == (21 * 123) // 50
        assert self.registers.fetch("R1", WORD_SIZE) == (x - 456) ** 2
        assert self.registers.fetch("PC", 2 * BYTE_SIZE) == 0x09
        assert self.ram.fetch(0x0104, WORD_SIZE) == canary
        assert self.control_unit.get_status() == RUNNING

        self.control_unit.step()
        assert self.registers.fetch("R0", WORD_SIZE) == (21 * 123) // 50
        assert self.registers.fetch("R1", WORD_SIZE) == (x - 456) ** 2
        assert self.registers.fetch("PC", 2 * BYTE_SIZE) == 0x0b
        assert self.ram.fetch(0x0104, WORD_SIZE) == (x - 456) ** 2
        assert self.control_unit.get_status() == RUNNING

        self.control_unit.step()
        assert self.registers.fetch("R0", WORD_SIZE) == (21 * 123) // 50
        assert self.registers.fetch("R1", WORD_SIZE) == (x - 456) ** 2
        assert self.registers.fetch("PC", 2 * BYTE_SIZE) == 0x0C
        assert self.control_unit.get_status() == HALTED

    def test_run(self):
        """Very simple program."""
        self.control_unit.registers = self.registers = RegisterMemory()
        for register in {'RI', 'RZ', 'S', 'R0', 'R1', 'R2', 'R3', 'R4', 'R5', 'R6', 'R7', 'R8', 'R9', 'RA', 'RB', 'RC', 'RD', 'RE', 'RF'}:
            self.registers.add_register(register, self.operand_size)

        self.alu = ArithmeticLogicUnit(self.registers,
                                       self.control_unit.register_names,
                                       self.operand_size,
                                       self.address_size)
        self.control_unit.alu = self.alu

        self.ram.put(0x0000, 0x00000100, WORD_SIZE)
        self.ram.put(0x0002, 0x0300000C, WORD_SIZE)
        self.ram.put(0x0004, 0x0400000E, WORD_SIZE)
        self.ram.put(0x0006, 0x02100102, WORD_SIZE)
        self.ram.put(0x0008, 0x2311, 2 * BYTE_SIZE)
        self.ram.put(0x0009, 0x10100104, WORD_SIZE)
        self.ram.put(0x000B, 0x9900, 2 * BYTE_SIZE)
        self.ram.put(0x000C, 0xffffffeb, WORD_SIZE)
        self.ram.put(0x000E, 0x00000032, WORD_SIZE)
        self.ram.put(0x0100, 0xffffff85, WORD_SIZE)
        self.ram.put(0x0102, 0x000001c8, WORD_SIZE)
        self.registers.put("PC", 0, 2 * BYTE_SIZE)

        self.control_unit.run()
        assert self.ram.fetch(0x0104, WORD_SIZE) == 178929
        assert self.registers.fetch("PC", 2 * BYTE_SIZE) == 0x000C
        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', self.operand_size)

        self.alu = ArithmeticLogicUnit(self.registers,
                                       self.control_unit.register_names,
                                       self.operand_size,
                                       self.address_size)
        self.control_unit.alu = self.alu

        self.ram.put(0x00, 0x9900, 2 * BYTE_SIZE)
        self.registers.put("PC", 0, 2 * BYTE_SIZE)

        self.control_unit.run()
        assert self.registers.fetch("PC", 2 * BYTE_SIZE) == 0x01
        assert self.control_unit.get_status() == HALTED
class TestControlUnit:

    """Test case for abstract bordachenkova control unit."""

    ram = None
    registers = None
    alu = None
    control_unit = None

    arithmetic_opcodes = None
    condjump_opcodes = None

    ir_size = 32
    operand_size = WORD_SIZE
    address_size = BYTE_SIZE

    def setup(self):
        """Init state."""
        self.ram = RandomAccessMemory(WORD_SIZE, 256, 'big')
        self.registers = create_autospec(RegisterMemory, True, True)
        self.alu = create_autospec(ArithmeticLogicUnit, True, True)
        self.control_unit = ControlUnit(WORD_SIZE,
                                        BYTE_SIZE,
                                        self.registers,
                                        self.ram,
                                        self.alu,
                                        WORD_SIZE)
        self.test_const()

    def test_const(self):
        """Test internal constants."""
        assert isinstance(self.control_unit, AbstractControlUnit)
        assert isinstance(self.control_unit, ControlUnit)
        assert self.control_unit.ir_size == self.ir_size
        assert self.control_unit.operand_size == self.operand_size
        assert self.control_unit.address_size == self.address_size
        assert self.control_unit.OPCODE_SIZE == BYTE_SIZE
        assert self.control_unit.OPCODES["move"] == OP_MOVE
        assert self.control_unit.OPCODES["load"] == OP_LOAD
        assert self.control_unit.OPCODES["store"] == OP_STORE
        assert self.control_unit.OPCODES["swap"] == OP_SWAP
        assert self.control_unit.OPCODES["add"] == OP_ADD
        assert self.control_unit.OPCODES["sub"] == OP_SUB
        assert self.control_unit.OPCODES["smul"] == OP_SMUL
        assert self.control_unit.OPCODES["sdivmod"] == OP_SDIVMOD
        assert self.control_unit.OPCODES["umul"] == OP_UMUL
        assert self.control_unit.OPCODES["udivmod"] == OP_UDIVMOD
        assert self.control_unit.OPCODES["comp"] == OP_COMP
        assert self.control_unit.OPCODES["stpush"] == OP_STPUSH
        assert self.control_unit.OPCODES["stpop"] == OP_STPOP
        assert self.control_unit.OPCODES["stdup"] == OP_STDUP
        assert self.control_unit.OPCODES["stswap"] == OP_STSWAP
        assert self.control_unit.OPCODES["jump"] == OP_JUMP
        assert self.control_unit.OPCODES["jeq"] == OP_JEQ
        assert self.control_unit.OPCODES["jneq"] == OP_JNEQ
        assert self.control_unit.OPCODES["sjl"] == OP_SJL
        assert self.control_unit.OPCODES["sjgeq"] == OP_SJGEQ
        assert self.control_unit.OPCODES["sjleq"] == OP_SJLEQ
        assert self.control_unit.OPCODES["sjg"] == OP_SJG
        assert self.control_unit.OPCODES["ujl"] == OP_UJL
        assert self.control_unit.OPCODES["ujgeq"] == OP_UJGEQ
        assert self.control_unit.OPCODES["ujleq"] == OP_UJLEQ
        assert self.control_unit.OPCODES["ujg"] == OP_UJG
        assert self.control_unit.OPCODES["halt"] == OP_HALT

    def test_fetch_and_decode(self):
        """Abstract class."""
        with raises(NotImplementedError):
            self.control_unit.fetch_and_decode()

    def test_load(self):
        """Abstract class."""
        with raises(NotImplementedError):
            self.control_unit.load()

    def test_write_back(self):
        """Abstract class."""
        with raises(NotImplementedError):
            self.control_unit.write_back()

    def run_fetch(self, value, opcode, instruction_size, and_decode=True,
                  address_size=BYTE_SIZE, ir_size=WORD_SIZE):
        """Run one fetch test."""
        address = 10
        self.ram.put(address, value, instruction_size)
        increment = instruction_size // self.ram.word_size

        self.registers.fetch.reset_mock()
        self.registers.put.reset_mock()

        def get_register(name, size):
            """Get PC."""
            assert name == "PC"
            assert size == self.control_unit.address_size
            return address
        self.registers.fetch.side_effect = get_register

        if and_decode:
            self.control_unit.fetch_and_decode()
        else:
            self.control_unit.fetch_instruction(instruction_size)
        self.registers.fetch.assert_any_call("PC", address_size)
        self.registers.put.assert_has_calls([call("RI", value, ir_size),
                                             call("PC", address + increment, address_size)])
        assert self.control_unit.opcode == opcode

    def test_fetch_instruction(self):
        """Right fetch and decode is a half of business."""
        self.run_fetch(0x01020304, 0x01, WORD_SIZE, False)

    def test_basic_execute(self, should_move=True):
        """Test basic operations."""
        self.registers.put.reset_mock()
        self.registers.fetch.reset_mock()

        if should_move is not None:
            self.control_unit.opcode = OP_MOVE
            self.alu.move.reset_mock()
            self.control_unit.execute()
            if should_move:
                self.alu.move.assert_called_once_with()
            else:
                assert not self.alu.move.called

        self.control_unit.opcode = OP_ADD
        self.alu.add.reset_mock()
        self.control_unit.execute()
        self.alu.add.assert_called_once_with()

        self.control_unit.opcode = OP_SUB
        self.alu.sub.reset_mock()
        self.control_unit.execute()
        self.alu.sub.assert_called_once_with()

        self.control_unit.opcode = OP_SMUL
        self.alu.smul.reset_mock()
        self.control_unit.execute()
        self.alu.smul.assert_called_once_with()

        self.control_unit.opcode = OP_UMUL
        self.alu.umul.reset_mock()
        self.control_unit.execute()
        self.alu.umul.assert_called_once_with()

        self.control_unit.opcode = OP_SDIVMOD
        self.alu.sdivmod.reset_mock()
        self.control_unit.execute()
        self.alu.sdivmod.assert_called_once_with()

        self.control_unit.opcode = OP_UDIVMOD
        self.alu.udivmod.reset_mock()
        self.control_unit.execute()
        self.alu.udivmod.assert_called_once_with()

        self.control_unit.opcode = OP_HALT
        self.alu.halt.reset_mock()
        self.control_unit.execute()
        self.alu.halt.assert_called_once_with()

        with raises(ValueError):
            self.control_unit.opcode = 0x98
            self.control_unit.execute()

        assert not self.registers.fetch.called
        assert not self.registers.put.called
class TestControlUnit3(TBCU):

    """Test case for  Mode Machine 3 Control Unit."""

    def setup(self):
        """Init state."""
        super().setup()
        self.ram = RandomAccessMemory(WORD_SIZE, 256, 'big')
        self.control_unit = ControlUnit3(WORD_SIZE,
                                         BYTE_SIZE,
                                         self.registers,
                                         self.ram,
                                         self.alu,
                                         WORD_SIZE)
        assert self.control_unit.opcodes == {0x00, 0x01, 0x02, 0x03, 0x04,
                                             0x13, 0x14,
                                             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 self.control_unit.opcodes:
            self.control_unit.address1, self.control_unit.address2 = None, None
            self.run_fetch(opcode << 24 | 0x020304, opcode, WORD_SIZE)
            assert self.control_unit.address1 == 0x02
            assert self.control_unit.address2 == 0x03
            assert self.control_unit.address3 == 0x04
        for opcode in set(range(2 ** BYTE_SIZE)) - self.control_unit.opcodes:
            with raises(ValueError):
                self.run_fetch(opcode << 24 | 0x020304, opcode, WORD_SIZE)

    def test_load(self):
        """R1 := [A1], R2 := [A2]."""
        addr1, val1 = 5, 123456
        addr2, val2 = 10, 654321
        addr3 = 15
        self.ram.put(addr1, val1, WORD_SIZE)
        self.ram.put(addr2, val2, WORD_SIZE)
        self.control_unit.address1 = addr1
        self.control_unit.address2 = addr2
        self.control_unit.address3 = addr3

        for opcode in ARITHMETIC_OPCODES:
            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 CONDJUMP_OPCODES:
            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),
                                                 call("ADDR", addr3, BYTE_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", val1, WORD_SIZE)

        for opcode in {OP_JUMP}:
            self.registers.put.reset_mock()
            self.control_unit.opcode = opcode
            self.control_unit.load()
            self.registers.put.assert_called_once_with("ADDR", addr3, 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_basic_execute(self, should_move=True):
        """Test basic operations."""
        super().test_basic_execute(should_move)

        for opcode in range(0, 256):
            if not opcode in self.control_unit.opcodes:
                with raises(ValueError):
                    self.control_unit.opcode = opcode
                    self.control_unit.execute()

    def run_cond_jump(self, opcode, signed, mol, equal):
        """Run one conditional jump test."""
        self.alu.cond_jump.reset_mock()
        self.alu.sub.reset_mock()
        self.registers.put.reset_mock()
        self.control_unit.opcode = opcode
        self.control_unit.execute()

        self.alu.sub.assert_called_once_with()
        assert not self.registers.put.called
        self.alu.cond_jump.assert_called_once_with(signed, mol, equal)

    def test_execute_cond_jumps(self):
        """Test for jumps."""
        self.run_cond_jump(OP_JEQ, True, EQUAL, True)
        self.run_cond_jump(OP_JNEQ, True, EQUAL, False)
        self.run_cond_jump(OP_SJL, True, LESS, False)
        self.run_cond_jump(OP_SJGEQ, True, GREATER, True)
        self.run_cond_jump(OP_SJLEQ, True, LESS, True)
        self.run_cond_jump(OP_SJG, True, GREATER, False)
        self.run_cond_jump(OP_UJL, False, LESS, False)
        self.run_cond_jump(OP_UJGEQ, False, GREATER, True)
        self.run_cond_jump(OP_UJLEQ, False, LESS, True)
        self.run_cond_jump(OP_UJG, False, GREATER, False)

    def test_execute_jump_halt(self):
        """Test for jump and halt."""
        self.alu.cond_jump.reset_mock()
        self.alu.sub.reset_mock()
        self.registers.put.reset_mock()

        self.control_unit.opcode = OP_JUMP
        self.control_unit.execute()
        assert not self.alu.sub.called
        assert not self.registers.put.called
        self.alu.jump.assert_called_once_with()

        self.control_unit.opcode = OP_HALT
        self.control_unit.execute()
        assert not self.alu.sub.called
        assert not self.registers.put.called
        self.alu.halt.assert_called_once_with()

    def run_write_back(self, should, opcode):
        """Run write back method for specific opcode."""
        first, second, third = 11111111, 22222222, 33333333
        size = WORD_SIZE // self.ram.word_size
        def get_register(name, size):
            """Get result."""
            assert name in {"S", "R1"}
            assert size == WORD_SIZE
            if name == "S":
                return second
            elif name == "R1":
                return third
        self.registers.fetch.side_effect = get_register

        for address in (10, 2 ** BYTE_SIZE - size):
            next_address = (address + size) % 2 ** BYTE_SIZE
            self.ram.put(address, first, WORD_SIZE)
            self.ram.put(next_address, first, WORD_SIZE)
            self.control_unit.address3 = address
            self.control_unit.opcode = opcode
            self.control_unit.write_back()
            if should:
                assert self.ram.fetch(address, WORD_SIZE) == second
                if opcode in {OP_SDIVMOD,
                              OP_UDIVMOD}:
                    assert self.ram.fetch(next_address, WORD_SIZE) == third
                else:
                    assert self.ram.fetch(next_address, WORD_SIZE) == first
            else:
                assert self.ram.fetch(address, WORD_SIZE) == first

    def test_write_back(self):
        """Test write back result to the memory."""
        for opcode in ARITHMETIC_OPCODES | {OP_MOVE}:
            self.run_write_back(True, opcode)

        for opcode in (CONDJUMP_OPCODES |
                       {OP_HALT,
                        OP_JUMP}):
            self.run_write_back(False, opcode)

    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(0, 0x01020304, WORD_SIZE)
        self.ram.put(1, 0x82020305, WORD_SIZE)
        self.ram.put(2, 12, WORD_SIZE)
        self.ram.put(3, 10, WORD_SIZE)
        self.ram.put(5, 0x99000000, WORD_SIZE)
        self.registers.put("PC", 0, BYTE_SIZE)
        self.control_unit.step()
        assert self.ram.fetch(4, WORD_SIZE) == 22
        assert self.registers.fetch("PC", BYTE_SIZE) == 1
        assert self.control_unit.get_status() == RUNNING
        self.control_unit.step()
        assert self.registers.fetch("PC", BYTE_SIZE) == 5
        assert self.control_unit.get_status() == RUNNING
        self.control_unit.step()
        assert self.registers.fetch("PC", BYTE_SIZE) == 6
        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(0, 0x01020304, WORD_SIZE)
        self.ram.put(1, 0x82020305, WORD_SIZE)
        self.ram.put(2, 12, WORD_SIZE)
        self.ram.put(3, 10, WORD_SIZE)
        self.ram.put(5, 0x99000000, WORD_SIZE)
        self.registers.put("PC", 0, BYTE_SIZE)
        self.control_unit.run()
        assert self.ram.fetch(4, WORD_SIZE) == 22
        assert self.registers.fetch("PC", BYTE_SIZE) == 6
        assert self.control_unit.get_status() == HALTED
Beispiel #12
0
class TestRandomAccessMemory:

    """Test case for RAM."""

    ram = None

    def setup(self):
        """Init state."""
        self.ram = RandomAccessMemory(WORD_SIZE, 512, endianess='big')
        assert self.ram.word_size == WORD_SIZE
        assert self.ram.memory_size == 512
        assert len(self.ram) == 512
        assert self.ram.is_protected is True

    def test_check_address(self):
        """It a second part of information protection."""
        for i in range(len(self.ram)):
            self.ram.check_address(i)
        for i in range(len(self.ram), 2 * len(self.ram)):
            with raises(KeyError):
                self.ram.check_address(i)
        with raises(TypeError):
            self.ram.check_address('R1')

    def test_setitem(self):
        """Address should be checked."""
        for i in range(len(self.ram)):
            self.ram[i] = len(self.ram) + i
            assert i in self.ram
        for i in range(len(self.ram), 2 * len(self.ram)):
            with raises(KeyError):
                self.ram[i] = i
            assert i not in self.ram
        with raises(TypeError):
            self.ram['R1'] = 10
        assert 'R1' not in self.ram
        with raises(ValueError):
            self.ram[2] = 2 ** WORD_SIZE

    def test_getitem(self):
        """Address should be checked."""
        for i in range(2 * len(self.ram)):
            with raises(KeyError):
                self.ram.__getitem__(i)
        with raises(TypeError):
            self.ram.__getitem__('R1')

        for i in range(len(self.ram) // 2):
            self.ram[i] = i
            assert self.ram[i] == i

    def test_not_protected_getitem(self):
        """Test if programmer can shut in his leg."""
        self.ram = RandomAccessMemory(WORD_SIZE, 512, 'big', is_protected=False)
        for i in range(len(self.ram)):
            assert self.ram[i] == 0
        for i in range(len(self.ram), 2 * len(self.ram)):
            with raises(KeyError):
                self.ram.__getitem__(i)

    def test_fetch(self):
        """Fetch is basic operation of transfer data."""
        for i in range(5, 9):
            self.ram[i] = i
            assert self.ram.fetch(i, WORD_SIZE) == i
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                0x00000005000000060000000700000008)
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                big_endian_decode([5, 6, 7, 8], WORD_SIZE))

        self.ram[5] = 0
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                big_endian_decode([0, 6, 7, 8], WORD_SIZE))
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                0x00000000000000060000000700000008)

        with raises(KeyError):
            self.ram.fetch(5, 4 * WORD_SIZE - 1)
        with raises(KeyError):
            self.ram.fetch(4, 4 * WORD_SIZE)

        self.ram = RandomAccessMemory(WORD_SIZE, 512, endianess="little")
        for i in range(5, 9):
            self.ram[i] = i
            assert self.ram.fetch(i, WORD_SIZE) == i
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                0x00000008000000070000000600000005)
        assert (self.ram.fetch(5, 4 * WORD_SIZE) ==
                little_endian_decode([5, 6, 7, 8], WORD_SIZE))

    def test_put(self):
        """Test put operation."""
        value_list = [0, 6, 7, 0]
        value = big_endian_decode(value_list, WORD_SIZE)
        self.ram.put(5, value, 4 * WORD_SIZE)
        with raises(ValueError):
            self.ram.put(5, 2 ** WORD_SIZE, WORD_SIZE)
        self.ram.put(4, 4, WORD_SIZE)
        for i in range(5, 9):
            assert self.ram[i] == value_list[i - 5]

        self.ram = RandomAccessMemory(WORD_SIZE, 512, endianess="little")
        value = little_endian_decode(value_list, WORD_SIZE)
        self.ram.put(5, value, 4 * WORD_SIZE)
        for i in range(5, 9):
            assert self.ram[i] == value_list[i - 5]