CPUが直接実行するCPU命令(機械命令)には、機能別に分類された数多くの様々な命令があります。ここでは、どのような処理を行うプログラムであっても外すことのできない最も基本となる命令について解説します。
レジスターとメモリー・アクセスに関する基本的な命令
1 2 3 4 5 6 7 8 9 10 |
----+----1----+----2----+----3----+----4----+----5----+----6----+----7-- LR r1,r2 レジスターのコピー LTR r1,r2 レジスターのコピーとテスト LA r1,d2(x2,b2) アドレス値のロード L r1,d2(x2,b2) レジスター←メモリー(フルワード) LM r1,r3,d2(b2) 複数レジスター←メモリー(フルワード) LH r1,d2(x2,b2) レジスター←メモリー(ハーフワード) ST r1,d2(x2,b2) レジスター→メモリー(フルワード) STM r1,r3,d2(b2) 複数レジスター→メモリー(フルワード) STH r1,d2(x2,b2) レジスター→メモリー(ハーフワード) |
LR、LTR
レジスター間でのデータのコピーです。r2で示されるレジスターに入っている内容がそのままr1で示されるレジスターにロードされます。r2で指定されたレジスターの内容は変わりません。LTRの場合は、ロードされる値の符号によって条件コード(値が0なのか正なのか負なのか)がセットされます。実際のプログラミングでは、同じレジスター番号を指定したLTR命令によってレジスター内の値がゼロか否かを判定することがよく行われます。
1 2 3 4 |
----+----1----+----2----+----3----+----4----+----5----+----6----+ LTR 15,15 FUNCTION SUCCEED ? BNZ ERROR NO, DO ERROR PROCESSING : |
LA
第2オペランドで示されるアドレスが計算されて、その値がr1で示されるレジスターにロードされます。アドレスの計算とは「b2で示されるレジスター内の値+x2で示されるレジスター内の値+d2で示される変位の値」です。命令の動きとしてはこういう解説になりますが、要は数値そのものをレジスターにセットする命令です。アドレスとなっていますが「アドレス」にこだわる必要はありません。0~x7FFFFFFF(またはx00FFFFFF)までの正の整数値がロードされるので、加算命令の代わりにもよく使われます。
※LA命令はアドレスモードによって動作が変わります。24ビット・モードではr1レジスターに格納される値の先頭バイト(ビット0~7)が、31ビット・モードではr1レジスターに格納される値の先頭ビット(ビット0)が0にクリアーされます。
1 2 3 4 5 |
----+----1----+----2----+----3----+----4----+----5----+----6----+ LA R1,AREA R1 = Address of 'AREA' LA R1,123 R1 = 123 LA R1,10(,R1) R1 = R1 + 10 : |
LとLH、STとSTH
LとLH命令は、第2オペランドで示される主記憶の内容をr1で示されるレジスターにロードします。Lはフルワード、LHはハーフワードです。LH命令ではレジスターの下位2バイトにロードされます。この時、読み込まれる値の先頭ビットは符号ビットと見なされ、0なら0が、1なら1がレジスターの上位2バイトにも設定されます。従って、32767(x7FFF)を超える値をLH命令で読み込むとレジスターはx00008000ではなくxFFFF8000となる事を知っておく必要があります。なお、32768(x8000)以上の値を符号無しハーフワードとしてレジスターにx00008000として読み込む場合にはLHではなくICM命令を利用します。
STとSTH命令は、r1で示されるレジスターの内容を第2オペランドで示される記憶域にストアーします。STH命令はLHと異なり、レジスターの下位2バイトの内容がそのまま2バイトでストアーされます。
1 2 3 4 |
----+----1----+----2----+----3----+----4----+----5----+----6----+ L R1,AREA R1 = Content of 'AREA' STH R1,HWAREA HWAREA = Low order 2bytes : of GR1 |
LM、STM
LMとSTM命令は、複数のレジスターと主記憶間でのロードとストアを行います。LM命令は、r1とr3で示される範囲の複数のレジスターに第2オペランドで指定される主記憶の内容がそれぞれロードされます。r1が5、r3が8ならば記憶域アドレス+0番地のフルワードがGR5へ、記憶域アドレス+4番地のフルワードがGR6へ、記憶域アドレス+8番地のフルワードがGR7へ、記憶域アドレス+12番地のフルワードがGR8へとロードされます。r3で示されるレジスター番号がr1で示されるレジスター番号より小さい場合、15から0へ循環して使用するレジスター範囲が決まります。例えば「14,12」とすれば、14,15,0,1,…,11,12番のレジスター(13以外の15個のレジスター)が操作の対象になります。STM命令は、LMとは逆に複数のレジスターの内容を記憶域にストアーします。
1 2 3 4 5 6 |
----+----1----+----2----+----3----+----4----+----5----+----6----+ STM R14,R12,12(R13) Save all GPRS to area points GR13 base address + 12 LM R2,R5,PLIST Load parameter address list into GR2,GR3,GR4,GR5 |
これらの他にも、加減乗除の四則演算、文字と文字列の操作、比較と分岐、ループ、サブルーチンの呼び出し、ビット操作と論理演算等の実務的な処理に欠かせない機能を果たす命令があります。それらの命令については記事を改めて解説します。
プログラム割込み
命令の使い方を誤るとCPUは割込みを起こします。これはプログラム割込みと呼ばれます。発生した内容に応じてコードが設定されていて、割込みによってOSに通知します。一般にプログラム割込み=バグと考えられていますが、正確にはそうではありません。
多くの割込みはプログラム・エラーではあるのですが、「仮想アドレスから対応する実記憶を参照しようとしたら、そこにページが無かった」というケースもあります。これは「ページ変換例外」という割込みで通知されます。MVSはこの割込みを受けると、本当にページが無いのか?実際はページ・アウトされているだけか?などを調べます。ページ・アウトされていれば、そのページを読み込めばいいのですからプログラムの実行をエラーにはしません。対応するページが本当に無い場合はアドレスが誤っているのですから、MVSによってプログラムはエラーにさせられます。このような時、MVSはCPUからの割込みコードをOSのシステム完了コードに変換してプログラムを異常終了させます。これが S0Cx または S0Dx というABENDです。xの部分はCPUの割込みコードに基本的に対応しますが例外もあります。我々は、通常のプログラムではCPUからの割込みコードを直接意識しませんので、ここではMVSのABENDコードで解説します。
コード | 理由 | 説明・備考 |
---|---|---|
S0C1 | 命令例外 | CPUに定義されていない命令を実行しようとした。誤ってデータ領域に飛んでってしまった場合や、アセンブル・エラーに気づかずに作ってしまったロードモジュールを実行した等が考えられる。 |
S0C2 | 特権命令例外 | 問題プログラム(一般のプログラム)が特権命令を実行しようとした。監視プログラム状態で呼び出さねばならないサブルーチンを誤って呼び出した、あるいは誤ってデータ領域にジャンプしたら、たまたまそこに特権命令と同じコードのデータがあった等が考えられる。 |
S0C3 | 実行例外 | EX命令で再度EX命令を実行しようとした。 |
S0C4 | 記憶保護例外 アクセス例外 |
誤った主記憶アドレスを参照しようとした、キーが異なる領域に書き込みをしようとした、リンクし忘れたサブルーチンを呼び出した(0番地へジャンプ)、等が考えられる。ABENDコードとしてはとてもポピュラーですが、規模が大きく複雑なプログラムでは原因がなかなかわからない、プログラマー泣かせのABENDでもあります。永久ループに入ろうとしたが、メモリーアドレスをずらしながらのループだったので、たまたま自分のプログラム領域の終わりで引っかかってABENDとなった、と言うのもありがちなケース。 |
S0C6 | 指定例外 | 命令やオペランドの指定方法に誤りがある。奇数番地にある命令を実行しようとした(間違って奇数番地にジャンプ)、奇数番号のレジスターで乗除算を行おうとした、等の原因がある。 |
S0C7 | データ例外 | 10進数演算命令等で符号や数値に誤りがある。本来数字でなければいけないデータに誤って文字(A~Zや空白、記号など)が含まれていることが原因で起きやすい。入力データの妥当性のチェックが甘いプログラムでよく起こす。 |
S0C9 | 除算例外 | 割り算の結果、商が大きすぎてレジスターに入らない、除数が0になっている。最も多いのが0で割ろうとするケース。 |