【发布时间】:2015-03-30 10:16:33
【问题描述】:
我目前正在开发一个 gameboy 模拟器,为了测试我的模拟器的正确性,我正在使用 GBDK 为我的模拟器编译 c 程序。
我注意到编译器(如预期的那样)通过旋转优化了具有 2 次幂的常量的乘法。但是,对于给定的功率,它似乎不会产生正确的旋转量。
例如下面这个非常简单的程序:
#include <gb/gb.h>
unsigned char one() { return 1; }
void main()
{
unsigned char r;
// Force compiler to generate muliplication by deferring the '1'
r = one() * 32;
// Store result somewhere
*((unsigned char*)(0xFFFE)) = r;
}
生成以下程序集:
___main_start:
_main:
push bc
; reproduce.c 14
; genCall
call _one
ld c,e
; genLeftShift
ld a,c
rr a
rr a
rr a
and a,#0xE0
ld c,a
; reproduce.c 16
; genAssign
ld de,#0xFFFE
; genAssign (pointer)
ld a,c
ld (de),a
; genLabel
00101$:
; genEndFunction
pop bc
ret
___main_end:
.area _CODE
这对我来说似乎是不正确的,因为 RR 指令实际上是通过进位标志旋转的,实际上是 9 位循环。这意味着应该有一个额外的旋转来产生正确的结果,而不是当前 (0x40) 的错误结果。
可视化:
Start: A = 00000001 Carry = 0
RR A: A = 00000000 Carry = 1
RR A: A = 10000000 Carry = 0
RR A: A = 01000000 Carry = 0 <- WRONG!
谁能验证这确实是GBDK附带的SDCC编译器中的一个错误?我也对旋转后的 and 指令的使用感兴趣。
使用来自 sourceforge 的最新 (3-2.93) 版本的 GBDK for windows。
【问题讨论】:
-
GBDK自带的SDCC版本好像是2.2.1,差不多15年了。 SDCC 的最新稳定版本是 3.4.0,它是从 2014 年 4 月开始的。如果您更新 SDCC 版本,您会得到相同的生成代码吗?
-
我认为GBDK自带的SDCC是一个fork,经过修改可以产生gb兼容的z80代码(至少sdcc的源代码包含在gbdk源码中)。但是,是的,GBDK 是古老的,但我认为像这样常见的东西会起作用。
-
可能SDCC主项目当时没有GB-Z80支持。但我相信现在确实如此。我同意这似乎是一种常见的情况。 OTOH,SDCC 显然没有像 e.g. 那样多的开发人员资源。 GCC 或 LLVM。过去我在 SDCC 的 Z80 编译器中遇到过奇怪的错误,例如必须将
memcpy替换为循环才能使副本正常工作。 -
啊,我明白了!稍后我将尝试使用最新的 sdcc。谢谢!
-
刚刚尝试了最新的 SDCC,效果非常好!将尝试重新编译 GBDK 库,此时我可以完全放弃 GBDK。
标签: assembly emulation z80 gameboy gbdk