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

把代码贴一下吧。

 #ifndef __CHIP8_H__
#define __CHIP8_H__ class Chip8
{
public:
bool drawFlag;
void emulateCycle();
bool loadApplication(const char* fileName);
unsigned char gfx[ * ];
unsigned char key[]; private:
//35条opcode写成函数,为了效率,使用inline
inline void op_0NNN();
inline void op_00E0();
inline void op_00EE();
inline void op_1NNN();
inline void op_2NNN();
inline void op_3XNN();
inline void op_4XNN();
inline void op_5XY0();
inline void op_6XNN();
inline void op_7XNN();
inline void op_8XY0();
inline void op_8XY1();
inline void op_8XY2();
inline void op_8XY3();
inline void op_8XY4();
inline void op_8XY5();
inline void op_8XY6();
inline void op_8XY7();
inline void op_8XYE();
inline void op_9XY0();
inline void op_ANNN();
inline void op_BNNN();
inline void op_CXNN();
inline void op_DXYN();
inline void op_EX9E();
inline void op_EXA1();
inline void op_FX07();
inline void op_FX0A();
inline void op_FX15();
inline void op_FX18();
inline void op_FX1E();
inline void op_FX29();
inline void op_FX33();
inline void op_FX55();
inline void op_FX65(); void init(); unsigned short pc;
unsigned short opcode;
unsigned short I;
unsigned short sp; unsigned char V[];
unsigned short stack[];
unsigned char memory[]; unsigned char delay_timer;
unsigned char sound_timer;
}; #endif
 #define _CRT_SECURE_NO_WARNINGS 1

 #include "Chip8.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h> unsigned char fontset[] =
{
0xF0, 0x90, 0x90, 0x90, 0xF0, //
0x20, 0x60, 0x20, 0x20, 0x70, //
0xF0, 0x10, 0xF0, 0x80, 0xF0, //
0xF0, 0x10, 0xF0, 0x10, 0xF0, //
0x90, 0x90, 0xF0, 0x10, 0x10, //
0xF0, 0x80, 0xF0, 0x10, 0xF0, //
0xF0, 0x80, 0xF0, 0x90, 0xF0, //
0xF0, 0x10, 0x20, 0x40, 0x40, //
0xF0, 0x90, 0xF0, 0x90, 0xF0, //
0xF0, 0x90, 0xF0, 0x10, 0xF0, //
0xF0, 0x90, 0xF0, 0x90, 0x90, //A
0xE0, 0x90, 0xE0, 0x90, 0xE0, //B
0xF0, 0x80, 0x80, 0x80, 0xF0, //C
0xE0, 0x90, 0x90, 0x90, 0xE0, //D
0xF0, 0x80, 0xF0, 0x80, 0xF0, //E
0xF0, 0x80, 0xF0, 0x80, 0x80 //F
}; void Chip8::init()
{
pc = 0x200;
opcode = ;
I = ;
sp = ;
delay_timer = ;
sound_timer = ;
drawFlag = true; memset(memory, , sizeof(memory));
memset(V, , sizeof(V));
memset(gfx, , sizeof(gfx));
memset(stack, , sizeof(stack));
memset(key, , sizeof(key)); for(int i = ; i < ; ++i) {
memory[i] = fontset[i];
}
srand((unsigned int)time(NULL));
} bool Chip8::loadApplication(const char* fileName)
{
init();
FILE* file = fopen(fileName, "rb");
fseek(file, , SEEK_END);
int fileSize = ftell(file);
rewind(file);
char* buffer = (char*)malloc(sizeof(char) * fileSize);
fread(buffer, sizeof(char), fileSize, file);
for(int i = ; i < fileSize; ++i) {
memory[+i] = buffer[i];
}
fclose(file);
free(buffer);
return true;
} void Chip8::emulateCycle()
{
opcode = memory[pc] << | memory[pc+];
switch(opcode & 0xF000) {
case 0x0000:
switch(opcode & 0x000F) {
case 0x0000:
op_00E0(); break;
case 0x000E:
op_00EE(); break;
}
break;
case 0x1000:
op_1NNN(); break;
case 0x2000:
op_2NNN(); break;
case 0x3000:
op_3XNN(); break;
case 0x4000:
op_4XNN(); break;
case 0x5000:
op_5XY0(); break;
case 0x6000:
op_6XNN(); break;
case 0x7000:
op_7XNN(); break;
case 0x8000:
switch(opcode & 0x000F) {
case 0x0000:
op_8XY0(); break;
case 0x0001:
op_8XY1(); break;
case 0x0002:
op_8XY2(); break;
case 0x0003:
op_8XY3(); break;
case 0x0004:
op_8XY4(); break;
case 0x0005:
op_8XY5(); break;
case 0x0006:
op_8XY6(); break;
case 0x0007:
op_8XY7(); break;
case 0x000E:
op_8XYE(); break;
}
break;
case 0x9000:
op_9XY0(); break;
case 0xA000:
op_ANNN(); break;
case 0xB000:
op_BNNN(); break;
case 0xC000:
op_CXNN(); break;
case 0xD000:
op_DXYN(); break;
case 0xE000:
switch(opcode & 0x000F) {
case 0x000E:
op_EX9E(); break;
case 0x0001:
op_EXA1(); break;
}
break;
case 0xF000:
switch(opcode & 0x00FF) {
case 0x0007:
op_FX07(); break;
case 0x000A:
op_FX0A(); break;
case 0x0015:
op_FX15(); break;
case 0x0018:
op_FX18(); break;
case 0x001E:
op_FX1E(); break;
case 0x0029:
op_FX29(); break;
case 0x0033:
op_FX33(); break;
case 0x0055:
op_FX55(); break;
case 0x0065:
op_FX65(); break;
}
}
if(delay_timer > ) {
--delay_timer;
}
if(sound_timer > ) {
--sound_timer;
}
} void Chip8::op_0NNN()
{
} void Chip8::op_00E0()
{
memset(gfx, , sizeof(gfx));
drawFlag = true;
pc += ;
} void Chip8::op_00EE()
{
pc = stack[--sp] + ;
} void Chip8::op_1NNN()
{
pc = opcode & 0x0FFF;
} void Chip8::op_2NNN()
{
stack[sp++] = pc;
pc = opcode & 0x0FFF;
} void Chip8::op_3XNN()
{
pc += (V[(opcode & 0x0F00) >> ] == (opcode & 0x00FF)) ? : ;
} void Chip8::op_4XNN()
{
pc += (V[(opcode & 0x0F00) >> ] != (opcode & 0x00FF)) ? : ;
} void Chip8::op_5XY0()
{
pc += (V[(opcode & 0x0F00) >> ] == V[(opcode & 0x00F0) >> ]) ? : ;
} void Chip8::op_6XNN()
{
V[(opcode & 0x0F00) >> ] = opcode & 0x00FF;
pc += ;
} void Chip8::op_7XNN()
{
V[(opcode & 0x0F00) >> ] += opcode & 0x00FF;
pc += ;
} void Chip8::op_8XY0()
{
V[(opcode & 0x0F00) >> ] = V[(opcode & 0x00F0) >> ];
pc += ;
} void Chip8::op_8XY1()
{
V[(opcode & 0x0F00) >> ] |= V[(opcode & 0x00F0) >> ];
pc += ;
} void Chip8::op_8XY2()
{
V[(opcode & 0x0F00) >> ] &= V[(opcode & 0x00F0) >> ];
pc += ;
} void Chip8::op_8XY3()
{
V[(opcode & 0x0F00) >> ] ^= V[(opcode & 0x00F0) >> ];
pc += ;
} void Chip8::op_8XY4()
{
V[0xF] = V[(opcode & 0x00F0) >> ] > (0xFF - V[(opcode &0x0F00) >> ]);
V[(opcode & 0x0F00) >> ] += V[(opcode & 0x00F0) >> ];
pc += ;
} void Chip8::op_8XY5()
{
V[0xF] = !(V[(opcode & 0x00F0) >> ] > V[(opcode & 0x0F00) >> ]);
V[(opcode & 0x0F00) >> ] -= V[(opcode & 0x00F0) >> ];
pc += ;
} void Chip8::op_8XY6()
{
V[0xF] = V[(opcode & 0x0F00) >> ] & 0x1;
V[(opcode & 0x0F00) >> ] >>= ;
pc += ;
} void Chip8::op_8XY7()
{
V[0xF] = !(V[(opcode & 0x0F00) >> ] > V[(opcode & 0x00F0) >> ]);
V[(opcode & 0x0F00) >> ] = V[(opcode & 0x00F0) >> ] - V[(opcode & 0x0F00) >> ];
pc += ;
} void Chip8::op_8XYE()
{
V[0xF] = V[(opcode & 0x0F00) >> ] >> ;
V[(opcode & 0x0F00) >> ] <<= ;
pc += ;
} void Chip8::op_9XY0()
{
pc += (V[(opcode & 0x0F00) >> ] != V[(opcode & 0x00F0) >> ]) ? : ;
} void Chip8::op_ANNN()
{
I = opcode & 0x0FFF;
pc += ;
} void Chip8::op_BNNN()
{
pc = (opcode & 0x0FFF) + V[];
} void Chip8::op_CXNN()
{
V[(opcode & 0x0F00) >> ] = (rand() % 0xFF) & (opcode & 0x00FF);
pc += ;
} void Chip8::op_DXYN()
{
unsigned short x = V[(opcode & 0x0F00) >> ];
unsigned short y = V[(opcode & 0x00F0) >> ];
unsigned short height = opcode & 0x000F;
unsigned short pixel = ;
V[0xF] = ;
for(int yline = ; yline < height; ++yline) {
pixel = memory[I+yline];
for(int xline = ; xline < ; ++xline) {
if((pixel & (0x80 >> xline)) != )
{
if(gfx[(x + xline + ((y + yline) * ))] == )
{
V[0xF] = ;
}
gfx[x + xline + ((y + yline) * )] ^= ;
}
}
}
drawFlag = true;
pc += ;
} void Chip8::op_EX9E()
{
pc += (key[V[(opcode & 0x0F00) >> ]]) ? : ;
} void Chip8::op_EXA1()
{
pc += (key[V[(opcode & 0x0F00) >> ]]) ? : ;
} void Chip8::op_FX07()
{
V[(opcode & 0x0F00) >> ] = delay_timer;
pc += ;
} void Chip8::op_FX0A()
{
bool keyPress = false; for(int i = ; i < ; ++i)
{
if(key[i] != )
{
V[(opcode & 0x0F00) >> ] = i;
keyPress = true;
}
} if(!keyPress) {
return;
}
pc += ;
} void Chip8::op_FX15()
{
delay_timer = V[(opcode & 0x0F00) >> ];
pc += ;
} void Chip8::op_FX18()
{
sound_timer = V[(opcode & 0x0F00) >> ];
pc += ;
} void Chip8::op_FX1E()
{
V[0xF] = (I + V[(opcode & 0x0F00) >> ]) > 0xFFF;
I += V[(opcode & 0x0F00) >> ];
pc += ;
} void Chip8::op_FX29()
{
I = V[(opcode & 0x0F00) >> ] * ;
pc += ;
} void Chip8::op_FX33()
{
unsigned short vx = V[(opcode & 0x0F00) >> ];
memory[I] = vx / ;
memory[I+] = vx / % ;
memory[I+] = vx % ;
pc += ;
} void Chip8::op_FX55()
{
unsigned short vx = V[(opcode & 0x0F00) >> ];
for(int i = ; i <= vx; ++i) {
memory[I+i] = V[i];
}
I += ((opcode & 0x0F00) >> ) + ;
pc += ;
} void Chip8::op_FX65()
{
unsigned short vx = V[(opcode & 0x0F00) >> ];
for(int i = ; i <= vx; ++i) {
V[i] = memory[I+i];
}
I += ((opcode & 0x0F00) >> ) + ;
pc += ;
}

