Ejemplo n.º 1
0
    def __init__(self):
        self.registers = bytearray(self.REG_COUNT)
        self.index_register = 0
        self.program_counter = self.ENTRY_POINT

        self.memory = Memory()
        self.screen = Screen()
        self.keyboard = bytearray(self.KEY_COUNT)
        self.stack = []

        self.delay_timer = 0
        self.sound_timer = 0

        self.INSTRUCTION_SET = {
            0x00E0: self.op_00E0,
            0x00EE: self.op_00EE,
            0x1: self.op_1NNN,
            0x2: self.op_2NNN,
            0x3: self.op_3XNN,
            0x4: self.op_4XNN,
            0x5: self.op_5XY0,
            0x6: self.op_6XNN,
            0x7: self.op_7XNN,
            0x8000: self.op_8XY0,
            0x8001: self.op_8XY1,
            0x8002: self.op_8XY2,
            0x8003: self.op_8XY3,
            0x8004: self.op_8XY4,
            0x8005: self.op_8XY5,
            0x8006: self.op_8XY6,
            0x8007: self.op_8XY7,
            0x800E: self.op_8XYE,
            0x9000: self.op_9XY0,
            0xA: self.op_ANNN,
            0xB: self.op_BNNN,
            0xC: self.op_CXNN,
            0xD: self.op_DXYN,
            0xE09E: self.op_EX9E,
            0xE0A1: self.op_EXA1,
            0xF007: self.op_FX07,
            0xF00A: self.op_FX0A,
            0xF015: self.op_FX15,
            0xF018: self.op_FX18,
            0xF01E: self.op_FX1E,
            0xF029: self.op_FX29,
            0xF033: self.op_FX33,
            0xF055: self.op_F055,
            0xF065: self.op_FX65,
        }
Ejemplo n.º 2
0
    def __init__(self):
        self.registers = bytearray(self.REG_COUNT)
        self.index_register = 0
        self.program_counter = self.ENTRY_POINT

        self.memory = Memory()
        self.screen = Screen()
        self.keyboard = bytearray(self.KEY_COUNT)
        self.stack = []

        self.delay_timer = 0
        self.sound_timer = 0

        self.INSTRUCTION_SET = {
            0x00E0: self.op_00E0,
            0x00EE: self.op_00EE,
            0x1   : self.op_1NNN,
            0x2   : self.op_2NNN,
            0x3   : self.op_3XNN,
            0x4   : self.op_4XNN,
            0x5   : self.op_5XY0,
            0x6   : self.op_6XNN,
            0x7   : self.op_7XNN,
            0x8000: self.op_8XY0,
            0x8001: self.op_8XY1,
            0x8002: self.op_8XY2,
            0x8003: self.op_8XY3,
            0x8004: self.op_8XY4,
            0x8005: self.op_8XY5,
            0x8006: self.op_8XY6,
            0x8007: self.op_8XY7,
            0x800E: self.op_8XYE,
            0x9000: self.op_9XY0,
            0xA   : self.op_ANNN,
            0xB   : self.op_BNNN,
            0xC   : self.op_CXNN,
            0xD   : self.op_DXYN,
            0xE09E: self.op_EX9E,
            0xE0A1: self.op_EXA1,
            0xF007: self.op_FX07,
            0xF00A: self.op_FX0A,
            0xF015: self.op_FX15,
            0xF018: self.op_FX18,
            0xF01E: self.op_FX1E,
            0xF029: self.op_FX29,
            0xF033: self.op_FX33,
            0xF055: self.op_F055,
            0xF065: self.op_FX65,
        }
