def subtract_vy_minus_vx(self, byte_1: Byte, byte_2: Byte): if self.V[byte_2.get_high_nibble()] > self.V[byte_1.get_low_nibble()]: self.V[0xF] = 1 else: self.V[0xF] = 0 self.V[byte_1.get_low_nibble( )] = self.V[byte_2.get_high_nibble()] - self.V[byte_1.get_low_nibble()]
def add_vx_byte(self, byte_1: Byte, byte_2: Byte): result = self.V[byte_1.get_low_nibble()] + byte_2.byte # Handle the case of overflowing an 8 bit register. if result > 0xFF: result = result % 0xFF self.V[0xF] = 1 self.V[byte_1.get_low_nibble()] = result
def shift_left_vx_to_vy(self, byte_1: Byte, byte_2: Byte): # VF needs to be set to 1 in case most significant number of VX is set to 1. if self.V[byte_1.get_low_nibble()] >= 0x80: self.V[0xF] = 1 else: self.V[0xF] = 0 self.V[byte_1.get_low_nibble()] = self.V[byte_1.get_low_nibble()] << 1
def shift_right_vx_to_vy(self, byte_1: Byte, byte_2: Byte): # We need to set VF to 1 if least significant bit of Vx is 1. # If VX is an even number, then the least significant bit will be 0. # In case of odd number, least significant bit must be 1 if self.V[byte_1.get_low_nibble()] % 2 == 0: self.V[0xF] = 0 else: self.V[0xF] = 1 self.V[byte_1.get_low_nibble()] = self.V[byte_1.get_low_nibble()] >> 1
def add_vx_to_vy(self, byte_1: Byte, byte_2: Byte): result = self.V[byte_1.get_low_nibble()] + self.V[ byte_2.get_high_nibble()] if result > 0xFF: self.V[ 0xF] = 1 # F register is used as a carry one flag. We're setting it up like that. self.V[byte_1.get_low_nibble()] = result % 0xFF else: self.V[0xF] = 0 self.V[byte_1.get_low_nibble()] = result
def registers_operation(self, byte_1: Byte, byte_2: Byte): # OPcodes starting with 8 are defined by the last nibble of the two byte opcode if byte_2.get_low_nibble() == 0x0: self.load_vy_into_vx(byte_1, byte_2) elif byte_2.get_low_nibble() == 0x1: self.bitwise_or_vx_with_vy(byte_1, byte_2) elif byte_2.get_low_nibble() == 0x2: self.bitwise_and_vx_with_vy(byte_1, byte_2) elif byte_2.get_low_nibble() == 0x3: self.bitwise_xor_vx_with_vy(byte_1, byte_2) elif byte_2.get_low_nibble() == 0x4: self.add_vx_to_vy(byte_1, byte_2) elif byte_2.get_low_nibble() == 0x5: self.subtract_vx_minus_vy(byte_1, byte_2) elif byte_2.get_low_nibble() == 0x6: self.shift_right_vx_to_vy(byte_1, byte_2) elif byte_2.get_low_nibble() == 0x7: self.subtract_vy_minus_vx(byte_1, byte_2) elif byte_2.get_low_nibble() == 0xE: self.shift_right_vx_to_vy(byte_1, byte_2)
def draw_sprite_on_vx_vy(self, byte_1: Byte, byte_2: Byte): sprite_size = byte_2.get_low_nibble() x = self.V[byte_1.get_low_nibble()] y = self.V[byte_2.get_high_nibble()] self.V[0xF] = self.screen.draw_sprite(self.memory, self.I, x, y, sprite_size)
def random_number_bitwise_and(self, byte_1: Byte, byte_2: Byte): random_number = randint(0x00, 0xFF) result = random_number & byte_2.byte self.V[byte_1.get_low_nibble()] = result
def jump_to_v0_plus_byte(self, byte_1: Byte, byte_2: Byte): address = ByteUtils.prefix_nibble_to_byte(byte_1.get_low_nibble(), byte_2.byte) self.program_counter = (address + self.V[0])
def load_i_from_byte(self, byte_1: Byte, byte_2: Byte): self.I = ByteUtils.prefix_nibble_to_byte(byte_1.get_low_nibble(), byte_2.byte)
def skip_if_vx_not_equal_to_vy(self, byte_1: Byte, byte_2: Byte): if self.V[byte_1.get_low_nibble()] != self.V[byte_2.get_high_nibble()]: self.program_counter += 2
def skip_if_vx__not_equal_to_byte(self, byte_1: Byte, byte_2: Byte): if byte_2.byte != self.V[byte_1.get_low_nibble()]: self.program_counter += 2
def load_vx_from_byte(self, byte_1: Byte, byte_2: Byte): self.V[byte_1.get_low_nibble()] = byte_2.byte
def call_addres(self, byte_1: Byte, byte_2: Byte): self.stack_pointer += 1 self.stack.append(self.program_counter) self.program_counter = ByteUtils.prefix_nibble_to_byte( byte_1.get_low_nibble(), byte_2.byte)
def load_vx_font_to_i(self, byte_1: Byte, byte_2: Byte): address = self.memory.get_font_starting_address( self.V[byte_1.get_low_nibble()]) self.I = address
def bitwise_xor_vx_with_vy(self, byte_1: Byte, byte_2: Byte): self.V[byte_1.get_low_nibble( )] = self.V[byte_1.get_low_nibble()] ^ self.V[byte_2.get_high_nibble()]
def load_vy_into_vx(self, byte_1: Byte, byte_2: Byte): self.V[byte_1.get_low_nibble()] = self.V[byte_2.get_high_nibble()]
def read_from_address(self, address) -> Byte: try: return Byte(self.memory[address]) except IndexError: return 0x00
def jump_to_addres(self, byte_1: Byte, byte_2: Byte): self.program_counter = ByteUtils.prefix_nibble_to_byte( byte_1.get_low_nibble(), byte_2.byte)