前回はファーポインタをレジスタ組にロードするLESとLDSでした。今回は符合拡張を行うCBWとCWDです。8086らしいなと思うのは、この命令、明示的なオペランドをとりません。レジスタはキメウチ、アキュムレータのみです。この辺のレジスタの使い方に偏りがあるのが御先祖に8ビットを頂くx86らしさかと。
※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら
※実機動作確認(といってもエミュレータなんだけれども)には以下を使用させていただいております。
CBWとCWD
どちらも整数の符号拡張命令です。
-
- CBWは、ALレジスタのバイト(8ビット)の符号付整数値を符号拡張してAXレジスタのワード(x86では16ビット)とする(AHレジスタを符号で埋める)
- CWDは、AXレジスタのワード(16ビット)の符号付整数値を符号拡張してDX:AXレジスタレジスタのダブルワード(x86では32ビット)とする。なお符号拡張結果の32ビット幅の値の上位16ビット(符号ビットを繰り返し並べたもの)がDXに格納される。下位16ビットを保持するAXはそのまま。
AX(その下位8ビットがAL)がアキュムレータとして一身にお役目を担っております。そしてDXがアキュムレータAXの上位となるのもお約束。
今回実験のプログラム
強力なx86用アセンブラNASM用のソースです。CBW、CWDともに入力値は元のビット幅の正の最大値と、負の最小値の2通りを通してます。また「書き替えられる」レジスタ、CBWではAH、CWDではDXに、書き替えられたことが明確になるように0x55または0x5555を入れてあります。
segment code ..start: mov ax, data0 mov ds, ax mov es, ax mov ax, stack mov ss, ax mov sp, stacktop test: mov ax, 0x557F cbw mov ax, 0x5580 cbw mov dx, 0x5555 mov ax, 0x7FFF cwd mov dx, 0x5555 mov ax, 0x8000 cwd fin: mov ax, 0x4c00 int 0x21 resb 2048 segment data0 align=16 resb 1024 * 63 segment stack class=STACK align=16 resb 2048 stacktop: dw 1024 dup (0) stackend:
アセンブルして実行
MS-DOS互換で機能強化されてるフリーなFreeDOS上、以下のステップで上記のアセンブラソースcbwcwd.asm から実行可能なオブジェクトファイルを生成して実行することができます(nasmとwatcom Cがインストール済であること。)
nasm -f obj -l cbwcwd.lst cbwcwd.asm wlink name cbwcwd.exe format dos file cbwcwd.obj debug cbwcwd.exe
以下は、対象のオブジェクトコードをデバッガで逆アセンブルしたものです。
以下の最初のケースは、バイト幅からの符号拡張。赤枠がバイト型の符号付整数の最大値127(0x7F)をワード型に符号拡張するもの。緑枠がバイト型の符号付整数の最小値-128(0x80)をワード型に符号拡張するもの。
お次は、ワード幅からのの符号拡張。赤枠がワード型の符号付整数の最大値32767(0x7FFF)をダーブルワード型に符号拡張するもの。
最後は、ワード幅からのの符号拡張。赤枠がワード型の符号付整数の最小値ー32768(0x8000)をダーブルワード型に符号拡張するもの。
符号拡張できましたな。ここでもアキュムレータ大活躍だったな、8086。