6502和小尾数转换 [英] 6502 and little-endian conversion

查看:102
本文介绍了6502和小尾数转换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为了娱乐,我正在实现NES模拟器。我目前正在阅读有关6502 CPU的文档,感到有些困惑。

For fun I'm implementing an NES emulator. I'm currently reading through documentation for the 6502 CPU and I'm a little confused.

我看过文档说明,因为6502是低位优先的,因此在使用时绝对寻址模式需要交换字节。我是在x86机上编写的,这台机器也是低端的,所以我不明白为什么我不能简单地转换为uint16_t *,然后取消引用,然后让编译器确定细节。

I've seen documentation stating because the 6502 is little-endian so when using absolute addressing mode you need to swap the bytes. I'm writing this on an x86 machine which is also little-endian, so I don't understand why I couldn't simply cast to a uint16_t*, dereference that, and let the compiler work out the details.

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

I've written some simple tests in google test and they seem to agree with me.

// 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));
}

通过,因此看来我的假设是正确的,但我认为d问一个比我更有经验的人。

This passes, so it appears my supposition is correct, but I thought I'd ask someone with more experience than I.

在6502绝对寻址模式下提取操作数是否正确?我可能会丢失一些东西吗?

Is this correct for pulling out the operand in 6502 absolute addressing mode? Am I possibly missing something?

推荐答案

在小端系统上,它适用于简单的情况,但是将实现与这些感觉联系在一起当相应的可移植实现很简单时,则不需要。坚持使用宏,您可以改为执行以下操作:

It will work for simple cases on little-endian systems, but tying your implementation to those feels unnecessary when the corresponding portable implementation is simple. Sticking to the macro, you could do this instead:

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

(为方便起见,您还应确保 addr [1] 不能超出范围,如果 addr ,则需要添加更多括号。可能是一个复杂的表达式。)

(Just to be pedantic, you should also make sure that addr[1] can't be out-of-bounds, and would need to add some more parentheses if addr could be a complex expression.)

但是,随着您不断开发模拟器,您会发现使用一对通用的<$ c $是最自然的c> read_mem()和 write_mem()函数可对单个字节进行操作。请记住,地址空间被分成多个区域(PPU和APU中的RAM,ROM和内存映射寄存器),因此具有您索引到的单个数组将无法正常工作。映射器可以重新映射内存区域的事实也使事情变得复杂。 (不过,对于简单的游戏,您不必为此担心-我建议从Donkey Kong开始。)

However, as you keep developing your emulator, you will find that it's most natural to use a pair of general-purpose read_mem() and write_mem() functions that operate on single bytes. Remember that the address space is split up into multiple regions (RAM, ROM, and memory-mapped registers from the PPU and APU), so having e.g. a single array that you index into won't work well. The fact that memory regions can be remapped by mappers also complicates things. (You won't have to worry about that for simple games though -- I recommend starting with Donkey Kong.)

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

What you need to do is to figure out what region or memory-mapped register the address belongs to inside your read_mem() and write_mem() functions (this is called address decoding), and do the right thing for the address.

回到原始问题,您最终将使用 read_mem()仍然可以读取地址的各个字节,这意味着 uint16_t 铸造骗局的可能性更低。 。这是最简单,最可靠的方法处理极端情况,以及我所见过的每个模拟器在实践中(Nestopia,Nintendulator和FCEUX)的作用。

Returning to the original question, the fact that you'll end up using read_mem() to read the individual bytes of the address anyway means that the uint16_t casting trickery is even less likely to be useful. This is the simplest and most robust approach w.r.t. handling corner cases, and what every emulator I've seen does in practice (Nestopia, Nintendulator, and FCEUX).

如果您错过了它,请 #nesdev 频道非常活跃,而且是一个很好的资源。我认为您已经熟悉NESDev Wiki。 :)

In case you've missed it, the #nesdev channel on EFNet is very active and a good resource by the way. I assume you're already familiar with the NESDev wiki. :)

我也一直在开发一个模拟器,该模拟器可以在此处

I've also been working on an emulator which can be found here.

这篇关于6502和小尾数转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