Пример #1
0
    def _load_from_memory(
            self,
            vm: Chip8VirtualMachine,
            max_register: int,
            read_src: int = 0xA00,
            value_start: int = 128
    ) -> None:
        """

        Helper function that executes a bulk register save operation.

        Will write value_start +0, ... value_start + max_register to
        the first max_register registers.

        Then runs FX55, with max_register as X.

        :param vm: vm object to write to
        :param max_register: the highest register that will be saved
        :param value_start: what the start of the written values will be
        :return:
        """

        # set up the memory with values to read into registers
        for register_index in range(0, max_register + 1):
            vm.memory[read_src + register_index] = 128 + register_index

        # set up where the registers will be stored to
        vm.i_register = read_src

        load_and_execute_instruction(
            vm, 0xF065, x=max_register
        )
Пример #2
0
    def _write_values_to_memory(
            self,
            vm: Chip8VirtualMachine,
            max_register: int,
            write_dest: int = 0xA00,
            value_start: int = 128
    ) -> None:
        """

        Helper function that executes a bulk register save operation.

        Will write value_start +0, ... value_start + max_register to
        the first max_register registers.

        Then runs FX55, with max_register as X.

        :param vm: vm object to write to
        :param max_register: the highest register that will be saved
        :param value_start: what the start of the written values will be
        :return:
        """

        # set up the registers with unique values that can be checked
        # for correct write order in memory.
        for index in range(0, max_register + 1):
            vm.v_registers[index] = value_start + index

        # set up where the registers will be stored to
        vm.i_register = write_dest

        load_and_execute_instruction(
            vm, 0xF055, x=max_register
        )
Пример #3
0
def test_00e0_calls_vram_clear_screen():
    """00E0 causes VM to call screen clear on video ram"""
    vm = VM()
    vm.video_ram = Mock(VideoRam)

    load_and_execute_instruction(vm, 0x00E0)
    assert vm.video_ram.clear_screen.called_once()
Пример #4
0
def test_1nnn_jumps_to_address(memory_location):
    """1nnn sets program counter to nnn"""
    vm = VM()

    assert vm.program_counter == DEFAULT_EXECUTION_START
    load_and_execute_instruction(vm, 0x1000, nnn=memory_location)
    assert vm.program_counter == memory_location
    assert vm.stack_size == 0
Пример #5
0
    def test_8xy0_same_value_for_x_and_y_leaves_reg_unchanged(self, reg_index):
        """8xy0 does not alter the value when x & y are the same"""
        vm = VM()

        vm.v_registers[reg_index] = 5
        load_and_execute_instruction(vm, 0x8000, x=reg_index, y=reg_index)

        assert vm.v_registers[reg_index] == 5
Пример #6
0
    def test_dxyn_sets_vf_when_turning_off_pixels(self, vm_will_draw_1_px):
        """Dxyn sets VF to 1 when overwriting a pixel"""

        load_and_execute_instruction(vm_will_draw_1_px, 0xD000, n=1)
        load_and_execute_instruction(vm_will_draw_1_px,
                                     0xD000,
                                     n=1,
                                     load_point=0x200 + INSTRUCTION_LENGTH)
        assert vm_will_draw_1_px.v_registers[0xF] == 1
Пример #7
0
    def test_6xy0_skips_next_if_vx_not_equal_vy(self, x, y):
        vm = VM()
        vm.v_registers[x] = 0
        vm.v_registers[y] = 1

        load_and_execute_instruction(vm, 0x9000, x=x, y=y)

        assert vm.program_counter ==\
               DEFAULT_EXECUTION_START + (2 * INSTRUCTION_LENGTH)
Пример #8
0
def test_00ee_decrements_stack_size(call_location):
    """Return instruction decrements stack size"""
    vm = VM()
    vm.stack_call(call_location)

    load_and_execute_instruction(
        vm,
        0x00EE,  # return instruction
        load_point=call_location)
    assert vm.stack_size == 0
Пример #9
0
def test_00ee_returns_to_last_location_plus_two(call_location):
    """Return instruction returns to last location on the stack"""
    vm = VM()
    vm.stack_call(call_location)

    load_and_execute_instruction(
        vm,
        0x00EE,  # return instruction
        load_point=call_location)
    assert vm.program_counter == DEFAULT_EXECUTION_START + 2
Пример #10
0
def test_2nnn_sets_program_counter_and_pushes_stack(memory_location):
    """2nnn instruction jumps to location and increments stack"""
    vm = VM()
    assert vm.stack_size == 0
    assert vm.program_counter == DEFAULT_EXECUTION_START
    load_and_execute_instruction(vm, 0x2000, nnn=memory_location)

    assert vm.program_counter == memory_location
    assert vm.stack_top == DEFAULT_EXECUTION_START
    assert vm.stack_size == 1
