CPU命令の解説の最後はビット操作と論理演算(AND、OR、XOR)です。ビット操作は、とてもアセンブラーっぽいプログラミング技法です。1バイトあれば8つの情報を持てますし、使いこなせるとプログラムはとてもスマートになります。
ビット操作の命令
1 2 3 4 5 6 |
----+----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 7 8 9 |
----+----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に条件コードがセットされます。
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にした場合はオペランドに指定した数はシフト数そのものになります。例えば、SLL R1,8(R0)はSLL R1,8と同じで、この場合の数字の8は変位8と見なされシフト数として扱われます。0以外のレジスターを指定した場合は、そのレジスターにシフトする数を格納しておきます。同時に変位も指定すればその値もシフト数に加算されます。第1オペランド側レジスターの左端(ビット0)あるいは右端(ビット31)にあるビットはシフトの度にこぼれ落ちます。
1 2 3 4 5 6 7 8 |
----+----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 7 |
----+----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 8 9 10 11 12 13 |
----+----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形式、SI形式及びSS形式の命令です。
NR、NI、N、NC
いずれの命令も「AND」(論理積)を取ります。第1オペランドと第2オペランドで示す値の論理積が、第1オペランドで示すレジスターあるいは主記憶に格納されます。第2オペランドの内容は変更されません。
XR、XI、X、XC
いずれの命令も「eXclusive OR」(排他的論理和)を取ります。第1オペランドと第2オペランドで示す値の排他的論理和が、第1オペランドで示すレジスターあるいは主記憶に格納されます。第2オペランドの内容は変更されません。
論理演算命令は条件コードがセットされます。OR、AND及びXORとも同じです。
1 … 結果がゼロでない(0でないビットが少なくとも1つはある)
2 … 使用されない
3 … 使用されない
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
----+----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としての制御を行っています。