0x00 前言
CHIP-8最初是以虚拟机的形式被开发出来的,在早期个人电脑上被用于游戏开发。鉴于CHIP-8只有4Mb的内存,16个8-bits寄存器,一个16-bits地址寄存器,和35条操作码,制作一个CHIP-8模拟器非常适合初学者了解计算机的大致工作方式.
本文章使用python3来实现CHIP-8模拟器.
0x01 内存
CHIP-8有4096(0x1000)
个内存空间(就是4兆内存), 每一个位置都能存储一个字节, 也就是8-bits
(这就是CHIP-8名字的由来).
- 前512个字节
0x000 ~ 0x1ff
原本是用于存储CHIP-8解释器的, 现在通常用于存储字体 - 从
0x200
开始(包括0x200
)往后的空间被用于存储CHIP-8的游戏(ROM)
这里要注意的是CHIP-8的操作码是两个字节的, 所以把ROM写到内存时一个操作码是被存储在连续的两个内存单元上的, 然后在读取时连续读两个字节并拼接成一个操作码.
创建内存
#创建内存
self.Memory = []
for i in range(0, 4096):
self.Memory.append(0x0)
#创建字体并把它存储于0x000~0x050
fonts = [
0xF0, 0x90, 0x90, 0x90, 0xF0, # 0
0x20, 0x60, 0x20, 0x20, 0x70, # 1
0xF0, 0x10, 0xF0, 0x80, 0xF0, # 2
0xF0, 0x10, 0xF0, 0x10, 0xF0, # 3
0x90, 0x90, 0xF0, 0x10, 0x10, # 4
0xF0, 0x80, 0xF0, 0x10, 0xF0, # 5
0xF0, 0x80, 0xF0, 0x90, 0xF0, # 6
0xF0, 0x10, 0x20, 0x40, 0x40, # 7
0xF0, 0x90, 0xF0, 0x90, 0xF0, # 8
0xF0, 0x90, 0xF0, 0x10, 0xF0, # 9
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
]
for i in range(len(fonts)):
self.Memory[i] = fonts[i]
#创建一个程序指针用于指向当前操作码
self.ProgramCounter = 0x200
读取ROM并写入内存
#写入(这两个方法名字写错了)
def readProg(self, filename):
rom = self.convertProg(filename)
offset = int('0x200', 16)
for i in rom:
self.Memory[offset] = i
offset += 1
#读取
def convertProg(self, filename):
rom = []
with open(filename, 'rb') as f:
wholeProgram = f.read()
for i in wholeProgram:
byte = i
rom.append(byte)
运行
#从内存读取操作码并运行
def execution(self):
index = self.ProgramCounter
high = self.hexHandler(self.Memory[index])
low = self.hexHandler(self.Memory[index + 1])
opcode = high + low
self.execOpcode(opcode)
#补全操作码
def hexHandler(self, Num):
newHex = hex(Num)[2:]
if len(newHex) == 1:
newHex = '0' + newHex
return newHex
0x02 寄存器
CHIP-8有16个8-bits
寄存器和一个16-bits
地址寄存器.
- 16个寄存器被命名为V0~VF, 其中VF通常被当做是一个状态标志寄存器, 用于表示是否有进位或者用于碰撞检测
- 地址寄存器通常被用于指向某个图像的位置
当寄存器存储的数字大于它的存储空间时会舍弃掉高位, 记得实现这个机制
寄存器类
class Register:
def __init__(self, bits):
self.value = 0
self.bits = bits
#检查是否有进位
def checkCarry(self):
hexValue = hex(self.value)[2:]
if len(hexValue) > self.bits / 4:
self.value = int(hexValue[-int(self.bits / 4):], 16)
return 1
return 0
#检查是否小于0
def checkBorrow(self):
if self.value < 0:
self.value = abs(self.value)
return 0
return 1
def readValue(self):
return hex(self.value)
def setValue(self, value):
self.value = value
创建寄存器实例
self.Registers = []
for i in range(16):
self.Registers.append(Register(8))
self.IRegister = Register(16)
0x03 栈
这里栈是用于存储函数的返回地址
栈类
class Stack:
def __init__(self):
self.stack = []
def push(self, value):
self.stack.append(value)
def pop(self):
return self