- 「メインフレーム・コンピューター」で遊ぼう - http://www.arteceed.net -

09.ビット操作と論理演算

CPU命令の解説の最後はビット操作と論理演算(AND,OR,XOR)です。ビット操作はとてもアセンブラーっぽいプログラミング技法です。1バイトあれば8つの情報を持てますし、使いこなせるとプログラムはとってもスマートになります。


ビット操作の命令

    ----+----1----+----2----+----3----+----4----+----5----+----6----+----7--
             TM    i1,d2(b2)           メモリー ← 1バイトのビットパターン
             SLL   r1,d2(b2)           レジスター ← 左シフト数
             SRL   r1,d2(b2)           レジスター ← 右シフト数
             SLDL   r1,d2(b2)          レジスター ← 左シフト数
             SRDL   r1,d2(b2)          レジスター ← 右シフト数
    

    TM(Test under Mask)

    第2オペランドで指定した主記憶の1バイトが、第1オペランドで指定されたビットパターン(マスクビット)でテストされます。マスク中のビットが0の場合、対応する主記憶側のビットはテストされません。マスクがx80であれば先頭ビットのON/OFFがテストされ、xFFであれば全てのビットのON/OFFがテストされます。主記憶の内容は変わりません。

      ----+----1----+----2----+----3----+----4----+----5----+----6----+
               TM    BYTE,X'F0'          HAVE ZONE BIT ?
               BNO    ...                NO,
      
               TM    WORD+3,X'01'        ODD ?
               BO    ...                 YES,
      
               TM    ENTADDR,X'80'       AMODE=31 ?
               BNO   ...                 NO,
      
      テストの結果、PSWに条件コードがセットされます。
      0 … 選択されたビットはすべて0、またはマスクビットが0
      1 … 選択されたビットは0と1が混在している
      2 … 使用されない
      3 … 選択されたビットはすべて1

    TM命令はOSの出口ルーチンなどシステム系プログラムを作る場合、比較的使用頻度の高い命令です。誤りやすいのはマスクビットの指定などTM命令自体ではなく、その後の分岐命令の条件指定です。複数のビットをテストする場合などに間違えやすいです。BNOとBZ、BOとBNZを混同しないように注意します。


    SLL,SRL(Shift Left|Right single Logical)

    第1オペランドで指定したレジスター内の各ビットが、第2オペランドで指定した数だけSLL命令では左へ、SRL命令では右にシフトされます。r2レジスターを0にした場合はオペランドに指定した数はシフト数そのものになります。0以外のレジスターを指定した場合は、そのレジスターにシフトする数を格納しておきます。同時に変位も指定すればその値もシフト数に加算されます。レジスターの左端(ビット0)あるいは右端(ビット31)にあるビットはシフトの度にこぼれ落ちます。

      ----+----1----+----2----+----3----+----4----+----5----+----6----+
               SLL   R0,8                DROP HIGH-ORDER BYTE
               SRL   R0,8
               :
               LA    R15,16              LOAD NUM OF SHIFT
               SLL   R14,0(15)           MAKE QSAM RDW(LENGTH+0000)
               :
               SLL   R0,3                GR0 = GR0 * 8 (2^3)
      

    シフト動作によって空いたビット位置には0がセットされます。条件コードはセットされません。
    SLL,SRLは論理シフト(レジスター内の全ビットが操作対象になる)動作です。符号ビットはずらされない算術シフト命令もあります。

    左へシフトすることは2のn乗を掛け算することと同じです。右へシフトすることは2のn乗で割り算することと同じです。乗除数が2のべき乗である時は乗除算命令の代わりにシフト命令を使うと計算が簡単です。


    SLDL,SRDL(Shift Left|Right Double Logical)

    第1オペランドでは乗除算命令同様に、偶数・奇数番号の対になったレジスターを指定します。それ以外はSLL/SRL命令と同じです。
    シフト動作は対になった2つのレジスターのすべてのビット(64ビット)について行われます。奇数番号レジスターの左端ビットは偶数番号レジスターの右端ビットに移ります。偶数番号レジスターの左端ビットと奇数番号レジスターの右端ビットはこぼれ落ちます。

      ----+----1----+----2----+----3----+----4----+----5----+----6----+
               SLR   R1,R1               CLEAR 'BIT BUCKET'
               SRDL  R0,1                SHIFT GR0 LOW ORDER BIT TO GR1
               LTR   R1,R1               ZERO ?
               BZ                        YES,
               :                         NO, ITS BIT ON.
               :
      

    S/370のシフト命令では、インテルCPUのようなキャリーフラグが使えません。シフトしてドロップしたビットが0か1かを調べるにはSLDL/SRDLで隣のレジスターにビットをこぼして、その値をテストするような事が行われます。


