RL78で16bit × 16bit = 32bit演算が狂う

CA78K0コンパイラで、16bit × 16bit = 32bit演算が狂う事象が発生しました。コード概略は、

U16 a=125; 
U16 b=430; 
U32 c;
 c = a * b;     // c=10になる

WindowsやAndroidアプリでは考えられない事象ですが、OS無しの16bitマイコンありがちな事象です。しかし、乗算結果の上位16bitが捨てられるありえそうですが、意味不明な演算結果です。試しにキャストを明示してもNGでした。

 c = (U32) ( a * b );     // これもNG

仕方がないので、アセンブラのコード展開をみてみました。

movw    ax,[hl+4]
movw    _@RTARG0,ax
movw    ax,[hl+8]
call    !@@iumul
clrw    bc
movw    [hl],ax
xchw    ax,bc
movw    [hl+2],ax

乗除算は、マイコンライブラリにまとめられているようです。16bit × 16bit = 32bitのmulhu命令が、なぜダイレクトに展開されないのでしょう? マイコンライブラリはあまり使わないようにしますが、元々使われていたら仕方ありません。でも怪しいのは、「clrw bc」のところです。明らかに16bit捨てられています。

キャストを明示した場合では、axレジスタの方がクリアされます。

movw    ax,[hl+4]
movw    _@RTARG0,ax
movw    ax,[hl+8]
call    !@@iumul
movw    _@RTARG0,ax
clrw    ax
movw    _@RTARG2,ax
movw    [hl+2],ax
movw    ax,_@RTARG0
movw    [hl],ax

マイコンライブラリを使用しないようにすると解消する気もしますが、全体的に、ロードモジュールに影響が生じます。正しい結果が得られるC言語の書き方を、TRY&ERRで探すしかいりません。

今回は、以下の書き方で直りました。

U16 a=125; 
U16 b=430; 
U32 c;
 c = a;      // 一旦32bit変数に入れる
 c *= b;     // c=53750になる

アセンブラ展開コードは、、、

movw    ax,[hl+4]
clrw    bc
xchw    ax,bc
movw    [hl+2],ax
movw    ax,[hl+8]
movw    _@RTARG4,ax
movw    _@RTARG6,#00H
movw    ax,[hl] 
movw    _@RTARG0,ax
movw    ax,[hl+2]
movw    _@RTARG2,ax
movw    ax,_@RTARG6
call    !@@lumul
movw    ax,_@RTARG2
movw    [hl+2],ax
movw    ax,_@RTARG0
movw    [hl],ax

clrw命令がなくなり、上下16bitがスタックに格納されていることが確認できました。だいぶコードが増えたのが気がかりです。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です