龙空技术网

C语言chip-8模拟器开发教程(1)chip-8简介

终于削了皮的茄子 182

前言:

现时各位老铁们对“c语言迷宫堆栈”大致比较关心,大家都需要剖析一些“c语言迷宫堆栈”的相关内容。那么小编在网络上汇集了一些关于“c语言迷宫堆栈””的相关知识,希望你们能喜欢,同学们一起来了解一下吧!

本教程将使用C语言以及raylib库来实现chip-8模拟器的开发。

什么是chip-8

Chip-8是一种解释型编程语言,由 Joseph Weisbecker 开发。它最初在20世纪70年代中期应用于 COSMAC VIP 和 Telmac 18008位微型计算机。Chip-8程序在 chip-8虚拟机上运行。它的出现是为了让电子游戏更容易为这些计算机编程, CHIP 8由于其简单性至今仍在使用,因此也可用于任何平台和二进制数的编程教学。

大约在15年后,chip-8被引入,衍生解释器出现在一些型号的图形计算器上(从20世纪80年代后期开始,这些手持设备在许多方面比大多数70年代中期的爱好者的微型计算机拥有更强的计算能力)。

chip-8应用程序

有许多经典的电子游戏移植到CHIP-8上,如《Pong》、《太空入侵者》、《俄罗斯方块》和《吃豆人》。还有一些应用,如随机迷宫生成器和康威的生命游戏。

chip-8架构

内存

Chip-8最常用于4k 系统,如 Cosmac VIP 和 Telmac 1800。这些机器有4096(0x1000)kb内存大小,chip-8解释器本身占用了这些机器上前512个字节的内存空间。由于这个原因,大多数chip-8程序从内存位置512(0x200)开始,不访问位置512(0x200)以下的任何内存。最上面的256个字节(0xF00-0xFFF)保留用于显示刷新,下面的96个字节(0xEA0-0xEFF)保留用于调用堆栈、内部使用和其他变量。

寄存器

CHIP-8有16个8位数据寄存器,命名为V0到VF。VF寄存器作为一些指令的标志。在加法操作中,VF是进位标志,而在减法操作中,它是“没有借位”标志。在绘制指令中,像素碰撞时也会设置VF。

地址寄存器名为I,宽度为12位,与几个涉及内存操作的操作码一起使用。

堆栈

堆栈仅用于在调用函数时存储返回地址。

计时器

CHIP-8有两个定时器。它们都以60赫兹的频率倒数,直到达到0。

延迟计时器:该计时器用于为游戏事件计时。它的值可以设置和读取。

声音计时器:这个计时器用于音效。当它的值非零时,发出哔哔声。

输入

输入是用十六进制键盘完成的,它有从0到f的16个键。'8','4','6'和'2'键通常用于方向输入。三个操作码用于检测输入。其中一个会在按下特定键时跳过指令,而另一个则在未按下特定键时跳过指令。第三个等待键按下,然后将其存储在数据寄存器之一。

图形和声音

chip-8显示分辨率为64×32,颜色为单色。图形仅通过绘制精灵绘制到屏幕上,精灵宽度为8像素,高度为1到15像素。精灵像素与相应的屏幕像素是异或的。换句话说,被设置的精灵像素会翻转相应屏幕像素的颜色,而未设置的精灵像素则什么都不做。当绘制精灵时,如果任何屏幕像素从set翻转到unset,则进位标志(VF)将被设置为1,否则将被设置为0。这是用于碰撞检测。

如前所述,当声音计时器的值非零时,将播放蜂鸣声。

操作码表

CHIP-8有35个操作码,都是两个字节长,存储大端数。操作码如下所示,以十六进制表示,并带有以下符号:

NNN:地址NN:8bit常数N:4bit常数X和Y: 4位寄存器标识符PC:程序计数器I: 16位寄存器(用于内存地址)(类似于void指针);VN: (寄存器)16个可用变量之一。N可以是0到F(十六进制);

操作码

类型

C 风格代码

解释

0NNN

Call

调用地址NNN处的机器码。

00E0

Display

disp_clear()

清空屏幕

00EE

Flow

return;

从一个函数返回

1NNN

Flow

goto NNN;

跳转到地址NNN

2NNN

Flow

*(0xNNN)()

调用地址NNN处的函数。

3XNN

