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がスタックに格納されていることが確認できました。だいぶコードが増えたのが気がかりです。