ぐだぐだ低レベルプログラミング(184)x86(16bit)、シフト、ローテイト(86のね)

Joseph Halfmoon

前回は、MUL(掛け算)命令。今回はレジスタやメモリの中のビットをシフトしたりローテイトしたりする命令について調査。全8種類(実際は7種類)もあり。「フツーの」RISCはこの系統の命令種類をこれほどもってません。それにキャリーフラグが影響うけること多いなど動作もクセ強。御先祖の8ビットの血統を色濃く受け継いでおると。

※「ぐだぐだ低レベル プログラミング」投稿順indexはこちら

「16ビット命令」でも命令拡張されているx86

前回は掛け算というのは「何かと何か」を掛け算するのに、MUL命令のオペランドは1個しかない件でもありました。御先祖の8ビット機を彷彿とさせる暗黙のレジスタ指定で、デスティネーションのレジスタは固定されているためです。しかし、80386の命令セットを眺めているとIMUL命令には2オペランド形式、3オペランド形式があるじゃありませんか。そんなIMUL命令8086/8088にはねえ。つまり、

16ビット命令でも80386は8086/8088より命令増えてる

のであります。「拡張の様子」はこんな感じっす。

80386>80286>80186>8086/8088

本シリーズでは、まず8086/8088範囲の命令を一通り撫でた後で、それ以降のものどもが備えることになった命令を80386追加命令ということで一気に調べる予定です。

実は、今回とりあげるシフト、ローテイト命令群でもそのような命令種類の増強はなされてます。

シフト、ローテイト命令群

今回調べるシフト、ローテイト命令群は、以下の部分的なオペコードマップの0xD0~0xD3までの4バイトをファーストバイトに持つものです。x86ShiftRotateOpMap

ところが上の0xC0、0xC1に緑の背景の似たような命令の一群が存在します。ここが後から「追加された」命令どもです。8086/8088では、

    • シフト、ローテイトのビット数は1固定
    • シフト、ローテイトのビット数をCLレジスタで指定

の2種類しかなかったのですが、80386では、

    • シフト、ローテイトのビット数を即値指定

という形式(緑のところ)が追加されておるのです。ここはまた後で。

8086では上の方の2形式ですが、当然、シフト、ローテイトの対象は

    • レジスタ、バイトまたはワード
    • メモリ、バイトまたはワード

となります。しつこいですが、x86でのワードは16ビットです。メモリを対象とする場合、各種のアドレシングモードを活用でき、中にはディスプレースメント(オフセット・アドレス)をとるものもあるので、命令長がその分長くなる場合もあります。

この命令エンコードの例が以下に。

x86SHREncoding

 

 

上記はSHR(論理右シフト)命令です。最初の例はバイト幅のレジスタ1個を1ビット論理シフトする場合のエンコード。第2バイト(mod R/M)のrrrに入るのはバイトレジスタの番号です。2番目はワード幅のレジスタ対象ですが、CLレジスタで指定されるビット数論理シフトする場合のエンコードです。例によって紫色のファーストバイトのLSBがバイトかワードかの識別に使われてます。

一方、第3と第4はターゲットがメモリです。第3はバイト幅のメモリを指定するのにレジスタに加えて符号拡張する1バイトのディスプレースメントを用いてアドレスするもの。第4はワード幅のメモリを指定をするのに16ビットのディスプレースメントを用いるものです。ここには書いてないですが、ディスプレースメントが無いアドレシング・モードもありだと。

何度も書きますが、CISCっす。

ここで、シフト、ローテイトのどの種類を行うかは、赤色の3ビットに込められています。こんな感じ。x86SFTROTEncoding

ローテイトもシフトも左右の区別があるのでLとRの2種類に分かれるだけでなく、ローテイトはキャリー・フラグを回転に含めるものと含めないものがあり、シフトには算術と論理の区別ありで合計8種にわかれます。

なお、アセンブラに手慣れたおねいさんおにいさん方がよっくご存じのとおり、論理左シフトと算術左シフトは同じ操作になってしまうので、SALはカッコつきです。8086/8088ではSALもちゃんと動作するハズ。SHLと同じ動作だけれども。

これらの命令の動作はなかなか言葉にしずらいので図を描いてお茶を濁します。こんな感じだあ。x86SFTROTfuncs

上記は8ビット操作な雰囲気ですが、16ビットの場合もMSBとLSBをそのまま転用すれば同じです。矢印に示した方向に、1ビット・キメウチの命令は1ビット、CLレジスタでビット数指定の命令はレジスタ中の数値で指定されるビット数だけシフトまたはローテイトされます。

ここで多くの命令でCF(キャリーフラグ)が含まれていることにご注目ください。大昔の8ビット機などでは掛け算や割り算命令などなかったのでシフト命令を駆使し、筆算やるような感じで計算してました。その時にキャリーが大活躍したものです。過去回でも述べたように8086/8088は御先祖の8080とアセンブリ言語レベルで上位互換となるように設計されているので、御先祖が出来た操作は皆できるようになってます。

ダラダラ調べていたら、練習する時間が無くなってしまった。動作確認はまた次回ね。

ぐだぐだ低レベルプログラミング(183)x86(16bit)、MULのオペランドは1個?へ戻る

ぐだぐだ低レベルプログラミング(185)x86(16bit)、シフト、ローテイト練習(86)へ進む