Пример #11
0
    def test_8xy2_leaves_other_registers_alone(self, x, y):
        """8xy2 leaves registers other than VX and VY alone"""

        vm = VM()
        vm.v_registers[x] = 0b10101010
        vm.v_registers[y] = 0b01010101

        load_and_execute_instruction(vm, 0x8002, x=x, y=y)

        assert other_registers_untouched(vm, (x, y))
Пример #12
0
    def test_8xy6_sets_vf_to_least_significant_digit_of_vy(self, x, y, a, b):
        """8xy6 sets VF to least significant"""
        vm = VM()

        vm.v_registers[x] = a
        vm.v_registers[y] = b

        load_and_execute_instruction(vm, 0x8006, x=x, y=y)

        assert vm.v_registers[0xF] == b & 1
Пример #13
0
    def test_8xye_sets_vf_to_most_significant_digit_of_vy(self, x, y, a, b):
        """8xyE sets VF to most significant digit of VY"""
        vm = VM()

        vm.v_registers[x] = a
        vm.v_registers[y] = b

        load_and_execute_instruction(vm, 0x800E, x=x, y=y)

        assert vm.v_registers[0xF] == bool(b & 0b10000000)
Пример #14
0
    def test_8xy0_leaves_original_alone(self, x, y):
        """8xy0 leaves VY alone"""

        vm = VM()
        vm.v_registers[x] = 2
        vm.v_registers[y] = 3

        load_and_execute_instruction(vm, 0x8000, x=x, y=y)

        assert other_registers_untouched(vm, {x, y})
Пример #15
0
    def test_9xy0_doesnt_skip_next_if_vx_eq_vy(self, x, y, equal_val):

        vm = VM()
        vm.v_registers[x] = 7
        vm.v_registers[y] = 7

        load_and_execute_instruction(vm, 0x9000, x=x, y=y)

        assert vm.program_counter ==\
               DEFAULT_EXECUTION_START + INSTRUCTION_LENGTH
Пример #16
0
 def test_4xkk_does_not_skip_next_instruction_if_vx_eq_kk(
         self, vx: int, vx_and_kk_value: int, exec_start: int):
     vm = VM(execution_start=exec_start)
     vm.v_registers[vx] = vx_and_kk_value
     load_and_execute_instruction(vm,
                                  0x4000,
                                  load_point=exec_start,
                                  x=vx,
                                  kk=vx_and_kk_value)
     assert vm.program_counter == exec_start + INSTRUCTION_LENGTH
Пример #17
0
    def test_8xy6_sets_vx_to_vy_shifted_right_one(self, x, y, a, b):
        """8xy6 sets VX = VY >> 1"""

        vm = VM()

        vm.v_registers[x] = a
        vm.v_registers[y] = b

        load_and_execute_instruction(vm, 0x8006, x=x, y=y)

        assert vm.v_registers[x] == b >> 1
Пример #18
0
    def test_8xy5_sets_vf_to_not_borrow(self, x, y, a, b):
        """8xy5 sets VF to 1 if VX >= VY, otherwise 0"""
        vm = VM()

        vm.v_registers[x] = a
        if x != y:
            vm.v_registers[y] = b

        load_and_execute_instruction(vm, 0x8005, x=x, y=y)

        assert vm.v_registers[0xF] == int(a >= b)
Пример #19
0
def test_fx07_set_vx_to_delay_timer_value(
        v_register_index,
        v_initial_value,
        delay_timer_value
):
    vm = Chip8VirtualMachine()
    vm.delay_timer = delay_timer_value

    load_and_execute_instruction(vm, 0xF007, x=v_register_index)

    assert vm.v_registers[v_register_index] == delay_timer_value
Пример #20
0
    def test_8xye_sets_vx_to_vy_shifted_left_one(self, x, y, a, b):
        """8xyE sets VX = VY >> 1"""

        vm = VM()

        vm.v_registers[x] = a
        vm.v_registers[y] = b

        load_and_execute_instruction(vm, 0x800E, x=x, y=y)

        assert vm.v_registers[x] == 0xFF & (b << 1)
Пример #21
0
    def test_8xy4_sets_vf_to_carry_bit(self, x, y, a, b):
        """8xy4 sets VF to 1 if VX + VY > 255, otherwise 0"""
        vm = VM()

        vm.v_registers[x] = a
        if x != y:
            vm.v_registers[y] = b

        load_and_execute_instruction(vm, 0x8004, x=x, y=y)

        assert vm.v_registers[0xF] == int(a + b > 255)
