こんにちは。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;}
こんにちは。NoMaYです。すみません、ちょっと蛇足になるかな、とも思いますけれども、以下のコードをGNURL78でコンパイルしたら、また、ESレジスタを操作していないコード、というか別の観点から言えば、ESプレフィクス無しでアクセスするコード、を生成しますね。これは、やはり、GNURL78のバグのような気がします。(細かいことを言えば、GNURL78での、uint32_tから__farポインタへのキャスト仕様が明記されていない(というより、私が探せていない?、ということ)ですので、「動作は不定である」と開発者さんから返事が返ってきたら、そこで話が終わってしまう部類のことですけれども。)GNURL78_far_pointer_issue_20220914.zip [追記] 2022/09/16 追加しました(プロジェクトのファイル一式です)GNURL78での生成コードがおかしいソース:
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;}
なお、あれこれ試行錯誤してみたところ、以下のようにすると(私が勝手に?)期待したようなコードが生成されるようでした。ただ、それこそ闇雲にやっていたら運良く気付いた、という部類のことであって、C言語の文法からのロジカルな帰結では全く無いです。そういうタイプの対症療法に過ぎないのですけれども、、、GNURL78で期待したコードが生成されるソース:
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 ) {#if defined(__GNUC__) && !defined(__llvm__) sum += *(volatile uint16_t __far *)prom; /* Using `volatile` is just a `workaround` for GNURL78. */#else sum += *(uint16_t __far *)prom;#endif } return sum;}
以下、リストファイル(最適化レベルは-Os)です。上側のソース: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 F0 00 00 movw r8, #0 0009 C9 F4 00 00 movw r12, #0 000d C9 F6 00 00 movw r14, #0 .L2: 0011 AD F4 movw ax, r12 0013 16 movw hl, ax 0014 AB movw ax, [hl] ← ESプレフィクス無し 0015 06 F0 addw ax, r8 0017 BD F0 movw r8, ax 0019 AD F4 movw ax, r12 001b 04 02 00 addw ax, #2 001e BD F4 movw r12, ax 0020 AD F6 movw ax, r14 0022 61 D8 sknc 0024 A1 incw ax 0025 BD F6 movw r14,ax 0027 AD F6 movw ax, r14 0029 44 01 00 cmpw ax, #1 002c AD F4 movw ax, r12 002e 61 F8 sknz 0030 44 FE 7D cmpw ax, #32254 0033 61 E8 skz 0035 EC 00 00 00 br !!.L2 0039 61 EF sel rb2 003b C0 pop ax ; r16 003c 61 CF sel rb0 003e D7 ret
下側のソース:ESレジスタを操作している、および、ESプレフィクスありでアクセスしている⇒ OKそう
.section .text._RomSum,"ax",@progbits .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 F0 00 00 movw r8, #0 000a C9 F4 00 00 movw r12, #0 000e C9 F6 00 00 movw r14, #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 00 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
[追記]ちなみに、先日の投稿でのGCC for Renesas RL78 4.9.2.202201のリリースノートの件の「1. ES is used without being initialized.」という項目の内容からインスピレーションを得て以下のコードも試しましたが、依然として同じく、ESレジスタを操作していないコード、および、ESプレフィクス無しでアクセスするコード、が生成されていました。(最適化レベルは-Osで試しました。余談ですが、それなりの強さの最適化が行われる最適化レベルですので、ソースの字面を少しぐらい弄っても(もっとも`字面`以上のものではありますけれども)コードが変化しないことはそれなりに良くあることですね。)GNURL78での生成コードがおかしい:
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 ) {#if defined(__GNUC__) && !defined(__llvm__) uint16_t __far *address = (uint16_t __far *)prom; sum += *address; /* NG! The generated code has neither `mov es,a` nor `movw ax,es:[hl]`. */#else sum += *(uint16_t __far *)prom;#endif } return sum;}