Cond

if (Vx == NN)

如果VX等于NN,则跳过下一条指令。(通常下一条指令是跳过代码块的跳转);

4XNN

Cond

if (Vx != NN)

如果VX不等于NN,则跳过下一条指令。(通常下一条指令是跳过代码块的跳转);

5XY0

Cond

if (Vx == Vy)

如果VX等于VY,则跳过下一条指令。(通常下一条指令是跳过代码块的跳转);

6XNN

Const

Vx = N

将VX设置为NN。

7XNN

Const

Vx += N

将NN添加到VX。(进位标志VF不改变);

8XY0

Assig

Vx = Vy

将VX设置为VY的值。

8XY1

BitOp

Vx |= Vy

将VX设置为VX或VY。(按位或操作);

8XY2

BitOp

Vx &= Vy

将VX设置为VX和VY。(按位和操作);

8XY3

BitOp

Vx ^= Vy

将VX设置为VX 异或 VY。

8XY4

Math

Vx += Vy

将VY添加到VX。当有进位时,VF被设为1,当没有进位时,VF被设为0。

8XY5

Math

Vx -= Vy

VX减去VY。当有借位时,VF设为0,当没有借位时,VF设为1。

8XY6

BitOp

Vx >>= 1

将VX的最低有效位存储在VF中,然后将VX向右移1。

8XY7

Math

Vx = Vy - Vx

将VX设置为VY - VX。当有借位时,VF设为0,当没有借位时,VF设为1。

8XYE

BitOp

Vx <<= 1

将VX的最高有效位存储在VF中,然后将VX向左移1。

9XY0

Cond

if (Vx != Vy)

如果VX不等于VY,则跳过下一条指令。(通常下一条指令是跳过代码块的跳转);

ANNN

MEM

I = NNN

设置I为地址NNN。

BNNN

Flow

PC = V0 + NNN

跳转到地址NNN + V0。

CXNN

Rand

Vx = rand() & NN

将VX设置为对随机数(通常为0到255)和NN进行按位操作的结果。

DXYN

Disp

draw(Vx, Vy, N)

在坐标(VX, VY)上绘制一个宽度为8像素、高度为N像素的精灵。从内存位置I开始,读取每一行8个像素作为位编码;I值在执行这条指令后不会改变。如上所述,如果任何屏幕像素在绘制精灵时从set翻转到unset, VF将被设置为1,如果没有发生这种情况,VF将被设置为0

EX9E

KeyOp

if (key() == Vx)

如果按下存储在VX中的键,则跳过下一条指令。(通常下一条指令是跳过代码块的跳转);

EXA1

KeyOp

if (key() != Vx)

如果没有按下存储在VX中的键,则跳过下一条指令。(通常下一条指令是跳过代码块的跳转);

FX07

Timer

Vx = get_delay()

将VX设置为延迟定时器的值。

FX0A

KeyOp

Vx = get_key()

等待按键,然后存储在VX中。(阻塞操作。所有指令暂停,直到下一个按键事件按下按键);

FX15

Timer

delay_timer(Vx)

将延迟定时器设置为VX。

FX18

Sound

sound_timer(Vx)

将声音计时器设置为VX。

FX1E

MEM

I += Vx

将VX添加到i, VF不受影响。

FX29

MEM

I = sprite_addr[Vx]

将I设置为VX中字符的精灵位置。字符0-F(十六进制)用4x5字体表示。

FX33

BCD

set_BCD(Vx)*(I+0) = BCD(3);*(I+1) = BCD(2);*(I+2) = BCD(1);

存储VX的二进制编码的十进制表示,地址为I的三位中最高有效的一位,中间的一位为I + 1,最低有效的一位为I + 2。(换句话说,取VX的十进制表示,将百位放在内存中I的位置,十位放在内存中I+1的位置,个位放在内存中I+2的位置。)

FX55

MEM

reg_dump(Vx, &I)

存储从V0到VX(包括VX)在内存中,从地址I开始。从I开始的偏移量为每写入一个值增加1,但I本身没有修改。

FX65

MEM

reg_load(Vx, &I)

从V0到VX(包括VX)填充内存中的值,从地址I开始。每写入一个值,从I开始的偏移量就增加1,但I本身没有被修改。

标签: #c语言迷宫堆栈 #c模拟器