論理演算命令(And,Or,Exclusive Or)

    ----+----1----+----2----+----3----+----4----+----5----+----6----+----7--
             OR    r1,r2               レジスター←レジスター
             OI    d1(b1),i2           即値 → メモリー(バイト)
             O     r1,d2(x2,b2)        レジスター←メモリー(フルワード)
             OC    d1(l,b1),d2(b2)     メモリー ← メモリー(バイト)
             NR    r1,r2               レジスター←レジスター
             NI    d1(b1),i2           即値 → メモリー(バイト)
             N     r1,d2(x2,b2)        レジスター←メモリー(フルワード)
             NC    d1(l,b1),d2(b2)     メモリー ← メモリー(バイト)
             XR    r1,r2               レジスター←レジスター
             XI    d1(b1),i2           即値 → メモリー(バイト)
             X     r1,d2(x2,b2)        レジスター←メモリー(フルワード)
             XC    d1(l,b1),d2(b2)     メモリー ← メモリー(バイト)
    

    OR,OI,O,OC

    いずれの命令も「OR」(論理和)を取ります。第1オペランドと第2オペランドで示す値の論理和が、第1オペランドで示すレジスターあるいは主記憶に格納されます。第2オペランドの内容は変更されません。命令の構文はすでに出てきた同形式の命令と同じです。ORはAR,SRと、OIはMVIと、OCはMVCの各命令と同じ構文を持ちます。RR形式、RX形式、SI形式、SS形式と、すでに何回も出てきていますからもうわかりますね。


    NR,NI,N,NC

    いずれの命令も「AND」(論理積)を取ります。第1オペランドと第2オペランドで示す値の論理積が、第1オペランドで示すレジスターあるいは主記憶に格納されます。第2オペランドの内容は変更されません。


    XR,XI,X,XC

    いずれの命令も「eXclusive OR」(排他的論理和)を取ります。第1オペランドと第2オペランドで示す値の排他的論理和が、第1オペランドで示すレジスターあるいは主記憶に格納されます。第2オペランドの内容は変更されません。

      論理演算命令は条件コードがセットされます。OR、ANDおよびXORとも同じです。
      0 … 結果がゼロ(すべてのビットが0になった)
      1 … 結果がゼロでない(0でないビットが少なくとも1つはある)
      2 … 使用されない
      3 … 使用されない
      ----+----1----+----2----+----3----+----4----+----5----+----6----+
               OI    ADDR,X'80'          MAKE IT AMODE=31
               NI    ADDR,255-X'80'      MAKE IT AMODE=24
               :
               OI    FLAG,VALID          INDICATES PARARMETER VALIDATED
               NI    FLAG,255-ERROR      CLEAR ERROR INDICATOR
               :
               NC    ADDR,ADDR           NULL ENTRY ?
               XR    R1,R1               CLEAR GR1
               :
               XC    DATA1,DATA2         SWAP DATA1 AND DATA2
               XC    DATA2,DATA1          I
               XC    DATA1,DATA2          V
               :
      ADDR     DC    A(0)                ENTRY ADDRESS
      FLAG     DC    XL1'00'             CONTROL FLAGS
      PARM     EQU   X'80'                PROVIDED PARAMETER
      VALID    EQU   X'40'                VALIDATED PARAMETER
      DO1ST    EQU   X'20'                DONE 1ST TIME PROCEDURE
      ERROR    EQU   X'10'                FOUND ANY ERRORS
      DATA1    DC    CL80' '             DATA-1
      DATA2    DC    CL80' '             DATA-2
      

    サンプルのように1バイトの領域に異なる意味を持つビットを割り当てて、そのON/OFFの状態でプログラムの実行を制御する手法は、システムプログラムでは非常によく使われます。それぞれのビットはフラグと呼ばれ、YES/NOのスイッチの意味を持たせます。フラグビットを格納する領域がフラグバイトです。2ビット使って4種類の意味を持たせることもあります。1バイトのフラグバイトには8つのフラグビットを持てますから、YES/NOかの情報なら8種類持てるわけです。必要ならフラグバイトを延ばし、2バイトで16種類、3バイトで24種類と拡張できます。フラグビットを1にするにはOR、0にするにはAND、反転ならXOR命令が使えます。OI、NI命令によるフラグ操作がポピュラーです。ORはそのままフラグビットを指定すればいいので簡単ですが、ANDはサンプルのように255から引き算した結果で行うことを知っておいて下さい。フラグビット値をそのまま指定すると、他のビットをすべて落としてしまいます。
    MVS自身もこのようなフラグを多用してOSとしての制御を行っています。