スパイス  組み込み制御装置の受注製作

モニタプログラムを移植する
平成26年4月 11日

最適化の悪影響
 モニタプログラムの細かな変更をしてROMを書き換えた所、動かなくなってしまいました。同時に何箇所かを変更してしまったのと、その間にほかの作業が入ったために何処を変更したのか記憶に頼る結果となってしまい、少し手間取りました。結果、原因はコンパイラの最適化が悪さしていました。当初は最適化を無効にしていたのを、他のパラメータを変更したときに一緒に最適化するように変更したようです。
直接の原因はCプログラムの中にアセンブラで書いた部分の前提が最適化によって変更されています。
元のプログラムを示します。 
(平26年4月12日追記)
 問題になる関数はinp(), outp()の二つの関数ですが、ここではoutp()関数のみを示します。変更するときは両方の関数を変更する必要があります。
(追記ここまで)
 void outp(uint addr, uchar data)
{
//引数は右側の引数から順にスタックに積まれる。
//一番左側の引数のアドレスは(sp+2)になる(スタックフレームなしの場合)
#asm
ld IY, 0
add IY,SP
ld c,(IY+2)
ld b,(IY+3)
ld a,(IY+4)
out (c),a
#endasm
}
 コメントに書いてあるように、この記述では関数がスタックフレームを使用しないことを前提に関数の引数へアクセスしています。スタックフレームを使用する場合は、(IX+4)のアドレスが一番左の引数アドレスになります。最適化しないときにはスタックフレームは使用されていなかったので、上記のように書いたのですが最適化を有効にするとスタックフレームが使用されてしまいます。どのような基準でスタックフレームの要否を決めているのかは不明です。
 こちらが最適化無効の時のリスト出力です。
                       0165 ;   addr -> offset 4    unsigned int   
                       0166 ;   value -> offset 6    char   
                       0167 %%LINE    000036   
                       0168 %%FUNC    outp,3,cls=2,type=0   
                       0169 _outp:   
                       0170 %%DFP     2   
                       0171 %%SYM     addr,14,type=6,cls=6,val=4,size=2   
                       0172 %%SYM     data,14,type=2,cls=6,val=6,size=1   
                       0173 %%ENDD       
                       0174 %%BF        
00000000 00000017 FD210000      0175    ld IY, 0   
        0000001B FD39      0176    add IY,SP   
        0000001D FD4E02      0177    ld c,(IY+2)   
        00000020 FD4603      0178    ld b,(IY+3)   
        00000023 FD7E04      0179    ld a,(IY+4)   
        00000026 ED79      0180    out (c),a   
                       0181 %%LINE    000047   
                       0182 %%EF        
        00000028 C9      0183    ret   
                       0184 %%FEND       
 次は最適化を有効にしたときのリスト出力です。青色で示す部分が追加されています。この追加部分がスタックフレームです。
                       0163 ;   addr -> offset 4    unsigned int   
                       0164 ;   value -> offset 6    char   
                       0165 %%LINE    000036   
                       0166 %%FUNC    outp,3,cls=2,type=0   
                       0167 _outp:   
00000000 00000012 CD0000    E 0168    call   cssent0  
                       0169 %%DFP     2   
                       0170 %%SYM     addr,14,type=6,cls=6,val=4,size=2   
                       0171 %%SYM     data,14,type=2,cls=6,val=6,size=1   
                       0172 %%ENDD       
                       0173 %%BF        
                       0174 %%LINE    000047   
00000000 00000015 FD210000      0175    ld IY, 0   
        00000019 FD39      0176    add IY,SP   
        0000001B FD4E02      0177    ld c,(IY+2)   
        0000001E FD4603      0178    ld b,(IY+3)   
        00000021 FD7E04      0179    ld a,(IY+4)   
        00000024 ED79      0180    out (c),a   
                       0181 %%EF        
        00000026 DDF9      0182    ld   SP,IX  
        00000028 DDE1      0183    pop   IX  
        0000002A C9      0184    ret   
                       0185 %%FEND       
 次は最適化を有効にしたときのリスト出力です。6行目に”call cssent0”が追加されています。この追加部分がスタックフレームです。
                   0163 ;   addr -> offset 4    unsigned int   
                       0164 ;   value -> offset 6    char   
                       0165 %%LINE    000036   
                       0166 %%FUNC    outp,3,cls=2,type=0   
                       0167 _outp:   
00000000 00000012 CD0000    E 0168    call   cssent0  
                       0169 %%DFP     2   
                       0170 %%SYM     addr,14,type=6,cls=6,val=4,size=2   
                       0171 %%SYM     data,14,type=2,cls=6,val=6,size=1   
                       0172 %%ENDD       
                       0173 %%BF        
                       0174 %%LINE    000047   
00000000 00000015 FD210000      0175    ld IY, 0   
        00000019 FD39      0176    add IY,SP   
        0000001B FD4E02      0177    ld c,(IY+2)   
        0000001E FD4603      0178    ld b,(IY+3)   
        00000021 FD7E04      0179    ld a,(IY+4)   
        00000024 ED79      0180    out (c),a   
                       0181 %%EF        
        00000026 DDF9      0182    ld   SP,IX  
        00000028 DDE1      0183    pop   IX  
        0000002A C9      0184    ret   
                       0185 %%FEND       
このコンパイラにはオプションとして”スタックフレームを強制的に生成させる”というチェックボックスもあるので、これにチェックを入れる手もあるのですが、時間がたった後で今度は最適化を禁止して同じような状況にはまりかねないので止めにします。この手の小さな処理ならアセンブラで書いても知れています。ソースファイルが一つ増えますが別ファイルにしておきます。プログラムは以下になります。
  misc.xasのリスト
   global _inp, _outp
C_inp   SECT    CODE
_inp:
       ld IY, 0
       add IY,SP
       ld c,(IY+2)
       ld b,(IY+3)
       in a,(c)
       ld c,a          ;8ビットの返り値はCレジスタで返す
       ret     
_outp:
       ld IY, 0
       add IY,SP
       ld c,(IY+2)
       ld b,(IY+3)
       ld a,(IY+4)
       out (c),a
       ret
;
       END
ページ先頭へ 前へ 次へ ページ末尾へ