6502和little-endian转换

时间:2015-04-26 05:47:14

标签: emulation 6502

为了好玩,我实现了NES模拟器。我目前正在阅读6502 CPU的文档,我有点困惑。

我已经看到文档说明因为6502是little-endian所以当使用绝对寻址模式时你需要交换字节。我在x86机器上写这个也是小端的,所以我不明白为什么我不能简单地转换为uint16_t *,取消引用,并让编译器解决问题的信息。

我在谷歌测试中写了一些简单的测试,他们似乎同意我的观点。

// implementation of READ16
#define READ16(addr) (*(uint16_t*)addr)

TEST(MemMacro, READ16) {
  uint8_t arr[] = {0xFF,0xCC};
  uint8_t *mem = (&arr[0]);

  EXPECT_EQ(0xCCFF, READ16(mem));
}

这个过去了,所以看来我的假设是正确的,但我想我会问一个比我更有经验的人。

在6502绝对寻址模式下拔出操作数是否正确?我可能错过了什么吗?

1 个答案:

答案 0 :(得分:4)

它适用于little-endian系统上的简单情况,但是当相应的便携式实现很简单时,将实现绑定到那些感觉是不必要的。坚持使用宏,你可以这样做:

#define READ16(addr) (addr[0] + (addr[1] << 8))

(只是为了迂腐,你还应该确保addr[1]不能超出范围,并且如果addr可能是一个复杂的话,还需要添加一些括号表达。)

但是,随着您不断开发模拟器,您会发现使用一对通用read_mem()write_mem()函数操作单个字节是最自然的。请记住,地址空间被分成多个区域(来自PPU和APU的RAM,ROM和存储器映射的寄存器),所以例如,您索引的单个数组无法正常工作。内存区域可以由映射器重新映射的事实也使事情复杂化。 (你不会为简单的游戏而担心 - 我建议从Donkey Kong开始。)

您需要做的是弄清楚read_mem()write_mem()函数中地址属于哪个区域或内存映射寄存器(这称为地址解码 ),并为地址做正确的事。

回到最初的问题,你最终会使用read_mem()来读取地址的各个字节这一事实意味着uint16_t施法技巧更不可能成为有用。这是最简单,最强大的方法w.r.t.处理角落案件,以及我在实践中看到的每个模拟器(Nestopia,Nintendulator和FCEUX)。

如果您错过了它,那么EFNet上的 #nesdev 频道非常活跃并且顺便说一下它是一个很好的资源。我假设您已经熟悉NESDev wiki。 :)

我也在使用可以找到here的模拟器。