我正在尝试学习仿真编程。我做了一个 CHIP-8 模拟器,不到 40 条指令,因为我的音乐而生活。我现在希望做一些更复杂的事情,比如 SNES。我遇到的问题是 CPU 指令的绝对数量。翻翻wiki.SuperFamicom.org 65c816指令列表,感觉后背很痛。我在各种互联网页面上到处都看到了 CPU 是模拟器中最容易实现的部分。
假设我做错了所以很难,我环顾四周,发现了一个简单的实现:SNES Emulator in 15 minutes,大约有 900 行代码。很容易完成。
于是,从SNES Emulator in 15 minutes Source 中,我找到了 CPU 指令所在的位置。它看起来比我想象的要简单得多。我不太了解它,但它是几行代码,而不是大量代码。我注意到的第一件事是每个指令只有一个暗示。如果您查看SuperFamicom中的表格,您会发现它有
ADC #const
ADC (_db_),X
ADC (_db_,X)
ADC addr
ADC long
...
并且(我认为)所有这些的模拟器来源是:
// Note: op 0x100 means "NMI", 0x101 means "Reset", 0x102 means "IRQ". They are implemented in terms of "BRK".
// User is responsible for ensuring that WB() will not store into memory while Reset is being processed.
unsigned addr=0, d=0, t=0xFF, c=0, sb=0, pbits = op<0x100 ? 0x30 : 0x20;
// Define the opcode decoding matrix, which decides which micro-operations constitute
// any particular opcode. (Note: The PLA of 6502 works on a slightly different principle.)
const unsigned o8 = op / 32, o8m = 1u << (op%32);
// Fetch op'th item from a bitstring encoded in a data-specific variant of base64,
// where each character transmits 8 bits of information rather than 6.
// This peculiar encoding was chosen to reduce the source code size.
// Enum temporaries are used in order to ensure compile-time evaluation.
#define t(w8,w7,w6,w5,w4,w3,w2,w1,w0) if( \
(o8<1?w0##u : o8<2?w1##u : o8<3?w2##u : o8<4?w3##u : \
o8<5?w4##u : o8<6?w5##u : o8<7?w6##u : o8<8?w7##u : w8##u) & o8m)
t(0,0xAAAAAAAA,0x00000000,0x00000000,0x00000000,0xAAAAA2AA,0x00000000,0x00000000,0x00000000) { c = t; t += A + P.C; P.V = (c^t) & (A^t) & 0x80; P.C = t & 0x100; }
简而言之,我的一般问题:
- 将 CPU 指令的惊人宇宙能力浓缩成一小段代码
15 分钟内特定于 SNES 模拟器的问题源(上面发布的部分):
- 如何
t(0, 0xAAAAAAAA, 0x00000000, ....)
解析指令?我看到了if
声明,但我不知道任何参数的数字来自哪里,或者它们对整个代码意味着什么。 - 为什么
o8 = op / 32
和o8m = 1u << (op%32)
? ADC
具有ADC #const
2 字节操作数或3ADC addr
字节操作数的操作码。代码t(0, 0xAAAAAAAA, ...)
暗示了这两种情况?
当我问:
dp
,_dp_
和sr
that 出现在ADC dp
,ADC (_dp_)
和是什么ADC sr,S
意思?ADC (_dp_,X)
和有什么区别ADC dp,X
?(考虑到上述问题,可能是多余的。)