4

我正在尝试学习仿真编程。我做了一个 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 / 32o8m = 1u << (op%32)
  • ADC具有ADC #const2 字节操作数或3ADC addr字节操作数的操作码。代码t(0, 0xAAAAAAAA, ...)暗示了这两种情况?

当我问:

  • dp,_dp_srthat 出现在ADC dp,ADC (_dp_)和是什么ADC sr,S意思?
  • ADC (_dp_,X)和有什么区别ADC dp,X?(考虑到上述问题,可能是多余的。)
4

1 回答 1

4

我不能回答所有这些,但dp代表 Direct Page,这意味着指令采用单字节操作数,它是 Direct Page 中的内存地址。直接页寻址是 6502 零页寻址模式的扩展,其中单字节地址$00通过$FF. 6502 的 16 位衍生产品有一个配置寄存器,它基本上将零页重新定位到另一个位置。f

在您链接到的 wiki 页面dp中,表中的一些带有下划线,而其他的则为斜体。我假设它们都是斜体的,并且 wiki 标记不起作用。快速检查编辑链接支持这一假设(在 wiki 源代码中,它们都有下划线)。所以不要读任何东西。

在 6502 汇编和它的派生中,ADC dp,X意思是……让我们举一个具体的例子……ADC $10,X意思是添加$10到寄存器中的值X以获得地址,然后从该地址加载一个值并将其添加到累加器中。ADC ($10,X)添加一个额外的间接级别:add $10toX获取地址,从该地址加载一个值,将加载的值解释为另一个地址,然后从地址加载值并将其添加到累加器。带括号的操作数总是添加一个间接级别。

请注意,可用的模式包括(dp,X)(dp),Y,括号相对于逗号和寄存器的位置很重要。将(dp),Y的值Y添加到第一个加载的值以获取要在第二个加载中使用的地址。

至于那个模拟器……代码高尔夫不会提高可读性!我不认为您发布的部分本身实际上是可以理解的,我不想追踪和阅读其余部分。但是t宏中的关键概念是bitstring。它的参数是一系列 9 个位掩码,每个位长 32 位,总共 288 位。因此,每个可能的操作码(其中 256 个)加上第一个注释中提到的 3 个伪操作码,都由这个 288 位长的位串中的一个位表示,剩下 29 位。

这就解释了o8和的构造o8m。8 位值分为 3 位部分(从提供给 的 8 个参数中选择一个参数t)和一个 5 位部分(从所选参数中选择一个位)。大?:链做第一次选择和组合,&1 << ...选择选择。

然后,哦,看我们也有一个变量t。它与宏无关。给他们取同一个名字简直太残忍了。

也许我可以弄清楚那个位串在做什么。当操作码为低数字时,o8(高位)将为 0,因此?:链将使用w0,这是宏的最后一个参数。随着操作码的增加,所选参数通过参数列表向左移动到w1, 然后w2... 并且o8m选择器同样从右侧开始并向左移动(& (1<<0)是最右边的位,& (1<<1)是下一位,等等),if条件将是当所选位为 1 时为真。值为:

0,          # opcodes $100 and up
0xAAAAAAAA, # opcodes $E0 to $FF
0x00000000, # opcodes $C0 to $DF
0x00000000, # opcodes $A0 to $BF
0x00000000, # opcodes $80 to $9F
0xAAAAA2AA, # opcodes $60 to $7F
0x00000000, # opcodes $40 to $5F
0x00000000, # opcodes $20 to $3F
0x00000000  # opcodes $00 to $1F

或二进制

0,                                  # opcodes $100 and up
0b10101010101010101010101010101010, # opcodes $E0 to $FF
0b00000000000000000000000000000000, # opcodes $C0 to $DF
0b00000000000000000000000000000000, # opcodes $A0 to $BF
0b00000000000000000000000000000000, # opcodes $80 to $9F
0x10101010101010101010001010101010, # opcodes $60 to $7F
0b00000000000000000000000000000000, # opcodes $40 to $5F
0b00000000000000000000000000000000, # opcodes $20 to $3F
0b00000000000000000000000000000000  # opcodes $00 to $1F

从右到左读取每一行,1 位于与这些操作码相对应的位置:$61 $63 $65 $67 $69 $6D $6F $71 $73 $75 $77 $79 $7B $7D $7F $E1 $E3 $E5 $E7 $E9 $EB $ED $EF $F1 $F3 $F5 $F7 $F9 $FB $FD $FF

嗯......这有点像ADCSBC操作码的列表,但其中一些是错误的。

哦(我终于放弃了,又看了一些模拟器代码)那是NES模拟器,不是SNES模拟器,所以它只有 6502 个操作码。

于 2013-06-22T23:34:46.203 回答