|
@@ -5,7 +5,7 @@
|
5
|
5
|
#include <time.h>
|
6
|
6
|
#include <SDL2/SDL.h>
|
7
|
7
|
|
8
|
|
-#define DEBUG 1
|
|
8
|
+#define DEBUG 0
|
9
|
9
|
#define TDISP 0
|
10
|
10
|
|
11
|
11
|
typedef uint8_t byte;
|
|
@@ -23,6 +23,26 @@ typedef struct {
|
23
|
23
|
byte stack_pointer;
|
24
|
24
|
} emulator_state_s;
|
25
|
25
|
|
|
26
|
+byte chip8_fontset[80] =
|
|
27
|
+{
|
|
28
|
+ 0xF0, 0x90, 0x90, 0x90, 0xF0, // 0
|
|
29
|
+ 0x20, 0x60, 0x20, 0x20, 0x70, // 1
|
|
30
|
+ 0xF0, 0x10, 0xF0, 0x80, 0xF0, // 2
|
|
31
|
+ 0xF0, 0x10, 0xF0, 0x10, 0xF0, // 3
|
|
32
|
+ 0x90, 0x90, 0xF0, 0x10, 0x10, // 4
|
|
33
|
+ 0xF0, 0x80, 0xF0, 0x10, 0xF0, // 5
|
|
34
|
+ 0xF0, 0x80, 0xF0, 0x90, 0xF0, // 6
|
|
35
|
+ 0xF0, 0x10, 0x20, 0x40, 0x40, // 7
|
|
36
|
+ 0xF0, 0x90, 0xF0, 0x90, 0xF0, // 8
|
|
37
|
+ 0xF0, 0x90, 0xF0, 0x10, 0xF0, // 9
|
|
38
|
+ 0xF0, 0x90, 0xF0, 0x90, 0x90, // A
|
|
39
|
+ 0xE0, 0x90, 0xE0, 0x90, 0xE0, // B
|
|
40
|
+ 0xF0, 0x80, 0x80, 0x80, 0xF0, // C
|
|
41
|
+ 0xE0, 0x90, 0x90, 0x90, 0xE0, // D
|
|
42
|
+ 0xF0, 0x80, 0xF0, 0x80, 0xF0, // E
|
|
43
|
+ 0xF0, 0x80, 0xF0, 0x80, 0x80 // F
|
|
44
|
+};
|
|
45
|
+
|
26
|
46
|
byte keymap[0x10] = { SDL_SCANCODE_X, SDL_SCANCODE_1, SDL_SCANCODE_2, SDL_SCANCODE_3, SDL_SCANCODE_Q,
|
27
|
47
|
SDL_SCANCODE_W, SDL_SCANCODE_E, SDL_SCANCODE_A, SDL_SCANCODE_S, SDL_SCANCODE_D,
|
28
|
48
|
SDL_SCANCODE_Z, SDL_SCANCODE_C, SDL_SCANCODE_4, SDL_SCANCODE_R, SDL_SCANCODE_F, SDL_SCANCODE_V };
|
|
@@ -41,6 +61,7 @@ int main(int argc, char **argv) {
|
41
|
61
|
|
42
|
62
|
emulator_state_s state = { 0 }; // initialize everything to 0
|
43
|
63
|
state.program_counter = 0x200; // chip8 programs start at 0x200 address space
|
|
64
|
+ memcpy(state.memory, chip8_fontset, 80);
|
44
|
65
|
|
45
|
66
|
FILE *f = fopen(argv[1], "rb");
|
46
|
67
|
fread(&state.memory[0x200], 0x1000 - 0x200, 1, f); // see above comment
|
|
@@ -75,7 +96,7 @@ int main(int argc, char **argv) {
|
75
|
96
|
// SDL_PumpEvents();
|
76
|
97
|
const byte *keystate = SDL_GetKeyboardState(NULL);
|
77
|
98
|
|
78
|
|
- for (int i = 0; i < 0x10 && !press; ++i) {
|
|
99
|
+ for (int i = 0; i < 0x10; ++i) {
|
79
|
100
|
if (keystate[keymap[i]]){
|
80
|
101
|
state.input[i] = 1;
|
81
|
102
|
press = 1;
|
|
@@ -103,12 +124,10 @@ int main(int argc, char **argv) {
|
103
|
124
|
case 0x0000: // screen clear or function return
|
104
|
125
|
if (opcode == 0x00E0){
|
105
|
126
|
memset(state.screen, 0, 64 * 32);
|
106
|
|
- SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xFF);
|
107
|
|
- SDL_RenderClear(renderer);
|
108
|
127
|
if (DEBUG) printf("Clearing screen ");
|
109
|
128
|
}
|
110
|
129
|
|
111
|
|
- else if (opcode = 0x00EE) {
|
|
130
|
+ else if (opcode == 0x00EE) {
|
112
|
131
|
state.program_counter = state.stack[--state.stack_pointer];
|
113
|
132
|
if (DEBUG) printf("Returning to %x ", state.stack[state.stack_pointer]);
|
114
|
133
|
}
|
|
@@ -161,14 +180,14 @@ int main(int argc, char **argv) {
|
161
|
180
|
|
162
|
181
|
case 0x6000: // set reg to constant
|
163
|
182
|
reg = (opcode & 0x0F00) >> 8;
|
164
|
|
- state.registers[reg] = opcode & 0x00FF;
|
|
183
|
+ state.registers[reg] = (byte) opcode;
|
165
|
184
|
if (DEBUG) printf("Assigning %hx to %i", state.registers[reg], reg);
|
166
|
185
|
|
167
|
186
|
break;
|
168
|
187
|
|
169
|
188
|
case 0x7000: // add constant to reg
|
170
|
189
|
reg = (opcode & 0x0F00) >> 8;
|
171
|
|
- state.registers[reg] += opcode & 0x00FF;
|
|
190
|
+ state.registers[reg] += (byte) opcode;
|
172
|
191
|
if (DEBUG) printf("Add %hi to reg %i (%hi)", opcode & 0x00FF, reg, state.registers[reg]);
|
173
|
192
|
|
174
|
193
|
break;
|
|
@@ -203,23 +222,23 @@ int main(int argc, char **argv) {
|
203
|
222
|
unsigned int add = state.registers[first] + state.registers[second];
|
204
|
223
|
if (add > 255) state.registers[0xF] = 1;
|
205
|
224
|
else state.registers[0xF] = 0;
|
206
|
|
- state.registers[first] = add & 0x00FF;
|
|
225
|
+ state.registers[first] = (byte) add;
|
207
|
226
|
if (DEBUG) printf("ADD register %i to %i (%hx) ", second, first, state.registers[first]);
|
208
|
227
|
if (DEBUG) printf("VF is %hx", state.registers[0xF]);
|
209
|
228
|
break;
|
210
|
229
|
|
211
|
230
|
case 5: // X = X - Y, VF = X - Y < 0
|
212
|
231
|
state.registers[first] -= state.registers[second];
|
213
|
|
- if (state.registers[first] > state.registers[second]) state.registers[0xF] = 1;
|
214
|
|
- else state.registers[0xF] = 0;
|
|
232
|
+ if (state.registers[first] > state.registers[second]) state.registers[0xF] = 0;
|
|
233
|
+ else state.registers[0xF] = 1;
|
215
|
234
|
if (DEBUG) printf("SUB register %i from %i (%hx) ", second, first, state.registers[first]);
|
216
|
235
|
if (DEBUG) printf("VF is %hx", state.registers[0xF]);
|
217
|
236
|
break;
|
218
|
237
|
|
219
|
238
|
case 6: // set least significant bit of X in VF, bitshift right
|
220
|
|
- state.registers[0xF] = state.registers[first] & 0x000F;
|
|
239
|
+ state.registers[0xF] = state.registers[first] & 0b00000001;
|
221
|
240
|
state.registers[first] /= 2;
|
222
|
|
- if (DEBUG) printf("RS register %i (%hx) ", first, second, state.registers[first]);
|
|
241
|
+ if (DEBUG) printf("RS register %i (%hx) ", first, state.registers[first]);
|
223
|
242
|
if (DEBUG) printf("VF is %hx", state.registers[0xF]);
|
224
|
243
|
break;
|
225
|
244
|
|
|
@@ -232,9 +251,9 @@ int main(int argc, char **argv) {
|
232
|
251
|
break;
|
233
|
252
|
|
234
|
253
|
case 0xE:; // set msot significant bit of X in VF, bitshift left
|
235
|
|
- state.registers[0xF] = (state.registers[first] & 0xF000) >> 12;
|
|
254
|
+ state.registers[0xF] = (state.registers[first] & 0b10000000) >> 7;
|
236
|
255
|
state.registers[first] *= 2;
|
237
|
|
- if (DEBUG) printf("LS register %i (%hx) ", first, second, state.registers[first]);
|
|
256
|
+ if (DEBUG) printf("LS register %i (%hx) ", first, state.registers[first]);
|
238
|
257
|
if (DEBUG) printf("VF is %hx", state.registers[0xF]);
|
239
|
258
|
break;
|
240
|
259
|
|
|
@@ -285,10 +304,13 @@ int main(int argc, char **argv) {
|
285
|
304
|
for (int xpos = 0; xpos < 8; ++xpos)
|
286
|
305
|
{
|
287
|
306
|
int ypos = y + line;
|
288
|
|
- if (ypos > 63) ypos -= 64;
|
289
|
|
- if (!(data & (1 << xpos))) continue;
|
290
|
|
- if (state.screen[x + (7 - xpos)][ypos]) state.registers[0xF] = 1;
|
291
|
|
- state.screen[x + (7 - xpos)][ypos] ^= 1;
|
|
307
|
+ byte mask = 1 << 7 - xpos;
|
|
308
|
+ if (ypos > 31) ypos -= 32;
|
|
309
|
+ if (!(data & mask)) continue;
|
|
310
|
+ if (state.screen[x + xpos][ypos]){
|
|
311
|
+ state.registers[0xF] = 1;
|
|
312
|
+ }
|
|
313
|
+ state.screen[x + xpos][ypos] ^= 1;
|
292
|
314
|
}
|
293
|
315
|
}
|
294
|
316
|
|
|
@@ -348,7 +370,8 @@ int main(int argc, char **argv) {
|
348
|
370
|
break;
|
349
|
371
|
|
350
|
372
|
case 0x29:
|
351
|
|
- break; // fontset not implemented yet
|
|
373
|
+ state.address_I = state.registers[reg] * 5;
|
|
374
|
+ break;
|
352
|
375
|
|
353
|
376
|
case 0x33:;
|
354
|
377
|
int value = state.registers[reg];
|
|
@@ -358,12 +381,12 @@ int main(int argc, char **argv) {
|
358
|
381
|
break;
|
359
|
382
|
|
360
|
383
|
case 0x55:
|
361
|
|
- for (int i = 0; i < (reg + 1); ++i)
|
|
384
|
+ for (int i = 0; i <= reg; ++i)
|
362
|
385
|
state.memory[state.address_I + i] = state.registers[i];
|
363
|
386
|
break;
|
364
|
387
|
|
365
|
388
|
case 0x65:
|
366
|
|
- for (int i = 0; i < (reg + 1); ++i)
|
|
389
|
+ for (int i = 0; i <= reg + 1; ++i)
|
367
|
390
|
state.registers[i] = state.memory[state.address_I + i];
|
368
|
391
|
break;
|
369
|
392
|
|