我正在构建一个x86模拟器,我使用this online x86 sandbox来检查我的工作。在我的模拟器中,运行以下代码:
mov AX, 0xFFFF
add AX, AX
...将AX设置为0xFFFE,并将溢出标志设置为0。
在沙箱中,相同的代码将溢出标志设置为1。这对我来说没有意义,因为我读过的OF的每个定义都解释,如果1)源操作数和目标操作数具有相同的符号,且2)结果的符号!=源操作数/目标操作数的符号,则设置溢出标志。
这里,我们将0 b1111 1111 1111 1111与0 b1111 1111 1111相加。结果为0 b1111 1111 1111 1110。源、目标和结果的符号位均为1。我们是否将其解释为0xFFFF + 0xFFFF = 0xFFFE(隐式为0x 1FFFE),或者-1 + -1 = -2,则符号不变。
这个沙盒实现有错吗?如果没有,你能帮助我理解我错过了什么吗?
2条答案
按热度按时间sg3maiej1#
你说得对。沙盒错了。
我在尝试之前就预料到了这一点,因为逻辑上(-1 + -1 = -2)没有发生有符号溢出。
qzlgjiam2#
模拟器是错误的,源代码显示了一个完全错误的实现,只是用与CF相同的条件设置OF。这些标志是分开的,这是有原因的!而且,每当CF被设置时,它们就设置SF,即使16位结果的最高位是零。
它是开源的,https://github.com/YJDoc2/8086-Emulator-Web是8086模拟器库的前端,由编写前端的同一个人用Rust编写(编译为wasm)。
有一个开源的模拟器可以单步调试,有一个很好的GUI,这是很好的,但是如果他们把这个最基本的东西弄错了,谁知道还会有什么其他的bug呢?我不会相信它,也不会推荐给任何人使用,直到它通过了一些压力测试,尝试检查许多输入值的每条指令的所有结果。我听说过各种8位ISA的这样的测试,我想8086号有。
我看了一下他们的8086-Emulator库,幸运的是在第一个看起来像
src/lib/instructions/arithmetic.rs
的文件中找到了add
的仿真代码。代码根据相同的条件设置CF和OF:将输入零扩展到32位,然后检查是否大于0xffff的无符号值,这对于进位输出应该有效,但它无法检测
0x7fff + anything
中的有符号溢出,以及像您这样将两个小负数相加时的假阳性。Rust有很多方法可以得到正确的结果,比如
(a as i16).wrapping_add(b as i16) == a as i16 as i32 + b as i16 as i32
,或者任何其他方法,在加法得到真值之前,将两边符号扩展到32位,然后与 Package 的16位加法比较,或者将真值截断回16位。或者
(a as i16).checked_add(b)
,并检查结果不是None
或(a as i16).overflowing_add(b)
,以获得单独的i16
和bool
输出(https://doc.rust-lang.org/std/primitive.i16.html#method.overflowing_add)。另请参见http://teaching.idallen.com/dat2343/10f/notes/040_overflow.txt re:了解结转的更多方式(无符号溢出)与有符号溢出的比较。对于加法,只有当两个输入具有相同的符号,而结果具有相反的符号时,才可能发生有符号溢出。或者,对于加法和减法始终有效的一种简单方法是对输入进行符号扩展,并执行更广泛的运算,并检查整个结果可在不改变值的情况下缩窄回8或16位(例如,
res as i16 as i32
以从16位重新进行符号扩展,以获得32位值来与整个结果进行比较)。SF条件也是错误的。他们会在
0x8000 + 0x8000
上设置SF,这会回零,因为他们在比较0x10000u >= 0x8000u
。他们只需要测试该位,比如(res >> 15) & 1
,而不是任何可能有进位输出的高位。他们使用更广泛的算法的技巧确实使他们很容易实现
adc
,即使是正确的(我认为)进位标志处理,但同样错误的OF处理。(只使用与
adc
相同宽度的运算来模拟adc
是相当困难的,因为a+b < a
的无符号进位公式不适用于a+b + CF < a
;把0xFFFFu + 1u加到某个东西上和加0是一样的,如果你使用的是16位加法,那么你必须分别检查每一步加法。除非你有更高的位来保存进位。或者你有语言或硬件支持,Rust在新的API中用carrying_add(self, rhs: i16, carry: bool) -> (i16, bool)
暴露了这个问题,而这个API仍然只在夜间构建中使用。对于i64
来说,这个问题将完全解决。)