我主要同意 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 仿真器。