Ejemplo n.º 3
0
class Chip8(object):
    ENTRY_POINT = 0x200
    REG_COUNT = 16
    KEY_COUNT = 16

    def __init__(self):
        self.registers = bytearray(self.REG_COUNT)
        self.index_register = 0
        self.program_counter = self.ENTRY_POINT

        self.memory = Memory()
        self.screen = Screen()
        self.keyboard = bytearray(self.KEY_COUNT)
        self.stack = []

        self.delay_timer = 0
        self.sound_timer = 0

        self.INSTRUCTION_SET = {
            0x00E0: self.op_00E0,
            0x00EE: self.op_00EE,
            0x1   : self.op_1NNN,
            0x2   : self.op_2NNN,
            0x3   : self.op_3XNN,
            0x4   : self.op_4XNN,
            0x5   : self.op_5XY0,
            0x6   : self.op_6XNN,
            0x7   : self.op_7XNN,
            0x8000: self.op_8XY0,
            0x8001: self.op_8XY1,
            0x8002: self.op_8XY2,
            0x8003: self.op_8XY3,
            0x8004: self.op_8XY4,
            0x8005: self.op_8XY5,
            0x8006: self.op_8XY6,
            0x8007: self.op_8XY7,
            0x800E: self.op_8XYE,
            0x9000: self.op_9XY0,
            0xA   : self.op_ANNN,
            0xB   : self.op_BNNN,
            0xC   : self.op_CXNN,
            0xD   : self.op_DXYN,
            0xE09E: self.op_EX9E,
            0xE0A1: self.op_EXA1,
            0xF007: self.op_FX07,
            0xF00A: self.op_FX0A,
            0xF015: self.op_FX15,
            0xF018: self.op_FX18,
            0xF01E: self.op_FX1E,
            0xF029: self.op_FX29,
            0xF033: self.op_FX33,
            0xF055: self.op_F055,
            0xF065: self.op_FX65,
        }

    def decode(self, op):
        if op in [0x00E0, 0x00EE]: # special case
            return (op, tuple())

        instruction = I(op)

        if instruction in [0x0, 0x1, 0x2, 0xA, 0xB]:
            args = (NNN(op),)

        elif instruction in [0x3, 0x4, 0x6, 0x7, 0xC]:
            args = X(op), NN(op)

        elif instruction == 0x5:
            args = X(op), Y(op)

        elif instruction == 0xD:
            args = X(op), Y(op), N(op)

        elif 0x8000 <= instruction <= 0x9000:
            args = X(op), Y(op)

        elif instruction >= 0xE:
            args = (X(op),)

        return instruction, args

    def execute(self, instruction, args):
        if instruction not in self.INSTRUCTION_SET:
            raise NotImplementedError('{:04x} - {}'.format(instruction, args))

        self.INSTRUCTION_SET.get(instruction)(*args)

    def fetch(self):
        return self.memory.read_word(self.program_counter)

    def cycle(self):
        word = self.fetch()
        instruction, args = self.decode(word)
        self.execute(instruction, args)

        if self.delay_timer > 0:
            self.delay_timer -= 1

        if self.sound_timer > 0:
            if self.sound_timer == 1:
                self.beep()
            self.sound_timer -= 1

    def increment_program_counter(self):
        self.program_counter += 0x2

    def skip_next_instruction(self):
        self.program_counter += 0x4

    def wait_for_keypress(self):
        raise NotImplementedError()

    def beep(self):
        print 'Beep!'

    # INSTRUCTIONS
    def op_00E0(self):
        'Clear screen'
        self.screen.clear()
        self.increment_program_counter()

    def op_00EE(self):
        'Return from a subroutine.'
        self.program_counter = self.stack.pop()

    def op_1NNN(self, address):
        'Jump to address NNN.'
        self.program_counter = address

    def op_2NNN(self, address):
        'Execute subroutine starting at address NNN.'
        self.increment_program_counter()
        self.stack.append(self.program_counter)
        self.program_counter = address

    def op_3XNN(self, X, NN):
        'Skip the following instruction if the value of VX == NN.'
        if self.registers[X] == NN:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_4XNN(self, X, NN):
        'Skip the following instruction if the value of VX != NN.'
        if self.registers[X] != NN:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_5XY0(self, X, Y):
        'Skip next instruction if the value of VX == the value of VY.'
        if self.registers[X] == self.registers[Y]:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_6XNN(self, X, NN):
        'Store number NN in register VX.'
        self.registers[X] = NN
        self.increment_program_counter()

    def op_7XNN(self, X, NN):
        'Add the value NN to register VX.'
        self.registers[X] = byte(self.registers[X] + NN)
        self.increment_program_counter()

    def op_8XY0(self, X, Y):
        'Store the value of register VY in register VX.'
        self.registers[X] = self.registers[Y]
        self.increment_program_counter()

    def op_8XY1(self, X, Y):
        'Set VX to VX OR VY'
        self.registers[X] |= self.registers[Y]
        self.increment_program_counter()

    def op_8XY2(self, X, Y):
        'Set VX to VX AND VY'
        self.registers[X] &= self.registers[Y]
        self.increment_program_counter()

    def op_8XY3(self, X, Y):
        'Set VX to VX XOR VY.'
        self.registers[X] ^= self.registers[Y]
        self.increment_program_counter()

    def op_8XY4(self, X, Y):
        '''Add the value of register VY to register VX
           Set VF to 01 if a carry occurs
           Set VF to 00 if a carry does not occur'''
        value = self.registers[X] + self.registers[Y]
        self.registers[X] = byte(value)
        self.registers[0xF] = 1 if value > 0xFF else 0
        self.increment_program_counter()

    def op_8XY5(self, X, Y):
        '''
        Subtract the value of register VY from register VX
        Set VF to 00 if a borrow occurs
        Set VF to 01 if a borrow does not occur
        '''
        value = self.registers[X] - self.registers[Y]
        self.registers[X] = byte(value)
        self.registers[0xF] = 0 if value < 0 else 1
        self.increment_program_counter()

    def op_8XY6(self, X, Y):
        '''
        Store the value of register VY shifted right one bit in  VX
        Set VF to the least significant bit prior to the shift
        '''
        self.registers[X] = self.registers[Y] >> 1
        self.registers[0xF] = self.registers[Y] & 1
        self.increment_program_counter()

    def op_8XY7(self, X, Y):
        '''
        Set register VX to the value of VY minus VX
        Set VF to 00 if a borrow occurs
        Set VF to 01 if a borrow does not occur
        '''
        value = self.registers[Y] - self.registers[X]
        self.registers[X] = byte(value)
        self.registers[0xF] = 0 if value < 0 else 1
        self.increment_program_counter()

    def op_8XYE(self, X, Y):
        '''
        Store the value of register VY shifted left one bit in VX
        Set VF to the most significant bit prior to the shift
        '''
        self.registers[X] = byte(self.registers[Y] << 1)
        self.registers[0xF] = self.registers[Y] >> 7
        self.increment_program_counter()

    def op_9XY0(self, X, Y):
        'Skip the following instruction if the value VX != value VY.'
        if self.registers[X] != self.registers[Y]:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_ANNN(self, address):
        'Store memory address NNN in register I.'
        self.index_register = address
        self.increment_program_counter()

    def op_BNNN(self, address):
        'Jump to address NNN + V0.'
        self.program_counter = address + self.registers[0]

    def op_CXNN(self, X, NN):
        'Set VX to a random number with a mask of NN.'
        self.registers[X] = randint(0, 0xFF) & NN
        self.increment_program_counter()

    def op_DXYN(self, VX, VY, N):
        x = self.registers[VX]
        y = self.registers[VY]
        sprite = self.memory.read(self.index_register, N)
        collision = self.screen.draw(sprite, x, y)
        self.registers[0xF] = bool(collision)
        self.increment_program_counter()

    def op_EX9E(self, X):
        key = self.registers[X]
        if self.keyboard[key]:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_EXA1(self, X):
        key = self.registers[X]
        if not self.keyboard[key]:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_FX0A(self, X):
        key = self.wait_for_keypress()
        self.keyboard[key] = True
        self.registers[X] = key
        self.increment_program_counter()

    def op_FX07(self, X):
        'Store the current value of the delay timer in register VX.'
        self.registers[X] = self.delay_timer
        self.increment_program_counter()

    def op_FX15(self, X):
        'Set the delay timer to the value of register VX.'
        self.delay_timer = self.registers[X]
        self.increment_program_counter()

    def op_FX18(self, X):
        'Set the sound timer to the value of register VX.'
        self.sound_timer = self.registers[X]
        self.increment_program_counter()

    def op_FX1E(self, X):
        'Add the value stored in register VX to register I.'
        self.index_register += self.registers[X]
        self.increment_program_counter()

    def op_FX29(self, X):
        '''
        Set I to the memory address of the sprite data corresponding
        to the hexadecimal digit stored in register VX.
        '''
        sprite = self.registers[X] % 16
        self.index_register = self.memory.font_address(sprite)
        self.increment_program_counter()

    def op_FX33(self, X):
        '''
        Store the binary-coded decimal equivalent of the value
        stored in register VX at addresses I, I+1, and I+2
        Example: VX=0xFF (255); I=2, I+1=5, I+2=5
        '''
        data = bcd(self.registers[X])
        self.memory.load(self.index_register, data)
        self.increment_program_counter()

    def op_F055(self, X):
        'Store values of V0 to VX inclusive in mem starting at addr I.'
        data = self.registers[0:X+1]
        self.memory.load(self.index_register, data)
        self.increment_program_counter()

    def op_FX65(self, X):
        '''
        Fill registers V0 to VX inclusive with the values stored in
        memory starting at address I
        I is set to I + X + 1 after operation
        '''
        data = self.memory.read(self.index_register, X+1)
        for R in range(X+1):
            self.registers[R] = data[R]
        self.increment_program_counter()
Ejemplo n.º 4
0
class Chip8(object):
    ENTRY_POINT = 0x200
    REG_COUNT = 16
    KEY_COUNT = 16

    def __init__(self):
        self.registers = bytearray(self.REG_COUNT)
        self.index_register = 0
        self.program_counter = self.ENTRY_POINT

        self.memory = Memory()
        self.screen = Screen()
        self.keyboard = bytearray(self.KEY_COUNT)
        self.stack = []

        self.delay_timer = 0
        self.sound_timer = 0

        self.INSTRUCTION_SET = {
            0x00E0: self.op_00E0,
            0x00EE: self.op_00EE,
            0x1: self.op_1NNN,
            0x2: self.op_2NNN,
            0x3: self.op_3XNN,
            0x4: self.op_4XNN,
            0x5: self.op_5XY0,
            0x6: self.op_6XNN,
            0x7: self.op_7XNN,
            0x8000: self.op_8XY0,
            0x8001: self.op_8XY1,
            0x8002: self.op_8XY2,
            0x8003: self.op_8XY3,
            0x8004: self.op_8XY4,
            0x8005: self.op_8XY5,
            0x8006: self.op_8XY6,
            0x8007: self.op_8XY7,
            0x800E: self.op_8XYE,
            0x9000: self.op_9XY0,
            0xA: self.op_ANNN,
            0xB: self.op_BNNN,
            0xC: self.op_CXNN,
            0xD: self.op_DXYN,
            0xE09E: self.op_EX9E,
            0xE0A1: self.op_EXA1,
            0xF007: self.op_FX07,
            0xF00A: self.op_FX0A,
            0xF015: self.op_FX15,
            0xF018: self.op_FX18,
            0xF01E: self.op_FX1E,
            0xF029: self.op_FX29,
            0xF033: self.op_FX33,
            0xF055: self.op_F055,
            0xF065: self.op_FX65,
        }

    def decode(self, op):
        if op in [0x00E0, 0x00EE]:  # special case
            return (op, tuple())

        instruction = I(op)

        if instruction in [0x0, 0x1, 0x2, 0xA, 0xB]:
            args = (NNN(op), )

        elif instruction in [0x3, 0x4, 0x6, 0x7, 0xC]:
            args = X(op), NN(op)

        elif instruction == 0x5:
            args = X(op), Y(op)

        elif instruction == 0xD:
            args = X(op), Y(op), N(op)

        elif 0x8000 <= instruction <= 0x9000:
            args = X(op), Y(op)

        elif instruction >= 0xE:
            args = (X(op), )

        return instruction, args

    def execute(self, instruction, args):
        if instruction not in self.INSTRUCTION_SET:
            raise NotImplementedError('{:04x} - {}'.format(instruction, args))

        self.INSTRUCTION_SET.get(instruction)(*args)

    def fetch(self):
        return self.memory.read_word(self.program_counter)

    def cycle(self):
        word = self.fetch()
        instruction, args = self.decode(word)
        self.execute(instruction, args)

        if self.delay_timer > 0:
            self.delay_timer -= 1

        if self.sound_timer > 0:
            if self.sound_timer == 1:
                self.beep()
            self.sound_timer -= 1

    def increment_program_counter(self):
        self.program_counter += 0x2

    def skip_next_instruction(self):
        self.program_counter += 0x4

    def wait_for_keypress(self):
        raise NotImplementedError()

    def beep(self):
        print 'Beep!'

    # INSTRUCTIONS
    def op_00E0(self):
        'Clear screen'
        self.screen.clear()
        self.increment_program_counter()

    def op_00EE(self):
        'Return from a subroutine.'
        self.program_counter = self.stack.pop()

    def op_1NNN(self, address):
        'Jump to address NNN.'
        self.program_counter = address

    def op_2NNN(self, address):
        'Execute subroutine starting at address NNN.'
        self.increment_program_counter()
        self.stack.append(self.program_counter)
        self.program_counter = address

    def op_3XNN(self, X, NN):
        'Skip the following instruction if the value of VX == NN.'
        if self.registers[X] == NN:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_4XNN(self, X, NN):
        'Skip the following instruction if the value of VX != NN.'
        if self.registers[X] != NN:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_5XY0(self, X, Y):
        'Skip next instruction if the value of VX == the value of VY.'
        if self.registers[X] == self.registers[Y]:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_6XNN(self, X, NN):
        'Store number NN in register VX.'
        self.registers[X] = NN
        self.increment_program_counter()

    def op_7XNN(self, X, NN):
        'Add the value NN to register VX.'
        self.registers[X] = byte(self.registers[X] + NN)
        self.increment_program_counter()

    def op_8XY0(self, X, Y):
        'Store the value of register VY in register VX.'
        self.registers[X] = self.registers[Y]
        self.increment_program_counter()

    def op_8XY1(self, X, Y):
        'Set VX to VX OR VY'
        self.registers[X] |= self.registers[Y]
        self.increment_program_counter()

    def op_8XY2(self, X, Y):
        'Set VX to VX AND VY'
        self.registers[X] &= self.registers[Y]
        self.increment_program_counter()

    def op_8XY3(self, X, Y):
        'Set VX to VX XOR VY.'
        self.registers[X] ^= self.registers[Y]
        self.increment_program_counter()

    def op_8XY4(self, X, Y):
        '''Add the value of register VY to register VX
           Set VF to 01 if a carry occurs
           Set VF to 00 if a carry does not occur'''
        value = self.registers[X] + self.registers[Y]
        self.registers[X] = byte(value)
        self.registers[0xF] = 1 if value > 0xFF else 0
        self.increment_program_counter()

    def op_8XY5(self, X, Y):
        '''
        Subtract the value of register VY from register VX
        Set VF to 00 if a borrow occurs
        Set VF to 01 if a borrow does not occur
        '''
        value = self.registers[X] - self.registers[Y]
        self.registers[X] = byte(value)
        self.registers[0xF] = 0 if value < 0 else 1
        self.increment_program_counter()

    def op_8XY6(self, X, Y):
        '''
        Store the value of register VY shifted right one bit in  VX
        Set VF to the least significant bit prior to the shift
        '''
        self.registers[X] = self.registers[Y] >> 1
        self.registers[0xF] = self.registers[Y] & 1
        self.increment_program_counter()

    def op_8XY7(self, X, Y):
        '''
        Set register VX to the value of VY minus VX
        Set VF to 00 if a borrow occurs
        Set VF to 01 if a borrow does not occur
        '''
        value = self.registers[Y] - self.registers[X]
        self.registers[X] = byte(value)
        self.registers[0xF] = 0 if value < 0 else 1
        self.increment_program_counter()

    def op_8XYE(self, X, Y):
        '''
        Store the value of register VY shifted left one bit in VX
        Set VF to the most significant bit prior to the shift
        '''
        self.registers[X] = byte(self.registers[Y] << 1)
        self.registers[0xF] = self.registers[Y] >> 7
        self.increment_program_counter()

    def op_9XY0(self, X, Y):
        'Skip the following instruction if the value VX != value VY.'
        if self.registers[X] != self.registers[Y]:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_ANNN(self, address):
        'Store memory address NNN in register I.'
        self.index_register = address
        self.increment_program_counter()

    def op_BNNN(self, address):
        'Jump to address NNN + V0.'
        self.program_counter = address + self.registers[0]

    def op_CXNN(self, X, NN):
        'Set VX to a random number with a mask of NN.'
        self.registers[X] = randint(0, 0xFF) & NN
        self.increment_program_counter()

    def op_DXYN(self, VX, VY, N):
        x = self.registers[VX]
        y = self.registers[VY]
        sprite = self.memory.read(self.index_register, N)
        collision = self.screen.draw(sprite, x, y)
        self.registers[0xF] = bool(collision)
        self.increment_program_counter()

    def op_EX9E(self, X):
        key = self.registers[X]
        if self.keyboard[key]:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_EXA1(self, X):
        key = self.registers[X]
        if not self.keyboard[key]:
            self.skip_next_instruction()
        else:
            self.increment_program_counter()

    def op_FX0A(self, X):
        key = self.wait_for_keypress()
        self.keyboard[key] = True
        self.registers[X] = key
        self.increment_program_counter()

    def op_FX07(self, X):
        'Store the current value of the delay timer in register VX.'
        self.registers[X] = self.delay_timer
        self.increment_program_counter()

    def op_FX15(self, X):
        'Set the delay timer to the value of register VX.'
        self.delay_timer = self.registers[X]
        self.increment_program_counter()

    def op_FX18(self, X):
        'Set the sound timer to the value of register VX.'
        self.sound_timer = self.registers[X]
        self.increment_program_counter()

    def op_FX1E(self, X):
        'Add the value stored in register VX to register I.'
        self.index_register += self.registers[X]
        self.increment_program_counter()

    def op_FX29(self, X):
        '''
        Set I to the memory address of the sprite data corresponding
        to the hexadecimal digit stored in register VX.
        '''
        sprite = self.registers[X] % 16
        self.index_register = self.memory.font_address(sprite)
        self.increment_program_counter()

    def op_FX33(self, X):
        '''
        Store the binary-coded decimal equivalent of the value
        stored in register VX at addresses I, I+1, and I+2
        Example: VX=0xFF (255); I=2, I+1=5, I+2=5
        '''
        data = bcd(self.registers[X])
        self.memory.load(self.index_register, data)
        self.increment_program_counter()

    def op_F055(self, X):
        'Store values of V0 to VX inclusive in mem starting at addr I.'
        data = self.registers[0:X + 1]
        self.memory.load(self.index_register, data)
        self.increment_program_counter()

    def op_FX65(self, X):
        '''
        Fill registers V0 to VX inclusive with the values stored in
        memory starting at address I
        I is set to I + X + 1 after operation
        '''
        data = self.memory.read(self.index_register, X + 1)
        for R in range(X + 1):
            self.registers[R] = data[R]
        self.increment_program_counter()