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.

843 lines
24KB

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