C++版 Chip8游戏模拟器的更多相关文章

  1. Swift版iOS游戏框架Sprite Kit基础教程下册

    Swift版iOS游戏框架Sprite Kit基础教程下册 试读下载地址:http://pan.baidu.com/s/1qWBdV0C 介绍:本教程是国内唯一的Swift版的Spritekit教程. ...

  2. android版猜拳游戏源码分享

    android版猜拳游戏源码分享安卓版猜拳游戏源码,该文件中带有安装测试包的,这个游戏源码比较简单的,现在有两个代码,一个自定义VIEW的,一个就是普通的imageView图片,游戏非常适合一些新手的 ...

  3. 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程:简介及目录》(附上完整工程文件)

    介绍:讲述如何使用Genesis-3D来制作一个横版格斗游戏,涉及如何制作连招系统,如何使用包围盒实现碰撞检测,软键盘的制作,场景切换,技能读表,简单怪物AI等等,并为您提供这个框架的全套资源,源码以 ...

  4. 一个用 C 语言写的迷你版 2048 游戏,仅仅有 500个字符

    Jay Chan 用 C 语言写的一个迷你版 2048 游戏,仅仅有 487 个字符. 来围观吧 M[16],X=16,W,k;main(){T(system("stty cbreak&qu ...

  5. 简易2D横版RPG游戏制作

    Unity学习笔记1 简易2D横版RPG游戏制作 http://m.blog.csdn.net/article/details?id=24601905

  6. Cocos2d-x 3.x版2048游戏开发

    Cocos2d-x 3.x版2048游戏开发 本篇博客给大家介绍怎样高速开发2048这样一款休闲游戏,理解整个2048游戏的开发流程.从本篇博客你将能够学习到下面内容: 这里注明一下,本教程来自极客学 ...

  7. 相当牛X的java版星际游戏

    分享一款牛人用java写的经典游戏,目录结构如下: 虽然只能算一个Demo,但是用到了很多Java基础技术和算法: Java2D,双缓冲,A星寻路,粒子系统,动画效果,处理图片,Swing ui ,U ...

  8. Beat &#39;Em Up Game Starter Kit (横版格斗游戏) cocos2d-x游戏源代码

    浓缩精华.专注战斗! 游戏的本质是什么?界面?养成?NoNo!    游戏来源于对实战和比赛的模拟,所以它的本源就是对抗.就是战斗! 是挥洒热血的一种方式! 一个游戏最复杂最难做的是什么?UI?商城? ...

  9. 创业游戏模拟器 Startup 游戏试玩

    买的正版游戏,还在beta阶段.因为对这种经营类的游戏挺感兴趣,结合自己也是做这个行当的.算是一次性通关了吧.我来评价一下这个游戏.足足玩了有5个多小时.从1级玩到15级.解锁了所有的内容.员工从1个 ...

随机推荐

  1. Java 加密解密 对称加密算法 非对称加密算法 MD5 BASE64 AES RSA

    版权声明:本文为博主原创文章,未经博主允许不得转载. [前言] 本文简单的介绍了加密技术相关概念,最后总结了java中现有的加密技术以及使用方法和例子 [最简单的加密] 1.简单的概念 明文:加密前的 ...

  2. 谋哥:App排行榜的秘密

    App在改变世界,改变人们的生活.       如今购物大家都用淘宝.京东,吃饭你会用饭否,看天气预报你用墨迹天气,看视频用优酷.K歌你用唱吧,聊天联系你用微信,看新闻你用今日头条等等.你的生活由你自 ...

  3. 使用json-lib进行Java和JSON之间的转换

    1. json-lib是一个java类库,提供将Java对象,包括beans, maps, collections, java arrays and XML等转换成JSON,或者反向转换的功能. 2. ...

  4. MySQL对于datetime 源码分析

    http://tsecer.blog.163.com/blog/static/150181720160117355684/   一.时间比较的语法分析 在mysql中,通常时间是一个必不可少的类型,而 ...

  5. zTree判断是否为父节点

    var treeObj = $.fn.zTree.getZTreeObj("tree"); var nodes = treeObj.getSelectedNodes(); if(t ...

  6. MySQL约束

    MySQL中约束保存在information_schema数据库的table_constraints中,可以通过该表查询约束信息: 常用5种约束: not null: 非空约束,指定某列不为空 uni ...

  7. MySQL数据库分表的3种方法

    原文地址:MySQL数据库分表的3种方法作者:dreamboycx 一,先说一下为什么要分表 当一张的数据达到几百万时,你查询一次所花的时间会变多,如果有联合查询的话,我想有可能会死在那儿了.分表的目 ...

  8. 创建本地RPM源之更新系统旧版软件mysql

    事情起因 系统版本为Centos6.6 ,因为之前同事没有采用最小化选择性安装,所以系统安装好后自带有mysql5.1的三个安装包: [root@test ~]# rpm -qa | grep mys ...

  9. Asp.net 上传文件小叙(修改FileUpload显示文字等)

    想要在asp.net网站上上传文件就得用到FileUpload,可是这个控件中“浏览”没法修改,可以使用html中<input type="file" 来解决该问题. 首先页 ...

  10. C#类和成员定义

    1 定义类     C#用关键字class来定义类.默认情况下,类声明为内部(internal)的,即只有当前项目中的代码才能访问它.与之相对应的,还可以用public关键字来修饰,这样该类还可以由其 ...