パスワードを忘れた? アカウント作成
15449860 journal
日記

kitune-sanの日記: 8086マイクロコードの読み方 6

日記 by kitune-san

2021/10/24 改めて読み返すと勘違いがいくつもあり、間違っている。とてもいいコメントをもらっており、消すのはもったいないので日記を残しておくが、日記の内容自体は参考にならないため注意。

------
8086のマイクロコードってどうなんているんだろうと思って調べていたら、メタルレイヤの画像から読み出している人がいてびっくり。
せっかくなのでマイクロコードを読めるように少しだけ調べてみた。
まだ少しだけしか読めていないけれど、自分の備忘録として残しておく。

読んでくれる人がいるかどうか微妙だが…もしも間違いなどを見つけたら忌憚なく教えてほしい。でも優しく教えてね。

理解するのに重要な資料はUS patent 4363091。ここに必要なこと全て書いてあると思う。
ただし、ここに書いてあることが8086/88と完全に一致していない可能性があることを考慮に入れておく必要がある。

前半はCPUのハードウェア的な説明と一部命令の説明が延々と続く。レジスタ、ALU、フラグの関係を理解していれば読む必要がないと思う。最終ページにあるFig.1〜3を必要に応じて参照する。
マイクロコードに関する詳細な記述は、27ページ目(PDFで15ページ目)のTABLE 7の上の「The microcode routines for〜」からである。

マイクロコードは21ビットで構成されている。この21ビットには前半10ビットと後半11ビットとで2種類の操作命令が格納できるようになっている。
ただし今回の説明では、実際のコードやビット配置については追求しない。自分もまだよくわかっていない。
なのでニーモニックから読み取ることを目標とする。

マイクロコードの構成は次のようになっている。
S/D: レジスタやALUとの転送操作を行う。
Typ/a/b/F: 転送以外の操作(ALU操作やアドレスジャンプ)を行う。
つまり、データ転送動作とALU操作(他、操作命令)を同時に行うことができる。

さて、ここまで来たところで実際にマイクロコードを読んでみよう。
読み取る内容はAAA/AAS命令のマイクロコード列である。

 AR  X 7 6 5 4 3 2 1 0 CR S    D      Typ  a    b     F
 ------------------------------------------------------
 AAA 0 0 0 1 1 X 1 1 1 0  A    tempaL  1   XI   tempa
 AAS                   1  ONES tempb   1
                       2  Σ    A       1   DEC  tempb F
                       3               0   XΦ   5
                       4               1   INC  tempb
                       5  X    tempb   0   NCY  7
                       6  Σ    X       4   none RNI
                       7               4   none RNI

うまく表示できないので、等幅のメモ帳に貼り付けるか、US patent 4363091の「TABLE 7」を見てほしい。
テーブルが使えないっぽい。

表のARは外部のROMから読み取られた(ARレジスタに格納された)命令とそのビット列を示している。このARレジスタの値を元にマイクロコードが記述されたアドレスをデコードする。
CRはマイクロコードを進めるたびにインクリメントされるレジスタの値を示している。ジャンプ先の指定などで使用する。結果として相対アドレスに近い感じになっている。

では、いってみよう。

まず最初の命令(CR=0)を読んでみる。S=A, D=tempalとあり、Aレジスタの内容をtempaの下位へコピーする。
次にa=XI, b=tmpaとある。これは、1stオペランドにtmpaを指定したXI操作をALUに指定する。これはType1の指示である。なお、Fig.1bより、ALUの第二オペランドはtempb固定であることがわかる。
(実は、資料の方ではb=temp2と記載があったのだが、temp2なぞここ以外見当たらなかった。リバースエンジニアされた方の資料にはtempaと書かれていたためこちらに差し替えた)

A->tempaL

tempa -> ALU(XI) -> Σ
tempb --/

