暫無描述

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. #include <stdint.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <stdlib.h>
  5. #include <time.h>
  6. #include <SDL2/SDL.h>
  7. #define DEBUG 0
  8. #define TDISP 0
  9. typedef uint8_t byte;
  10. typedef uint16_t word;
  11. typedef struct {
  12. byte memory[0x1000];
  13. byte screen[64][32];
  14. byte registers[0x10];
  15. word stack[24];
  16. byte input[0x10];
  17. word address_I;
  18. word program_counter;
  19. byte stack_pointer;
  20. } emulator_state_s;
  21. byte chip8_fontset[80] =
  22. {
  23. 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
  24. 0x20, 0x60, 0x20, 0x20, 0x70, // 1
  25. 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
  26. 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
  27. 0x90, 0x90, 0xF0, 0x10, 0x10, // 4
  28. 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
  29. 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
  30. 0xF0, 0x10, 0x20, 0x40, 0x40, // 7
  31. 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
  32. 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
  33. 0xF0, 0x90, 0xF0, 0x90, 0x90, // A
  34. 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
  35. 0xF0, 0x80, 0x80, 0x80, 0xF0, // C
  36. 0xE0, 0x90, 0x90, 0x90, 0xE0, // D
  37. 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
  38. 0xF0, 0x80, 0xF0, 0x80, 0x80 // F
  39. };
  40. byte keymap[0x10] = { SDL_SCANCODE_X, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_Q,
  41. SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D,
  42. SDL_SCANCODE_Z, SDL_SCANCODE_C, SDL_SCANCODE_4, SDL_SCANCODE_R, SDL_SCANCODE_F, SDL_SCANCODE_V };
  43. int main(int argc, char **argv) {
  44. SDL_Window *window = NULL;
  45. SDL_Renderer *renderer = NULL;
  46. SDL_Init(SDL_INIT_VIDEO);
  47. window = SDL_CreateWindow("Chip8 Emulator", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 64 * 8, 32 * 8, SDL_WINDOW_SHOWN);
  48. renderer = SDL_CreateRenderer(window, 0, SDL_RENDERER_ACCELERATED);
  49. if (renderer == NULL) printf( "Renderer could not be created! SDL Error: %s\n", SDL_GetError() );
  50. SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
  51. srand(time(NULL));
  52. emulator_state_s state = { 0 }; // initialize everything to 0
  53. state.program_counter = 0x200; // chip8 programs start at 0x200 address space
  54. memcpy(state.memory, chip8_fontset, 80);
  55. FILE *f = fopen(argv[1], "rb");
  56. fread(&state.memory[0x200], 0x1000 - 0x200, 1, f); // see above comment
  57. fclose(f);
  58. SDL_Event e;
  59. int delay = 0;
  60. int sound = 0;
  61. int press = 0;
  62. int wait = 0;
  63. int store = 0;
  64. while (1) {
  65. if (DEBUG) printf("0x%x ", state.program_counter);
  66. if (delay > 0) --delay;
  67. if (sound > 0) --sound;
  68. memset(state.input, 0, 0x10);
  69. press = 0;
  70. // opcodes are 16 bits
  71. SDL_PollEvent(&e);
  72. if (e.type == SDL_QUIT) break;
  73. // SDL_PumpEvents();
  74. const byte *keystate = SDL_GetKeyboardState(NULL);
  75. for (int i = 0; i < 0x10; ++i) {
  76. if (keystate[keymap[i]]){
  77. state.input[i] = 1;
  78. press = 1;
  79. }
  80. }
  81. if (wait && !press) continue;
  82. if (wait && press)
  83. {
  84. for (int i = 0; i < 0x10; ++i) {
  85. if (state.input[i] != 0)
  86. {
  87. state.registers[store] = i;
  88. break;
  89. }
  90. }
  91. wait = 0;
  92. }
  93. int ops = 0;
  94. loop:;
  95. word opcode = (state.memory[state.program_counter++] << 8) | (state.memory[state.program_counter++]);
  96. switch (opcode & 0xF000)
  97. {
  98. case 0x0000: // screen clear or function return
  99. if (opcode == 0x00E0){
  100. memset(state.screen, 0, 64 * 32);
  101. if (DEBUG) printf("Clearing screen ");
  102. }
  103. else if (opcode == 0x00EE) {
  104. state.program_counter = state.stack[--state.stack_pointer];
  105. if (DEBUG) printf("Returning to %x ", state.stack[state.stack_pointer]);
  106. }
  107. break;
  108. case 0x1000: // goto statement
  109. state.program_counter = opcode & 0x0FFF;
  110. if (DEBUG) printf("Jumping to %x ", state.program_counter);
  111. break;
  112. case 0x2000: // CALL
  113. state.stack[state.stack_pointer++] = state.program_counter;
  114. state.program_counter = opcode & 0x0FFF;
  115. if (DEBUG) printf("Calling subroutine at %x (returning to %x)", state.program_counter, state.stack[state.stack_pointer - 1]);
  116. break;
  117. case 0x3000:; // skip if reg 0x0F00 is equal to constant 0x00FF
  118. int reg = (opcode & 0x0F00) >> 8;
  119. if (DEBUG) printf("Comparing (==) register %i (%x) to %x ", reg, state.registers[reg], (byte) opcode);
  120. if (state.registers[reg] == (byte) opcode){
  121. state.program_counter += 2;
  122. if (DEBUG) printf("and incrementing program_counter ");
  123. }
  124. break;
  125. case 0x4000: // skip if not equal
  126. reg = (opcode & 0x0F00) >> 8;
  127. if (DEBUG) printf("Comparing (!=) register %i (%x) to %x ", reg, state.registers[reg], (byte) opcode);
  128. if (state.registers[reg] != (byte) opcode){
  129. state.program_counter += 2;
  130. if (DEBUG) printf("and incrementing program_counter ");
  131. }
  132. break;
  133. case 0x5000:; // skip if reg 0x0F00 is equal to 0x00F0
  134. int first = (opcode & 0x0F00) >> 8;
  135. int second = (opcode & 0x00F0) >> 4;
  136. if (DEBUG) printf("Comparing (==) register %i (%x) to %i (%x) ", first, state.registers[first], second, state.registers[second]);
  137. if (state.registers[first] == state.registers[second]){
  138. state.program_counter += 2;
  139. if (DEBUG) printf("and incrementing program_counter ");
  140. }
  141. break;
  142. case 0x6000: // set reg to constant
  143. reg = (opcode & 0x0F00) >> 8;
  144. state.registers[reg] = (byte) opcode;
  145. if (DEBUG) printf("Assigning %hx to %i", state.registers[reg], reg);
  146. break;
  147. case 0x7000: // add constant to reg
  148. reg = (opcode & 0x0F00) >> 8;
  149. state.registers[reg] += (byte) opcode;
  150. if (DEBUG) printf("Add %hi to reg %i (%hi)", opcode & 0x00FF, reg, state.registers[reg]);
  151. break;
  152. case 0x8000:; // math/bitop operators
  153. first = (opcode & 0x0F00) >> 8; // all use XY regs
  154. second = (opcode & 0x00F0) >> 4;
  155. switch (opcode & 0x000F)
  156. {
  157. case 0: // copy 1 register to another
  158. state.registers[first] = state.registers[second];
  159. if (DEBUG) printf("Copied register %i to %i (%hx)", first, second, state.registers[first]);
  160. break;
  161. case 1: // X = X | Y
  162. state.registers[first] |= state.registers[second];
  163. if (DEBUG) printf("OR register %i and %i (%hx)", first, second, state.registers[first]);
  164. break;
  165. case 2: // X = X & Y
  166. state.registers[first] &= state.registers[second];
  167. if (DEBUG) printf("AND register %i and %i (%hx)", first, second, state.registers[first]);
  168. break;
  169. case 3: // X = X ^ Y
  170. state.registers[first] ^= state.registers[second];
  171. if (DEBUG) printf("XOR register %i to %i (%hx)", first, second, state.registers[first]);
  172. break;
  173. case 4:; // X = X + Y, VF = X + 5 > 255
  174. unsigned int add = state.registers[first] + state.registers[second];
  175. if (add > 255) state.registers[0xF] = 1;
  176. else state.registers[0xF] = 0;
  177. state.registers[first] = (byte) add;
  178. if (DEBUG) printf("ADD register %i to %i (%hx) ", second, first, state.registers[first]);
  179. if (DEBUG) printf("VF is %hx", state.registers[0xF]);
  180. break;
  181. case 5: // X = X - Y, VF = X - Y < 0
  182. state.registers[first] -= state.registers[second];
  183. if (state.registers[first] > state.registers[second]) state.registers[0xF] = 0;
  184. else state.registers[0xF] = 1;
  185. if (DEBUG) printf("SUB register %i from %i (%hx) ", second, first, state.registers[first]);
  186. if (DEBUG) printf("VF is %hx", state.registers[0xF]);
  187. break;
  188. case 6: // set least significant bit of X in VF, bitshift right
  189. state.registers[0xF] = state.registers[first] & 0b00000001;
  190. state.registers[first] /= 2;
  191. if (DEBUG) printf("RS register %i (%hx) ", first, state.registers[first]);
  192. if (DEBUG) printf("VF is %hx", state.registers[0xF]);
  193. break;
  194. case 7: // X = Y - X, VF = Y - X < 0
  195. state.registers[first] = state.registers[second] - state.registers[first];
  196. if (state.registers[second] > state.registers[first]) state.registers[0xF] = 1;
  197. else state.registers[0xF] = 0;
  198. if (DEBUG) printf("SUB %i from %i (%hx) ", first, second, state.registers[first]);
  199. if (DEBUG) printf("VF is %hx", state.registers[0xF]);
  200. break;
  201. case 0xE:; // set msot significant bit of X in VF, bitshift left
  202. state.registers[0xF] = (state.registers[first] & 0b10000000) >> 7;
  203. state.registers[first] *= 2;
  204. if (DEBUG) printf("LS register %i (%hx) ", first, state.registers[first]);
  205. if (DEBUG) printf("VF is %hx", state.registers[0xF]);
  206. break;
  207. default: break;
  208. } break;
  209. case 0x9000: // skip if two regs are not equal
  210. first = (opcode & 0x0F00) >> 8;
  211. second = (opcode & 0x00F0) >> 4;
  212. if (DEBUG) printf("Comparing (!=) register %i (%hx) to %i (%hx) ", first, state.registers[first], second, state.registers[second]);
  213. if (state.registers[first] != state.registers[second]) {
  214. state.program_counter += 2;
  215. if (DEBUG) printf("and incrementing program_counter");
  216. }
  217. break;
  218. case 0xA000: // assign I address
  219. state.address_I = opcode & 0x0FFF;
  220. if (DEBUG) printf("Assigning %x to I address ", opcode & 0x0FFF);
  221. break;
  222. case 0xB000: // jump to 0x0FFF + V0
  223. state.program_counter = (opcode & 0x0FFF) + state.registers[0x0];
  224. if (DEBUG) printf("Jumping to %x + %hx (%x)", opcode & 0x0FFF, state.registers[0], (opcode & 0x0FFF) + state.registers[0x0]);
  225. break;
  226. case 0xC000: // random generator
  227. reg = (opcode & 0x0F00) >> 8;
  228. state.registers[reg] = (rand() % 256) & ((byte) opcode);
  229. if (DEBUG) printf("Storing random in %i (%x)\n", reg, state.registers[reg]);
  230. break;
  231. case 0xD000: // draw sprite
  232. state.registers[0xF] = 0;
  233. first = (opcode & 0x0F00) >> 8;
  234. second = (opcode & 0x00F0) >> 4;
  235. int x = state.registers[first];
  236. int y = state.registers[second];
  237. int h = (opcode & 0x000F);
  238. for (int line = 0; line < h; ++line)
  239. {
  240. byte data = state.memory[state.address_I + line];
  241. for (int xpos = 0; xpos < 8; ++xpos)
  242. {
  243. int ypos = y + line;
  244. byte mask = 1 << 7 - xpos;
  245. if (ypos > 31) ypos -= 32;
  246. if (!(data & mask)) continue;
  247. if (state.screen[x + xpos][ypos]){
  248. state.registers[0xF] = 1;
  249. }
  250. state.screen[x + xpos][ypos] ^= 1;
  251. }
  252. }
  253. if (DEBUG) printf("Drawing");
  254. if (!TDISP) break;
  255. printf("\n");
  256. for (int y = 0; y < 32; ++y) {
  257. for (int x = 0; x < 64; ++x) {
  258. printf(state.screen[x][y] ? "O" : " ");
  259. }
  260. printf("\n");
  261. }
  262. break;
  263. case 0xE000: // input handling
  264. reg = (opcode & 0x0F00) >> 8;
  265. switch ((byte) opcode)
  266. {
  267. case 0x9E: // skip if button pressed
  268. if (DEBUG) printf("Testing if %i is pressed", state.registers[reg]);
  269. if (state.input[state.registers[reg]]) state.program_counter += 2;
  270. break;
  271. case 0xA1: // skip if button *not* pressed
  272. if (DEBUG) printf("Testing if %i is not pressed", state.registers[reg]);
  273. if (!state.input[state.registers[reg]]) state.program_counter += 2;
  274. break;
  275. }
  276. break;
  277. case 0xF000: // misc (timer, input, sound, memory)
  278. reg = (opcode & 0x0F00) >> 8;
  279. switch ((byte) opcode)
  280. {
  281. case 0x07: // set reg to delay time
  282. if (DEBUG) printf("Copying delay timer to reg %i (%hx)", reg, state.registers[reg]);
  283. state.registers[reg] = delay;
  284. break;
  285. case 0x0A: // wait for input and store it in reg
  286. wait = 1;
  287. store = reg;
  288. break;
  289. case 0x15: // set delay timer to value in reg
  290. delay = state.registers[reg];
  291. break;
  292. case 0x18: // set sound timer to value in reg
  293. sound = state.registers[reg];
  294. break;
  295. case 0x1E: // Add value stored in VX to I
  296. state.address_I += state.registers[reg];
  297. if (DEBUG) printf("Adding reg %i (%hx) to I (%x)", reg, state.registers[reg], state.address_I);
  298. break;
  299. case 0x29: // set I to address of font character
  300. state.address_I = state.registers[reg] * 5;
  301. break;
  302. case 0x33:; // encode value in reg as a BCD at I, I+1, I+2
  303. int value = state.registers[reg];
  304. state.memory[state.address_I] = value / 100;
  305. state.memory[state.address_I + 1] = (value / 10) % 10;
  306. state.memory[state.address_I + 2] = value % 10;
  307. break;
  308. case 0x55: // dump registers V0 -> VX at I
  309. for (int i = 0; i <= reg; ++i)
  310. state.memory[state.address_I + i] = state.registers[i];
  311. break;
  312. case 0x65: // retrieve registers V0 -> VX from I
  313. for (int i = 0; i <= reg; ++i)
  314. state.registers[i] = state.memory[state.address_I + i];
  315. break;
  316. default:
  317. break;
  318. }
  319. break;
  320. default:
  321. if (DEBUG) printf("%x", opcode);
  322. break;
  323. }
  324. if (DEBUG) printf("\n");
  325. if (ops < 10)
  326. {
  327. ops++;
  328. goto loop;
  329. }
  330. for (int x = 0; x < 64; ++x) {
  331. for (int y = 0; y < 32; ++y)
  332. {
  333. SDL_Rect pixel = { .x = (x * 8), .y = (y * 8), .w = 8, .h = 8};
  334. if (state.screen[x][y])
  335. {
  336. SDL_SetRenderDrawColor(renderer, 0xff, 0x69, 0xb4, 0xFF);
  337. SDL_RenderFillRect(renderer, &pixel);
  338. }
  339. else
  340. {
  341. SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF);
  342. SDL_RenderFillRect(renderer, &pixel);
  343. }
  344. }
  345. }
  346. SDL_RenderPresent(renderer);
  347. SDL_Delay(16);
  348. // SDL_DestroyWindow(window);
  349. // SDL_Quit();
  350. }
  351. }