GNURL78やLLVM-RL78でのover 64KB ROMのchecksumを計算するcodeを考えてみるスレッド

こんにちは。NoMaYです。

最近、以下のスレッドに関わったのですが、暫く時間が経った後で思い返してみると、farキーワードの起源の8086のマイクロソフトコンパイラでの仕様とか、CC-RL及びそれに準ずるLLVM-RL78での仕様とか、それらを鑑みると、投稿した以下のコードでの64KB境界を跨いだfarポインタのインクリメントやポインタ比較は素朴に期待したようには動かないのが本来の仕様である可能性が高い筈、と思い直しました。そこで、コードを考え直してみることにしました。

続く。

C言語からのアセンブラ関数呼び出しについて
community-ja.renesas.com/cafe_rene/forums-groups/beginners/f/002-2095199602/9532/c

上のスレッドに投稿した、素朴に期待したようには動かないのが本来の仕様である可能性が高い、そんなコード(現状はGNURL78でOKだが):

#include <stdint.h>
const uint16_t __far psum_rom = 0x1234; /* This variable is placed at the end of the ROM by linker script. */
uint16_t _RomSum(void);
uint16_t __attribute__((noinline, optimize("no-isolate-erroneous-paths-dereference"))) _RomSum(void)
{
    // FIXME: In case of using the immediate value in stead of `&psum_rom`, if other than -O0 is used,
    // the generated code has no ES register handling. It seems to be a bug of GNURL78 (ex. 4.9.2.202201).

    const uint16_t __far *prom, *sum_s, *sum_e;
    uint16_t sum = 0;

    sum_s = 0;
    sum_e = &psum_rom; // (const uint16_t __far *)0x017DFEUL; --> No ES register handling.
    for( prom = sum_s; prom < sum_e; prom++ )
    {
        sum += *prom;
    }
    return sum;
}

 