注意する点として、ALUの操作指示は指示後次のコード読み取りに入ったとしても、別のALU操作指示(TYPE1指示)がくるまではその指示状態が維持されるということがある。これを頭に入れておかないと後のINC/DECで混乱する。

XI命令のALU動作は、Fig.2に示されている。AASの場合のマイナスはどこで指定されるのか記載がなく、実は私の中で疑問が残っているが、とりあえず今回は無視して読み進める。

2つめの命令(CR=1)へ進む。S=ONES, D=tempbとあり、ONESをtempbへコピーする。ONESというのは資料を見た感じでは6のようだ。つまりXI命令の第二オペランドはここで設定される。

ONES(6) -> tempb

tempa -> ALU(XI) -> Σ
tempb --/

3つめの命令(CR=2)へ進む。S=Σ, D=Aとある。これはALU(XI)の演算結果をAレジスタへ格納することを示している。
また、Fのフラグが立っていることが確認できる。これは、ALU(XI)の演算で生じたフラグ変化を記録することを示している。

tempa -> ALU(XI) -> Σ -> A
tempb --/       \-> Σ(F) -> flags

同時に、a=DEC, b=tempbの指示がある。これはtempbのデクリメントを指示する。これによりALUはXIからDECへ切り替わる。

tempb -> ALU(DEC) -> Σ

4つめの命令(CR=3)へ進む。a=XΦ, b=5とある。これはMレジスタの下位ビット---ARレジスタの3ビット目を検査し真であればCR=5まで移動させるというタイプ5の指示である。
3ビット目は一体何かというと、このビットによってAAA/AAS命令のどちらであるかを決定している。

ではまずAAAの場合(XΦの結果が偽であった場合)を考える。

5つめの命令(CR=4)では、a=INC, b=tempbが指定されている。これによりALUはDECからINCへ切り替わる。

tempb -> ALU(INC) -> Σ

6つめの命令(CR=5)では、S=X, D=tempbとある。これは、Xレジスタの内容をtempbの下位へコピーする。

X -> tempb
tempb -> ALU(INC) -> Σ

また同時にキャリーフラグの検査を行う。キャリーフラグは3つめの命令(CR=2)のときに格納したflagsで立つことがある。ざっくり条件を書くと、6を足した(AAAの場合)計算結果が9を超えた場合である。
キャリーフラグが立っていない場合はCR=7まで移動する。CR=7の命令はRNI(Run Next Instruction)となっておりマイクロコードの終了を示す。そうでなければ次の命令へ進む。

7つめの命令(CR=6)では、S=Σ, D=Xとある。これは、これはALU(INC)の演算結果をXレジスタへ格納することを示している。

tempb -> ALU(INC) -> Σ -> X

同時にRNI司令が入り、マイクロコードの実行を終了する。

次に、AASの場合(XΦの結果が真であった場合)を考える。

飛び先の6つめの命令(CR=5)では、S=X, D=tempbとある。これは、Xレジスタの内容をtempbの下位へコピーする。注目する点は、AAAと違いALCがDECの状態が継続していることである。

X -> tempb
tempb -> ALU(DEC) -> Σ

また同時にキャリーフラグの検査を行う。キャリーフラグは3つめの命令(CR=2)のときに格納したflagsで立つことがある。ざっくり条件を書くと、6を引いた(AASの場合)計算結果が9を超えた場合である。
キャリーフラグが立っていない場合はCR=7まで移動する。CR=7の命令はRNI(Run Next Instruction)となっておりマイクロコードの終了を示す。そうでなければ次の命令へ進む。

7つめの命令(CR=6)では、S=Σ, D=Xとある。これは、これはALU(DEC)の演算結果をXレジスタへ格納することを示している。

tempb -> ALU(DEC) -> Σ -> X

同時にRNI司令が入り、マイクロコードの実行を終了する。

