3

私は現在、ゲームボーイエミュレーターを開発しており、エミュレーターの正確性をテストするために、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 の Windows 用 GBDK の最新 (3-2.93) バージョンを使用します。

4

2 に答える 2

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)にあります:

BGB バージョン 1.5.1: 1 * 32 = 64

そして、これはVBA-M (バージョンSVN1149)にあります:

VBA-M バージョン SVN1149: 1 * 32 = 64


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

and がなければ、1 バイトの正解 ( 32) ではなく、17 * 32 = 33 になります。これらの答えはどちらも真の答えではありませんが (544)、32最初のバイトの正しい値です。

于 2015-05-13T16:08:43.527 に答える