Beispiel #1
0
    def ini_registers(self):
        self.b    = Register(self)
        self.c    = Register(self)
        self.bc   = DoubleRegister(self, self.b, self.c, constants.RESET_BC)
        
        self.d    = Register(self)
        self.e    = Register(self)
        self.de   = DoubleRegister(self, self.d, self.e, constants.RESET_DE)

        self.h    = Register(self)
        self.l    = Register(self)
        self.hl   = DoubleRegister(self, self.h, self.l, constants.RESET_HL)
        
        self.hli  = ImmediatePseudoRegister(self, self.hl)
        self.pc   = ReservedDoubleRegister(self, reset_value=constants.RESET_PC)
        self.sp   = ReservedDoubleRegister(self, reset_value=constants.RESET_SP)
        
        self.a    = Register(self, constants.RESET_A)
        self.flag = FlagRegister(self, constants.RESET_F)
        self.af   = DoubleRegister(self, self.a, self.flag)
Beispiel #2
0
class CPU(object):
    """
    PyGIRL GameBoy (TM) Emulator
    
    Central Unit Processor_a (Sharp LR35902 CPU)
    """
    def __init__(self, interrupt, memory):
        assert isinstance(interrupt, Interrupt)
        self.interrupt = interrupt
        self.memory    = memory
        self.ime       = False
        self.halted    = False
        self.cycles    = 0
        self.ini_registers()
        self.rom       = [0]
        self.reset()

    def ini_registers(self):
        self.b    = Register(self)
        self.c    = Register(self)
        self.bc   = DoubleRegister(self, self.b, self.c, constants.RESET_BC)
        
        self.d    = Register(self)
        self.e    = Register(self)
        self.de   = DoubleRegister(self, self.d, self.e, constants.RESET_DE)

        self.h    = Register(self)
        self.l    = Register(self)
        self.hl   = DoubleRegister(self, self.h, self.l, constants.RESET_HL)
        
        self.hli  = ImmediatePseudoRegister(self, self.hl)
        self.pc   = ReservedDoubleRegister(self, reset_value=constants.RESET_PC)
        self.sp   = ReservedDoubleRegister(self, reset_value=constants.RESET_SP)
        
        self.a    = Register(self, constants.RESET_A)
        self.flag = FlagRegister(self, constants.RESET_F)
        self.af   = DoubleRegister(self, self.a, self.flag)
        

    def reset(self):
        self.reset_registers()
        self.flag.reset()
        self.flag.is_zero = True
        self.ime          = False
        self.halted       = False
        self.cycles       = 0
        self.instruction_counter        = 0
        self.last_op_code               = -1
        self.last_fetch_execute_op_code = -1
        
    def reset_registers(self):
        self.a.reset()
        self.flag.reset()
        self.bc.reset()
        self.de.reset()
        self.hl.reset()
        self.sp.reset()
        self.pc.reset()
    
    # ---------------------------------------------------------------

    def get_af(self):
        return self.af
        
    def get_a(self):
        return self.a
    
    def get_f(self):
        return self.f
        
    def get_bc(self):
        return self.bc
    
    def get_b(self):
        return self.b
    
    def get_c(self):
        return self.c
        
    def get_de(self):
        return self.de
        
    def get_d(self):
        return self.d
        
    def get_e(self):
        return self.e
        
    def get_hl(self):
        return self.hl
        
    def get_hli(self):
        return self.hli
        
    def get_h(self):
        return self.h
        
    def get_l(self):
        return self.l
             
    def get_sp(self):
        return self.sp

    def get_if(self):
        val = 0x00
        if self.ime:
            val = 0x01
        if self.halted:
            val += 0x80
        return val

    def is_z(self):
        """ zero flag"""
        return self.flag.is_zero

    def is_c(self):
        """ carry flag, true if the result did not fit in the register"""
        return self.flag.is_carry

    def is_h(self):
        """ half carry, carry from bit 3 to 4"""
        return self.flag.is_half_carry

    def is_n(self):
        """ subtract flag, true if the last operation was a subtraction"""
        return self.flag.is_subtraction
    
    def isS(self):
        return self.flag.s_flag
    
    def is_p(self):
        return self.flag.p_flag
    
    def is_not_z(self):
        return not self.is_z()

    def is_not_c(self):
        return not self.is_c()
    
    def is_not_h(self):
        return not self.is_h()

    def is_not_n(self):
        return not self.is_n()

    def set_rom(self, banks):
        self.rom = banks       
    
    # ---------------------------------------------------------------
    
    def emulate(self, ticks):
        self.cycles += ticks
        self.handle_pending_interrupts()
        while self.cycles > 0:
            self.execute(self.fetch(use_cycles=False))
            
    def emulate_step(self):
        self.handle_pending_interrupts()
        self.execute(self.fetch(use_cycles=False))
        

    def handle_pending_interrupts(self):
        if self.halted:
            self.update_interrupt_cycles()
        if self.ime and self.interrupt.is_pending():
            self.lower_pending_interrupt()
            
    def update_interrupt_cycles(self):
        if self.interrupt.is_pending():
            self.halted = False
            self.cycles -= 4
        elif self.cycles > 0:
            self.cycles = 0
        
    def lower_pending_interrupt(self):
        for flag in self.interrupt.interrupt_flags:
            if flag.is_pending():
                self.ime = False
                self.call(flag.call_code, use_cycles=False)
                flag.set_pending(False)
                return

    def fetch_execute(self):
        op_code = self.fetch()
        self.last_fetch_execute_op_code = op_code
        FETCH_EXECUTE_OP_CODES[op_code](self)
        
        
    def execute(self, op_code):
        self.instruction_counter += 1
        self.last_op_code = op_code
        OP_CODES[op_code](self)
        
        
    # -------------------------------------------------------------------
        
    def debug(self):
        #print "0xDD called"
        pass
        
    def read(self, hi, lo=None):
        # memory Access, 1 cycle
        address = hi
        if lo is not None:
            address = (hi << 8) + lo
        self.cycles -= 1
        return self.memory.read(address)

    def write(self, address, data):
        # 2 cycles
        self.memory.write(address, data)
        self.cycles -= 2

    def fetch(self, use_cycles=True):
        # Fetching  1 cycle
        if use_cycles:
            self.cycles += 1
        pc = self.pc.get(use_cycles)
        if pc <= 0x3FFF:
            data =  self.rom[self.pc.get(use_cycles)]
        else:
            data = self.memory.read(self.pc.get(use_cycles))
        self.pc.inc(use_cycles) # 2 cycles
        return data
    
    def fetch_double_address(self):
        lo = self.fetch() # 1 cycle
        hi = self.fetch() # 1 cycle
        return (hi << 8) + lo
        
    def fetch_double_register(self, register):
        self.double_register_inverse_call(CPUFetchCaller(self), register)
        self.cycles += 1

    def push(self, data, use_cycles=True):
        # Stack, 2 cycles
        self.sp.dec(use_cycles) # 2 cycles
        self.memory.write(self.sp.get(use_cycles), data)
        
    def push_double_register(self, register, use_cycles=True):
        # PUSH rr 4 cycles
        self.push(register.get_hi(), use_cycles) # 2 cycles
        self.push(register.get_lo(), use_cycles) # 2 cycles

    def pop(self, use_cycles=True):
        # 1 cycle
        data = self.memory.read(self.sp.get())
        self.sp.inc() # 2 cycles
        self.cycles += 1
        return data
    
    def pop_double_register(self, register):
        # 3 cycles
        self.double_register_inverse_call(CPUPopCaller(self), register)
        self.cycles += 1
        
    def double_register_inverse_call(self, getCaller, register):
        register.set_lo(getCaller.get()) # 2 cycles
        register.set_hi(getCaller.get()) # 2 cycles
        
    def call(self, address, use_cycles=True):
        # 4 cycles
        self.push_double_register(self.pc, use_cycles)
        self.pc.set(address, use_cycles=use_cycles)       # 1 cycle
        if use_cycles:
            self.cycles += 1
        
    def load(self, getCaller, setCaller):
        # 1 cycle
        value = getCaller.get()
        setCaller.set(value) # 1 cycle
        
    def load_fetch_register(self, register):
        self.load(CPUFetchCaller(self), RegisterCallWrapper(register))
        
    def store_hl_in_pc(self):
        # LD PC,HL, 1 cycle
        self.load(DoubleRegisterCallWrapper(self.hl), 
                  DoubleRegisterCallWrapper(self.pc))
        
    def fetch_load(self, getCaller, setCaller):
        self.load(CPUFetchCaller(self), setCaller)

    def add_a(self, getCaller, setCaller=None):
        # TODO: Test overflow -> carry flag
        data = getCaller.get()
        # ALU, 1 cycle
        added = self.a.get() + data
        self.add_sub_flag_finish(added, data)
        
    def add_hl(self, register):
        # 2 cycles
        data = register.get()
        added = (self.hl.get() + data) # 1 cycle
        self.flag.partial_reset(keep_is_zero=True)
        self.flag.is_half_carry = (((added ^ self.hl.get() ^ data) & 0x1000) != 0) 
        self.flag.is_carry = (added >= 0x10000 or added < 0)
        self.hl.set(added & 0xFFFF)
        self.cycles -= 1
        
    def add_a_with_carry(self, getCaller, setCaller=None):
        # 1 cycle
        data = getCaller.get()
        s = self.a.get() + data + int(self.flag.is_carry)
        self.add_sub_flag_finish(s,data)

    def subtract_with_carry_a(self, getCaller, setCaller=None):
        # 1 cycle
        data = getCaller.get()
        s = self.a.get() - data - int(self.flag.is_carry)
        self.add_sub_flag_finish(s, data)
        self.flag.is_subtraction = True
        
    def add_sub_flag_finish(self, s, data):
        self.flag.reset()
        # set the h flag if the 0x10 bit was affected
        self.flag.is_half_carry = (((s ^ self.a.get() ^ data) & 0x10) != 0)
        self.flag.is_carry = (s > 0xFF or s < 0)
        self.flag.zero_check(s)
        self.a.set(s & 0xFF)  # 1 cycle
        
    def subtract_a(self, getCaller, setCaller=None):
        # 1 cycle
        data = getCaller.get()
        self.compare_a_simple(data)
        self.a.sub(data, False)
 
    def fetch_subtract_a(self):
        data = self.fetch()
        # 1 cycle
        self.compare_a_simple(data) # 1 cycle
        self.a.sub(data, False)

    def compare_a(self, getCaller, setCaller=None):
        # 1 cycle
        self.compare_a_simple(getCaller.get())
        
    def compare_a_simple(self, s):
        s = (self.a.get() - s) & 0xFF
        self.flag.reset()
        self.flag.is_subtraction = True
        self.flag.zero_check(s)
        self.subtract_his_carry_finish(s)
        self.cycles -= 1
            
    def subtract_his_carry_finish(self, data):
        self.flag.is_carry = (data > self.a.get())
        self.flag.is_half_carry_compare(data, self.a.get())
        
    def and_a(self, getCaller, setCaller=None):
        # 1 cycle
        self.a.set(self.a.get() & getCaller.get())  # 1 cycle
        self.flag.reset()
        self.flag.zero_check(self.a.get())
        self.flag.is_half_carry = True

    def xor_a(self, getCaller, setCaller=None):
        # 1 cycle
        self.a.set( self.a.get() ^ getCaller.get())  # 1 cycle
        self.flag.reset()
        self.flag.zero_check(self.a.get())

    def or_a(self, getCaller, setCaller=None):
        # 1 cycle
        self.a.set(self.a.get() | getCaller.get())  # 1 cycle
        self.flag.reset()
        self.flag.zero_check(self.a.get())

    def inc_double_register(self, register):
        # INC rr
        register.inc()

    def dec_double_register(self, register):
        # DEC rr
        register.dec()

    def inc(self, getCaller, setCaller):
        # 1 cycle
        data = (getCaller.get() + 1) & 0xFF
        self.dec_inis_carry_finish(data, setCaller, 0x00)
        
    def dec(self, getCaller, setCaller):
        # 1 cycle
        data = (getCaller.get() - 1) & 0xFF
        self.dec_inis_carry_finish(data, setCaller, 0x0F)
        self.flag.is_subtraction = True
     
    def dec_inis_carry_finish(self, data, setCaller, compare):
        self.flag.partial_reset(keep_is_carry=True)
        self.flag.zero_check(data)
        self.flag.is_half_carry = ((data & 0x0F) == compare)
        setCaller.set(data) # 1 cycle

    def rotate_left_circular(self, getCaller, setCaller):
        # RLC 1 cycle
        data = getCaller.get()
        s = ((data << 1) & 0xFF) + ((data & 0x80) >> 7)
        self.flags_and_setter_finish(s, data, setCaller, 0x80)
        # self.cycles -= 1

    def rotate_left_circular_a(self):
        # RLCA rotate_left_circular_a 1 cycle
        self.rotate_left_circular(RegisterCallWrapper(self.a), 
                                  RegisterCallWrapper(self.a))

    def rotate_left(self, getCaller, setCaller):
        # 1 cycle
        data = getCaller.get()
        s = ((data & 0x7F) << 1) + int(self.flag.is_carry)
        self.flags_and_setter_finish(s, data, setCaller, 0x80) # 1 cycle

    def rotate_left_a(self):
        # RLA  1 cycle
        self.rotate_left(RegisterCallWrapper(self.a), 
                         RegisterCallWrapper(self.a))
        
    def rotate_right_circular(self, getCaller, setCaller):
        data = getCaller.get()
        # RRC 1 cycle
        s = (data >> 1) + ((data & 0x01) << 7)
        self.flags_and_setter_finish(s, data, setCaller) # 1 cycle
   
    def rotate_right_circular_a(self):
        # RRCA 1 cycle
        self.rotate_right_circular(RegisterCallWrapper(self.a), 
                                   RegisterCallWrapper(self.a))

    def rotate_right(self, getCaller, setCaller):
        # 1 cycle
        data = getCaller.get()
        s = (data >> 1)
        if self.flag.is_carry:
            s +=  0x80
        self.flags_and_setter_finish(s, data, setCaller) # 1 cycle

    def rotate_right_a(self):
        # RRA 1 cycle
        self.rotate_right(RegisterCallWrapper(self.a), 
                          RegisterCallWrapper(self.a))
   
    def shift_left_arithmetic(self, getCaller, setCaller):
        # 2 cycles
        data = getCaller.get()
        s = (data << 1) & 0xFF
        self.flags_and_setter_finish(s, data, setCaller, 0x80) # 1 cycle

    def shift_right_arithmetic(self, getCaller, setCaller):
        data = getCaller.get()
        # 1 cycle
        s = (data >> 1) + (data & 0x80)
        self.flags_and_setter_finish(s, data, setCaller) # 1 cycle

    def shift_word_right_logical(self, getCaller, setCaller):
        # 2 cycles
        data = getCaller.get()
        s = (data >> 1)
        self.flags_and_setter_finish(s, data, setCaller) # 2 cycles
         
    def flags_and_setter_finish(self, s, data, setCaller, compare_and=0x01):
        # 2 cycles
        s &= 0xFF
        self.flag.reset()
        self.flag.zero_check(s)
        self.flag.is_carry_compare(data, compare_and)
        setCaller.set(s) # 1 cycle

    def swap(self, getCaller, setCaller):
        # 1 cycle
        data = getCaller.get()
        s = ((data << 4) + (data >> 4)) & 0xFF
        self.flag.reset()
        self.flag.zero_check(s)
        setCaller.set(s)

    def test_bit(self, getCaller, setCaller, n):
        # 1 cycle
        self.flag.partial_reset(keep_is_carry=True)
        self.flag.is_half_carry = True
        self.flag.is_zero = ((getCaller.get() & (1 << n)) == 0)
        self.cycles -= 1

    def set_bit(self, getCaller, setCaller, n):
        # 1 cycle
        setCaller.set(getCaller.get() | (1 << n)) # 1 cycle
        
    def reset_bit(self, getCaller, setCaller, n):
        # 1 cycle
        setCaller.set(getCaller.get() & (~(1 << n))) # 1 cycle
        
    def store_fetched_memory_in_a(self):
        # LD A,(nnnn), 4 cycles
        self.a.set(self.read(self.fetch_double_address()))  # 1+1 + 2 cycles

    def write_a_at_bc_address(self):
        # 2 cycles
        self.write(self.bc.get(), self.a.get())
        
    def write_a_at_de_address(self):
        self.write(self.de.get(), self.a.get())
           
    def store_memory_at_bc_in_a(self):
        self.a.set(self.read(self.bc.get()))

    def store_memory_at_de_in_a(self):
        self.a.set(self.read(self.de.get()))

    def ld_dbRegisteri_A(self, register):
        # LD (rr),A  2 cycles
        self.write(register.get(), self.a.get()) # 2 cycles

    def load_mem_sp(self):
        # LD (nnnn),SP  5 cycles
        address = self.fetch_double_address() # 2 cycles
        self.write(address,       self.sp.get_lo())  # 2 cycles
        self.write((address + 1), self.sp.get_hi()) # 2 cycles
        self.cycles += 1

    def store_a_at_fetched_address(self):
        # LD (nnnn),A  4 cycles
        self.write(self.fetch_double_address(), self.a.get()) # 2 cycles

    def store_memory_at_expanded_fetch_address_in_a(self):
        # LDH A,(nn) 3 cycles
        self.a.set(self.read(0xFF00 + self.fetch())) # 1+1+1 cycles
        
    def store_expanded_c_in_a(self):
        # LDH A,(C) 2 cycles
        self.a.set(self.read(0xFF00 + self.bc.get_lo())) # 1+2 cycles
        
    def load_and_increment_a_hli(self):
        # loadAndIncrement A,(HL) 2 cycles
        self.a.set(self.read(self.hl.get())) # 2 cycles
        self.hl.inc()# 2 cycles
        self.cycles += 2
        
    def load_and_decrement_a_hli(self):
        # loadAndDecrement A,(HL)  2 cycles
        self.a.set(self.read(self.hl.get())) # 2 cycles
        self.hl.dec() # 2 cycles
        self.cycles += 2
        
    def write_a_at_expanded_fetch_address(self):
        # LDH (nn),A 3 cycles
        self.write(0xFF00 + self.fetch(), self.a.get()) # 2 + 1 cycles

    def write_a_at_expanded_c_address(self):
        # LDH (C),A 2 cycles
        self.write(0xFF00 + self.c.get(), self.a.get()) # 2 cycles
        
    def load_and_increment_hli_a(self):
        # loadAndIncrement (HL),A 2 cycles
        self.write(self.hl.get(), self.a.get()) # 2 cycles
        self.hl.inc() # 2 cycles
        self.cycles += 2

    def load_and_decrement_hli_a(self):
        # loadAndDecrement (HL),A  2 cycles
        self.write(self.hl.get(), self.a.get()) # 2 cycles
        self.hl.dec() # 2 cycles
        self.cycles += 2

    def store_hl_in_sp(self):
        # LD SP,HL 2 cycles
        self.sp.set(self.hl.get()) # 1 cycle
        self.cycles -= 1

    def complement_a(self):
        # CPA
        self.a.set(self.a.get() ^ 0xFF)
        self.flag.is_subtraction = True
        self.flag.is_half_carry = True

    def decimal_adjust_a(self):
        # DAA 1 cycle
        delta = 0
        if self.is_h(): 
            delta |= 0x06
        if self.is_c():
            delta |= 0x60
        if (self.a.get() & 0x0F) > 0x09:
            delta |= 0x06
            if (self.a.get() & 0xF0) > 0x80:
                delta |= 0x60
        if (self.a.get() & 0xF0) > 0x90:
            delta |= 0x60
        if not self.is_n():
            self.a.set((self.a.get() + delta) & 0xFF) # 1 cycle
        else:
            self.a.set((self.a.get() - delta) & 0xFF) # 1 cycle
        self.flag.partial_reset(keep_is_subtraction=True)
        if delta >= 0x60:
            self.flag.is_carry = True
        self.flag.zero_check(self.a.get())

    def increment_sp_by_fetch(self):
        # ADD SP,nn 4 cycles
        self.sp.set(self.get_fetchadded_sp()) # 1+1 cycle
        self.cycles -= 2

    def store_fetch_added_sp_in_hl(self):
        # LD HL,SP+nn   3  cycles
        self.hl.set(self.get_fetchadded_sp()) # 1+1 cycle
        self.cycles -= 1

    def get_fetchadded_sp(self):
        # 1 cycle
        offset = process_2s_complement(self.fetch()) # 1 cycle
        s = (self.sp.get() + offset) & 0xFFFF
        self.flag.reset()
        if (offset >= 0):
            self.flag.is_carry = (s < self.sp.get())
            if (s & 0x0F00) < (self.sp.get() & 0x0F00):
                self.flag.is_half_carry = True
        else:
            self.flag.is_carry = (s > self.sp.get())
            if (s & 0x0F00) > (self.sp.get() & 0x0F00):
                self.flag.is_half_carry = True
        return s
        
    def complement_carry_flag(self):
        # CCF/SCF
        self.flag.partial_reset(keep_is_zero=True, keep_is_carry=True)
        self.flag.is_carry = not self.flag.is_carry

    def set_carry_flag(self):
        self.flag.partial_reset(keep_is_zero=True)
        self.flag.is_carry = True

    def nop(self):
        # NOP 1 cycle
        self.cycles -= 1

    def jump(self):
        # JP nnnn, 4 cycles
        self.pc.set(self.fetch_double_address()) # 1+2 cycles
        self.cycles -= 1

    def conditional_jump(self, cc):
        # JP cc,nnnn 3,4 cycles
        if cc:
            self.jump() # 4 cycles
        else:
            self.pc.add(2) # 3 cycles

    def relative_jump(self):
        # JR +nn, 3 cycles
        self.pc.add(process_2s_complement(self.fetch())) # 3 + 1 cycles
        self.cycles += 1

    def relative_conditional_jump(self, cc):
        # JR cc,+nn, 2,3 cycles
        if cc:
            self.relative_jump() # 3 cycles
        else:
            self.pc.inc() # 2 cycles
    
    def unconditional_call(self):
        # CALL nnnn, 6 cycles
        self.call(self.fetch_double_address())  # 4+2 cycles

    def conditional_call(self, cc):
        # CALL cc,nnnn, 3,6 cycles
        if cc:
            self.unconditional_call() # 6 cycles
        else:
            self.pc.add(2) # 3 cycles

    def ret(self):
        # RET 4 cycles
        self.double_register_inverse_call(CPUPopCaller(self), self.pc)

    def conditional_return(self, cc):
        # RET cc 2,5 cycles
        if cc:
            self.ret() # 4 cycles
            # FIXME maybe this should be the same
            self.cycles -= 1
        else:
            self.cycles -= 2

    def return_from_interrupt(self):
        # RETI 4 cycles
        self.ret() # 4 cycles
        self.cycles += 1
        self.enable_interrupts()

    def restart(self, nn):
        # RST nn 4 cycles
        self.call(nn) # 4 cycles

    def disable_interrupts(self):
        # DI/EI 1 cycle
        self.ime     = False
        self.cycles -= 1

    def enable_interrupts(self):
        # 1 cycle
        self.ime = True
        self.execute(self.fetch())
        self.handle_pending_interrupts()

    def halt(self):
        # HALT/STOP
        self.halted = True
        # emulate bug when interrupts are pending
        if not self.ime and self.interrupt.is_pending():
            self.execute(self.memory.read(self.pc.get()))
        self.handle_pending_interrupts()

    def stop(self):
        # 0 cycles
        self.cycles += 1
        self.fetch()