很早就想写个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 }