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です。

    ところで、RL78向けのもうひとつのコンパイラであるIAR社のコンパイラには__near/__farに加えて__hugeがありますので、64KB境界を跨いだポインタ操作が必要な場合は素朴に__hugeを使えば事足りることになっています。

    他方、__hugeの無いCC-RL(やLLVM-RL78)で64KB境界を跨いだポインタ操作が必要な場合はどうするかというと、前の投稿の関連リンクにURLを書いたスレッドで行われていたように、CC-RLの以下のキャスト仕様に基づき、uint32_tを__farポインタへ随時キャストしながら行うのが常套手段かと思うのです。

    tool-support.renesas.com/autoupdate/support/onlinehelp/ja-JP/csp/V8.08.00/CS+.chm/Compiler-CCRL.chm/Output/ccrl04c0206y0003.html

    - 変数からポインタへの変換

    signed char sc;
    signed short ss;
    signed long sl;

    unsigned char uc;
    unsigned short us;
    unsigned long ul;

    void func3(){

            (char __near*)uc;       //0x00, uc
            (char __near*)sc;       //(0x00 or 0xff), sc

            (char __far*)uc;        //nn, 0x00, 0x00, uc
            (char __far*)us;        //nn, 0x00, us(1), us(0)
            (char __far*)ul;        //nn, ul(2), ul(1), ul(0)
            (char __far*)sc;        //nn, (0x0000 or 0xffff), sc
            (char __far*)ss;        //nn, (0x00 or 0xff), ss(1), ss(0)
            (char __far*)sl;        //nn, sl(2), sl(1), sl(0)

            (__far FT*)uc;          //nn, 0x00, 0x00, uc
            (__far FT*)us;          //nn, 0x00, us(1), us(0)
            (__far FT*)ul;          //nn, ul(2), ul(1), ul(0)

            (__far FT*)sc;          //nn, (0x0000 or 0xffff), sc
            (__far FT*)ss;          //nn, (0x00 or 0xff), ss(1), ss(0)
            (__far FT*)sl;          //nn, sl(2), sl(1), sl(0)
    }



    ですので、CC-RL(やLLVM-RL78)で64KB境界(64KB,128KB,192KB,等)を跨ぐチェックサムのコードは以下のようにするのが常套手段かと思うのです。(16ビット単位で加算する例です。)

    uint16_t _RomSum(void)
    {
        uint32_t prom, sum_s, sum_e;
        uint16_t sum = 0;

        sum_s = 0;
        sum_e = 0x017DFEUL;
        for( prom = sum_s; prom < sum_e; prom += 2 )
        {
            sum += *(uint16_t __far *)prom;
        }

        return sum;
    }

     
    続く。

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

    ところで、RL78向けのもうひとつのコンパイラであるIAR社のコンパイラには__near/__farに加えて__hugeがありますので、64KB境界を跨いだポインタ操作が必要な場合は素朴に__hugeを使えば事足りることになっています。

    他方、__hugeの無いCC-RL(やLLVM-RL78)で64KB境界を跨いだポインタ操作が必要な場合はどうするかというと、前の投稿の関連リンクにURLを書いたスレッドで行われていたように、CC-RLの以下のキャスト仕様に基づき、uint32_tを__farポインタへ随時キャストしながら行うのが常套手段かと思うのです。

    tool-support.renesas.com/autoupdate/support/onlinehelp/ja-JP/csp/V8.08.00/CS+.chm/Compiler-CCRL.chm/Output/ccrl04c0206y0003.html

    - 変数からポインタへの変換

    signed char sc;
    signed short ss;
    signed long sl;

    unsigned char uc;
    unsigned short us;
    unsigned long ul;

    void func3(){

            (char __near*)uc;       //0x00, uc
            (char __near*)sc;       //(0x00 or 0xff), sc

            (char __far*)uc;        //nn, 0x00, 0x00, uc
            (char __far*)us;        //nn, 0x00, us(1), us(0)
            (char __far*)ul;        //nn, ul(2), ul(1), ul(0)
            (char __far*)sc;        //nn, (0x0000 or 0xffff), sc
            (char __far*)ss;        //nn, (0x00 or 0xff), ss(1), ss(0)
            (char __far*)sl;        //nn, sl(2), sl(1), sl(0)

            (__far FT*)uc;          //nn, 0x00, 0x00, uc
            (__far FT*)us;          //nn, 0x00, us(1), us(0)
            (__far FT*)ul;          //nn, ul(2), ul(1), ul(0)

            (__far FT*)sc;          //nn, (0x0000 or 0xffff), sc
            (__far FT*)ss;          //nn, (0x00 or 0xff), ss(1), ss(0)
            (__far FT*)sl;          //nn, sl(2), sl(1), sl(0)
    }



    ですので、CC-RL(やLLVM-RL78)で64KB境界(64KB,128KB,192KB,等)を跨ぐチェックサムのコードは以下のようにするのが常套手段かと思うのです。(16ビット単位で加算する例です。)

    uint16_t _RomSum(void)
    {
        uint32_t prom, sum_s, sum_e;
        uint16_t sum = 0;

        sum_s = 0;
        sum_e = 0x017DFEUL;
        for( prom = sum_s; prom < sum_e; prom += 2 )
        {
            sum += *(uint16_t __far *)prom;
        }

        return sum;
    }

     
    続く。

Children
No Data