我正在开发一个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编译器中的错误吗?我也对旋转后使用和指令感兴趣。
使用最新的(3-2.93)版本的GBDK for source from sourceforge。
答案 0 :(得分:3)
这不是您的模拟器的错误 - 我测试过的其他模拟器也会为64
提供以下代码:
#include <stdio.h>
unsigned char one() { return 1; }
void main()
{
unsigned int r;
// Force compiler to generate multiplication by deferring the '1'
r = one() * 32;
printf("1 * 32 = %u", r);
}
此处位于BGB (版本1.5.1):
这是VBA-M (版本SVN1149):
至于为何包含and a,#0xE0
?这实际上很简单。它只是确保溢出不会弄乱价值。
首先,假设乘法实际上正常,1 * 32仍然等于32.(我只需要添加额外的RR A
)。
对于1 * 32,这看起来像这样:
Start ; A = 00000001 Carry = 0
RR A ; A = 00000000 Carry = 1
RR A ; A = 10000000 Carry = 0
RR A ; A = 01000000 Carry = 0
RR A ; A = 00100000 Carry = 0
AND A,0xE0 ; A = 00100000 Carry = 0
这里,AND没有效果。但是,假设我们乘以会导致溢出的东西,例如17 * 32:
Start ; A = 00010001 Carry = 0
RR A ; A = 00001000 Carry = 1
RR A ; A = 10000100 Carry = 0
RR A ; A = 01000010 Carry = 0
RR A ; A = 00100001 Carry = 1
AND A,0xE0 ; A = 00100000 Carry = 0
没有和,我们得到17 * 32 = 33,而不是1字节(32
)的正确答案。虽然这些答案都不是真正的答案(544),但32
是其第一个字节的正确值。
答案 1 :(得分:2)
我使用CPCtelera(包括SDCC 3.4.3)测试了它,结果似乎是正确的。我用了这段代码:
#include <stdio.h>
unsigned char one() { return 1; }
void main() {
unsigned char r;
r = one() * 32;
printf("1 * 32 = %d\n\r", r);
while (1);
}
这是生成的代码(只是代码的相关部分):
_main::
;src/main.c:28: r = one() * 32;
call _one
ld a,l
rrca
rrca
rrca
and a,#0xE0
我似乎很清楚你是对的,你所拥有的SDCC版本错误地使用了rr
而不是rrca
。
最后,这是WinAPE Amstrad CPC模拟器上程序的输出: