NESe (pronounced "Nessie") is a NES emulator based on the e6502 emulator, also written in C with a focus on speed and portability for use on embedded platforms, especially ARM.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

421 строка
11KB

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