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)
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()