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 }

 

你可能感兴趣的:(C++)