Parents
  • こんにちは。NoMaYです。

    すみません、また、ちょっと蛇足になるかな、とも思いますけれども、発端となったスレッドにも投稿していますが、以下のコードもGNURL78でコンパイルすると、ESレジスタを操作していないコード、というか別の観点から言えば、ESプレフィクス無しでアクセスするコード、を生成します。これも、やはり、GNURL78のバグのような気がします。

    GNURL78_far_pointer_issue_20220915.zip    [追記] 2022/09/16 追加しました(プロジェクトのファイル一式です)

    GNURL78での生成コードがおかしいソース:

    uint16_t _RomSum(void)
    {
        // FIXME: If one of -O2, -O3, -Os is used, the generated code calls `abort()` immediately.
        // FIXME: In case of using the immediate value in stead of `&psum_rom`, if other than -O0, -Og is
        // used, the generated code has no ES register handling. (Note: If one of -O2, -O3, -Os is used,
        // the generated code calls `abort()` immediately. Therefore `other than -O0, -Og` means only -O1.)

        const uint16_t __far *prom, *sum_s, *sum_e;
        uint16_t sum = 0;

        sum_s = 0;
        //sum_e = &psum_rom; // (const uint16_t __far *)0x017DFEUL; --> No ES register handling.
        sum_e = (const uint16_t __far *)0x017DFEUL;
        for( prom = sum_s; prom < sum_e; prom++ )
        {
            sum += *prom;
        }

        return sum;
    }

     
    そして、これも、前の投稿と同様な記述にすると(私が勝手に?)期待したようなコードが生成されるようでした。これも、前の投稿に書いたことですが、前の投稿で、それこそ闇雲にやっていたら運良く気付いた、という部類のことであって、C言語の文法からのロジカルな帰結では全く無いです。そういうタイプの対症療法に過ぎないのですけれども、、、

    GNURL78で期待したコードが生成されるソース: (発端となったスレッドと同じ__attribute__()の追加もしています)

    uint16_t __attribute__((noinline, optimize("no-isolate-erroneous-paths-dereference"))) _RomSum(void)
    {
        const uint16_t __far *prom, *sum_s, *sum_e;
        uint16_t sum = 0;

        sum_s = 0;
        sum_e = (const uint16_t __far *)0x017DFEUL;
        for( prom = sum_s; prom < sum_e; prom++ )
        {
            sum += *(volatile uint16_t __far *)prom; /* Using cast with `volatile` is just a `workaround` for GNURL78. */
        }

        return sum;
    }

     
    以下、リストファイル(最適化レベルは-O1)です。(発端となっだスレッドにも投稿していますが、上側のソースでソッコーでabort()を呼び出すコードが生成されてしまいますので、ここでは-Osではなく-O1としています。)

    上側のソース:
    ESレジスタを操作していないコード、および、ESプレフィクス無しでアクセスするコード、が生成される
    ⇒ GNURL78のバグなのでは?

                                        .section    .text._RomSum,"ax",@progbits
                                        .global __RomSum
                                    __RomSum:
                                        ; start of function
                                        ; push 2: r16
                                        ; uses ES register ← 実際はESレジスタを操作していない
     0000 61 EF                         sel rb2
     0002 C1                            push    ax ; r16
     0003 61 CF                         sel     rb0
     0005 C9 F4 00 00                   movw    r12, #0
     0009 C9 F6 00 00                   movw    r14, #0
     000d C9 F0 00 00                   movw    r8, #0
                                    .L2:
     0011 AD F4                         movw    ax, r12
     0013 BD F2                         movw    r10, ax
     0015 FA F2                         movw    hl, r10
     0017 AB                            movw    ax, [hl] ← ESプレフィクス無し
     0018 06 F0                         addw    ax, r8
     001a BD F0                         movw    r8, ax
     001c AD F4                         movw    ax, r12
     001e 04 02 00                      addw    ax, #2
     0021 BD F4                         movw    r12, ax
     0023 AD F6                         movw    ax, r14
     0025 61 D8                         sknc
     0027 A1                            incw    ax
     0028 BD F6                         movw    r14,ax
     002a AD F6                         movw    ax, r14
     002c 44 01 00                      cmpw    ax, #1
     002f AD F4                         movw    ax, r12
     0031 61 F8                         sknz
     0033 44 FE 7D                      cmpw    ax, #32254
     0036 61 E8                         skz
     0038 EC 11 00 00                   br      !!.L2
     003c 61 EF                         sel     rb2
     003e C0                            pop     ax ; r16
     003f 61 CF                         sel     rb0
     0041 D7                            ret

     
    下側のソース:
    ESレジスタを操作している、および、ESプレフィクスありでアクセスしている
    ⇒ OKそう


                                        .global __RomSum
                                    __RomSum:
                                        ; start of function
                                        ; push 4: r16 r18
                                        ; uses ES register
     0000 61 EF                         sel     rb2
     0002 C1                            push    ax ; r16
     0003 C3                            push    bc ; r18
     0004 61 CF                         sel     rb0
     0006 C9 F4 00 00                   movw    r12, #0
     000a C9 F6 00 00                   movw    r14, #0
     000e C9 F0 00 00                   movw    r8, #0
                                    .L2:
     0012 AD F4                         movw    ax, r12
     0014 BD E8                         movw    r16, ax
     0016 AD F6                         movw    ax, r14
     0018 60                            mov     a, x
     0019 9E FD                         mov     es, a
     001b FA E8                         movw    hl, r16
     001d 11 AB                         movw    ax, es:[hl]
     001f 06 F0                         addw    ax, r8
     0021 BD F0                         movw    r8, ax
     0023 AD F4                         movw    ax, r12
     0025 04 02 00                      addw    ax, #2
     0028 BD F4                         movw    r12, ax
     002a AD F6                         movw    ax, r14
     002c 61 D8                         sknc
     002e A1                            incw    ax
     002f BD F6                         movw    r14,ax
     0031 AD F6                         movw    ax, r14
     0033 44 01 00                      cmpw    ax, #1
     0036 AD F4                         movw    ax, r12
     0038 61 F8                         sknz
     003a 44 FE 7D                      cmpw    ax, #32254
     003d 61 E8                         skz
     003f EC 12 00 00                   br      !!.L2
     0043 61 EF                         sel     rb2
     0045 C2                            pop     bc ; r18
     0046 C0                            pop     ax ; r16
     0047 61 CF                         sel     rb0
     0049 D7                            ret

      

