def RTS(self, address: int, mode: str): cpu = self.cpu vl = cpu.pop() vh = cpu.pop() v = utils.number_from_bytes([vl, vh]) pc = v + 1 cpu.pc = pc
def SBC(self, address: int, mode: str): cpu = self.cpu mvalue = self.value_from_address(address, mode) v = mvalue r = cpu.a c = cpu.status.carry v = r - v - (1 - c) # C flag: clear if overflow if v < 0: v += 256 cpu.status.carry = 0 else: cpu.status.carry = 1 cpu.a = v cpu.status.set_negative(v) cpu.status.set_zero(v) # 处理 v flag v = utils.number_from_bytes([mvalue], signed=True) r = utils.number_from_bytes([r], signed=True) v = r - v - (1 - c) cpu.status.overflow = int(v > 128 or v < -127)
def ADC(self, address: int, mode: str): cpu = self.cpu mvalue = self.value_from_address(address, mode) v = mvalue r = cpu.a c = cpu.status.carry v = r + v + c # C flag: set if overflow if v > 255: v -= 256 cpu.status.carry = 1 else: cpu.status.carry = 0 cpu.a = v cpu.status.set_negative(v) cpu.status.set_zero(v) # 处理 v flag v = utils.number_from_bytes([mvalue], signed=True) r = utils.number_from_bytes([r], signed=True) v = r + v + c cpu.status.overflow = int(v > 128 or v < -127)
def RTI(self, address: int, mode: str): cpu = self.cpu v = cpu.pop() s = _Status(v) # 从栈里弹出的值,外面不会作用到 P 的 B flag 上 s.break_command = cpu.status.break_command cpu.status = s vl = cpu.pop() vh = cpu.pop() v = utils.number_from_bytes([vl, vh]) # 这里不需要像 RTS 一样 +1 pc = v cpu.pc = pc
def test_number_from_bytes(): test_cases = [ (dict(byte_list=[1]), 1), (dict(byte_list=[1, 0]), 1), (dict(byte_list=[0, 1]), 256), (dict(byte_list=[255]), 255), (dict(byte_list=[255], signed=True), -1), (dict(byte_list=[255, 255], signed=True), -1), (dict(byte_list=[0, 255], signed=True), -256), ] for case in test_cases: input = case[0] expected = case[1] result = utils.number_from_bytes(**input) assert expected == result, (case, result)
def interrupt(self, name: str): if name == 'NMI': # 将 pc 和 p 压栈 pc = self.pc v = pc self.push((v & 0xff00) >> 8) self.push(v & 0x00ff) # 只有「被压入栈」的 status 的 B flag 被置为 1 s = copy.copy(self.status) s.break_command = 1 self.push(s.value) al_pos = 0xfffa elif name == 'RESET': al_pos = 0xfffc else: raise ValueError('错误的 interrupt: <{}>'.format(name)) al = self.memory[al_pos] ah = self.memory[al_pos + 1] addr = utils.number_from_bytes([al, ah]) self.pc = addr
def _execute(self, op: str, addr: Optional[int], mode: str): if op == 'JMP': self.set_reg_value('pc', addr) elif op == 'LDX': v = self._value_from_address(addr, mode) self.set_reg_value('x', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'STX': v = self.reg_value('x') self.set_mem_value(addr, v) elif op == 'JSR': pc = self.reg_value('pc') v = pc - 1 self.push((v & 0xff00) >> 8) self.push(v & 0x00ff) self.set_reg_value('pc', addr) elif op == 'NOP': # do nothing pass elif op == 'SEC': self.set_flag('c', True) elif op == 'BCS': f = self.flag('c') if f: self.set_reg_value('pc', addr) elif op == 'CLC': self.set_flag('c', False) elif op == 'BCC': f = self.flag('c') if not f: self.set_reg_value('pc', addr) elif op == 'LDA': v = self._value_from_address(addr, mode) self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'BEQ': f = self.flag('z') if f: self.set_reg_value('pc', addr) elif op == 'BNE': f = self.flag('z') if not f: self.set_reg_value('pc', addr) elif op == 'STA': v = self.reg_value('a') self.set_mem_value(addr, v) elif op == 'BIT': v = self._value_from_address(addr, mode) a = self.reg_value('a') self.set_flag('n', v & 0b10000000 != 0) self.set_flag('v', v & 0b01000000 != 0) self.set_flag('z', v & a == 0) elif op == 'BVS': f = self.flag('v') if f: self.set_reg_value('pc', addr) elif op == 'BVC': f = self.flag('v') if not f: self.set_reg_value('pc', addr) elif op == 'BPL': f = self.flag('n') if not f: self.set_reg_value('pc', addr) elif op == 'RTS': vl = self.pop() vh = self.pop() v = number_from_bytes([vl, vh]) pc = v + 1 self.set_reg_value('pc', pc) elif op == 'SEI': self.set_flag('i', True) elif op == 'SED': self.set_flag('d', True) elif op == 'PHP': # 在这条指令中,只有「被压入栈」的 P 的 B flag 被置为 True bv = self.reg_value('p') self.set_flag('b', True) v = self.reg_value('p') self.push(v) self.set_reg_value('p', bv) elif op == 'PLA': v = self.pop() self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'AND': v = self._value_from_address(addr, mode) r = self.reg_value('a') v = r & v self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'CMP': v = self._value_from_address(addr, mode) r = self.reg_value('a') v = r - v self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) self.set_flag('c', v >= 0) elif op == 'CLD': self.set_flag('d', False) elif op == 'PHA': v = self.reg_value('a') self.push(v) elif op == 'PLP': v = self.pop() # 从栈里弹出的值,外面不会作用到 P 的 B flag 上 for b in 'NVDIZC': m = self.p_masks[b] f = v & m != 0 self.set_flag(b, f) elif op == 'BMI': f = self.flag('n') if f: self.set_reg_value('pc', addr) elif op == 'ORA': v = self._value_from_address(addr, mode) r = self.reg_value('a') v = r | v self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'CLV': self.set_flag('v', False) elif op == 'EOR': v = self._value_from_address(addr, mode) r = self.reg_value('a') v = r ^ v self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'ADC': mvalue = self._value_from_address(addr, mode) v = mvalue r = self.reg_value('a') c = int(self.flag('c')) v = r + v + c # C flag: set if overflow if v > 255: v -= 256 self.set_flag('c', True) else: self.set_flag('c', False) self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) # 处理 v flag v = number_from_bytes([mvalue], signed=True) r = number_from_bytes([r], signed=True) v = r + v + c self.set_flag('v', v > 128 or v < -127) elif op == 'LDY': v = self._value_from_address(addr, mode) self.set_reg_value('y', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'CPY': v = self._value_from_address(addr, mode) r = self.reg_value('y') v = r - v self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) self.set_flag('c', v >= 0) elif op == 'CPX': v = self._value_from_address(addr, mode) r = self.reg_value('x') v = r - v self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) self.set_flag('c', v >= 0) elif op == 'SBC': mvalue = self._value_from_address(addr, mode) v = mvalue r = self.reg_value('a') c = int(self.flag('c')) v = r - v - (1 - c) # C flag: clear if overflow if v < 0: v += 256 self.set_flag('c', False) else: self.set_flag('c', True) self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) # 处理 v flag v = number_from_bytes([mvalue], signed=True) r = number_from_bytes([r], signed=True) v = r - v - (1 - c) self.set_flag('v', v > 128 or v < -127) elif op == 'INY': v = self.reg_value('y') v += 1 v %= 256 self.set_reg_value('y', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'INX': v = self.reg_value('x') v += 1 v %= 256 self.set_reg_value('x', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'DEY': v = self.reg_value('y') v -= 1 v %= 256 self.set_reg_value('y', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'DEX': v = self.reg_value('x') v -= 1 v %= 256 self.set_reg_value('x', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'TAY': v = self.reg_value('a') self.set_reg_value('y', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'TAX': v = self.reg_value('a') self.set_reg_value('x', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'TYA': v = self.reg_value('y') self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'TXA': v = self.reg_value('x') self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'TSX': v = self.reg_value('s') self.set_reg_value('x', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'TXS': v = self.reg_value('x') self.set_reg_value('s', v) elif op == 'RTI': v = self.pop() # 从栈里弹出的值,外面不会作用到 P 的 B flag 上 for b in 'NVDIZC': m = self.p_masks[b] f = v & m != 0 self.set_flag(b, f) vl = self.pop() vh = self.pop() v = number_from_bytes([vl, vh]) # 这里不需要像 RTS 一样 +1 pc = v self.set_reg_value('pc', pc) elif op == 'LSR': if addr is not None: old_v = self._value_from_address(addr, mode) v = old_v >> 1 self.set_mem_value(addr, v) else: old_v = self.reg_value('a') v = old_v >> 1 self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) self.set_flag('c', old_v & 0b00000001 != 0) elif op == 'ASL': if addr is not None: old_v = self._value_from_address(addr, mode) v = old_v << 1 v %= 256 self.set_mem_value(addr, v) else: old_v = self.reg_value('a') v = old_v << 1 v %= 256 self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) self.set_flag('c', old_v & 0b10000000 != 0) elif op == 'ROR': c = int(self.flag('c')) if addr is not None: old_v = self._value_from_address(addr, mode) v = (old_v >> 1) + (c * 128) self.set_mem_value(addr, v) else: old_v = self.reg_value('a') v = (old_v >> 1) + (c * 128) self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) self.set_flag('c', old_v & 0b00000001 != 0) elif op == 'ROL': c = int(self.flag('c')) if addr is not None: old_v = self._value_from_address(addr, mode) v = (old_v << 1) + c v %= 256 self.set_mem_value(addr, v) else: old_v = self.reg_value('a') v = (old_v << 1) + c v %= 256 self.set_reg_value('a', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) self.set_flag('c', old_v & 0b10000000 != 0) elif op == 'STY': v = self.reg_value('y') self.set_mem_value(addr, v) elif op == 'INC': v = self._value_from_address(addr, mode) v += 1 v %= 256 self.set_mem_value(addr, v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'DEC': v = self._value_from_address(addr, mode) v -= 1 v %= 256 self.set_mem_value(addr, v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'LAX': v = self._value_from_address(addr, mode) self.set_reg_value('a', v) self.set_reg_value('x', v) self.set_flag('n', v & 0b10000000 != 0) self.set_flag('z', v == 0) elif op == 'SAX': v1 = self.reg_value('a') v2 = self.reg_value('x') v = v1 & v2 self.set_mem_value(addr, v) elif op == 'DCP': self._execute('DEC', addr, mode) self._execute('CMP', addr, mode) elif op == 'ISB': self._execute('ISC', addr, mode) elif op == 'ISC': self._execute('INC', addr, mode) self._execute('SBC', addr, mode) elif op == 'SLO': self._execute('ASL', addr, mode) self._execute('ORA', addr, mode) elif op == 'RLA': self._execute('ROL', addr, mode) self._execute('AND', addr, mode) elif op == 'SRE': self._execute('LSR', addr, mode) self._execute('EOR', addr, mode) elif op == 'RRA': self._execute('ROR', addr, mode) self._execute('ADC', addr, mode) elif op == 'BRK': # pc 压栈 # 这里不需要 pc - 1 pc = self.reg_value('pc') v = pc self.push((v & 0xff00) >> 8) self.push(v & 0x00ff) # p 压栈 # 在这条指令中,只有「被压入栈」的 P 的 B flag 被置为 True bv = self.reg_value('p') self.set_flag('b', True) v = self.reg_value('p') self.push(v) self.set_reg_value('p', bv) # 设置中断跳转 vl = self.mem_value(0xfffe) vh = self.mem_value(0xffff) v = number_from_bytes([vl, vh]) self.set_reg_value('pc', v) self.set_flag('i', True) self.set_flag('b', True) else: raise ValueError('错误的 op: <{}>'.format(op))
def address(self, mode: str): if mode == 'IMP': return None elif mode == 'IMM': a = self.next_mem_value() return a elif mode == 'ABS': al = self.next_mem_value() ah = self.next_mem_value() a = number_from_bytes([al, ah]) return a elif mode == 'ZPG': a = self.next_mem_value() return a elif mode == 'ABX': al = self.next_mem_value() ah = self.next_mem_value() a = number_from_bytes([al, ah]) i = self.reg_value('x') return (a + i) % 0x10000 elif mode == 'ABY': al = self.next_mem_value() ah = self.next_mem_value() a = number_from_bytes([al, ah]) i = self.reg_value('y') return (a + i) % 0x10000 elif mode == 'ZPX': a = self.next_mem_value() i = self.reg_value('x') return (a + i) % 0x100 elif mode == 'ZPY': a = self.next_mem_value() i = self.reg_value('y') return (a + i) % 0x100 elif mode == 'IND': tal = self.next_mem_value() tah = self.next_mem_value() ta = number_from_bytes([tal, tah]) # 模拟 6502 的 BUG ta2 = (ta & 0xFF00) | ((ta + 1) & 0x00FF) al = self.mem_value(ta) ah = self.mem_value(ta2) a = number_from_bytes([al, ah]) return a elif mode == 'INX': t = self.next_mem_value() i = self.reg_value('x') ta = (t + i) % 0x100 ta2 = (ta + 1) % 0x100 al = self.mem_value(ta) ah = self.mem_value(ta2) a = number_from_bytes([al, ah]) return a elif mode == 'INY': ta = self.next_mem_value() ta2 = (ta + 1) % 0x100 al = self.mem_value(ta) ah = self.mem_value(ta2) a = number_from_bytes([al, ah]) i = self.reg_value('y') return (a + i) % 0x10000 elif mode == 'REL': diff = self.next_mem_value() diff = number_from_bytes([diff], signed=True) pc = self.reg_value('pc') return (pc + diff) % 0x10000 else: raise ValueError('错误的寻址模式:<{}>'.format(mode))
def test_ppu(): nes = nft.prepared_nes() cpu = nc.NesCPU() cpu.load_nes(nes) rl = cpu.mem_value(0xfffc) rh = cpu.mem_value(0xfffd) reset = number_from_bytes([rl, rh]) cpu.set_reg_value('pc', reset) for _ in range(20000): cpu.execute() expected = [ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 82, 117, 110, 32, 97, 108, 108, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 66, 114, 97, 110, 99, 104, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 70, 108, 97, 103, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 73, 109, 109, 101, 100, 105, 97, 116, 101, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 73, 109, 112, 108, 105, 101, 100, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 83, 116, 97, 99, 107, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 65, 99, 99, 117, 109, 117, 108, 97, 116, 111, 114, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 40, 73, 110, 100, 105, 114, 101, 99, 116, 44, 88, 41, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 90, 101, 114, 111, 112, 97, 103, 101, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 65, 98, 115, 111, 108, 117, 116, 101, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 40, 73, 110, 100, 105, 114, 101, 99, 116, 41, 44, 89, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 65, 98, 115, 111, 108, 117, 116, 101, 44, 89, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 90, 101, 114, 111, 112, 97, 103, 101, 44, 88, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 45, 45, 32, 65, 98, 115, 111, 108, 117, 116, 101, 44, 88, 32, 116, 101, 115, 116, 115, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 85, 112, 47, 68, 111, 119, 110, 58, 32, 115, 101, 108, 101, 99, 116, 32, 116, 101, 115, 116, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 83, 116, 97, 114, 116, 58, 32, 114, 117, 110, 32, 116, 101, 115, 116, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 83, 101, 108, 101, 99, 116, 58, 32, 73, 110, 118, 97, 108, 105, 100, 32, 111, 112, 115, 33, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ] result = cpu.ppu.memory[0x2000:0x2400] assert expected == result, result