A MOS 6502 emulator written in C with a focus on speed, especially for ARM targets.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1029 lines
30KB

  1. #include "e6502.h"
  2. #ifdef E6502_DEBUG
  3. #include <stdio.h>
  4. #include "opcodes.h"
  5. #endif
  6. // Instruction Addressing
  7. #ifdef E6502_POLL_MEM
  8. typedef uint8_t* e6502_Address;
  9. static inline e6502_Address e6502_mem_adr(e6502_Core* core,
  10. e6502_Mem_Addr adr) {
  11. return &core->memory[adr];
  12. }
  13. static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core* core,
  14. e6502_Address adr) {
  15. return (adr - core->memory);
  16. }
  17. static inline uint8_t e6502_adr_r8(e6502_Core* core,
  18. e6502_Address adr) {
  19. return adr[0];
  20. }
  21. static inline uint8_t e6502_adr_r16(e6502_Core* core,
  22. e6502_Address adr) {
  23. return (adr[0] | ((uint16_t)adr[1] << 8));
  24. }
  25. static inline void e6502_adr_w8(e6502_Core* core,
  26. e6502_Address adr,
  27. uint8_t val) {
  28. adr[0] = val;
  29. }
  30. static inline void e6502_adr_w16(e6502_Core* core,
  31. e6502_Address adr,
  32. uint16_t val) {
  33. adr[0] = val;
  34. adr[1] = val >> 8;
  35. }
  36. #else // !E6502_POLL_MEM
  37. typedef uint16_t e6502_Address;
  38. static inline e6502_Address e6502_mem_adr(e6502_Core* core,
  39. e6502_Mem_Addr adr) {
  40. return adr;
  41. }
  42. static inline e6502_Mem_Addr e6502_adr_mem(e6502_Core* core,
  43. e6502_Address adr) {
  44. return adr;
  45. }
  46. static inline uint8_t e6502_adr_r8(e6502_Core* core,
  47. e6502_Address adr) {
  48. return e6502_r8(core, adr);
  49. }
  50. static inline void e6502_adr_w8(e6502_Core* core,
  51. e6502_Address adr,
  52. uint8_t val) {
  53. e6502_w8(core, adr, val);
  54. }
  55. #endif // !E6502_POLL_MEM
  56. // Read values after opcodes
  57. static inline uint8_t arg8(e6502_Core* core) {
  58. return e6502_r8(core, core->registers.PC++);
  59. }
  60. static inline uint16_t arg16(e6502_Core* core) {
  61. return (arg8(core) | ((uint16_t)arg8(core) << 8));
  62. }
  63. // Interpret opcode values
  64. static inline e6502_Address adr_imp(e6502_Core* core) {
  65. return 0;
  66. }
  67. static inline e6502_Address adr_acc(e6502_Core* core) {
  68. return 0;
  69. }
  70. static inline e6502_Address adr_ind(e6502_Core* core) {
  71. return e6502_mem_adr(core, e6502_r16(core, arg16(core)));
  72. }
  73. static inline e6502_Address adr_ind_x(e6502_Core* core) {
  74. return e6502_mem_adr(core, e6502_r16(
  75. core,
  76. (uint8_t)(core->registers.X + arg8(core))
  77. ));
  78. }
  79. static inline e6502_Address adr_ind_y(e6502_Core* core) {
  80. uint16_t zp_adr = e6502_r16(core, arg8(core));
  81. uint8_t old_page = zp_adr >> 8;
  82. uint16_t new_adr = core->registers.Y + zp_adr;
  83. if (new_adr >> 8 != old_page) core->cycle++;
  84. return e6502_mem_adr(core, new_adr);
  85. }
  86. static inline e6502_Address adr_abs_i(e6502_Core* core,
  87. uint8_t i) {
  88. uint16_t abs_adr = arg16(core);
  89. uint8_t old_page = abs_adr >> 8;
  90. uint16_t new_adr = i + abs_adr;
  91. if (new_adr >> 8 != old_page) core->cycle++;
  92. return e6502_mem_adr(core, new_adr);
  93. }
  94. static inline e6502_Address adr_abs_x(e6502_Core* core) {
  95. return adr_abs_i(core, core->registers.X);
  96. }
  97. static inline e6502_Address adr_abs_y(e6502_Core* core) {
  98. return adr_abs_i(core, core->registers.Y);
  99. }
  100. static inline e6502_Address adr_zp(e6502_Core* core) {
  101. return e6502_mem_adr(core, arg8(core));
  102. }
  103. static inline e6502_Address adr_zp_x(e6502_Core* core) {
  104. return e6502_mem_adr(
  105. core, (uint8_t)(arg8(core) + core->registers.X)
  106. );
  107. }
  108. static inline e6502_Address adr_zp_y(e6502_Core* core) {
  109. return e6502_mem_adr(
  110. core, (uint8_t)(arg8(core) + core->registers.Y)
  111. );
  112. }
  113. static inline e6502_Address adr_abs(e6502_Core* core) {
  114. return e6502_mem_adr(core, arg16(core));
  115. }
  116. static inline e6502_Address adr_imm(e6502_Core* core) {
  117. return e6502_mem_adr(core, core->registers.PC++);
  118. }
  119. static inline e6502_Address adr_rel(e6502_Core* core) {
  120. return e6502_mem_adr(
  121. core, (int8_t)arg8(core) + core->registers.PC
  122. );
  123. }
  124. // Instructions
  125. static inline void nop(e6502_Core* core, e6502_Address adr) {
  126. // NOP
  127. }
  128. static inline void brk(e6502_Core *core, e6502_Address adr) {
  129. e6502_push16(core, core->registers.PC + 1);
  130. e6502_push8(core, core->registers.P |
  131. e6502_Status_1 |
  132. e6502_Status_B);
  133. core->registers.P |= e6502_Status_I;
  134. core->registers.PC = e6502_r16(core, e6502_IRQ_Vec);
  135. }
  136. static inline void rti(e6502_Core *core, e6502_Address adr) {
  137. core->registers.P = e6502_pop8(core) |
  138. e6502_Status_1 |
  139. e6502_Status_B;
  140. core->registers.PC = e6502_pop16(core);
  141. }
  142. static inline void ora(e6502_Core *core, e6502_Address adr) {
  143. core->registers.A |= e6502_adr_r8(core, adr);
  144. core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
  145. core->registers.P |= (core->registers.A & e6502_Status_N);
  146. if (!core->registers.A) core->registers.P |= e6502_Status_Z;
  147. }
  148. static inline void eor(e6502_Core *core, e6502_Address adr) {
  149. core->registers.A ^= e6502_adr_r8(core, adr);
  150. core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
  151. core->registers.P |= (core->registers.A & e6502_Status_N);
  152. if (!core->registers.A) core->registers.P |= e6502_Status_Z;
  153. }
  154. static inline void asl(e6502_Core *core, e6502_Address adr) {
  155. // TODO: Emulate double-read or double-write
  156. uint8_t val = e6502_adr_r8(core, adr);
  157. core->registers.P &= ~(e6502_Status_C |
  158. e6502_Status_Z |
  159. e6502_Status_N);
  160. if (val & 0x80) core->registers.P |= e6502_Status_C;
  161. val <<= 1;
  162. core->registers.P |= (val & e6502_Status_N);
  163. if (!val) core->registers.P |= e6502_Status_Z;
  164. e6502_adr_w8(core, adr, val);
  165. }
  166. static inline void asl_a(e6502_Core *core, e6502_Address adr) {
  167. uint8_t val = core->registers.A;
  168. core->registers.P &= ~(e6502_Status_C |
  169. e6502_Status_Z |
  170. e6502_Status_N);
  171. if (val & 0x80) core->registers.P |= e6502_Status_C;
  172. val <<= 1;
  173. core->registers.P |= (val & e6502_Status_N);
  174. if (!val) core->registers.P |= e6502_Status_Z;
  175. core->registers.A = val;
  176. }
  177. static inline void lsr(e6502_Core *core, e6502_Address adr) {
  178. // TODO: Emulate double-read or double-write
  179. uint8_t val = e6502_adr_r8(core, adr);
  180. core->registers.P &= ~(e6502_Status_C |
  181. e6502_Status_Z |
  182. e6502_Status_N);
  183. core->registers.P |= (val & e6502_Status_C);
  184. val >>= 1;
  185. core->registers.P |= (val & e6502_Status_N);
  186. if (!val) core->registers.P |= e6502_Status_Z;
  187. e6502_adr_w8(core, adr, val);
  188. }
  189. static inline void lsr_a(e6502_Core *core, e6502_Address adr) {
  190. uint8_t val = core->registers.A;
  191. core->registers.P &= ~(e6502_Status_C |
  192. e6502_Status_Z |
  193. e6502_Status_N);
  194. core->registers.P |= (val & e6502_Status_C);
  195. val >>= 1;
  196. core->registers.P |= (val & e6502_Status_N);
  197. if (!val) core->registers.P |= e6502_Status_Z;
  198. core->registers.A = val;
  199. }
  200. static inline void rol(e6502_Core *core, e6502_Address adr) {
  201. // TODO: Emulate double-read or double-write
  202. uint8_t val = e6502_adr_r8(core, adr);
  203. uint8_t new_c = (val & 0x80) ? e6502_Status_C : 0;
  204. val <<= 1;
  205. val |= (core->registers.P & e6502_Status_C);
  206. core->registers.P &= ~(e6502_Status_C |
  207. e6502_Status_Z |
  208. e6502_Status_N);
  209. core->registers.P |= new_c;
  210. if (!val) core->registers.P |= e6502_Status_Z;
  211. core->registers.P |= (val & e6502_Status_N);
  212. e6502_adr_w8(core, adr, val);
  213. }
  214. static inline void rol_a(e6502_Core *core, e6502_Address adr) {
  215. uint8_t val = core->registers.A;
  216. uint8_t new_c = (val & 0x80) ? e6502_Status_C : 0;
  217. val <<= 1;
  218. val |= (core->registers.P & e6502_Status_C);
  219. core->registers.P &= ~(e6502_Status_C |
  220. e6502_Status_Z |
  221. e6502_Status_N);
  222. core->registers.P |= new_c;
  223. if (!val) core->registers.P |= e6502_Status_Z;
  224. core->registers.P |= (val & e6502_Status_N);
  225. core->registers.A = val;
  226. }
  227. static inline void ror(e6502_Core *core, e6502_Address adr) {
  228. // TODO: Emulate double-read or double-write
  229. uint8_t val = e6502_adr_r8(core, adr);
  230. uint8_t new_c = (val & e6502_Status_C);
  231. val >>= 1;
  232. if (core->registers.P & e6502_Status_C) val |= e6502_Status_N;
  233. core->registers.P &= ~(e6502_Status_C |
  234. e6502_Status_Z |
  235. e6502_Status_N);
  236. core->registers.P |= new_c;
  237. if (!val) core->registers.P |= e6502_Status_Z;
  238. core->registers.P |= (val & e6502_Status_N);
  239. e6502_adr_w8(core, adr, val);
  240. }
  241. static inline void ror_a(e6502_Core *core, e6502_Address adr) {
  242. uint8_t val = core->registers.A;
  243. uint8_t new_c = (val & e6502_Status_C);
  244. val >>= 1;
  245. if (core->registers.P & e6502_Status_C) val |= e6502_Status_N;
  246. core->registers.P &= ~(e6502_Status_C |
  247. e6502_Status_Z |
  248. e6502_Status_N);
  249. core->registers.P |= new_c;
  250. if (!val) core->registers.P |= e6502_Status_Z;
  251. core->registers.P |= (val & e6502_Status_N);
  252. core->registers.A = val;
  253. }
  254. static inline void pha(e6502_Core *core, e6502_Address adr) {
  255. e6502_push8(core, core->registers.A);
  256. }
  257. static inline void php(e6502_Core *core, e6502_Address adr) {
  258. e6502_push8(core, core->registers.P |
  259. e6502_Status_1 |
  260. e6502_Status_B);
  261. }
  262. static inline void pla(e6502_Core *core, e6502_Address adr) {
  263. core->registers.A = e6502_pop8(core);
  264. core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
  265. if (!core->registers.A) core->registers.P |= e6502_Status_Z;
  266. core->registers.P |= (core->registers.A & e6502_Status_N);
  267. }
  268. static inline void plp(e6502_Core *core, e6502_Address adr) {
  269. core->registers.P = (e6502_pop8(core) |
  270. e6502_Status_1 |
  271. e6502_Status_B);
  272. }
  273. static inline void b(e6502_Core *core, e6502_Address adr) {
  274. uint8_t old_page = core->registers.PC >> 8;
  275. uint16_t new_addr = e6502_adr_mem(core, adr);
  276. if (old_page != (new_addr >> 8)) core->cycle++;
  277. core->registers.PC = new_addr;
  278. core->cycle++;
  279. }
  280. static inline void bpl(e6502_Core *core, e6502_Address adr) {
  281. if (!(core->registers.P & e6502_Status_N)) {
  282. b(core, adr);
  283. }
  284. }
  285. static inline void bmi(e6502_Core *core, e6502_Address adr) {
  286. if (core->registers.P & e6502_Status_N) {
  287. b(core, adr);
  288. }
  289. }
  290. static inline void bcc(e6502_Core *core, e6502_Address adr) {
  291. if (!(core->registers.P & e6502_Status_C)) {
  292. b(core, adr);
  293. }
  294. }
  295. static inline void bcs(e6502_Core *core, e6502_Address adr) {
  296. if (core->registers.P & e6502_Status_C) {
  297. b(core, adr);
  298. }
  299. }
  300. static inline void bvc(e6502_Core *core, e6502_Address adr) {
  301. if (!(core->registers.P & e6502_Status_V)) {
  302. b(core, adr);
  303. }
  304. }
  305. static inline void bvs(e6502_Core *core, e6502_Address adr) {
  306. if (core->registers.P & e6502_Status_V) {
  307. b(core, adr);
  308. }
  309. }
  310. static inline void bne(e6502_Core *core, e6502_Address adr) {
  311. if (!(core->registers.P & e6502_Status_Z)) {
  312. b(core, adr);
  313. }
  314. }
  315. static inline void beq(e6502_Core *core, e6502_Address adr) {
  316. if (core->registers.P & e6502_Status_Z) {
  317. b(core, adr);
  318. }
  319. }
  320. static inline void clc(e6502_Core *core, e6502_Address adr) {
  321. core->registers.P &= ~e6502_Status_C;
  322. }
  323. static inline void cli(e6502_Core *core, e6502_Address adr) {
  324. core->registers.P &= ~e6502_Status_I;
  325. }
  326. static inline void cld(e6502_Core *core, e6502_Address adr) {
  327. core->registers.P &= ~e6502_Status_D;
  328. }
  329. static inline void clv(e6502_Core *core, e6502_Address adr) {
  330. core->registers.P &= ~e6502_Status_V;
  331. }
  332. static inline void sec(e6502_Core *core, e6502_Address adr) {
  333. core->registers.P |= e6502_Status_C;
  334. }
  335. static inline void sei(e6502_Core *core, e6502_Address adr) {
  336. core->registers.P |= e6502_Status_I;
  337. }
  338. static inline void sed(e6502_Core *core, e6502_Address adr) {
  339. core->registers.P |= e6502_Status_D;
  340. }
  341. static inline void jsr(e6502_Core *core, e6502_Address adr) {
  342. e6502_push16(core, core->registers.PC - 1);
  343. core->registers.PC = e6502_adr_mem(core, adr);
  344. }
  345. static inline void jmp(e6502_Core *core, e6502_Address adr) {
  346. core->registers.PC = e6502_adr_mem(core, adr);
  347. }
  348. static inline void rts(e6502_Core *core, e6502_Address adr) {
  349. core->registers.PC = e6502_pop16(core) + 1;
  350. }
  351. static inline void bit(e6502_Core *core, e6502_Address adr) {
  352. uint8_t val = e6502_adr_r8(core, adr);
  353. core->registers.P &= ~(e6502_Status_Z |
  354. e6502_Status_V |
  355. e6502_Status_N);
  356. core->registers.P |= (val & (e6502_Status_V |
  357. e6502_Status_N));
  358. if (!(val & core->registers.A)) {
  359. core->registers.P |= e6502_Status_Z;
  360. }
  361. }
  362. static inline void cmp(e6502_Core *core,
  363. e6502_Address adr,
  364. uint8_t minuend) {
  365. uint8_t val = e6502_adr_r8(core, adr);
  366. uint8_t diff = minuend - val;
  367. core->registers.P &= ~(e6502_Status_C |
  368. e6502_Status_Z |
  369. e6502_Status_N);
  370. if (minuend >= val) core->registers.P |= e6502_Status_C;
  371. if (diff == 0) core->registers.P |= e6502_Status_Z;
  372. core->registers.P |= (diff & e6502_Status_N);
  373. }
  374. static inline void cpa(e6502_Core *core, e6502_Address adr) {
  375. cmp(core, adr, core->registers.A);
  376. }
  377. static inline void cpx(e6502_Core *core, e6502_Address adr) {
  378. cmp(core, adr, core->registers.X);
  379. }
  380. static inline void cpy(e6502_Core *core, e6502_Address adr) {
  381. cmp(core, adr, core->registers.Y);
  382. }
  383. static inline void and(e6502_Core *core, e6502_Address adr) {
  384. core->registers.A &= e6502_adr_r8(core, adr);
  385. core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
  386. core->registers.P |= (core->registers.A & e6502_Status_N);
  387. if (!core->registers.A) core->registers.P |= e6502_Status_Z;
  388. }
  389. static inline void adc(e6502_Core *core, e6502_Address adr) {
  390. uint8_t addend = e6502_adr_r8(core, adr);
  391. uint32_t sum = core->registers.A +
  392. addend +
  393. (core->registers.P & e6502_Status_C);
  394. core->registers.P &= ~(e6502_Status_C | e6502_Status_Z |
  395. e6502_Status_V | e6502_Status_N);
  396. if (sum > 0xFF) core->registers.P |= e6502_Status_C;
  397. if (!(uint8_t)sum) core->registers.P |= e6502_Status_Z;
  398. if ( (addend & 0x80) == (core->registers.A & 0x80) &&
  399. (sum & 0x80) != (addend & 0x80)) {
  400. core->registers.P |= e6502_Status_V;
  401. }
  402. core->registers.P |= (sum & e6502_Status_N);
  403. core->registers.A = sum;
  404. }
  405. static inline void sbc(e6502_Core *core, e6502_Address adr) {
  406. uint8_t addend = e6502_adr_r8(core, adr);
  407. uint32_t sum = core->registers.A -
  408. addend -
  409. (1 - (core->registers.P & e6502_Status_C));
  410. core->registers.P &= ~(e6502_Status_C | e6502_Status_Z |
  411. e6502_Status_V | e6502_Status_N);
  412. if (sum < 0x100) core->registers.P |= e6502_Status_C;
  413. if (!(uint8_t)sum) core->registers.P |= e6502_Status_Z;
  414. if ( (sum & 0x80) != (core->registers.A & 0x80) &&
  415. (addend & 0x80) != (core->registers.A & 0x80)) {
  416. core->registers.P |= e6502_Status_V;
  417. }
  418. core->registers.P |= (sum & e6502_Status_N);
  419. core->registers.A = sum;
  420. }
  421. static inline void inc(e6502_Core *core, e6502_Address adr) {
  422. // TODO: Emulate double-read or double-write
  423. uint8_t val = e6502_adr_r8(core, adr);
  424. e6502_adr_w8(core, adr, val);
  425. val += 1;
  426. core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
  427. core->registers.P |= (val & e6502_Status_N);
  428. if (!val) core->registers.P |= e6502_Status_Z;
  429. e6502_adr_w8(core, adr, val);
  430. }
  431. static inline void ini(e6502_Core *core, uint8_t* reg) {
  432. uint8_t val = *reg + 1;
  433. core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
  434. core->registers.P |= (val & e6502_Status_N);
  435. if (!val) core->registers.P |= e6502_Status_Z;
  436. *reg = val;
  437. }
  438. static inline void inx(e6502_Core *core, e6502_Address adr) {
  439. ini(core, &core->registers.X);
  440. }
  441. static inline void iny(e6502_Core *core, e6502_Address adr) {
  442. ini(core, &core->registers.Y);
  443. }
  444. static inline void dec(e6502_Core *core, e6502_Address adr) {
  445. // TODO: Emulate double-read or double-write
  446. uint8_t val = e6502_adr_r8(core, adr) - 1;
  447. core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
  448. core->registers.P |= (val & e6502_Status_N);
  449. if (!val) core->registers.P |= e6502_Status_Z;
  450. e6502_adr_w8(core, adr, val);
  451. }
  452. static inline void dei(e6502_Core *core, uint8_t* reg) {
  453. uint8_t val = *reg - 1;
  454. core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
  455. core->registers.P |= (val & e6502_Status_N);
  456. if (!val) core->registers.P |= e6502_Status_Z;
  457. *reg = val;
  458. }
  459. static inline void dex(e6502_Core *core, e6502_Address adr) {
  460. return dei(core, &core->registers.X);
  461. }
  462. static inline void dey(e6502_Core *core, e6502_Address adr) {
  463. return dei(core, &core->registers.Y);
  464. }
  465. static inline void sta(e6502_Core *core, e6502_Address adr) {
  466. e6502_adr_w8(core, adr, core->registers.A);
  467. }
  468. static inline void stx(e6502_Core *core, e6502_Address adr) {
  469. e6502_adr_w8(core, adr, core->registers.X);
  470. }
  471. static inline void sty(e6502_Core *core, e6502_Address adr) {
  472. e6502_adr_w8(core, adr, core->registers.Y);
  473. }
  474. static inline void t(e6502_Core *core,
  475. uint8_t* reg,
  476. uint8_t val) {
  477. core->registers.P &= ~(e6502_Status_Z | e6502_Status_N);
  478. core->registers.P |= (val & e6502_Status_N);
  479. if (!val) core->registers.P |= e6502_Status_Z;
  480. *reg = val;
  481. }
  482. static inline void tax(e6502_Core *core, e6502_Address adr) {
  483. t(core, &core->registers.X, core->registers.A);
  484. }
  485. static inline void tay(e6502_Core *core, e6502_Address adr) {
  486. t(core, &core->registers.Y, core->registers.A);
  487. }
  488. static inline void txs(e6502_Core *core, e6502_Address adr) {
  489. core->registers.S = core->registers.X;
  490. }
  491. static inline void txa(e6502_Core *core, e6502_Address adr) {
  492. t(core, &core->registers.A, core->registers.X);
  493. }
  494. static inline void tya(e6502_Core *core, e6502_Address adr) {
  495. t(core, &core->registers.A, core->registers.Y);
  496. }
  497. static inline void tsx(e6502_Core *core, e6502_Address adr) {
  498. t(core, &core->registers.X, core->registers.S);
  499. }
  500. static inline void lda(e6502_Core *core, e6502_Address adr) {
  501. t(core, &core->registers.A, e6502_adr_r8(core, adr));
  502. }
  503. static inline void ldx(e6502_Core *core, e6502_Address adr) {
  504. t(core, &core->registers.X, e6502_adr_r8(core, adr));
  505. }
  506. static inline void ldy(e6502_Core *core, e6502_Address adr) {
  507. t(core, &core->registers.Y, e6502_adr_r8(core, adr));
  508. }
  509. typedef struct {
  510. void(*operator)(e6502_Core*, e6502_Address);
  511. e6502_Address(*address)(e6502_Core*);
  512. uint16_t cycles;
  513. } e6502_Instruction;
  514. static const e6502_Instruction e6502_instructions[256] = {
  515. // 0x00
  516. [0b00000000] = {brk, adr_imp, 7},
  517. [0b00000001] = {ora, adr_ind_x, 6},
  518. [0b00000101] = {ora, adr_zp, 3},
  519. [0b00001001] = {ora, adr_imm, 2},
  520. [0b00001101] = {ora, adr_abs, 4},
  521. [0b00000110] = {asl, adr_zp, 5},
  522. [0b00001010] = {asl_a, adr_acc, 2},
  523. [0b00001110] = {asl, adr_abs, 6},
  524. [0b00001000] = {php, adr_imp, 3},
  525. // 0x10
  526. [0b00010000] = {bpl, adr_rel, 2},
  527. [0b00010001] = {ora, adr_ind_y, 5},
  528. [0b00010101] = {ora, adr_zp_x, 4},
  529. [0b00011001] = {ora, adr_abs_y, 4},
  530. [0b00011101] = {ora, adr_abs_x, 4},
  531. [0b00011000] = {clc, adr_imp, 2},
  532. [0b00010110] = {asl, adr_zp_x, 6},
  533. [0b00011110] = {asl, adr_abs_x, 7},
  534. // 0x20
  535. [0b00100000] = {jsr, adr_abs, 6},
  536. [0b00100100] = {bit, adr_zp, 3},
  537. [0b00101100] = {bit, adr_abs, 4},
  538. [0b00100001] = {and, adr_ind_x, 6},
  539. [0b00100101] = {and, adr_zp, 3},
  540. [0b00101001] = {and, adr_imm, 2},
  541. [0b00101101] = {and, adr_abs, 4},
  542. [0b00100110] = {rol, adr_zp, 5},
  543. [0b00101010] = {rol_a, adr_acc, 2},
  544. [0b00101110] = {rol, adr_abs, 6},
  545. [0b00101000] = {plp, adr_imp, 4},
  546. // 0x30
  547. [0b00110000] = {bmi, adr_rel, 2},
  548. [0b00110001] = {and, adr_ind_y, 5},
  549. [0b00110101] = {and, adr_zp_x, 4},
  550. [0b00111001] = {and, adr_abs_y, 3},
  551. [0b00111101] = {and, adr_abs_x, 3},
  552. [0b00110110] = {rol, adr_zp_x, 6},
  553. [0b00111110] = {rol, adr_abs_x, 7},
  554. [0b00111000] = {sec, adr_imp, 2},
  555. // 0x40
  556. [0b01000000] = {rti, adr_imp, 6},
  557. [0b01000001] = {eor, adr_ind_x, 6},
  558. [0b01000101] = {eor, adr_zp, 3},
  559. [0b01001001] = {eor, adr_imm, 2},
  560. [0b01001101] = {eor, adr_abs, 4},
  561. [0b01000110] = {lsr, adr_zp, 5},
  562. [0b01001010] = {lsr_a, adr_acc, 2},
  563. [0b01001110] = {lsr, adr_abs, 6},
  564. [0b01001000] = {pha, adr_imp, 3},
  565. [0b01001100] = {jmp, adr_abs, 3},
  566. // 0x50
  567. [0b01010000] = {bvc, adr_rel, 2},
  568. [0b01010001] = {eor, adr_ind_y, 5},
  569. [0b01010101] = {eor, adr_zp_x, 4},
  570. [0b01011001] = {eor, adr_abs_y, 4},
  571. [0b01011101] = {eor, adr_abs_x, 4},
  572. [0b01010110] = {lsr, adr_zp_x, 6},
  573. [0b01011110] = {lsr, adr_abs_x, 7},
  574. [0b01011000] = {cli, adr_imp, 2},
  575. // 0x60
  576. [0b01100000] = {rts, adr_imp, 6},
  577. [0b01100001] = {adc, adr_ind_x, 6},
  578. [0b01100101] = {adc, adr_zp, 3},
  579. [0b01101001] = {adc, adr_imm, 2},
  580. [0b01101101] = {adc, adr_abs, 4},
  581. [0b01100110] = {ror, adr_zp, 5},
  582. [0b01101010] = {ror_a, adr_acc, 2},
  583. [0b01101110] = {ror, adr_abs, 6},
  584. [0b01101000] = {pla, adr_imp, 4},
  585. [0b01101100] = {jmp, adr_ind, 5},
  586. // 0x70
  587. [0b01110000] = {bvs, adr_rel, 2},
  588. [0b01110001] = {adc, adr_ind_y, 5},
  589. [0b01110101] = {adc, adr_zp_x, 4},
  590. [0b01111001] = {adc, adr_abs_y, 4},
  591. [0b01111101] = {adc, adr_abs_x, 4},
  592. [0b01110110] = {ror, adr_zp_x, 6},
  593. [0b01111110] = {ror, adr_abs_x, 7},
  594. [0b01111000] = {sei, adr_imp, 2},
  595. // 0x80
  596. [0b10000001] = {sta, adr_ind_x, 6},
  597. [0b10000101] = {sta, adr_zp, 3},
  598. [0b10001101] = {sta, adr_abs, 4},
  599. [0b10000110] = {stx, adr_zp, 3},
  600. [0b10001110] = {stx, adr_abs, 4},
  601. [0b10000100] = {sty, adr_zp, 3},
  602. [0b10001100] = {sty, adr_abs, 4},
  603. [0b10001000] = {dey, adr_imp, 2},
  604. [0b10001010] = {txa, adr_imp, 2},
  605. // 0x90
  606. [0b10010000] = {bcc, adr_rel, 2},
  607. [0b10010001] = {sta, adr_ind_y, 6},
  608. [0b10010101] = {sta, adr_zp_x, 4},
  609. [0b10011001] = {sta, adr_abs_y, 5},
  610. [0b10011101] = {sta, adr_abs_x, 5},
  611. [0b10010110] = {stx, adr_zp_y, 4},
  612. [0b10010100] = {sty, adr_zp_x, 4},
  613. [0b10011000] = {tya, adr_imp, 2},
  614. [0b10011010] = {txs, adr_imp, 2},
  615. // 0xA0
  616. [0b10100001] = {lda, adr_ind_x, 6},
  617. [0b10100101] = {lda, adr_zp, 3},
  618. [0b10101001] = {lda, adr_imm, 2},
  619. [0b10101101] = {lda, adr_abs, 4},
  620. [0b10100010] = {ldx, adr_imm, 2},
  621. [0b10100110] = {ldx, adr_zp, 3},
  622. [0b10101110] = {ldx, adr_abs, 4},
  623. [0b10100000] = {ldy, adr_imm, 2},
  624. [0b10100100] = {ldy, adr_zp, 3},
  625. [0b10101100] = {ldy, adr_abs, 4},
  626. [0b10101010] = {tax, adr_imp, 2},
  627. [0b10101000] = {tay, adr_imp, 2},
  628. // 0xB0
  629. [0b10110000] = {bcs, adr_rel, 2},
  630. [0b10110001] = {lda, adr_ind_y, 5},
  631. [0b10110101] = {lda, adr_zp_x, 4},
  632. [0b10111001] = {lda, adr_abs_y, 4},
  633. [0b10111101] = {lda, adr_abs_x, 4},
  634. [0b10110110] = {ldx, adr_zp_y, 4},
  635. [0b10111110] = {ldx, adr_abs_y, 4},
  636. [0b10110100] = {ldy, adr_zp_x, 4},
  637. [0b10111100] = {ldy, adr_abs_x, 4},
  638. [0b10111000] = {clv, adr_imp, 2},
  639. [0b10111010] = {tsx, adr_imp, 2},
  640. // 0xC0
  641. [0b11000000] = {cpy, adr_imm, 2},
  642. [0b11000100] = {cpy, adr_zp, 3},
  643. [0b11001100] = {cpy, adr_abs, 4},
  644. [0b11000001] = {cpa, adr_ind_x, 6},
  645. [0b11000101] = {cpa, adr_zp, 3},
  646. [0b11001001] = {cpa, adr_imm, 2},
  647. [0b11001101] = {cpa, adr_abs, 4},
  648. [0b11001000] = {iny, adr_imp, 2},
  649. [0b11000110] = {dec, adr_zp, 5},
  650. [0b11001110] = {dec, adr_abs, 6},
  651. [0b11010110] = {dec, adr_zp_x, 6},
  652. [0b11011110] = {dec, adr_abs_x, 7},
  653. [0b11001010] = {dex, adr_imp, 2},
  654. // 0xD0
  655. [0b11010000] = {bne, adr_rel, 2},
  656. [0b11011000] = {cld, adr_imp, 2},
  657. [0b11010001] = {cpa, adr_ind_y, 5},
  658. [0b11010101] = {cpa, adr_zp_x, 4},
  659. [0b11011001] = {cpa, adr_abs_y, 4},
  660. [0b11011101] = {cpa, adr_abs_x, 4},
  661. // 0xE0
  662. [0b11100000] = {cpx, adr_imm, 2},
  663. [0b11100100] = {cpx, adr_zp, 3},
  664. [0b11101100] = {cpx, adr_abs, 4},
  665. [0b11100001] = {sbc, adr_ind_x, 6},
  666. [0b11100101] = {sbc, adr_zp, 3},
  667. [0b11101001] = {sbc, adr_imm, 2},
  668. [0b11101101] = {sbc, adr_abs, 4},
  669. [0b11100110] = {inc, adr_zp, 5},
  670. [0b11101110] = {inc, adr_abs, 6},
  671. [0b11101000] = {inx, adr_imp, 2},
  672. [0b11101010] = {nop, adr_imp, 2},
  673. // 0xF0
  674. [0b11110000] = {beq, adr_rel, 2},
  675. [0b11110001] = {sbc, adr_ind_y, 5},
  676. [0b11110101] = {sbc, adr_zp_x, 4},
  677. [0b11111001] = {sbc, adr_abs_y, 4},
  678. [0b11111101] = {sbc, adr_abs_x, 4},
  679. [0b11110110] = {inc, adr_zp_x, 6},
  680. [0b11111110] = {inc, adr_abs_x, 7},
  681. [0b11111000] = {sed, adr_imp, 2},
  682. };
  683. #ifdef E6502_DEBUG
  684. int e6502_instr_size(uint8_t opcode) {
  685. const e6502_Instruction* instr = &e6502_instructions[opcode];
  686. if ( instr->address == adr_imp ||
  687. instr->address == adr_acc) {
  688. return 1;
  689. } else if ( instr->address == adr_abs ||
  690. instr->address == adr_abs_x ||
  691. instr->address == adr_abs_y) {
  692. return 3;
  693. } else {
  694. return 2;
  695. }
  696. }
  697. void e6502_dump_instr(e6502_Core* core, e6502_Mem_Addr addr,
  698. FILE* file) {
  699. uint8_t opcode = e6502_r8(core, addr);
  700. int size = e6502_instr_size(opcode);
  701. fprintf(file, "$%02x", opcode);
  702. if (size == 2) {
  703. fprintf(file, " $%02x", e6502_r8(core, addr + 1));
  704. } else if (size == 3) {
  705. fprintf(file, " $%04x", e6502_r16(core, addr + 1));
  706. }
  707. // fputc('\n', file);
  708. }
  709. void e6502_dump_regs(e6502_Core* core, FILE* file) {
  710. fprintf(file, "S:%02x A:%02x X:%02x Y:%02x P:%02x\n",
  711. core->registers.S, core->registers.A,
  712. core->registers.X, core->registers.Y,
  713. core->registers.P);
  714. }
  715. #endif
  716. static void e6502_irq(e6502_Core* core) {
  717. if (!(core->registers.P & e6502_Status_I)) {
  718. e6502_push16(core, core->registers.PC);
  719. e6502_push8(core, (core->registers.P & ~e6502_Status_B) |
  720. e6502_Status_1);
  721. core->registers.P |= e6502_Status_I;
  722. core->registers.PC = e6502_r16(core, e6502_IRQ_Vec);
  723. }
  724. }
  725. static void e6502_nmi(e6502_Core* core) {
  726. e6502_push16(core, core->registers.PC);
  727. e6502_push8(core, (core->registers.P & ~e6502_Status_B) |
  728. e6502_Status_1);
  729. core->registers.P |= e6502_Status_I;
  730. core->registers.PC = e6502_r16(core, e6502_NMI_Vec);
  731. }
  732. int e6502_step(e6502_Core* core) {
  733. core->cycle = 0;
  734. #ifdef E6502_DEBUG
  735. int last_pc = core->registers.PC;
  736. #endif
  737. uint8_t opcode = e6502_r8(core, core->registers.PC);
  738. const e6502_Instruction* instr =
  739. &e6502_instructions[opcode];
  740. if (!instr->operator) {
  741. #ifdef E6502_DEBUG
  742. fprintf(stdout, "$%04x: $%02x -> ILLEGAL\n", last_pc, opcode);
  743. #endif
  744. #ifndef E6502_ILLEGAL
  745. core->cycle = -1;
  746. #else
  747. core->registers.PC++;
  748. core->cycle += 1;
  749. #endif
  750. } else {
  751. core->registers.PC++;
  752. e6502_Address adr = instr->address(core);
  753. #ifdef E6502_DEBUG
  754. uint16_t size = core->registers.PC - last_pc;
  755. uint16_t val = 0;
  756. if (size > 1) {
  757. if (size == 2) val = e6502_r8(core, last_pc + 1);
  758. else val = e6502_r16(core, last_pc + 1);
  759. }
  760. e6502_dump_regs(core, stdout);
  761. fprintf(stdout, "$%04x: ", last_pc);
  762. e6502_dump_instr(core, last_pc, stdout);
  763. fputs(" -> ", stdout);
  764. e6502_fprintf_instr(stdout, opcode, (uint8_t*)&val);
  765. fputc('\n', stdout);
  766. #endif
  767. instr->operator(core, adr);
  768. core->cycle += instr->cycles;
  769. if ( (core->pins & e6502_Pin_NMI) &&
  770. !(core->pins & e6502_NMI_Serviced)) {
  771. core->pins |= e6502_NMI_Serviced;
  772. e6502_nmi(core);
  773. } else if ( (core->pins & e6502_Pin_IRQ) &&
  774. !(core->registers.P & e6502_Status_I)) {
  775. e6502_irq(core);
  776. }
  777. }
  778. return core->cycle;
  779. }
  780. int e6502_run(e6502_Core* core,
  781. int remaining,
  782. int* run,
  783. int instructions) {
  784. int status = 0;
  785. int count = 0;
  786. int last_pc = -1;
  787. (void)last_pc;
  788. while (count < remaining) {
  789. #ifdef E6502_HCF
  790. if (core->registers.PC == last_pc) {
  791. // Trapped.
  792. status = -2;
  793. break;
  794. }
  795. #endif
  796. last_pc = core->registers.PC;
  797. int cpu_cycles = e6502_step(core);
  798. if (cpu_cycles <= 0) {
  799. status = cpu_cycles;
  800. break;
  801. }
  802. count += (instructions ? 1 : cpu_cycles);
  803. }
  804. if (run) {
  805. *run = count;
  806. }
  807. return status;
  808. }
  809. #ifdef E6502_POLL_MEM
  810. void e6502_init(e6502_Core* core) { /* nuthin' */ }
  811. #else
  812. void e6502_init(e6502_Core* core, e6502_Read read,
  813. e6502_Write write, void* context) {
  814. core->bus_read = read;
  815. core->bus_write = write;
  816. core->bus_context = context;
  817. }
  818. #endif
  819. void e6502_reset(e6502_Core* core) {
  820. core->registers.PC = e6502_r16(core, e6502_Reset_Vec);
  821. core->registers.S -= 3;
  822. core->registers.P |= (e6502_Status_B | e6502_Status_1);
  823. }
  824. void e6502_set_nmi(e6502_Core* core, int active) {
  825. if (active) core->pins |= e6502_Pin_NMI;
  826. else core->pins &= ~(e6502_Pin_NMI | e6502_NMI_Serviced);
  827. }
  828. void e6502_set_irq(e6502_Core* core, int active) {
  829. if (active) core->pins |= e6502_Pin_IRQ;
  830. else core->pins &= ~e6502_Pin_IRQ;
  831. }