Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

205 wiersze
7.3KB

  1. """Minimal NMOS 6502 emulator (official opcodes, binary-mode ADC/SBC) with cycle counts.
  2. Used to check that a rewritten runtime helper behaves exactly like the original one
  3. (same zero page / memory / registers afterwards) and to compare their cycle costs.
  4. """
  5. import sys, os
  6. sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
  7. from pcopt import DEC, SIZE
  8. BASECYC = {
  9. 'imp': 2, 'acc': 2, 'imm': 2, 'zp': 3, 'zpx': 4, 'zpy': 4, 'abs': 4, 'abx': 4, 'aby': 4,
  10. 'izx': 6, 'izy': 5, 'rel': 2, 'ind': 5,
  11. }
  12. # read-modify-write and store extra cycles
  13. RMW = {'asl', 'lsr', 'rol', 'ror', 'inc', 'dec'}
  14. STORE = {'sta', 'stx', 'sty'}
  15. class CPU:
  16. def __init__(s):
  17. s.m = bytearray(65536)
  18. s.a = s.x = s.y = 0
  19. s.sp = 0xFF
  20. s.pc = 0
  21. s.c = s.z = s.n = s.v = 0
  22. s.cyc = 0
  23. s.i = 0; s.d = 0
  24. s.watch = None
  25. # --- helpers
  26. def rd(s, a):
  27. return s.m[a & 0xFFFF]
  28. def wr(s, a, v):
  29. s.m[a & 0xFFFF] = v & 255
  30. def push(s, v):
  31. s.m[0x100 + s.sp] = v & 255
  32. s.sp = (s.sp - 1) & 255
  33. def pull(s):
  34. s.sp = (s.sp + 1) & 255
  35. return s.m[0x100 + s.sp]
  36. def nz(s, v):
  37. v &= 255
  38. s.z = 1 if v == 0 else 0
  39. s.n = v >> 7
  40. return v
  41. def flags(s):
  42. return s.c | s.z << 1 | s.i << 2 | s.d << 3 | 0x30 | s.v << 6 | s.n << 7
  43. def setflags(s, p):
  44. s.c = p & 1; s.z = p >> 1 & 1; s.i = p >> 2 & 1; s.d = p >> 3 & 1; s.v = p >> 6 & 1; s.n = p >> 7 & 1
  45. def ea(s, md, pc):
  46. """effective address, extra-cycle flag"""
  47. m = s.m
  48. if md == 'zp': return m[pc + 1], 0
  49. if md == 'zpx': return (m[pc + 1] + s.x) & 255, 0
  50. if md == 'zpy': return (m[pc + 1] + s.y) & 255, 0
  51. base = m[pc + 1] | m[pc + 2] << 8
  52. if md == 'abs': return base, 0
  53. if md == 'abx':
  54. a = (base + s.x) & 0xFFFF; return a, (a >> 8) != (base >> 8)
  55. if md == 'aby':
  56. a = (base + s.y) & 0xFFFF; return a, (a >> 8) != (base >> 8)
  57. if md == 'izx':
  58. p = (m[pc + 1] + s.x) & 255
  59. return m[p] | m[(p + 1) & 255] << 8, 0
  60. if md == 'izy':
  61. p = m[pc + 1]
  62. b = m[p] | m[(p + 1) & 255] << 8
  63. a = (b + s.y) & 0xFFFF; return a, (a >> 8) != (b >> 8)
  64. raise ValueError(md)
  65. def step(s):
  66. pc = s.pc
  67. op = s.m[pc]
  68. if op == 0x80: # undocumented NOP #imm (2 bytes, 2 cycles) on the NMOS 6502
  69. s.pc = (pc + 2) & 0xFFFF
  70. s.cyc += 2
  71. return
  72. if op not in DEC:
  73. raise ValueError('bad opcode %02x at %04x' % (op, pc))
  74. mn, md = DEC[op]
  75. n = SIZE[md]
  76. cyc = BASECYC[md]
  77. s.pc = (pc + n) & 0xFFFF
  78. if md == 'imm':
  79. val = s.m[pc + 1]; addr = None
  80. elif md in ('imp', 'acc', 'rel', 'ind'):
  81. val = None; addr = None
  82. else:
  83. addr, cross = s.ea(md, pc)
  84. val = None
  85. if mn in RMW or mn in STORE:
  86. if md in ('abx', 'aby', 'izy'): cyc += 1 # always penalised
  87. if mn in RMW: cyc += 2
  88. if mn in STORE and md == 'abs': pass
  89. elif cross:
  90. cyc += 1
  91. if mn in RMW and md in ('zp', 'zpx', 'abs', 'abx'):
  92. pass
  93. rdv = lambda: s.m[addr] if addr is not None else val
  94. if mn == 'lda': s.a = s.nz(rdv())
  95. elif mn == 'ldx': s.x = s.nz(rdv())
  96. elif mn == 'ldy': s.y = s.nz(rdv())
  97. elif mn == 'sta': s.wr(addr, s.a)
  98. elif mn == 'stx': s.wr(addr, s.x)
  99. elif mn == 'sty': s.wr(addr, s.y)
  100. elif mn == 'tax': s.x = s.nz(s.a)
  101. elif mn == 'tay': s.y = s.nz(s.a)
  102. elif mn == 'txa': s.a = s.nz(s.x)
  103. elif mn == 'tya': s.a = s.nz(s.y)
  104. elif mn == 'tsx': s.x = s.nz(s.sp)
  105. elif mn == 'txs': s.sp = s.x
  106. elif mn == 'adc':
  107. b = rdv(); t = s.a + b + s.c
  108. s.v = 1 if (~(s.a ^ b) & (s.a ^ t) & 0x80) else 0
  109. s.c = 1 if t > 255 else 0
  110. s.a = s.nz(t)
  111. elif mn == 'sbc':
  112. b = rdv() ^ 255; t = s.a + b + s.c
  113. s.v = 1 if (~(s.a ^ b) & (s.a ^ t) & 0x80) else 0
  114. s.c = 1 if t > 255 else 0
  115. s.a = s.nz(t)
  116. elif mn == 'and': s.a = s.nz(s.a & rdv())
  117. elif mn == 'ora': s.a = s.nz(s.a | rdv())
  118. elif mn == 'eor': s.a = s.nz(s.a ^ rdv())
  119. elif mn in ('cmp', 'cpx', 'cpy'):
  120. r = {'cmp': s.a, 'cpx': s.x, 'cpy': s.y}[mn]
  121. t = r - rdv()
  122. s.c = 1 if t >= 0 else 0
  123. s.nz(t)
  124. elif mn == 'bit':
  125. b = rdv(); s.z = 1 if (s.a & b) == 0 else 0; s.n = b >> 7; s.v = b >> 6 & 1
  126. elif mn in ('asl', 'lsr', 'rol', 'ror'):
  127. v = s.a if md == 'acc' else s.m[addr]
  128. if mn == 'asl': c = v >> 7; v = v << 1
  129. elif mn == 'lsr': c = v & 1; v = v >> 1
  130. elif mn == 'rol': c = v >> 7; v = v << 1 | s.c
  131. else: c = v & 1; v = v >> 1 | s.c << 7
  132. s.c = c; v = s.nz(v)
  133. if md == 'acc': s.a = v
  134. else: s.wr(addr, v)
  135. elif mn == 'inc': s.wr(addr, s.nz(s.m[addr] + 1))
  136. elif mn == 'dec': s.wr(addr, s.nz(s.m[addr] - 1))
  137. elif mn == 'inx': s.x = s.nz(s.x + 1)
  138. elif mn == 'dex': s.x = s.nz(s.x - 1)
  139. elif mn == 'iny': s.y = s.nz(s.y + 1)
  140. elif mn == 'dey': s.y = s.nz(s.y - 1)
  141. elif mn == 'clc': s.c = 0
  142. elif mn == 'sec': s.c = 1
  143. elif mn == 'cld': s.d = 0
  144. elif mn == 'sed': s.d = 1
  145. elif mn == 'cli': s.i = 0
  146. elif mn == 'sei': s.i = 1
  147. elif mn == 'clv': s.v = 0
  148. elif mn == 'nop': pass
  149. elif mn == 'pha': s.push(s.a); cyc = 3
  150. elif mn == 'pla': s.a = s.nz(s.pull()); cyc = 4
  151. elif mn == 'php': s.push(s.flags()); cyc = 3
  152. elif mn == 'plp': s.setflags(s.pull()); cyc = 4
  153. elif mn in ('bpl', 'bmi', 'bvc', 'bvs', 'bcc', 'bcs', 'bne', 'beq'):
  154. cond = {'bpl': not s.n, 'bmi': s.n, 'bvc': not s.v, 'bvs': s.v, 'bcc': not s.c, 'bcs': s.c,
  155. 'bne': not s.z, 'beq': s.z}[mn]
  156. if cond:
  157. off = s.m[pc + 1]
  158. if off > 127: off -= 256
  159. t = (s.pc + off) & 0xFFFF
  160. cyc += 1 + ((t >> 8) != (s.pc >> 8))
  161. s.pc = t
  162. elif mn == 'jmp':
  163. if md == 'abs':
  164. s.pc = s.m[pc + 1] | s.m[pc + 2] << 8; cyc = 3
  165. else:
  166. p = s.m[pc + 1] | s.m[pc + 2] << 8
  167. s.pc = s.m[p] | s.m[(p & 0xFF00) | ((p + 1) & 0xFF)] << 8
  168. elif mn == 'jsr':
  169. r = (pc + 2) & 0xFFFF
  170. s.push(r >> 8); s.push(r & 255)
  171. s.pc = s.m[pc + 1] | s.m[pc + 2] << 8; cyc = 6
  172. elif mn == 'rts':
  173. lo = s.pull(); hi = s.pull()
  174. s.pc = ((hi << 8 | lo) + 1) & 0xFFFF; cyc = 6
  175. else:
  176. raise ValueError('unsupported ' + mn)
  177. s.cyc += cyc
  178. def call(s, addr, maxsteps=200000):
  179. """JSR addr and run until it returns; returns cycles used (excluding the JSR itself)"""
  180. SENT = 0xFFF0
  181. s.push((SENT - 1) >> 8); s.push((SENT - 1) & 255)
  182. s.pc = addr
  183. c0 = s.cyc
  184. steps = 0
  185. while s.pc != SENT:
  186. s.step()
  187. steps += 1
  188. if steps > maxsteps:
  189. raise RuntimeError('runaway')
  190. return s.cyc - c0

Powered by TurnKey Linux.