C++版 Chip8游戏模拟器

很早就想写个FC模拟器,但真是一件艰难的事情。。

所以先写个Chip8模拟器,日后再继续研究FC模拟器。

Chip8只有35条指令,属于RISC指令集,4k内存,2k显存,16个寄存器(其中15个通用寄存器),支持16个按键,没有中断,但是有两个计时器。

读了下面两个链接,就完全能理解了。

http://www.cnblogs.com/YiranXie/category/539179.html

http://en.wikipedia.org/wiki/CHIP-8

 

把代码贴一下吧。

 1 #ifndef __CHIP8_H__
 2 #define __CHIP8_H__
 3 
 4 class Chip8
 5 {
 6 public:
 7     bool drawFlag;
 8     void emulateCycle();
 9     bool loadApplication(const char* fileName);
10     unsigned char gfx[64 * 32];
11     unsigned char key[16];
12 
13 private:
14     //35条opcode写成函数,为了效率,使用inline
15     inline void op_0NNN();
16     inline void op_00E0();
17     inline void op_00EE();
18     inline void op_1NNN();
19     inline void op_2NNN();
20     inline void op_3XNN();
21     inline void op_4XNN();
22     inline void op_5XY0();
23     inline void op_6XNN();
24     inline void op_7XNN();
25     inline void op_8XY0();
26     inline void op_8XY1();
27     inline void op_8XY2();
28     inline void op_8XY3();
29     inline void op_8XY4();
30     inline void op_8XY5();
31     inline void op_8XY6();
32     inline void op_8XY7();
33     inline void op_8XYE();
34     inline void op_9XY0();
35     inline void op_ANNN();
36     inline void op_BNNN();
37     inline void op_CXNN();
38     inline void op_DXYN();
39     inline void op_EX9E();
40     inline void op_EXA1();
41     inline void op_FX07();
42     inline void op_FX0A();
43     inline void op_FX15();
44     inline void op_FX18();
45     inline void op_FX1E();
46     inline void op_FX29();
47     inline void op_FX33();
48     inline void op_FX55();
49     inline void op_FX65();
50 
51     void init();
52 
53     unsigned short pc;
54     unsigned short opcode;
55     unsigned short I;
56     unsigned short sp;
57 
58     unsigned char V[16];
59     unsigned short stack[16];
60     unsigned char memory[4096];
61 
62     unsigned char delay_timer;
63     unsigned char sound_timer;
64 };
65 
66 #endif
  1 #define _CRT_SECURE_NO_WARNINGS 1
  2 
  3 #include "Chip8.h"
  4 #include <string.h>
  5 #include <stdio.h>
  6 #include <stdlib.h>
  7 #include <time.h>
  8 
  9 unsigned char fontset[80] =
 10 {
 11     0xF0, 0x90, 0x90, 0x90, 0xF0, //0
 12     0x20, 0x60, 0x20, 0x20, 0x70, //1
 13     0xF0, 0x10, 0xF0, 0x80, 0xF0, //2
 14     0xF0, 0x10, 0xF0, 0x10, 0xF0, //3
 15     0x90, 0x90, 0xF0, 0x10, 0x10, //4
 16     0xF0, 0x80, 0xF0, 0x10, 0xF0, //5
 17     0xF0, 0x80, 0xF0, 0x90, 0xF0, //6
 18     0xF0, 0x10, 0x20, 0x40, 0x40, //7
 19     0xF0, 0x90, 0xF0, 0x90, 0xF0, //8
 20     0xF0, 0x90, 0xF0, 0x10, 0xF0, //9
 21     0xF0, 0x90, 0xF0, 0x90, 0x90, //A
 22     0xE0, 0x90, 0xE0, 0x90, 0xE0, //B
 23     0xF0, 0x80, 0x80, 0x80, 0xF0, //C
 24     0xE0, 0x90, 0x90, 0x90, 0xE0, //D
 25     0xF0, 0x80, 0xF0, 0x80, 0xF0, //E
 26     0xF0, 0x80, 0xF0, 0x80, 0x80  //F
 27 };
 28 
 29 void Chip8::init()
 30 {
 31     pc = 0x200;
 32     opcode = 0;
 33     I = 0;
 34     sp = 0;
 35     delay_timer = 0;
 36     sound_timer = 0;
 37     drawFlag = true;
 38 
 39     memset(memory, 0, sizeof(memory));
 40     memset(V, 0, sizeof(V));
 41     memset(gfx, 0, sizeof(gfx));
 42     memset(stack, 0, sizeof(stack));
 43     memset(key, 0, sizeof(key));
 44 
 45     for(int i = 0; i < 80; ++i) {
 46         memory[i] = fontset[i];
 47     }
 48     srand((unsigned int)time(NULL));
 49 }
 50 
 51 bool Chip8::loadApplication(const char* fileName)
 52 {
 53     init();
 54     FILE* file = fopen(fileName, "rb");
 55     fseek(file, 0, SEEK_END);
 56     int fileSize = ftell(file);
 57     rewind(file);
 58     char* buffer = (char*)malloc(sizeof(char) * fileSize);
 59     fread(buffer, sizeof(char), fileSize, file);
 60     for(int i = 0; i < fileSize; ++i) {
 61         memory[512+i] = buffer[i];
 62     }
 63     fclose(file);
 64     free(buffer);
 65     return true;
 66 }
 67 
 68 void Chip8::emulateCycle()
 69 {
 70     opcode = memory[pc] << 8 | memory[pc+1];
 71     switch(opcode & 0xF000) {
 72     case 0x0000:
 73         switch(opcode & 0x000F) {
 74         case 0x0000:
 75             op_00E0(); break;
 76         case 0x000E:
 77             op_00EE(); break;
 78         }
 79         break;
 80     case 0x1000:
 81         op_1NNN(); break;
 82     case 0x2000:
 83         op_2NNN(); break;
 84     case 0x3000:
 85         op_3XNN(); break;
 86     case 0x4000:
 87         op_4XNN(); break;
 88     case 0x5000:
 89         op_5XY0(); break;
 90     case 0x6000:
 91         op_6XNN(); break;
 92     case 0x7000:
 93         op_7XNN(); break;
 94     case 0x8000:
 95         switch(opcode & 0x000F) {
 96         case 0x0000:
 97             op_8XY0(); break;
 98         case 0x0001:
 99             op_8XY1(); break;
100         case 0x0002:
101             op_8XY2(); break;
102         case 0x0003:
103             op_8XY3(); break;
104         case 0x0004:
105             op_8XY4(); break;
106         case 0x0005:
107             op_8XY5(); break;
108         case 0x0006:
109             op_8XY6(); break;
110         case 0x0007:
111             op_8XY7(); break;
112         case 0x000E:
113             op_8XYE(); break;
114         }
115         break;
116     case 0x9000:
117         op_9XY0(); break;
118     case 0xA000:
119         op_ANNN(); break;
120     case 0xB000:
121         op_BNNN(); break;
122     case 0xC000:
123         op_CXNN(); break;
124     case 0xD000:
125         op_DXYN(); break;
126     case 0xE000:
127         switch(opcode & 0x000F) {
128         case 0x000E:
129             op_EX9E(); break;
130         case 0x0001:
131             op_EXA1(); break;
132         }
133         break;
134     case 0xF000:
135         switch(opcode & 0x00FF) {
136         case 0x0007:
137             op_FX07(); break;
138         case 0x000A:
139             op_FX0A(); break;
140         case 0x0015:
141             op_FX15(); break;
142         case 0x0018:
143             op_FX18(); break;
144         case 0x001E:
145             op_FX1E(); break;
146         case 0x0029:
147             op_FX29(); break;
148         case 0x0033:
149             op_FX33(); break;
150         case 0x0055:
151             op_FX55(); break;
152         case 0x0065:
153             op_FX65(); break;
154         }
155     }
156     if(delay_timer > 0) {
157         --delay_timer;
158     }
159     if(sound_timer > 0) {
160         --sound_timer;
161     }
162 }
163 
164 void Chip8::op_0NNN()
165 {
166 }
167 
168 void Chip8::op_00E0()
169 {
170     memset(gfx, 0, sizeof(gfx));
171     drawFlag = true;
172     pc += 2;
173 }
174 
175 void Chip8::op_00EE()
176 {
177     pc = stack[--sp] + 2;
178 }
179 
180 void Chip8::op_1NNN()
181 {
182     pc = opcode & 0x0FFF;
183 }
184 
185 void Chip8::op_2NNN()
186 {
187     stack[sp++] = pc;
188     pc = opcode & 0x0FFF;
189 }
190 
191 void Chip8::op_3XNN()
192 {
193     pc += (V[(opcode & 0x0F00) >> 8] == (opcode & 0x00FF)) ? 4 : 2;
194 }
195 
196 void Chip8::op_4XNN()
197 {
198     pc += (V[(opcode & 0x0F00) >> 8] != (opcode & 0x00FF)) ? 4 : 2;
199 }
200 
201 void Chip8::op_5XY0()
202 {
203     pc += (V[(opcode & 0x0F00) >> 8] == V[(opcode & 0x00F0) >> 4]) ? 4 : 2;
204 }
205 
206 void Chip8::op_6XNN()
207 {
208     V[(opcode & 0x0F00) >> 8] = opcode & 0x00FF;
209     pc += 2;
210 }
211 
212 void Chip8::op_7XNN()
213 {
214     V[(opcode & 0x0F00) >> 8] += opcode & 0x00FF;
215     pc += 2;
216 }
217 
218 void Chip8::op_8XY0()
219 {
220     V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4];
221     pc += 2;
222 }
223 
224 void Chip8::op_8XY1()
225 {
226     V[(opcode & 0x0F00) >> 8] |= V[(opcode & 0x00F0) >> 4];
227     pc += 2;
228 }
229 
230 void Chip8::op_8XY2()
231 {
232     V[(opcode & 0x0F00) >> 8] &= V[(opcode & 0x00F0) >> 4];
233     pc += 2;
234 }
235 
236 void Chip8::op_8XY3()
237 {
238     V[(opcode & 0x0F00) >> 8] ^= V[(opcode & 0x00F0) >> 4];
239     pc += 2;
240 }
241 
242 void Chip8::op_8XY4()
243 {
244     V[0xF] = V[(opcode & 0x00F0) >> 4] > (0xFF - V[(opcode &0x0F00) >> 8]);
245     V[(opcode & 0x0F00) >> 8] += V[(opcode & 0x00F0) >> 4];
246     pc += 2;
247 }
248 
249 void Chip8::op_8XY5()
250 {
251     V[0xF] = !(V[(opcode & 0x00F0) >> 4] > V[(opcode & 0x0F00) >> 8]);
252     V[(opcode & 0x0F00) >> 8] -= V[(opcode & 0x00F0) >> 4];
253     pc += 2;
254 }
255 
256 void Chip8::op_8XY6()
257 {
258     V[0xF] = V[(opcode & 0x0F00) >> 8] & 0x1;
259     V[(opcode & 0x0F00) >> 8] >>= 1;
260     pc += 2;
261 }
262 
263 void Chip8::op_8XY7()
264 {
265     V[0xF] = !(V[(opcode & 0x0F00) >> 8] > V[(opcode & 0x00F0) >> 4]);
266     V[(opcode & 0x0F00) >> 8] = V[(opcode & 0x00F0) >> 4] - V[(opcode & 0x0F00) >> 8];
267     pc += 2;
268 }
269 
270 void Chip8::op_8XYE()
271 {
272     V[0xF] = V[(opcode & 0x0F00) >> 8] >> 7;
273     V[(opcode & 0x0F00) >> 8] <<= 1;
274     pc += 2;
275 }
276 
277 void Chip8::op_9XY0()
278 {
279     pc += (V[(opcode & 0x0F00) >> 8] != V[(opcode & 0x00F0) >> 4]) ? 4 : 2;
280 }
281 
282 void Chip8::op_ANNN()
283 {
284     I = opcode & 0x0FFF;
285     pc += 2;
286 }
287 
288 void Chip8::op_BNNN()
289 {
290     pc = (opcode & 0x0FFF) + V[0];
291 }
292 
293 void Chip8::op_CXNN()
294 {
295     V[(opcode & 0x0F00) >> 8] = (rand() % 0xFF) & (opcode & 0x00FF);
296     pc += 2;
297 }
298 
299 void Chip8::op_DXYN()
300 {
301     unsigned short x = V[(opcode & 0x0F00) >> 8];
302     unsigned short y = V[(opcode & 0x00F0) >> 4];
303     unsigned short height = opcode & 0x000F;
304     unsigned short pixel = 0;
305     V[0xF] = 0;
306     for(int yline = 0; yline < height; ++yline) {
307         pixel = memory[I+yline];
308         for(int xline = 0; xline < 8; ++xline) {
309             if((pixel & (0x80 >> xline)) != 0)
310             {
311                 if(gfx[(x + xline + ((y + yline) * 64))] == 1)
312                 {
313                     V[0xF] = 1;
314                 }
315                 gfx[x + xline + ((y + yline) * 64)] ^= 1;
316             }
317         }
318     }
319     drawFlag = true;
320     pc += 2;
321 }
322 
323 void Chip8::op_EX9E()
324 {
325     pc += (key[V[(opcode & 0x0F00) >> 8]]) ? 4 : 2;
326 }
327 
328 void Chip8::op_EXA1()
329 {
330     pc += (key[V[(opcode & 0x0F00) >> 8]]) ? 2 : 4;
331 }
332 
333 void Chip8::op_FX07()
334 {
335     V[(opcode & 0x0F00) >> 8] = delay_timer;
336     pc += 2;
337 }
338 
339 void Chip8::op_FX0A()
340 {
341     bool keyPress = false;
342 
343     for(int i = 0; i < 16; ++i)
344     {
345         if(key[i] != 0)
346         {
347             V[(opcode & 0x0F00) >> 8] = i;
348             keyPress = true;
349         }
350     }
351 
352     if(!keyPress) {
353         return;
354     }
355     pc += 2;
356 }
357 
358 void Chip8::op_FX15()
359 {
360     delay_timer = V[(opcode & 0x0F00) >> 8];
361     pc += 2;
362 }
363 
364 void Chip8::op_FX18()
365 {
366     sound_timer = V[(opcode & 0x0F00) >> 8];
367     pc += 2;
368 }
369 
370 void Chip8::op_FX1E()
371 {
372     V[0xF] = (I + V[(opcode & 0x0F00) >> 8]) > 0xFFF;
373     I += V[(opcode & 0x0F00) >> 8];
374     pc += 2;
375 }
376 
377 void Chip8::op_FX29()
378 {
379     I = V[(opcode & 0x0F00) >> 8] * 5;
380     pc += 2;
381 }
382 
383 void Chip8::op_FX33()
384 {
385     unsigned short vx = V[(opcode & 0x0F00) >> 8];
386     memory[I] = vx / 100;
387     memory[I+1] = vx / 10 % 10;
388     memory[I+2] = vx % 10;
389     pc += 2;
390 }
391 
392 void Chip8::op_FX55()
393 {
394     unsigned short vx = V[(opcode & 0x0F00) >> 8];
395     for(int i = 0; i <= vx; ++i) {
396         memory[I+i] = V[i];
397     }
398     I += ((opcode & 0x0F00) >> 8) + 1;
399     pc += 2;
400 }
401 
402 void Chip8::op_FX65()
403 {
404     unsigned short vx = V[(opcode & 0x0F00) >> 8];
405     for(int i = 0; i <= vx; ++i) {
406         V[i] = memory[I+i];
407     }
408     I += ((opcode & 0x0F00) >> 8) + 1;
409     pc += 2;
410 }

 

posted @ 2014-07-04 21:07  Anti-Magic  阅读(1664)  评论(0编辑  收藏  举报