以上がAAA/AAS命令のマイクロコードである。他の命令も読めそうな気がしてこない? 読める・・・読めるぞ・・・!

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • by Anonymous Coward on 2021年10月15日 1時11分 (#4132525)

    また同時にキャリーフラグの検査を行う。キャリーフラグは3つめの命令(CR=2)のときに格納したflagsで立つことがある。ざっくり条件を書くと、6を足した(AAAの場合)計算結果が9を超えた場合である。

    この理解は間違いです。キャリーが立つのは入力の下位ニブルが9より大きい時です。計算結果ではありません。インテルのマニュアルからだと

    IF ((AL AND 0FH) > 9) OR (AF ← 1)
    THEN
            AL ← AL + 6;
            AH ← AH + 1;
            AF ← 1;
            CF ← 1;
    ELSE
            AF ← 0;
            CF ← 0;
    FI;
    AL ← AL AND 0FH;

    キャリーを設定するのはCR=0の命令です。

    特許のページからですが、まず、この文書のAレジスタはAL、Xレジスタ82はAHに相当するようです。Xレジスタ82とXレジスタ108は全くの別物です。

    There are six types of microcode instructions in the present invention. Type 1 is an ALU conditioning instruction which sets up ALU 134, which is taken to include PSW 136, to perform a specified function. A type 0 microcode instruction is a short jump which provides for a conditional jump within the microcode burst or sequence. A type 4 instruction is a bookkeeping instruction. Other types include a type 6 memory cycle, type 5 jump cycle and type 6 long jump cycle with an address save.

    AAA/AASの例に出てくるのはタイプ0,1,4だけです。

    In the case of the ASCII addition adjust and subtract adjust, as shown in TABLE 7, the microcode burst consists of 8 microcode instructions. The first microcode instruction, moves the contents of A to the lower 8 bits of the 16 bit temporary register TMP A 138.


    0 A tmpaL 1 XI tmpa

    Aレジスタの内容をTMP Aレジスタの下位8ビットに転送します。

    The second half of the microcode instruction is an ALU conditioning command which preconditions ALU 134 to add without carry the contents of TMP A 138 and TMP B 142. The opcode symbolically represented by XI consists of bits 13 through 17, which five bits are loaded in opcode register 110 and decoded through ROM 132 to ALU 134.

    0番地の命令はTMP AとTMP Bレジスタのキャリーなし加算をALUにセットアップします。データが揃っていないので、設定するだけです。

    Bit 21 is a flag bit which indicates whether or not the PSW flags are to be updated. The ALU is preconditioned to test the contents of temporary register A to determine whether or not they exceed 9 or whether the auxiliary carry flag is set.

    TMP Aレジスタの下位4ビットを9と比較し、キャリーフラグをセットします。bit3 and (bit2 or bit1)ですみます。

    The precharged ALU bus 16 is set at the beginning of each clock cycle to a full complement of ones and is selectively pulled down by microcode instruction 1, by enabling appropriate pull down circuitry 160 diagrammatically shown in FIG. 2 to discharge selected lines of ALU bus 16 and to load a binary 6 into TMP B 142.


    1 ONES tmpb

    定数6をTMP Bレジスタに転送します。加算はキャリーがあって大変なのでALUを使います。

    A conventional comparator circuit 162 tests the contents of temporary register A to determine whether or not the contents is greater than 9. If so the output of comparator 162 is true and combined in OR gate 164 with the AUX-CARRY bit from PSW 136. The output of OR gate 164 enables adder 166 which then adds the contents of TMP A 138 and TMP B 142. The circuitry of FIG. 2 or its equivalent is included within ALU 134 and is enabled by the corresponding ALU opcode.

    比較器の出力にしたがってALUの動作を決めます。つまり下位ニブルが9より大きいか、補助キャリーが立っていれば6を足し(AASなら引き)ます。いずれの場合でも上位ニブルは0にします。PDFの終わりについてあるfig.2に、ADDERとTMP Bレジスタの間に[+/-]という箱がありますが、これで加算と減算を切り替えます。その下に0FhとANDして上位ニブルをクリアする回路も描いてあります。この

    • ご指摘ありがとうございます。
      キャリーの件は私の間違いです。
      続きをすぐに読みたかったのですが、仕事ですぐに読めませんので、
      後でにじっくり読ませていただきます。

      親コメント
    • by Anonymous Coward

      AAAとAASの+6と-6の切り替えはワイヤ一本でインプリシットにできるのに、インクリメントとデクリメントはマイクロコードで切り替えているのは不思議かもしれません。しかしAH←AH+1をマイクロコードで書くと

      0 X tmpa 1 ADD tmpa
      1 1 tmpb
      2 Σ X

      どのみち3命令必要な上、定数「1」の発生回路が余分に必要になります。定数はセレクタが爆発するので普通は定数ROMに格納されますが、それでも結構なリソース喰いです。

      一般に、A-B-CY = A+~B+!CYです。BとCYを反転させるだけで加算回路で減算できます。ビットの反転はOP=SUB信号とBの各データビットやCYをXO

      • > これで比較的ローコストに、少なくともセレクタを使うよりずっと簡潔にADD/SUBとINC/DECが統合されました。

        これを読んだときに気がついたのですが、特定(クロック速度の短い)のx86命令の各命令と先頭5ビットを並べると

        INC Register 01000
        DEC Register 01001

        ADC Reg/Memory and register to ether 00010
        SBB Reg/Memory and register to ether 00011

        ADD Reg/Memory and register to ether 00000
        SUB Reg/Memory and register to ether 00101

        このようになり、ADD/SUBはちょっと違いますが、前から(0から数えて)0ビット目から3ビット目までは共通で、4ビット目だけが異なっており、このビットで+-の操作を決めているように見えます。
        ALUへの操作命令は5ビット長で、一部の命令は直接ALUへ入力されているようですので、(その場合はマイクロコードでALU操作はせずにもう一方のALUへの入力だけをしているっぽい)

        これらのビット列が命令取り込み時に直接ALUへ入力されていると考えてみると、
        > ADD/SUBとINC/DECが統合
        というのは確かにそのとおりなのでしょう。

        もう少し考えると、とのビットがどういう操作に対応しているかわかるかもしれないです。

        親コメント
      • by Anonymous Coward

        > データ計算はBの全ビットにOP=SUBをxorすれば望みのものが得られます。ボロ―計算はBの全ビットにOP=SUB or OP=DECをxorしたものを使えばよいです。

        OP=SUBとOP=DECは決して両立しないので、orはロジックは不要で、加減算計算用B'=B xor (OP=SUB)*16とすると、キャリー・ボロ―計算用はB''=B' xor (OP=DEC)*16ですみます。

        > Aの全ビットにOP=ADD or OP=SUBをandすれば、容易に0を手に入れられます。

        オペランドが一つしかなく、相手が0である命令にNEGやNOTがありますが、こういった情報はマイクロコードから供給され、orのようなロジックは不要でし

    • by Anonymous Coward

      こういう記述がありました。

      The opcode will either be a unique ASCII adjustment for addition or subtraction to be performed upon the contents of the microcode b field, which field includes bits 18 through 20 in the case of an ALU instruction. Bit 21 is a flag bit which indicates whether or not the PSW flags are to be updated.

      Typは3ビット、aは4ビット、bは3ビット、Fは1ビットのようです。


      2 Σ A 1 DEC tmpb F

      TMP Aの下位ニブルと9との比較の結果をPSWに転送するのがこのサイクルのようです。命令によってアップデートされるフラグはばらばらですが、それはaフィールド(オペコード)が内包するようです。AAA/AASではCFとAFだけがアップデートされますが、それはオペコード(XI)からテーブルでも引いているのでしょう。

typodupeerror

私はプログラマです。1040 formに私の職業としてそう書いています -- Ken Thompson

読み込み中...