
前回はpartialでexactな「剰余算」でした。今回もメンドクセー命令がつづきます。packed な BCD 整数のロード、ストア命令っす。BCD=Binary-coded decimalデス。8087FPUには「フツーの」整数とは別にBCD数を扱うための命令あり。計算できる桁数は10進18桁です。なんで18桁?
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。
8087のpacked Decimal
8087系FPUは、メモリ上にフツーの(2の補数)整数を置いておいてそれを取り扱えます。それに加えてパックされたBCD整数のサポートもあります。そのフォーマットが以下に。
80ビット幅(内部テンポラリ実数型と同じ)を使い、上記のようにMSBに符号ビットを置き、LSB側の72ビットに10進各桁4ビットx18桁を格納するフォーマットです。ビット78から72は使用してません。
いわゆるパックドデシマル(4ビットのニブルに十進数1桁づつを格納し、上下のニブルで1バイトに合計2桁を格納)です。十進なので0~9のみ格納し、0xAから0xFまでは使いませぬ。
この18桁のBCD整数は以下の命令によりFPUのレジスタ・スタックとやりとりされます
-
- FBLD、パックドBCD整数をメモリからレジスタへロード
- FBSTP、レジスタの内容をパックドBCD整数形式でメモリにストア
レジスタ・スタック上での演算は、整数も浮動小数もないので、過去回でやってきた命令どもは何でもアリです(当然、エラーになるやつはエラーになる。)
さて、18桁という仕様について、どこかで「COBOLの標準が18桁だったから18桁になった」という記述を読んだ記憶があります。元より忘却力の老人、その真偽を知らず。そこで例によってGoogleの生成AI、Gemini 2.5 Flash様にその経緯をお聞きしてみましたぞ。
上記のように、Gemini様は、今に至るコンピュータの歴史の中で燦然と輝くIBM System/360 を「推し」てます。たしかに「360」のお名前を見るだけで、お惚け老人などひれ伏してしまうのですが、土下座しながらもホントか?と疑問。なぜなら、
-
- IBM System/360は1964年発表、製品が出回ったのは翌年くらいかららしい
- COBOLは1959年開発、翌1960年から規格書が出回ったらしい
そうでした、System/360はマイクロコードマシンだったみたいです。CISC中のCISCね。それに比べたら「ロード・ストア」っぽいところのある8087など腰が引けてるCISCだと。別にレジスタ使わずともいいじゃん。
今回実験のプログラム
今回は以下のような処理を行ってみます。
-
- 2つのBCD数をFBLD命令でメモリからレジスタスタックにロードする
- ロードした数2個をレジスタスタック上の加算する(通常のFADD命令)
- 加算結果をFBSTP命令でレジスタスタックからメモリにストアする
そしてメモリ上で計算結果が確認できればOKっと。
なお以下は「強力なx86用アセンブラNASM」用のソースです(MSのMASMともインテルASM86とも微妙に異なるけど、まあ分かるっしょ。)
%use fp segment code ..start: mov ax, data mov ds, ax mov ax, stack mov ss, ax mov sp, stacktop test: mov si, src1 mov di, src2 mov bx, dst1 fbld tword [si] fbld tword [di] fadd fbstp tword [bx] nop fin: mov ax, 0x4c00 int 0x21 resb 2048 segment data align=16 resb 1024 * 63 src1: dt 12_345_678_901_245_678p src2: dt -00_000_000_001_245_678p dst1: dt 0p segment stack class=STACK align=16 resb 2048 stacktop: dw 1024 dup (0) stackend:
アセンブルして実行
MS-DOS互換で機能強化されているフリーなFreeDOS上、以下のステップで上記のアセンブラソース fbld.asm から実行可能なオブジェクトファイルを生成して実行することができます(nasmとwatcom Cがインストール済であること。)
なお、FreeDOS付属の「debugx」デバッガは、8087のレジスタ内容を浮動小数で見せてくれます
nasm -f obj -l fbld.lst fbld.asm wlink name fbld.exe format dos file fbld.obj debugx fbld.exe
SIが指しているのが赤枠、DIが指しているのが緑枠です。後でストアされる領域が黄枠。なお、8086/8087はリトル・エンディアンです。先頭バイトの0x78が、アセンブラの以下のところの末尾の78ね。
src1: dt 12_345_678_901_245_678p
レジスタスタック上の緑枠のマイナスの値と赤枠の値を加算したら、黄枠の結果が得られることが分かるよね。
そしてFBSTP命令でスタックトップの値をメモリにストアしたところが以下に
歴史的経緯は別にして、18桁のパックドBCD数の計算は今も健在。大丈夫か?