feat: input handling
fix: 0xc0 parsingA · README.md +0, -0
M · main.c
+192, -108 1@@ -70,8 +70,8 @@ unsigned char chip8_fontset[80] = {
2 unsigned char keypad[16];
3
4 // Screen dimension constants
5-const int SCREEN_WIDTH = 64 * 10;
6-const int SCREEN_HEIGHT = 32 * 10;
7+const int SCREEN_WIDTH = 64 * 20;
8+const int SCREEN_HEIGHT = 32 * 20;
9
10 /*** initialize CPU ***/
11 void chip8_initialize(void)
12@@ -167,10 +167,11 @@ void chip8_draw(unsigned char* gfx)
13 for (int x = 0; x < 64; x++) {
14 if (gfx[x + (y * 64)]) {
15 SDL_Rect rect;
16- rect.x = x * 10;
17- rect.y = y * 10;
18- rect.w = 10;
19- rect.h = 10;
20+ rect.x = x * 20;
21+ rect.y = y * 20;
22+ // size of each "pixel" keep it consistent with the scaling of the display in SCREEN_WIDTH/HEIGHT
23+ rect.w = 20;
24+ rect.h = 20;
25
26 SDL_RenderFillRect(renderer, &rect);
27 }
28@@ -202,24 +203,29 @@ void chip8_emulate_cycle()
29 printf("0x%X \n", opcode);
30 switch (opcode & 0xF000) {
31 case 0x0000:
32- for (int i = 0; i < 64 * 32; i++) {
33- gfx[i] = 0;
34+ switch (opcode & 0x00FF) {
35+ case 0x00E0:
36+ for (int i = 0; i < 64 * 32; i++) {
37+ gfx[i] = 0;
38+ }
39+ printf("00E0: Display Cleared\n");
40+ pc += 2;
41+ break;
42+ case 0x00EE:
43+ pc = stack[stack_pointer];
44+ stack_pointer--;
45+ printf("00EE: Retrurn from a subroutine\n");
46+ pc += 2;
47+ break;
48+ default:
49+ break;
50 }
51- printf("00E0: Display Cleared\n");
52- pc += 2;
53- break;
54-
55- case 0xC000:
56- V[x] = (rand() % 256) & (opcode & 0x00FF);
57- pc += 2;
58- printf("Cxkk: The value at V[x] is %d \n", V[x]);
59 break;
60
61- case 0xA000:
62- I = opcode & 0x0FFF;
63- pc += 2;
64- printf("Annn: The value at register I is set to 0x%X \n",
65- opcode & 0x0FFF);
66+ // 1NNN: Jumps to address NNN
67+ case 0x1000:
68+ printf("1nnn: Jump to location nnn \n");
69+ pc = opcode & 0x0FFF;
70 break;
71
72 // 2nnn CALL subroutine at nnn
73@@ -248,6 +254,15 @@ void chip8_emulate_cycle()
74 printf("4xkk: Skip next instruction if V[x] != kk \n");
75 break;
76
77+ // 5xy0 - SE Vx, Vy Skip next instruction if Vx = Vy.
78+ case 0x5000:
79+ if (V[x] == V[y]) {
80+ pc += 2;
81+ }
82+ pc += 2;
83+ printf("5xy0: Skip next instruction if V[x] != kk \n");
84+ break;
85+
86 // 6XNN: Sets Vx to NN
87 case 0x6000:
88 V[x] = (opcode & 0x00FF);
89@@ -263,10 +278,92 @@ void chip8_emulate_cycle()
90 "V[x] \n");
91 break;
92
93- // 1NNN: Jumps to address NNN
94- case 0x1000:
95- printf("1nnn: Jump to location nnn \n");
96- pc = opcode & 0x0FFF;
97+ case 0x9000:
98+ if (V[x] != V[y]) {
99+ pc += 2;
100+ }
101+ pc += 2;
102+ break;
103+
104+ // Instructions starting with 8
105+ case 0x8000:
106+ switch (opcode & 0x000F) {
107+ // 8xy0: Sets Vx to Vy
108+ case 0x0000:
109+ V[x] = V[y];
110+ pc += 2;
111+ break;
112+
113+ // 8xy1: V[x] = V[x] | V[y]
114+ case 0x0001:
115+ V[x] = (V[x] | V[y]);
116+ pc += 2;
117+ break;
118+
119+ // 8xy2: V[x] = V[x] | V[y]
120+ case 0x0002:
121+ V[x] = (V[x] & V[y]);
122+ pc += 2;
123+ break;
124+
125+ // 8xy3: V[x] = [Vx] ^ V[y]
126+ case 0x0003:
127+ V[x] = (V[x] ^ V[y]);
128+ pc += 2;
129+ break;
130+
131+ // 8xy4: V[x] = V[x] + V[y], set VF = carry.
132+ case 0x0004:
133+ if (V[x] + V[y] > 255) {
134+ printf("is this valid?");
135+ V[0xF] = 1;
136+ } else {
137+ V[0xF] = 0;
138+ }
139+ V[x] += V[y];
140+ pc += 2;
141+ break;
142+
143+ // 8xy5: V[x] = V[x] - V[y], set VF = NOT BORROW
144+ case 0x0005:
145+ if (V[x] > V[y]) {
146+ V[0xF] = 1;
147+ } else {
148+ V[0xF] = 0;
149+ }
150+ V[x] -= V[y];
151+ pc += 2;
152+ break;
153+
154+ // 8xy6: Sets Vx to Vy minus Vx. Vf is set to 0 when there's a borrow
155+ case 0x0006:
156+ V[0xF] = V[x] & 0x1;
157+ V[x] = (V[x] >> 1);
158+ pc += 2;
159+ break;
160+
161+ // Set Vx = Vy - Vx, set VF = NOT borrow
162+ case 0x0007:
163+ if (V[y] > V[x]) {
164+ V[0xF] = 1;
165+ } else {
166+ V[0xF] = 0;
167+ }
168+ V[x] = V[y] - V[x];
169+ pc += 2;
170+ break;
171+
172+ // 8xyE: Stores the most significant bit of V[x] and shifts V[x]
173+ case 0x000E:
174+ V[0xF] = (V[x] >> 7) & 0x1;
175+ V[x] = (V[x] << 1);
176+ pc += 2;
177+ break;
178+
179+ default:
180+ printf("Unknown opcode 0x%X.\n", opcode);
181+ break;
182+ }
183 break;
184
185 // Display n-byte sprite starting at memory location I at (Vx, Vy)
186@@ -282,7 +379,7 @@ void chip8_emulate_cycle()
187 // fetch the pixel value from the memory starting at location I
188 pixel = memory[I + row];
189 // loop over 8 bits of one row
190- for (int col = 0; col < 10; col++) {
191+ for (int col = 0; col < 8; col++) {
192 // check if current evaluated pixel is set to 1 (0x80 >>
193 // col scnas throught the byte, one bit at the time)
194 if ((pixel & (0x80 >> col)) != 0) {
195@@ -302,6 +399,43 @@ void chip8_emulate_cycle()
196 pc += 2;
197 break;
198
199+ case 0xC000:
200+ V[x] = (rand() % 256) & (opcode & 0x00FF);
201+ pc += 2;
202+ printf("Cxkk: The value at V[x] is %d \n", V[x]);
203+ break;
204+
205+ case 0xA000:
206+ I = opcode & 0x0FFF;
207+ pc += 2;
208+ printf("Annn: The value at register I is set to 0x%X \n",
209+ opcode & 0x0FFF);
210+ break;
211+
212+ case 0xE000:
213+ switch (opcode & 0x00FF) {
214+
215+ // Ex9e: Skips next instructuion if key stored in V[x]is pressed
216+ case 0x009E:
217+ if (keypad[V[x]]) {
218+ pc += 2;
219+ }
220+ pc += 2;
221+ break;
222+
223+ // ExA1: Skips next instruction if key stroed in V[x] is not pressed
224+ case 0x00A1:
225+ if (!keypad[V[x]]) {
226+ pc += 2;
227+ }
228+ pc += 2;
229+ break;
230+
231+ default:
232+ printf("Uknown opcode: 0x%X\n", opcode);
233+ }
234+ break;
235+
236 // Instructions starting with FX
237 case 0xF000:
238 switch (opcode & 0x00FF) {
239@@ -399,88 +533,14 @@ void chip8_emulate_cycle()
240 pc += 2;
241 break;
242
243- default:
244- printf("Unknown opcode 0x%x.\n", opcode);
245- break;
246- }
247- break;
248-
249- // Instructions starting with 8
250- case (0x8000):
251- switch (opcode & 0x0FFF) {
252- // 8xy0: Sets Vx to Vy
253- case (0x0000):
254- V[x] = V[y];
255- pc += 2;
256- break;
257-
258- // 8xy1: V[x] = V[x] | V[y]
259- case (0x0001):
260- V[x] = (V[x] | V[y]);
261- pc += 2;
262- break;
263-
264- // 8xy2: V[x] = V[x] | V[y]
265- case (0x0002):
266- V[x] = (V[x] & V[y]);
267- pc += 2;
268- break;
269-
270- // 8xy3: V[x] = [Vx] ^ V[y]
271- case (0x0003):
272- V[x] = (V[x] ^ V[y]);
273- pc += 2;
274- break;
275-
276- // 8xy4: V[x] = V[x] + V[y], set VF = carry.
277- case (0x0004):
278- if (V[x] + V[y] > 255) {
279- printf("is this valid?");
280- V[0xF] = 1;
281- } else {
282- V[0xF] = 0;
283- }
284- V[x] += V[y];
285- pc += 2;
286- break;
287-
288- // 8xy5: V[x] = V[x] - V[y], set VF = NOT BORROW
289- case (0x0005):
290- if (V[x] > V[y]) {
291- V[0xF] = 1;
292- } else {
293- V[0xF] = 0;
294- }
295- V[x] -= V[y];
296- pc += 2;
297- break;
298-
299- // 8xy6: Sets Vx to Vy minus Vx. Vf is set to 0 when there's a borrow
300- case (0x0006):
301- V[0xF] = V[x] & 0x1;
302- V[x] = (V[x] >> 1);
303- pc += 2;
304- break;
305-
306- // Set Vx = Vy - Vx, set VF = NOT borrow
307- case (0x0007):
308- if (V[y] > V[x]) {
309- V[0xF] = 1;
310- } else {
311- V[0xF] = 0;
312- }
313- V[x] = V[y] - V[x];
314- pc += 2;
315- break;
316-
317 default:
318 printf("Unknown opcode 0x%X.\n", opcode);
319 break;
320 }
321 break;
322-
323 default:
324 printf("Unknown opcode 0x%X.\n", opcode);
325+ break;
326 }
327
328 // Update timers
329@@ -493,21 +553,45 @@ void chip8_emulate_cycle()
330 }
331 }
332
333+SDL_Event event;
334+SDL_Scancode keymappings[16] = {
335+ SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_4,
336+ SDL_SCANCODE_Q, SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_R,
337+ SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D, SDL_SCANCODE_F,
338+ SDL_SCANCODE_Z, SDL_SCANCODE_X, SDL_SCANCODE_C, SDL_SCANCODE_V
339+};
340+
341 int main(int argc, char* argv[])
342 {
343+ const Uint8* state = SDL_GetKeyboardState(NULL);
344 chip8_initialize();
345 chip8_load_program(argv[1]);
346 chip8_init_display();
347- /* while (1) {} */
348-
349- for (int i = 0; i < 500; i++) {
350+ while (1) {
351 chip8_emulate_cycle();
352+
353 if (draw_flag == 1) {
354 chip8_draw(gfx);
355+ // Delay to slow down the clock
356+ /* usleep(45000); */
357+ sleep(1);
358+ }
359+ while (SDL_PollEvent(&event) != 0) {
360+ switch (event.type) {
361+ case SDL_QUIT:
362+ SDL_DestroyWindow(window);
363+ SDL_Quit();
364+ return 0;
365+ break;
366+ default:
367+ if (state[SDL_SCANCODE_ESCAPE]) {
368+ return 0;
369+ }
370+ // update keyboard state
371+ for (int keycode = 0; keycode < 16; keycode++) {
372+ keypad[keycode] = state[keymappings[keycode]];
373+ }
374+ }
375 }
376- usleep(10000);
377 }
378- SDL_DestroyWindow(window);
379- SDL_Quit();
380- return 0;
381 }