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
把代码贴一下吧。
#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游戏模拟器的更多相关文章
- Swift版iOS游戏框架Sprite Kit基础教程下册
Swift版iOS游戏框架Sprite Kit基础教程下册 试读下载地址:http://pan.baidu.com/s/1qWBdV0C 介绍:本教程是国内唯一的Swift版的Spritekit教程. ...
- android版猜拳游戏源码分享
android版猜拳游戏源码分享安卓版猜拳游戏源码,该文件中带有安装测试包的,这个游戏源码比较简单的,现在有两个代码,一个自定义VIEW的,一个就是普通的imageView图片,游戏非常适合一些新手的 ...
- 《Genesis-3D开源游戏引擎--横版格斗游戏制作教程:简介及目录》(附上完整工程文件)
介绍:讲述如何使用Genesis-3D来制作一个横版格斗游戏,涉及如何制作连招系统,如何使用包围盒实现碰撞检测,软键盘的制作,场景切换,技能读表,简单怪物AI等等,并为您提供这个框架的全套资源,源码以 ...
- 一个用 C 语言写的迷你版 2048 游戏,仅仅有 500个字符
Jay Chan 用 C 语言写的一个迷你版 2048 游戏,仅仅有 487 个字符. 来围观吧 M[16],X=16,W,k;main(){T(system("stty cbreak&qu ...
- 简易2D横版RPG游戏制作
Unity学习笔记1 简易2D横版RPG游戏制作 http://m.blog.csdn.net/article/details?id=24601905
- Cocos2d-x 3.x版2048游戏开发
Cocos2d-x 3.x版2048游戏开发 本篇博客给大家介绍怎样高速开发2048这样一款休闲游戏,理解整个2048游戏的开发流程.从本篇博客你将能够学习到下面内容: 这里注明一下,本教程来自极客学 ...
- 相当牛X的java版星际游戏
分享一款牛人用java写的经典游戏,目录结构如下: 虽然只能算一个Demo,但是用到了很多Java基础技术和算法: Java2D,双缓冲,A星寻路,粒子系统,动画效果,处理图片,Swing ui ,U ...
- Beat 'Em Up Game Starter Kit (横版格斗游戏) cocos2d-x游戏源代码
浓缩精华.专注战斗! 游戏的本质是什么?界面?养成?NoNo! 游戏来源于对实战和比赛的模拟,所以它的本源就是对抗.就是战斗! 是挥洒热血的一种方式! 一个游戏最复杂最难做的是什么?UI?商城? ...
- 创业游戏模拟器 Startup 游戏试玩
买的正版游戏,还在beta阶段.因为对这种经营类的游戏挺感兴趣,结合自己也是做这个行当的.算是一次性通关了吧.我来评价一下这个游戏.足足玩了有5个多小时.从1级玩到15级.解锁了所有的内容.员工从1个 ...
随机推荐
- Android内存、性能是程序永恒的话题
内存.性能是程序永恒的话题,实际开发中关于卡顿.OOM也经常是打不完的两只老虎,关于卡顿.OOM的定位方法和工具比较多,这篇文章也不打算赘述了,本章主要是来整理一下JVM的内存模型以及Java对象的生 ...
- winform button设计(一)
对于winform的button设计来说,vs真心没有给太多的样式布局.为了能给予用户更加人性化的界面.我们在做程序时往往会设计美观的button. 比方,我今天在设计一个项目button时,我想将b ...
- linux shell read command-Getting User Input Via Keyboard--ref
ref:http://bash.cyberciti.biz/guide/Getting_User_Input_Via_Keyboard You can accept input from the ke ...
- 【转】hibernate.hbm.xml详解
在Hibernate中,各表的映射文件….hbm.xml可以通过工具生成,例如在使用MyEclipse开发时,它提供了自动生成映射文件的工具.配置文件的基本结构如下: Xml代码 <?xmlve ...
- C#用副线程改主线程(UI线程)的控件属性的方法(包括Winform和WPF)
C#用副线程去试图修改主线程的UI控件会报出异常,解决方案是使用副线程注册事件通知主线程自己去修改UI控件 在winform中,方法如下 private void button1_Click(obje ...
- JavaScript入门(5)
一.什么是数组? 数组是一个值的集合,每一个值都有一个索引号,从0开始,每个索引都有一个相应的值,根据需要添加更多数值. 好比一个团,团里有很多人.如下使用数组存储5个学生成绩: 二.如何创建数组 使 ...
- C#的类型、变量和值
大学学了C#,工作也是使用C#,虽然在日常的开发中没什么大的问题,但个人觉得在C#的理解还不是很清晰,所以决定花一定的时间来理一理学过的知识,顺便革新下脑袋里的知识,因为坑爹的学校在教.net的时候, ...
- T-SQL基础 (子查询,连接查询,交叉查询,事务|| 笔记0807)
一: A.子查询: 1.select 字段名 from table where 字段名=(select 字段名 from table 条件) //只能做1个匹配 2.select 字段名 from ...
- java中关于时间的格式化
long time = System.currentTimeMillis(); SimpleDateFormat format = new SimpleDateFormat(); String s = ...
- 关于dialog引起的 java.lang.IllegalArgumentException: View=com.android.internal.policy.impl.PhoneWindow$DecorView not attached to window manager 错误的分析
在跑Monkey测试的时候出现了一个比较特别的问题,先来看看Log: // CRASH: com.meizu.media.painter (pid 12491) // Short Msg: java. ...