这两天撸代码,看别人的源码,总算是有了点收获。除了GLUT部分还不太懂外,其他核心部分都已经搞定。
动手!从哪里下手?
观看了前篇的CHIP8介绍,对CHIP8这种语言有了初步的了解,现在就是用代码实现一个CHIP8的虚拟机。参考源码是用C++写的,不太熟。我这里用C语言进行了实现。
下面讲讲实现流程,这里主要要实现三个文件:
- mychip8.c CHIP8实现的核心代码
- mychip8.h CHIP8的相关定义
- main.c 利用GLUT实现图形/输入等逻辑
首先我们来通过写mychip8.h来了解下怎么用代码来定义CHIP8:
CHIP8基本变量定义
//变量声明
unsigned char Gfx[64*32]; //chip8显存
unsigned char V[16]; //16个寄存器,V0~VF
unsigned char Memory[4096]; //4K内存
unsigned short int I; //地址寄存器
unsigned short int Pc; //程序指针
unsigned short int Stack[16];//栈
unsigned short int Sp; //栈指针
unsigned char Keyboard[16];//16个键值
unsigned short int Opcode; //操作码
unsigned char Delaytimer;//延时定时器
unsigned char Soundtimer;//声音定时器
unsigned char DrawFlag; //绘图标识
上面的这些变量定义都是跟前篇CHIP8介绍有关的,我们在实现一个CHIP8虚拟机时,都要用到上面的变量。
CHIP8用到的几个函数:
void InitializeChip8(); //CHIP8初始化
void HandleOpcode(); //操作码处理,核心部分
int LoadApp(const char *filename); //加载应用(游戏)
void InitializeChip8()
主要是对上述定义CHIP8变量的初始化,比如显存/栈/程序指针等初始化。
代码如下:
void InitializeChip8()
{
unsigned int i;
for(i=0;i<15;i++)
{
V[i] = 0; //寄存器清零
Stack[i] = 0; //栈清零
Keyboard[i] = 0;//按键清零
}
for(i=0;i<4095;i++)
Memory[i] = 0; //内存清零
for(i=0; i<2048; ++i)
Gfx[i] = 0; //显存清零
I = 0; //地址寄存器清零
Sp = 0; //栈指针清零
Pc = 0x200; //PC指针指向程序开始的地方
Opcode = 0; //操作码清零
Delaytimer = 0; //定时器清零
Soundtimer = 0;
DrawFlag = 1; //绘画标识为真
srand(time(NULL)); //产生随机数种子,后面一个操作码要用到
}
上面代码需要注意的就是程序指针初始是指向0x200处的,程序运行代码开始的地方。
void HandleOpcode()
这个函数中的代码就是CHIP8实现的关键代码,就是对CHIP8操作码取码解码的实现。
代码如下:
void HandleOpcode()
{
int i;
Opcode = Memory[Pc] << 8 | Memory[Pc+1]; //取操作码,高位在低地址
switch(Opcode & 0xF000)
{
case 0x0000:
switch(Opcode & 0x000F)
{
case 0x0000: //Clears the screen.
for(i=0; i<2048; i++)
Gfx[i] = 0x0;
DrawFlag = 1;
Pc += 2;
break;
case 0x000E: //Returns from a subroutine.
Sp -= 1;
Pc = Stack[Sp];
Pc +=