首页 > 代码库 > C++版 Chip8游戏模拟器

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写成函数,为了效率,使用inline15     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 }