Reply
  • こんにちは。NoMaYです。

    すみません、また、ちょっと蛇足になるかな、とも思いますけれども、発端となったスレッドにも投稿していますが、以下のコードもGNURL78でコンパイルすると、ESレジスタを操作していないコード、というか別の観点から言えば、ESプレフィクス無しでアクセスするコード、を生成します。これも、やはり、GNURL78のバグのような気がします。

    GNURL78_far_pointer_issue_20220915.zip    [追記] 2022/09/16 追加しました(プロジェクトのファイル一式です)

    GNURL78での生成コードがおかしいソース:

    uint16_t _RomSum(void)
    {
        // FIXME: If one of -O2, -O3, -Os is used, the generated code calls `abort()` immediately.
        // FIXME: In case of using the immediate value in stead of `&psum_rom`, if other than -O0, -Og is
        // used, the generated code has no ES register handling. (Note: If one of -O2, -O3, -Os is used,
        // the generated code calls `abort()` immediately. Therefore `other than -O0, -Og` means only -O1.)

        const uint16_t __far *prom, *sum_s, *sum_e;
        uint16_t sum = 0;

        sum_s = 0;
        //sum_e = &psum_rom; // (const uint16_t __far *)0x017DFEUL; --> No ES register handling.
        sum_e = (const uint16_t __far *)0x017DFEUL;
        for( prom = sum_s; prom < sum_e; prom++ )
        {
            sum += *prom;
        }

        return sum;
    }

     
    そして、これも、前の投稿と同様な記述にすると(私が勝手に?)期待したようなコードが生成されるようでした。これも、前の投稿に書いたことですが、前の投稿で、それこそ闇雲にやっていたら運良く気付いた、という部類のことであって、C言語の文法からのロジカルな帰結では全く無いです。そういうタイプの対症療法に過ぎないのですけれども、、、

    GNURL78で期待したコードが生成されるソース: (発端となったスレッドと同じ__attribute__()の追加もしています)

    uint16_t __attribute__((noinline, optimize("no-isolate-erroneous-paths-dereference"))) _RomSum(void)
    {
        const uint16_t __far *prom, *sum_s, *sum_e;
        uint16_t sum = 0;

        sum_s = 0;
        sum_e = (const uint16_t __far *)0x017DFEUL;
        for( prom = sum_s; prom < sum_e; prom++ )
        {
            sum += *(volatile uint16_t __far *)prom; /* Using cast with `volatile` is just a `workaround` for GNURL78. */
        }

        return sum;
    }

     
    以下、リストファイル(最適化レベルは-O1)です。(発端となっだスレッドにも投稿していますが、上側のソースでソッコーでabort()を呼び出すコードが生成されてしまいますので、ここでは-Osではなく-O1としています。)

    上側のソース:
    ESレジスタを操作していないコード、および、ESプレフィクス無しでアクセスするコード、が生成される
    ⇒ GNURL78のバグなのでは?

                                        .section    .text._RomSum,"ax",@progbits
                                        .global __RomSum
                                    __RomSum:
                                        ; start of function
                                        ; push 2: r16
                                        ; uses ES register ← 実際はESレジスタを操作していない
     0000 61 EF                         sel rb2
     0002 C1                            push    ax ; r16
     0003 61 CF                         sel     rb0
     0005 C9 F4 00 00                   movw    r12, #0
     0009 C9 F6 00 00                   movw    r14, #0
     000d C9 F0 00 00                   movw    r8, #0
                                    .L2:
     0011 AD F4                         movw    ax, r12
     0013 BD F2                         movw    r10, ax
     0015 FA F2                         movw    hl, r10
     0017 AB                            movw    ax, [hl] ← ESプレフィクス無し
     0018 06 F0                         addw    ax, r8
     001a BD F0                         movw    r8, ax
     001c AD F4                         movw    ax, r12
     001e 04 02 00                      addw    ax, #2
     0021 BD F4                         movw    r12, ax
     0023 AD F6                         movw    ax, r14
     0025 61 D8                         sknc
     0027 A1                            incw    ax
     0028 BD F6                         movw    r14,ax
     002a AD F6                         movw    ax, r14
     002c 44 01 00                      cmpw    ax, #1
     002f AD F4                         movw    ax, r12
     0031 61 F8                         sknz
     0033 44 FE 7D                      cmpw    ax, #32254
     0036 61 E8                         skz
     0038 EC 11 00 00                   br      !!.L2
     003c 61 EF                         sel     rb2
     003e C0                            pop     ax ; r16
     003f 61 CF                         sel     rb0
     0041 D7                            ret

     
    下側のソース:
    ESレジスタを操作している、および、ESプレフィクスありでアクセスしている
    ⇒ OKそう


                                        .global __RomSum
                                    __RomSum:
                                        ; start of function
                                        ; push 4: r16 r18
                                        ; uses ES register
     0000 61 EF                         sel     rb2
     0002 C1                            push    ax ; r16
     0003 C3                            push    bc ; r18
     0004 61 CF                         sel     rb0
     0006 C9 F4 00 00                   movw    r12, #0
     000a C9 F6 00 00                   movw    r14, #0
     000e C9 F0 00 00                   movw    r8, #0
                                    .L2:
     0012 AD F4                         movw    ax, r12
     0014 BD E8                         movw    r16, ax
     0016 AD F6                         movw    ax, r14
     0018 60                            mov     a, x
     0019 9E FD                         mov     es, a
     001b FA E8                         movw    hl, r16
     001d 11 AB                         movw    ax, es:[hl]
     001f 06 F0                         addw    ax, r8
     0021 BD F0                         movw    r8, ax
     0023 AD F4                         movw    ax, r12
     0025 04 02 00                      addw    ax, #2
     0028 BD F4                         movw    r12, ax
     002a AD F6                         movw    ax, r14
     002c 61 D8                         sknc
     002e A1                            incw    ax
     002f BD F6                         movw    r14,ax
     0031 AD F6                         movw    ax, r14
     0033 44 01 00                      cmpw    ax, #1
     0036 AD F4                         movw    ax, r12
     0038 61 F8                         sknz
     003a 44 FE 7D                      cmpw    ax, #32254
     003d 61 E8                         skz
     003f EC 12 00 00                   br      !!.L2
     0043 61 EF                         sel     rb2
     0045 C2                            pop     bc ; r18
     0046 C0                            pop     ax ; r16
     0047 61 CF                         sel     rb0
     0049 D7                            ret

      

Children
No Data