This addin is a Chip 8 Emulator.
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.

Machine.c 7.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. /*
  2. This emulator has been written based on the
  3. Cowgod's Chip-8 Technical Reference ( http://devernay.free.fr/hacks/chip8/C8TECH10.HTM#00E0 ).
  4. */
  5. #include "fxlib.h"
  6. #include "MonochromeLib.h"
  7. #include "Machine.h"
  8. #include <stdlib.h>
  9. #define kk state->Memory[state->PC+1]
  10. #define nnn (state->Memory[state->PC] & 0x0F) << 8 | kk
  11. const byte chip8_font[80] = { //80 bytes = 16 characters * 5 bytes
  12. 0xF0, 0x90, 0x90, 0x90, 0xF0, //0
  13. 0x20, 0x60, 0x20, 0x20, 0x70, //1
  14. 0xF0, 0x10, 0xF0, 0x80, 0xF0, //2
  15. 0xF0, 0x10, 0xF0, 0x10, 0xF0, //3
  16. 0x90, 0x90, 0xF0, 0x10, 0x10, //4
  17. 0xF0, 0x80, 0xF0, 0x10, 0xF0, //5
  18. 0xF0, 0x80, 0xF0, 0x90, 0xF0, //6
  19. 0xF0, 0x10, 0x20, 0x40, 0x40, //7
  20. 0xF0, 0x90, 0xF0, 0x90, 0xF0, //8
  21. 0xF0, 0x90, 0xF0, 0x10, 0xF0, //9
  22. 0xF0, 0x90, 0xF0, 0x90, 0x90, //A
  23. 0xE0, 0x90, 0xE0, 0x90, 0xE0, //B
  24. 0xF0, 0x80, 0x80, 0x80, 0xF0, //C
  25. 0xE0, 0x90, 0x90, 0x90, 0xE0, //D
  26. 0xF0, 0x80, 0xF0, 0x80, 0xF0, //E
  27. 0xF0, 0x80, 0xF0, 0x80, 0x80 //F
  28. };
  29. void Machine_Init(Machine_State* state){
  30. int i;
  31. state->PC = 0x200;
  32. state->SP = 0x00;
  33. state->I = 0x00;
  34. state->DT = 0x00;
  35. state->ST = 0x00;
  36. for(i = 0; i < sizeof(state->Memory); i++){
  37. /* Put the fontset into memory */
  38. if(i < sizeof(chip8_font))
  39. state->Memory[i] = chip8_font[i];
  40. /* Clear the other bytes */
  41. else
  42. state->Memory[i] = 0;
  43. }
  44. /* Clear the stack and the V registers */
  45. for(i = 0; i < 16; i++){
  46. state->Stack[i] = 0;
  47. state->V[i] = 0;
  48. }
  49. }
  50. void Machine_Update(Machine_State* state){
  51. int i, x, y, j;
  52. byte line;
  53. switch(state->Memory[state->PC] & 0xF0){
  54. /* Call a subroutine */
  55. case 0x00:
  56. switch(kk){
  57. // Clear the screen
  58. case 0xE0:
  59. ML_clear_vram();
  60. ML_display_vram();
  61. break;
  62. // Return from a call
  63. case 0xEE:
  64. state->SP--;
  65. state->PC = state->Stack[state->SP];
  66. state->Stack[state->SP] = 0;
  67. break;
  68. }
  69. break;
  70. /* JP nnn */
  71. case 0x10:
  72. state->PC = nnn - 2;
  73. break;
  74. /* CALL nnn */
  75. case 0x20:
  76. state->Stack[state->SP] = state->PC;
  77. state->SP++;
  78. state->PC = nnn - 2;
  79. break;
  80. /* SE Vx, kk */
  81. case 0x30:
  82. if(state->V[state->Memory[state->PC] & 0x0F] == kk)
  83. state->PC += 2;
  84. break;
  85. /* SNE Vx, kk */
  86. case 0x40:
  87. if(state->V[state->Memory[state->PC] & 0x0F] != kk)
  88. state->PC += 2;
  89. break;
  90. /* SE Vx, Vy */
  91. case 0x50:
  92. if(state->V[state->Memory[state->PC] & 0x0F] == state->V[kk >> 4])
  93. state->PC += 2;
  94. break;
  95. /* LD Vx, kk */
  96. case 0x60:
  97. state->V[state->Memory[state->PC] & 0x0F] = kk;
  98. break;
  99. /* ADD Vx, kk */
  100. case 0x70:
  101. state->V[state->Memory[state->PC] & 0x0F] += kk;
  102. break;
  103. /* Vx - Vy instructions */
  104. case 0x80:
  105. switch(state->Memory[state->PC + 1] & 0x0F){
  106. /* LD Vx, Vy */
  107. case 0:
  108. state->V[state->Memory[state->PC] & 0x0F] = state->V[state->Memory[state->PC + 1] >> 4];
  109. break;
  110. /* OR Vx, Vy */
  111. case 1:
  112. state->V[state->Memory[state->PC] & 0x0F] |= state->V[state->Memory[state->PC + 1] >> 4];
  113. break;
  114. /* AND Vx, Vy */
  115. case 2:
  116. state->V[state->Memory[state->PC] & 0x0F] &= state->V[state->Memory[state->PC + 1] >> 4];
  117. break;
  118. /* XOR Vx, Vy */
  119. case 3:
  120. state->V[state->Memory[state->PC] & 0x0F] ^= state->V[state->Memory[state->PC + 1] >> 4];
  121. break;
  122. /* ADD Vx, Vy */
  123. case 4:
  124. // If there's a carry
  125. state->V[15] = (state->V[state->Memory[state->PC] & 0x0F] + state->V[state->Memory[state->PC + 1] >> 4] >= 256);
  126. state->V[state->Memory[state->PC] & 0x0F] += state->V[state->Memory[state->PC + 1] >> 4];
  127. break;
  128. /* SUB Vx, Vy */
  129. case 5:
  130. // If Vx > Vy
  131. state->V[15] = (state->V[state->Memory[state->PC] & 0x0F] > state->V[state->Memory[state->PC + 1] >> 4]);
  132. state->V[state->Memory[state->PC] & 0x0F] -= state->V[state->Memory[state->PC + 1] >> 4];
  133. break;
  134. /* SHR Vx */
  135. case 6:
  136. state->V[15] = state->V[state->Memory[state->PC] & 0x0F] & 0x01;
  137. state->V[state->Memory[state->PC] & 0x0F] >>= 1;
  138. break;
  139. /* SUBN Vx, Vy */
  140. case 7:
  141. // If Vx < Vy
  142. state->V[15] = (state->V[state->Memory[state->PC] & 0x0F] < state->V[state->Memory[state->PC + 1] >> 4]);
  143. state->V[state->Memory[state->PC] & 0x0F] -= state->V[state->Memory[state->PC + 1] >> 4];
  144. break;
  145. /* SHL Vx */
  146. case 14:
  147. state->V[15] = state->V[state->Memory[state->PC] & 0x0F] >> 7;
  148. state->V[state->Memory[state->PC] & 0x0F] <<= 1;
  149. break;
  150. }
  151. break;
  152. /* SNE Vx, Vy */
  153. case 0x90:
  154. if(state->V[state->Memory[state->PC] & 0x0F] != state->V[kk >> 4])
  155. state->PC += 2;
  156. break;
  157. /* LD I, nnn */
  158. case 0xA0:
  159. state->I = nnn;
  160. break;
  161. /* JP V0, nnn */
  162. case 0xB0:
  163. state->PC = nnn + state->V[0] - 2;
  164. break;
  165. /* RND Vx, kk */
  166. case 0xC0:
  167. state->V[state->Memory[state->PC] & 0x0F] = (rand() * 0xFF) / RAND_MAX;
  168. state->V[state->Memory[state->PC] & 0x0F] &= kk;
  169. break;
  170. /* DRAW Vx, Vy, nibble */
  171. case 0xD0:
  172. x = state->V[state->Memory[state->PC] & 0x0F];
  173. y = state->V[state->Memory[state->PC + 1] >> 4];
  174. // If any black pixel is cleared, then V15 = 1
  175. state->V[15] = 0;
  176. for(i = 0; i < (state->Memory[state->PC + 1] & 0x0F); i++){
  177. line = state->Memory[state->I + i];
  178. for(j = 0; j < 8; j++){
  179. if((line >> (7-j) & 0x01) == 1){
  180. state->V[15] |= ML_pixel_test((x + j) % SCREEN_WIDTH, (y + i) % SCREEN_HEIGHT) == ML_BLACK;
  181. ML_pixel((x + j) % SCREEN_WIDTH, (y + i) % SCREEN_HEIGHT, ML_XOR);
  182. }
  183. }
  184. }
  185. // Update the screen
  186. ML_display_vram();
  187. break;
  188. /* SKP/SKNP Vx */
  189. case 0xE0:
  190. /* SKP Vx */
  191. if(kk == 0x9E && getKeyPressed() == (state->V[state->Memory[state->PC] & 0x0F]))
  192. state->PC += 2;
  193. /* SKNP Vx */
  194. if(kk == 0xA1 && getKeyPressed() != (state->V[state->Memory[state->PC] & 0x0F]))
  195. state->PC += 2;
  196. break;
  197. /* Other instructions */
  198. case 0xF0:
  199. switch(kk){
  200. /* LD Vx, DT */
  201. case 0x07:
  202. state->V[state->Memory[state->PC] & 0x0F] = state->DT;
  203. break;
  204. /* LD Vx, K */
  205. case 0x0A:
  206. state->V[state->Memory[state->PC] & 0x0F] = getKeyPressed();
  207. break;
  208. /* LD DT, Vx */
  209. case 0x15:
  210. state->DT = state->V[state->Memory[state->PC] & 0x0F];
  211. break;
  212. /* LD ST, Vx */
  213. case 0x18:
  214. state->ST = state->V[state->Memory[state->PC] & 0x0F];
  215. break;
  216. /* ADD I, Vx */
  217. case 0x1E:
  218. state->I += state->V[state->Memory[state->PC] & 0x0F];
  219. break;
  220. /* LD F, Vx */
  221. case 0x29:
  222. state->I = state->V[state->Memory[state->PC] & 0x0F] * 5;
  223. break;
  224. /* LD B, Vx */
  225. case 0x33:
  226. state->Memory[state->I] = state->V[state->Memory[state->PC] & 0x0F] / 100;
  227. state->Memory[state->I+1] = state->V[state->Memory[state->PC] & 0x0F] / 10 % 10;
  228. state->Memory[state->I+2] = state->V[state->Memory[state->PC] & 0x0F] % 10;
  229. break;
  230. /* LD [I], Vx */
  231. case 0x55:
  232. for(i = 0; i < state->V[state->Memory[state->PC] & 0x0F]; i++)
  233. state->Memory[i] = state->V[i];
  234. break;
  235. /* LD Vx, [I] */
  236. case 0x65:
  237. for(i = 0; i < state->V[state->Memory[state->PC] & 0x0F]; i++)
  238. state->V[i] = state->Memory[i];
  239. break;
  240. }
  241. break;
  242. }
  243. /* Update the timers */
  244. if(state->DT > 0) state->DT--;
  245. if(state->ST > 0) state->ST--;
  246. /* Update PC */
  247. state->PC += 2;
  248. state->PC &= 0x0FFF;
  249. }
  250. int getKeyPressed(){
  251. if(IsKeyDown(KEY_CHAR_7)) return 0x1;
  252. if(IsKeyDown(KEY_CHAR_8)) return 0x2;
  253. if(IsKeyDown(KEY_CHAR_9)) return 0x3;
  254. if(IsKeyDown(KEY_CHAR_4)) return 0x4;
  255. if(IsKeyDown(KEY_CHAR_5)) return 0x5;
  256. if(IsKeyDown(KEY_CHAR_6)) return 0x6;
  257. if(IsKeyDown(KEY_CHAR_1)) return 0x7;
  258. if(IsKeyDown(KEY_CHAR_2)) return 0x8;
  259. if(IsKeyDown(KEY_CHAR_3)) return 0x9;
  260. if(IsKeyDown(KEY_CHAR_0)) return 0xA;
  261. if(IsKeyDown(KEY_CHAR_EXP)) return 0xB;
  262. if(IsKeyDown(KEY_CTRL_DEL)) return 0xC;
  263. if(IsKeyDown(KEY_CHAR_MULT)) return 0xD;
  264. if(IsKeyDown(KEY_CHAR_PLUS)) return 0xE;
  265. if(IsKeyDown(KEY_CHAR_PMINUS)) return 0xF;
  266. return 0;
  267. }