我要编程的Game Boy模拟器( Z80是万一有人CPU不熟悉它),而我在做我的研究,我发现有些事情我不那么肯定。
第一个是,C是编程语言选择这里。 这与其说是一个问题,但我想听听从今天的角度来看你的意见。 即使不推荐C ++。
我发现的第二件事是,每个人都在使用每一个操作码功能。 这似乎是合乎逻辑的,因为它只是一个函数调用,可能比具有“添加”指令一个功能优化,那么你一定要找出哪些寄存器被用在这里。 但是,今天是怎么必要的? 它说的是,我应该坚持还是应该相当重写我的模拟器,如果我发现另一种方式,这可能是更方便的只是不削减它(或多或少现代游戏机跳进我的脑海里现在)?
此外,它是一种士气低落写“该寄存器该寄存器加上”一遍又一遍的功能。 有没有办法在一个码映射或类似的东西自动执行?
第一个建议,你不应该使用嵌套switch语句,你应该宁愿使用函数指针数组,快得多 - >更好的仿真,以及更好的代码,嵌套switch-ES还可以得到一个有点乱,这里有一些链接,你可以了解更多有关这些阵列
http://www.newty.de/fpt/fpt.html
http://www.multigesture.net/wp-content/uploads/mirror/zenogais/FunctionPointers.htm
第二个建议,是的,你可以做到这一点在C#,Java和C ++,但既然你想让你的CPU周期的每一个位,所以你可以得到接近仿真越好 - 模拟目标架构的一个CPU周期与数最少的CPU周期curret架构和面向对象也不是那么好在这种情况下,从我听到/从人们阅读。 的事情之一就是性能,二是非常明显的,模拟的,因为你可能已经注意到了,非常复杂的任务,并在OOP包木窗它可以在脖子上不必要的痛苦。
我大多与WingsOfIcarus同意。 我写了几个模拟器已经所以这里是我的见解:
- 使用函数指针是一个好主意 (对速度和代码的清晰度)
OOP是没有问题的
是的,成员的呼叫都有点慢,但如果你小心它不会影响性能太多。 在另一方面,OOP仿真代码是更好的管理/阅读/理解。
使用指令数据库,而不是固定的指令译码。
我使用的包括所有指令的所有必要信息的单一文本文件。 仿真器初始化过程中对其进行解析(供稿函数指针和操作数的阵列......)。 在这种架构中是很容易纠正的指令集错误,而无需更改任何代码。
复杂指令集文档几乎都是错误的一些点。 最坏的情况是Z80(我从来没有看到一个100%无差错的指令集)。 因此,使用更多的指令集,对它们进行比较,并创建一个无差错集(如果可以的话)。
加入声音,视频,键盘和鼠标的仿真
这通常不是一个问题。 在Windows上使用waveout的 ,而不是DirectSound的 。 这是更稳定,速度更快(DSOUND的可用等待时间有时甚至> 400毫秒)。 随着waveout的我能够情人延迟20-80毫秒这是确定。
通过每秒仿真CPU的T循环应用极限速度
我使用的机器周期正确的时序是非常慢的,但让我正确地贯彻执行任何硬件外围仿真为(FDC,DMAC,声音芯片,...没有任何黑客)
应用加载/保存文件为仿真平台
例如,这是我的指令集(其被直接供给到CPU仿真的一部分:
opc T0 T1 MC1 MC2 MC3 MC4 MC5 MC6 MC7 mnemonic
B8 04 00 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 ... 0 CP A,B
B9 04 00 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 ... 0 CP A,C
BA 04 00 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 ... 0 CP A,D
BB 04 00 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 ... 0 CP A,E
BC 04 00 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 ... 0 CP A,H
BD 04 00 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 ... 0 CP A,L
BE 07 00 M1R 4 MRD 3 ... 0 ... 0 ... 0 ... 0 ... 0 CP A,(HL)
BF 04 00 M1R 4 ... 0 ... 0 ... 0 ... 0 ... 0 ... 0 CP A,A
C0 11 05 M1R 5 MRD 3 MRD 3 ... 0 ... 0 ... 0 ... 0 RET NZ
C1 10 00 M1R 4 MRD 3 MRD 3 ... 0 ... 0 ... 0 ... 0 POP BC
C2L2H2 10 10 M1R 4 MRD 3 MRD 3 ... 0 ... 0 ... 0 ... 0 JP NZ,U16
C3L1H1 10 00 M1R 4 MRD 3 MRD 3 ... 0 ... 0 ... 0 ... 0 JP U16
C4L2H2 17 10 M1R 4 MRD 3 MRD 4 MWR 3 MWR 3 ... 0 ... 0 CALL NZ,U16
C5 11 00 M1R 5 MWR 3 MWR 3 ... 0 ... 0 ... 0 ... 0 PUSH BC
C6U2 07 00 M1R 4 MRD 3 ... 0 ... 0 ... 0 ... 0 ... 0 ADD A,U8
C7 11 00 M1R 5 MWR 3 MWR 3 ... 0 ... 0 ... 0 ... 0 RST 00H
C8 11 05 M1R 5 MRD 3 MRD 3 ... 0 ... 0 ... 0 ... 0 RET Z
C9 10 00 M1R 4 MRD 3 MRD 3 ... 0 ... 0 ... 0 ... 0 RET
CAL2H2 10 10 M1R 4 MRD 3 MRD 3 ... 0 ... 0 ... 0 ... 0 JP Z,U16
opc: operation code [hex]
L1,H1,U1,S1 means first operand direct number or address
L2,H2,U2,S2 means second operand direct number or address
L3,H3,U3,S3 means third operand direct number or address
H,L ... U16 high and low byte
U ... U8 unsigned byte
S ... S8 signed byte
T0 normal instruction duration [T] always 2 decimal digits
T1 instruction duration if condition not met [T] always 2 decimal digits
MC1++ Machine cycle first is type,second is duration [T] always 1 decimal digit
... unused
M1R M1 cycle
MRD memory read
MWR memory write
IOR IO read
IOW IO write
NON no external operation (internal computation)
INT interrupt cycle
mnem instruction text (mnemonic)
-
opc
被用于地址指针数组 -
mnemonic
用于选择适当的函数的指针,和操作数输入 -
T0
和T1
是用于定时的指令(这是足够的粗糙仿真) -
MC1++
用于正确MC定时(实施正确的硬件仿真和争论定时)
这里是我的Zilog Z80A完整的指令与机器周期时序设置链接下载。 随意使用(只提我的昵称的地方)。 移植到这后,我终于能100%通过测试ZEXALL。 欲了解更多信息请参阅编写C或C图形Z80模拟器++ 。
这里是一个很酷的实现一些操作码为NES模拟器的工作:
http://bisqwit.iki.fi/jutut/kuvat/programming_examples/nesemu1/
下面是一个具有多一点解释,这是怎么回事伴随YouTube视频
http://www.youtube.com/watch?v=y71lli8MS8s
它使用C ++模板和一些额外的C ++ 11功能。 至于您是选择C ++或C是你的,但它不应该真正的问题一大堆。 如果你只是仿效GAMEBOY我怀疑,速度将是对现代处理器的问题,所以尽量只使用任何你舒服。