A MOS 6502 emulator written in C with a focus on speed, especially for ARM targets.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

396 lignes
9.9KB

  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include "opcodes.h"
  4. #define adr_imp (NULL)
  5. static int adr_imm(const uint8_t* operand, char* str, int max) {
  6. return snprintf(str, max, "#$%02X", *operand);
  7. }
  8. static int adr_acc(const uint8_t* operand, char* str, int max) {
  9. return snprintf(str, max, "A");
  10. }
  11. static int adr_ind(const uint8_t* operand, char* str, int max) {
  12. return snprintf(str, max, "($%04X)", *(uint16_t*)operand);
  13. }
  14. static int adr_abs(const uint8_t* operand, char* str, int max) {
  15. return snprintf(str, max, "$%04X", *(uint16_t*)operand);
  16. }
  17. static inline int adr_abs_reg(char reg, const uint8_t* op,
  18. char* str, int max) {
  19. return snprintf(str, max, "$%04X,%c", *(uint16_t*)op, reg);
  20. }
  21. static int adr_abs_x(const uint8_t* operand, char* str, int max) {
  22. return adr_abs_reg('X', operand, str, max);
  23. }
  24. static int adr_abs_y(const uint8_t* operand, char* str, int max) {
  25. return adr_abs_reg('Y', operand, str, max);
  26. }
  27. #define adr_rel adr_zp
  28. static int adr_zp(const uint8_t* operand, char* str, int max) {
  29. return snprintf(str, max, "$%02X", *operand);
  30. }
  31. static inline int adr_zp_reg(char reg, const uint8_t* operand,
  32. char* str, int max) {
  33. return snprintf(str, max, "$%02X,%c", *operand, reg);
  34. }
  35. static int adr_zp_x(const uint8_t* operand, char* str, int max) {
  36. return adr_zp_reg('X', operand, str, max);
  37. }
  38. static int adr_zp_y(const uint8_t* operand, char* str, int max) {
  39. return adr_zp_reg('Y', operand, str, max);
  40. }
  41. static inline int adr_ind_reg(char reg, const uint8_t* op,
  42. char* str, int max) {
  43. return snprintf(str, max, "($%04X,%c)", *(uint16_t*)op, reg);
  44. }
  45. static int adr_ind_x(const uint8_t* operand, char* str, int max) {
  46. return adr_ind_reg('X', operand, str, max);
  47. }
  48. static int adr_ind_y(const uint8_t* operand, char* str, int max) {
  49. return adr_ind_reg('Y', operand, str, max);
  50. }
  51. typedef int(*adr_Mode)(const uint8_t*, char*, int);
  52. typedef struct {
  53. const char *operator;
  54. int(*mode)(const uint8_t*, char*, int);
  55. int cycles; // Unused
  56. } e6502_Instruction;
  57. #define brk "BRK"
  58. #define ora "ORA"
  59. #define asl "ASL"
  60. #define asl_a asl
  61. #define php "PHP"
  62. #define bpl "BPL"
  63. #define clc "CLC"
  64. #define jsr "JSR"
  65. #define bit "BIT"
  66. #define and "AND"
  67. #define rol "ROL"
  68. #define rol_a rol
  69. #define plp "PLP"
  70. #define bmi "BMI"
  71. #define sec "SEC"
  72. #define rti "RTI"
  73. #define eor "EOR"
  74. #define lsr "LSR"
  75. #define lsr_a lsr
  76. #define pha "PHA"
  77. #define jmp "JMP"
  78. #define bvc "BVC"
  79. #define cli "CLI"
  80. #define rts "RTS"
  81. #define adc "ADC"
  82. #define ror "ROR"
  83. #define ror_a ror
  84. #define pla "PLA"
  85. #define bvs "BVS"
  86. #define sei "SEI"
  87. #define sta "STA"
  88. #define stx "STX"
  89. #define sty "STY"
  90. #define txa "TXA"
  91. #define dey "DEY"
  92. #define bcc "BCC"
  93. #define tya "TYA"
  94. #define txs "TXS"
  95. #define lda "LDA"
  96. #define ldx "LDX"
  97. #define ldy "LDY"
  98. #define tax "TAX"
  99. #define tay "TAY"
  100. #define bcs "BCS"
  101. #define clv "CLV"
  102. #define tsx "TSX"
  103. #define cpy "CPY"
  104. #define cpa "CPA"
  105. #define iny "INY"
  106. #define dec "DEC"
  107. #define dex "DEX"
  108. #define bne "BNE"
  109. #define cld "CLD"
  110. #define cpx "CPX"
  111. #define sbc "SBC"
  112. #define inc "INC"
  113. #define inx "INX"
  114. #define nop "NOP"
  115. #define beq "BEQ"
  116. #define sed "SED"
  117. static const e6502_Instruction e6502_instructions[256] = {
  118. // 0x00
  119. [0b00000000] = {brk, adr_imp, 7},
  120. [0b00000001] = {ora, adr_ind_x, 6},
  121. [0b00000101] = {ora, adr_zp, 3},
  122. [0b00001001] = {ora, adr_imm, 2},
  123. [0b00001101] = {ora, adr_abs, 4},
  124. [0b00000110] = {asl, adr_zp, 5},
  125. [0b00001010] = {asl_a, adr_acc, 2},
  126. [0b00001110] = {asl, adr_abs, 6},
  127. [0b00001000] = {php, adr_imp, 3},
  128. // 0x10
  129. [0b00010000] = {bpl, adr_rel, 2},
  130. [0b00010001] = {ora, adr_ind_y, 5},
  131. [0b00010101] = {ora, adr_zp_x, 4},
  132. [0b00011001] = {ora, adr_abs_y, 4},
  133. [0b00011101] = {ora, adr_abs_x, 4},
  134. [0b00011000] = {clc, adr_imp, 2},
  135. [0b00010110] = {asl, adr_zp_x, 6},
  136. [0b00011110] = {asl, adr_abs_x, 7},
  137. // 0x20
  138. [0b00100000] = {jsr, adr_abs, 6},
  139. [0b00100100] = {bit, adr_zp, 3},
  140. [0b00101100] = {bit, adr_abs, 4},
  141. [0b00100001] = {and, adr_ind_x, 6},
  142. [0b00100101] = {and, adr_zp, 3},
  143. [0b00101001] = {and, adr_imm, 2},
  144. [0b00101101] = {and, adr_abs, 4},
  145. [0b00100110] = {rol, adr_zp, 5},
  146. [0b00101010] = {rol_a, adr_acc, 2},
  147. [0b00101110] = {rol, adr_abs, 6},
  148. [0b00101000] = {plp, adr_imp, 4},
  149. // 0x30
  150. [0b00110000] = {bmi, adr_rel, 2},
  151. [0b00110001] = {and, adr_ind_y, 5},
  152. [0b00110101] = {and, adr_zp_x, 4},
  153. [0b00111001] = {and, adr_abs_y, 3},
  154. [0b00111101] = {and, adr_abs_x, 3},
  155. [0b00110110] = {rol, adr_zp_x, 6},
  156. [0b00111110] = {rol, adr_abs_x, 7},
  157. [0b00111000] = {sec, adr_imp, 2},
  158. // 0x40
  159. [0b01000000] = {rti, adr_imp, 6},
  160. [0b01000001] = {eor, adr_ind_x, 6},
  161. [0b01000101] = {eor, adr_zp, 3},
  162. [0b01001001] = {eor, adr_imm, 2},
  163. [0b01001101] = {eor, adr_abs, 4},
  164. [0b01000110] = {lsr, adr_zp, 5},
  165. [0b01001010] = {lsr_a, adr_acc, 2},
  166. [0b01001110] = {lsr, adr_abs, 6},
  167. [0b01001000] = {pha, adr_imp, 3},
  168. [0b01001100] = {jmp, adr_abs, 3},
  169. // 0x50
  170. [0b01010000] = {bvc, adr_rel, 2},
  171. [0b01010001] = {eor, adr_ind_y, 5},
  172. [0b01010101] = {eor, adr_zp_x, 4},
  173. [0b01011001] = {eor, adr_abs_y, 4},
  174. [0b01011101] = {eor, adr_abs_x, 4},
  175. [0b01010110] = {lsr, adr_zp_x, 6},
  176. [0b01011110] = {lsr, adr_abs_x, 7},
  177. [0b01011000] = {cli, adr_imp, 2},
  178. // 0x60
  179. [0b01100000] = {rts, adr_imp, 6},
  180. [0b01100001] = {adc, adr_ind_x, 6},
  181. [0b01100101] = {adc, adr_zp, 3},
  182. [0b01101001] = {adc, adr_imm, 2},
  183. [0b01101101] = {adc, adr_abs, 4},
  184. [0b01100110] = {ror, adr_zp, 5},
  185. [0b01101010] = {ror_a, adr_acc, 2},
  186. [0b01101110] = {ror, adr_abs, 6},
  187. [0b01101000] = {pla, adr_imp, 4},
  188. [0b01101100] = {jmp, adr_ind, 5},
  189. // 0x70
  190. [0b01110000] = {bvs, adr_rel, 2},
  191. [0b01110001] = {adc, adr_ind_y, 5},
  192. [0b01110101] = {adc, adr_zp_x, 4},
  193. [0b01111001] = {adc, adr_abs_y, 4},
  194. [0b01111101] = {adc, adr_abs_x, 4},
  195. [0b01110110] = {ror, adr_zp_x, 6},
  196. [0b01111110] = {ror, adr_abs_x, 7},
  197. [0b01111000] = {sei, adr_imp, 2},
  198. // 0x80
  199. [0b10000001] = {sta, adr_ind_x, 6},
  200. [0b10000101] = {sta, adr_zp, 3},
  201. [0b10001101] = {sta, adr_abs, 4},
  202. [0b10000110] = {stx, adr_zp, 3},
  203. [0b10001110] = {stx, adr_abs, 4},
  204. [0b10000100] = {sty, adr_zp, 3},
  205. [0b10001100] = {sty, adr_abs, 4},
  206. [0b10001000] = {dey, adr_imp, 2},
  207. [0b10001010] = {txa, adr_imp, 2},
  208. // 0x90
  209. [0b10010000] = {bcc, adr_rel, 2},
  210. [0b10010001] = {sta, adr_ind_y, 6},
  211. [0b10010101] = {sta, adr_zp_x, 4},
  212. [0b10011001] = {sta, adr_abs_y, 5},
  213. [0b10011101] = {sta, adr_abs_x, 5},
  214. [0b10010110] = {stx, adr_zp_y, 4},
  215. [0b10010100] = {sty, adr_zp_x, 4},
  216. [0b10011000] = {tya, adr_imp, 2},
  217. [0b10011010] = {txs, adr_imp, 2},
  218. // 0xA0
  219. [0b10100001] = {lda, adr_ind_x, 6},
  220. [0b10100101] = {lda, adr_zp, 3},
  221. [0b10101001] = {lda, adr_imm, 2},
  222. [0b10101101] = {lda, adr_abs, 4},
  223. [0b10100010] = {ldx, adr_imm, 2},
  224. [0b10100110] = {ldx, adr_zp, 3},
  225. [0b10101110] = {ldx, adr_abs, 4},
  226. [0b10100000] = {ldy, adr_imm, 2},
  227. [0b10100100] = {ldy, adr_zp, 3},
  228. [0b10101100] = {ldy, adr_abs, 4},
  229. [0b10101010] = {tax, adr_imp, 2},
  230. [0b10101000] = {tay, adr_imp, 2},
  231. // 0xB0
  232. [0b10110000] = {bcs, adr_rel, 2},
  233. [0b10110001] = {lda, adr_ind_y, 5},
  234. [0b10110101] = {lda, adr_zp_x, 4},
  235. [0b10111001] = {lda, adr_abs_y, 4},
  236. [0b10111101] = {lda, adr_abs_x, 4},
  237. [0b10110110] = {ldx, adr_zp_y, 4},
  238. [0b10111110] = {ldx, adr_abs_y, 4},
  239. [0b10110100] = {ldy, adr_zp_x, 4},
  240. [0b10111100] = {ldy, adr_abs_x, 4},
  241. [0b10111000] = {clv, adr_imp, 2},
  242. [0b10111010] = {tsx, adr_imp, 2},
  243. // 0xC0
  244. [0b11000000] = {cpy, adr_imm, 2},
  245. [0b11000100] = {cpy, adr_zp, 3},
  246. [0b11001100] = {cpy, adr_abs, 4},
  247. [0b11000001] = {cpa, adr_ind_x, 6},
  248. [0b11000101] = {cpa, adr_zp, 3},
  249. [0b11001001] = {cpa, adr_imm, 2},
  250. [0b11001101] = {cpa, adr_abs, 4},
  251. [0b11001000] = {iny, adr_imp, 2},
  252. [0b11000110] = {dec, adr_zp, 5},
  253. [0b11001110] = {dec, adr_abs, 6},
  254. [0b11010110] = {dec, adr_zp_x, 6},
  255. [0b11011110] = {dec, adr_abs_x, 7},
  256. [0b11001010] = {dex, adr_imp, 2},
  257. // 0xD0
  258. [0b11010000] = {bne, adr_rel, 2},
  259. [0b11011000] = {cld, adr_imp, 2},
  260. [0b11010001] = {cpa, adr_ind_y, 5},
  261. [0b11010101] = {cpa, adr_zp_x, 4},
  262. [0b11011001] = {cpa, adr_abs_y, 4},
  263. [0b11011101] = {cpa, adr_abs_x, 4},
  264. // 0xE0
  265. [0b11100000] = {cpx, adr_imm, 2},
  266. [0b11100100] = {cpx, adr_zp, 3},
  267. [0b11101100] = {cpx, adr_abs, 4},
  268. [0b11100001] = {sbc, adr_ind_x, 6},
  269. [0b11100101] = {sbc, adr_zp, 3},
  270. [0b11101001] = {sbc, adr_imm, 2},
  271. [0b11101101] = {sbc, adr_abs, 4},
  272. [0b11100110] = {inc, adr_zp, 5},
  273. [0b11101110] = {inc, adr_abs, 6},
  274. [0b11101000] = {inx, adr_imp, 2},
  275. [0b11101010] = {nop, adr_imp, 2},
  276. // 0xF0
  277. [0b11110000] = {beq, adr_rel, 2},
  278. [0b11110001] = {sbc, adr_ind_y, 5},
  279. [0b11110101] = {sbc, adr_zp_x, 4},
  280. [0b11111001] = {sbc, adr_abs_y, 4},
  281. [0b11111101] = {sbc, adr_abs_x, 4},
  282. [0b11110110] = {inc, adr_zp_x, 6},
  283. [0b11111110] = {inc, adr_abs_x, 7},
  284. [0b11111000] = {sed, adr_imp, 2},
  285. };
  286. int e6502_fprintf_instr(FILE* file,
  287. uint8_t opcode, uint8_t* operand) {
  288. int ret = 0;
  289. const e6502_Instruction* instr = &e6502_instructions[opcode];
  290. if (NULL == instr) {
  291. ret += fprintf(file, "ILLEGAL: $%02x", opcode);
  292. } else {
  293. ret += fputs(instr->operator, file);
  294. if (NULL != instr->mode) {
  295. char str[16] = {0};
  296. int len = instr->mode(operand, str, sizeof(str) - 1);
  297. ret += fprintf(file, " %.*s", len, str);
  298. }
  299. }
  300. return ret;
  301. }