Пример #22
0
 def test_4xkk_skips_next_instruction_if_vx_neq_kk(self, vx: int, vx_value,
                                                   kk_value, exec_start):
     vm = VM(execution_start=exec_start)
     vm.v_registers[vx] = vx_value
     load_and_execute_instruction(
         vm,
         0x4000,
         load_point=exec_start,
         x=vx_value,
         kk=kk_value,
     )
     assert vm.program_counter == exec_start + (2 * INSTRUCTION_LENGTH)
Пример #23
0
    def test_8xy0_sets_vx_to_vy(self, x, y):
        """8xy0 sets VX = VX OR VY"""

        vm = VM()
        original_x_value = 2
        default_y_value = 3

        vm.v_registers[x] = original_x_value
        vm.v_registers[y] = default_y_value

        load_and_execute_instruction(vm, 0x8000, x=x, y=y)

        assert vm.v_registers[x] == default_y_value
Пример #24
0
    def test_8xye_leaves_other_registers_alone_unless_theyre_vf(self, x, y):
        """8xy6 leaves registers other than VX alone except for VF"""

        vm = VM()

        vm.v_registers[x] = 2
        vm.v_registers[y] = 1

        load_and_execute_instruction(vm, 0x800E, x=x, y=y)

        # make sure we don't check VF since it should always be set
        touched = {x, 0xF}

        assert other_registers_untouched(vm, touched)
Пример #25
0
    def test_8xy2_sets_vx_to_and_of_vx_and_vy(self, x, y):
        """8xy2 sets VX to VX AND VY"""

        vm = VM()

        left_half_filled = 0b11110000

        vm.v_registers[x] = 0xFF
        vm.v_registers[y] = left_half_filled

        # set vx = vx AND 0x11110000. If vx is already set to 0x11110000,
        # the value will still be 0x11110000 after the instruction runs.
        load_and_execute_instruction(vm, 0x8002, x=x, y=y)

        assert vm.v_registers[x] == left_half_filled
Пример #26
0
def test_bnnn_jumps_to_address_plus_offset(memory_location, v0):
    """Bnnn sets program counter to nnn + v0"""
    vm = VM()

    assert vm.program_counter == DEFAULT_EXECUTION_START
    assert vm.stack_size == 0

    vm.v_registers[0] = v0
    load_and_execute_instruction(
        vm,
        0xB000,
        nnn=memory_location,
    )
    assert vm.program_counter == memory_location + v0
    assert vm.stack_size == 0
Пример #27
0
    def test_8xy3_sets_vx_to_xor_of_vx_and_vy(self, x, y):
        """8xy3 sets VX to VX XOR VY"""

        vm = VM()

        vm.v_registers[x] = 0b10101111
        vm.v_registers[y] = 0b01011111

        load_and_execute_instruction(vm, 0x8003, x=x, y=y)

        if x != y:
            assert vm.v_registers[x] == 0b11110000

        else:  # any value xor itself yields zero
            assert vm.v_registers[x] == 0
Пример #28
0
    def test_8xy4_sets_vx_to_sum_of_vx_and_vy(self, x, y, a, b):
        """8xy4 sets VX to VX + VY, modulo 256"""

        vm = VM()

        vm.v_registers[x] = a

        if x != y:
            vm.v_registers[y] = b

        load_and_execute_instruction(vm, 0x8004, x=x, y=y)

        if x != y:
            assert vm.v_registers[x] == (a + b) % 256
        else:
            assert vm.v_registers[x] == (a * 2) % 256
Пример #29
0
    def test_8xy1_sets_vx_to_logical_or_of_vx_and_vy(self, x, y):
        """8xy1 sets VX = VX OR VY"""

        vm = VM()
        original_x_value = 0b10101010
        default_y_value = 0b01010101

        vm.v_registers[x] = original_x_value
        if y != x:
            vm.v_registers[y] = default_y_value

        load_and_execute_instruction(vm, 0x8001, x=x, y=y)

        if y != x:
            assert vm.v_registers[x] == original_x_value | default_y_value
        else:
            assert vm.v_registers[x] == original_x_value
Пример #30
0
    def test_8xy7_sets_vx_to_vy_minus_vx(self, x, y, a, b):
        """8xy7 sets VX = VY - VX, clamped to 0 minimum"""

        vm = VM()

        vm.v_registers[x] = a

        if x != y:
            vm.v_registers[y] = b

        load_and_execute_instruction(vm, 0x8007, x=x, y=y)

        if x != y:
            assert vm.v_registers[x] == max(b - a, 0)

        else:  # any value minus itself yields zero
            assert vm.v_registers[x] == 0