caslⅡプログラミングのような場合、定数 0...
TRANSCRIPT
Copyright 守屋悦朗 2004
CASLⅡプログラミング
1.プログラムの書き方 ラベル欄、命令コード欄、オペランド欄それぞれの先頭を揃える必要は必ずしもない(欄
と欄の間に空白が1つ以上あるだけでよい)が、揃えた方が分かりやすい。注釈は、「;」
で始まりさえすれば、どこに書いてもよい。 (例)
EXMPL START BEGIN ; EXMPLはこのプログラムの入口アドレスとなる
; (他のルーティンから参照できる)
; BEGINが実行開始番地となる
BEGIN LD GR1,A ; GR1に(A)をロードする
LD GR2,A ; GR2にも(A)をロードする
SUBA GR1,B ; GR1から(B)を減算する
; 演算の結果、(GR1)=(A)-(B)となる
JPL DONE ; (A)>(B)なら DONEへジャンプする。(GR2)=(A)
LD GR2,B ; (A)≦(B)のとき、(GR2)に(B)をロードする
DONE ST GR2,MAX ; (A),(B)の大きい方が MAXへ格納される
RET ; 呼び出しプログラムへ戻る
MAX DS 1 ; 1語の領域を確保し、MAXと名付ける
A DC 123 ; 定数 123を定義し、Aと名づける
B DC 45 ; 定数 45を定義し、Bと名づける
END
2.アセンブラ命令 アセンブラ制御命令とも言う。アセンブラへの指示を行う。 ① START命令
プログラムの実行開始番地をアセンブラに指示する。 (例) MAIN START FROMHERE
FROMHERE LD GR0,A プログラムの実行は ここから開始される
ADD GR0,B
1
ST GR0,C
RET
A DC 123
B DC -15
C DS 1
END
② END命令
プログラムの記述の最後であることをアセンブラに知らせる。END命令のラベル欄や
オペランド欄は書いてはならない。END命令の後ろに注釈行があってもよい。
③ DC命令 (define constant)
定数データを定義する。定数には、10 進数、16 進数、文字定数、アドレス定数の4
種類がある。
(例)
DC 12 ; 内部表現は 0000000000001100 正の 10進数
DC -12 ; 内部表現は 1111111111110100 負の 10進数
DC #A1 ; 内部表現は 0000000010100001 16進数(符号無し)
DC #FFFF : 内部表現は 1111111111111111 最大の 16進数
1文字を 1語の下位 8ビットで
表す(上位 8 ビットは0)。文字
数分の語数を使う。
DC ‘A*2’ ; 内部表現は 0000000001000001
; 0000000000101010
; 0000000000110010
COMETⅡにおける文字コード(JIS X0210)
上位4ビット
下位4ビット 2 3 4 5
0 空白 0 @ P
1 ! 1 A Q
2 “ 2 B R
3 # 3 C S
4 $ 4 D T
5 % 5 E U
6 & 6 F V
7 ‘ 7 G W
8 ( 8 H X
9 ) 9 I Y
2
A * : J Z
B + ; K [
C , < L \
D - = M ]
E . > N ^
F / ? O -
上例に示したように、
LD GR0,A
…
A DC 123
によって、GR0に 123をロードすることができるが、このように DC命令で定数を定義せず、
命令のオペランド部にリテラル(literal)を指定することにより同じことができる。
LD GR0,=123
のように書く。=123 の部分をリテラルという(「文字通り」の意)。リテラルは、命令の adr
相当部分に
=123 (10進数の場合)
=#A12 (16進数の場合)
=’a’ (文字定数の場合)
のように書く。
リテラルとして指定したデータがメモリ内のどこにつくられるのかは CASLⅡの仕様では
定まっていない(通常は、機械語コード、定数・変数領域、リテラル定数領域の順にメモ
リ内に格納されることが多い)。リテラルはこのように、データを置くための領域を1語使
うが、例えば
LD GR1,=0
のような場合、定数 0 のためにわざわざ1語使うことをせず、4ビット以内で表現できる
値を直接に命令の中に作り出すことを許す命令(即値命令、immediate data instruction)
を備えたアセンブラ言語もある。例えば、LD r1,r2 タイプの命令の第2オペランドとして
r2 の代わりにリテラルを書くことを許し(ニモニックを例えば LDIとする)、
LDI GR1,=5 (load immediate data)
によって、この命令の r2を表す部分(命令語の下位4ビット)に 5=(0101)2 が作られる。
3
④ DS命令 (define storage)
指定した語数の連続した領域を確保する。
(例)
A→ A DS 3
B DS 0
B→
B1→
B1 DS 2 BとB1は同じ 場所を指す B2 DS 1
B2→
1語=16ビット
3.繰り返し
一定回数の繰り返しは、繰り返しの回数を初期設定し、繰り返しを1回実
それから1減算し(または、1加算し)、その値が0になった時点(または、
返し回数に達した時点)で終了すればよい。終了判定をそれぞれの繰り返し
合と、後に行う場合とがある。
(例)繰り返しの冒頭で判定する/繰り返し回数をインクリメントする
LOOPING START
…
LD GR1,=0 ; GR1←0
; LAD GR1,0 でもよい
LOOPTOP CPA GR1,=10 ; (GR1)=10?
JZE LOOPEND ; (GR1)=0なら繰り返しは終了
…
ADDA GR1,=1 ; GR1に1足す
; LAD GR1,1,GR1 でもよい
JUMP LOOPTOP ; 次回の繰り返しへ
LOOPEND … ; ループ終了後に続けられる処理
…
RET
…
END
連続する領域
行するごとに
その値が繰り
の前に行う場
4
(例)繰り返しの末尾で判定する/繰り返し回数をデクリメントする
LOOPING START
LD GR1,=10 ; 10回繰り返す
LOOPTOP … ; 繰り返しの先頭
…
SUBA GR1,=1 ; GR1から 1引く
CPA GR1,=0 ; (GR1)=0?
JPL LOOPTOP ; (GR1)>0なら次回の繰り返しへ
LOOPEND … ; ループ終了後に続けられる処理
…
RET
…
END
⑤ LD命令 (load)
LD r1,r2 r1←(r2) r2レジスタの内容をr1レジスタにロードする
LD r,adr[,x] r←(adr+(x)) 実効アドレスの内容をrレジスタにロードする
LD r,=l r←l rレジスタにリテラルlをロードする
ここで、( ) は( )内のレジスタまたはアドレスに格納されている内容を表すこと、実
効アドレスとは adrと xの内容の加算値に対応する番地(すなわち、adr+(x))のことであ
ったことを思い出そう。
⑥ LAD命令 (load address)
LAD r,adr[,x] r←実効アドレス rレジスタに実効アドレスをロードする
LAD r,l[,x] r←l rレジスタにリテラルで示される絶対アドレス
l をロードする
rにロードされるのは、第2オペランドで示されるアドレスである(そのアドレスに格
納されているデータではない)ことに注意のこと。
実効アドレスとして絶対番地を書くことが許されている。例えば、
5
LAD R1,5,R2
と書くと、R1 レジスタには 5+(R2) 番地のアドレス、すなわち、整数値 5+(R2) が入る。
とくに、
LAD R1,5,R1
とすると、R1 レジスタの値は現在値より 5 増えることになる。このように、LAD 命令はレ
ジスタの値を増減させる命令としてしばしば使われる。
(問)CASLⅡのプログラムを書け。
1.A番地と B番地の内容を入れ替える。
2.X番地に入っている整数値から 12を引く。
3.3番レジスタ R3の内容を 0にする。
4.A番地に入っている整数の方が B番地に入っている整数より大きかったら C番地に0を
入れ、そうでなかったら何もしない。
5.4において、そうでなかったときに C番地に1を入れる。
⑦ 比較命令 CPA (compare arithmetic) と CPL (compare logical)
CPA r1,r2
CPA r,adr[,x]
CPA r,=l
CPL r1,r2
CPL r,adr[,x]
CPL r,=l
(r1)と(r2)、または(r)と(実効アドレス)またはリテラル l との算
術比較または論理比較を行い、比較結果によってFRに次の値を設定
する:
(r1)>(r2) あるいは (r)>(実効アドレス)なら SF←0, ZF←0
(r1)=(r2) あるいは (r)>(実効アドレス)なら SF←0, ZF←1
(r1)<(r2) あるいは (r)<(実効アドレス)なら SF←1, ZF←0
ここで、算術比較(arithmetical comparison)とは2数を符号付き(すなわち、1語の
先頭1ビットが符号ビットとみなされる)数として比較することであり、論理比較(logical
comparison)とは2数を符号無し数(1語の先頭の1ビットを符号とみなさない、16 ビッ
トの非負整数)として比較することである。比較の際、例えば CPA r1,r2 なら (r1)-(r2)
が計算され、その値の正零/負により SF=0/1 となり、=0 である/でないにより ZF=1/0 と
なる。演算の結果、レジスタ r1, r2, rの値は変化しない。
(例) (GR1)=(000A)16, (GR2)=(8003)16 のとき、
CPA GR1,GR2 によって SF=0, ZF=0, OF=0
CPL GR1,GR2 によって SF=1, ZF=0, OF=0
6
⑧ 分岐命令 JPL (jump on plus), JMI (jump on minus), JZE (jump on zero),
JNZ (jump on nonzero), JOV (jump on overflow), JUMP
JPL adr[,x] (SF)=0 かつ (ZF)=0 のとき実効アドレスにジャンプする
JMI adr[,x] (SF)=1 のとき実効アドレスにジャンプする
JZE adr[,x] (ZF)=1 のとき実効アドレスにジャンプする
JNZ adr[,x] (ZF)=0 のとき実効アドレスにジャンプする
JOV adr[,x] (OF)=1 のとき実効アドレスにジャンプする
JUMP 無条件に実効アドレスにジャンプする
4.インデックス修飾
インデックスレジスタを使ってアドレスの値を変えることをインデックス修飾と言う。
インデックス修飾は、連続する領域に置かれているデータを順次1つずつ処理するとき等
に効果を発揮する。
(例) DATA 番地から始まる連続する 100 語に格納されている数の総和を求める。結果は
SUM番地に格納する。計算途中でオーバーフローは起こらないものとする。
START BGN
BGN IN INAREA,INLEN
SUBA GR1,GR1 ; GR1のクリア(数を GR1に足しこんでいく)
LAD GR2,0 ; GR2をインデックスレジスタ 兼
; 繰り返し回数カウント用に使う.
; 初期値は 0
LOOP ADDA GR1,DATA,GR2 ; 次の数を GR1に加える
LAD GR2,1,GR2 ; GR2をインクリメント
CPL GR2,=100 ; (GR2)=100?
JMI LOOP ; 100回未満なら次の繰り返しへ
ST GR1,SUM ; 求めた総和を SUMに格納する
RET
DATA DS 0 ; データ用領域
INAREA DS 256 ; 入力領域
INLEN DS 1 ; 入力された文字数が入る
SUM DS 1 ; 結果を格納する
END
7
⑨ 算術加減算命令 ADDA (add arithmetic), SUBA (subtract arithmetic) と
論理加減算命令 ADDL (add logical)、SUBL (subtract logical)
ADDA r1,r2 r1←(r1)+(r2) r1レジスタにr2レジスタの内容を算術加算する
ADDA r,adr[,x] r←(r)+(adr+(x)) rレジスタに実効アドレスの内容を算術加算する
ADDA r,=l r←(r)+l rレジスタにリテラルlを算術加算する
SUBA r1,r2 r1←(r1)-(r2) r1レジスタからr2レジスタの内容を算術減算する
SUBA r,adr[,x] r←(r)-(adr+(x)) rレジスタから実効アドレスの内容を算術減算する
SUBA r,=l r←(r)- l rレジスタからリテラルlを算術減算する
ADDL r1,r2 r1←(r1)+L(r2) r1レジスタにr2レジスタの内容を論理加算する
ADDL r,adr[,x] r←(r)+L(adr+(x)) rレジスタに実効アドレスの内容を論理加算する
ADDL r,=l r←(r)+Ll rレジスタにリテラルlを論理加算する
SUBL r1,r2 r1←(r1)-L(r2) r1レジスタからr2レジスタの内容を論理減算する
SUBL r,adr[,x] r←(r)-L(adr+(x)) rレジスタから実効アドレスの内容を論理減算する
SUBL r,= l r←(r)-Ll rレジスタからリテラルlを論理減算する
乗除算は無いので、ユーザが自分で定義する必要がある。
算術加減算とは、オペランドを符号付き数として(すなわち、先頭ビットを符号ビット
と考えて)加減算するものである。演算結果の正負零に従って、SF=0 & ZF=0, SF=1 & ZF=0,
SF=0 & ZF=1 が設定される。オーバーフロー(あふれ、overflow: 数値が1語で表現でき
ない値となった場合)が起こったときは OF=1 が設定される(オーバーフローが起こらな
ければ OF=0)。
論理加減算とは、オペランドを符号なしの数として(すなわち、先頭ビットは符号ビッ
トとは考えずに)加減算を行うものである。演算結果の正負零・オーバーフローの有無に
よって SF,ZF,OF が設定されるのは算術加減算と同様である。
(例)(GR1)=(000A)16, (GR2)=(FFFA)16 のとき、(000A)16 は符号付きの数と見ても符号無し
数と見ても (10)10 であり、(FFFA)16 は符号付き数と見ると (-6)10 であり、符号無し数と
見ると (65530)10 であるから、
ADDA GR1,GR2 によって (GR1)=(0004)16, SF=0, ZF=0, OF=0
ADDL GR1,GR2 によって (GR1)=オーバーフロー(0005)16, SF=0, ZF=0, OF=1
SUBA GR1,GR2 によって (GR1)=(0010)16, SF=0, ZF=0, OF=0
SUBL GR2,GR1 によって (GR2)=(FFF0)16, SF=0, ZF=0, OF=0
SUBA GR1,GR1 によって (GR1)=(0000)16, SF=0, ZF=1, OF=0
SUBA GR2,GR1 によって (GR2)=(FFF0)16, SF=1, ZF=0, OF=0
8
(問) CASLⅡのプログラムを書け。 1.1~nまでの和を Sに求める。nは記号番地 Nに入っているものとする。 2.A, B, Cの中の最小値をMINに求める。 3.DATA 番地からはじまる 100 番地に入っている整数の中に正の数、負の数がそれぞれ何個あるかを求める。 4.DATA番地からはじまる 100番地に文字@があるかどうかを判定する。 5.入出力とマクロ
たいていのアセンブラでは、同じようなプログラム部分を何度も書くのを防ぎコーディ
ングの効率を上げるため、あるいは、入出力のようにユーザがその都度ソースプログラム
内に書くには複雑すぎる処理を簡単に書くことができるようにするための機能として、マ
クロ機能とサブルーティン機能を備えている。サブルーティンについては後述するが、マ
クロ(macro)機能とは、生成したい命令語の列のパターンをあらかじめ定義しておき(そ
の中の一部の記号名を置き換えられるように、マクロのパラメータ(仮引数という)とし
て定義するのが普通である)、ソースプログラム内の必要なところでその定義をパラメータ
への値(実引数という)とともに引用することにより、そのソースプログラムをアセンブ
ラが実行可能な機械語プログラムに翻訳する(すなわち、アセンブルする)時に、マクロ
定義のパラメータ仮引数のところに実引数を代入したもの(マクロの展開という)をマク
ロ引用が行われた箇所に生成する機能のことである。
CASLⅡにはそのような一般的なマクロ機能は無いが、入出力は(たいていのアセンブラ
もそうであるが)マクロ命令で記述できる。
⑩ マクロ命令 INと OUT
IN inarea,lg 入力装置からinareaから始まる256語の領域にデータが転送され、そ
の語数がlg番地に入れられる
OUT outarea,lg outareaから始まるlg語分のデータが出力装置に送られる
IN命令により、あらかじめ定まった入力装置から読み込まれたデータ(文字列)が、inarea
で指定した記号番地で始まる 256語分の領域(CASLⅡではこれを入力領域といい、この 256
語を1レコードと呼ぶ)に格納される。文字データしか入力できないことに注意のこと。
1つの文字は1語を使って下位 8ビットに入れられる(上位 8ビットはオール 0)。記号番
地 lgにある1語には、入力された文字の長さが入れられる。文字数が 256未満のときには、
inarea領域の余った所の内容は元のまま、256を超える場合には、257文字目以降は読み捨
てられる。リターンキーだけを入力すると、長さ 0 の文字列として扱われることに注意す
る(→データの末尾を判定するために使うことができる)。
9
IN命令とは逆に OUT命令は、outareaから始まる領域の内容を、記号番地 lgに入ってい
る値だけの長さの文字列(1文字=1語の下位 8ビット。上位 8ビットは無視される)だけ
取り出し、1レコード(=256文字)の文字列として、あらかじめ指定された出力装置に出
力する。
(例)1桁の数字を1つずつ(データの区切りはリターンキー)読み込み、数値に変換し
て AREA領域に格納する。その総和を 16進数として出力する。
START DATAIN
DATAIN IN DATA,ILEN ; 1文字入力
LAD GR1,0
CPA GR1,ILEN ; 改行だけが入力されたか?
JNZ DATAIN
; ここから数値への変換と和を求めるためのループが始まる
LAD GR0,0 ; GR0に和を求める
LD GR1,ILEN ; (LEN)>0と仮定する
LOOP SUBA GR1,=1 ; GR1はインデックスレジスタとして使う
; データは領域の後ろから順次処理する
LD GR2,DATA,GR1 ; 1文字 GR2にロードする
AND GR2,MASK ; 数値に変換する
; AND GR2,=#000F でもよい
ADDA GR0,GR2 ; 変換した数値を総和に加える
CPA GR1,=0 ; 必要回数ループしたか?
JPL LOOP ; まだなら、次のループをやるためにジャンプ
ST GR0,SUM ; 総和を SUMへ格納
; ここから総和(数値)を 16進数4文字に変換し、結果を OUTAREAに格納する
; 詳細は省略
OUT OUTAREA,OLEN
RET
MASK DC #000F
DATA DS 256
ILEN DS 1
SUM DS 1
OUTAREA DS 4
OLEN DS 1
END
10
⑩ 論理演算命令 AND, OR, EOR
AND r1,r2 r1←(r1)∧(r2)
AND r,adr[,x] r←(r)∧(adr+(x))
AND r,=l r←(r)∧l
(r1)と(r2)、または(r)と(実効アドレス)ま
たはリテラル l との論理積を取り、r1または
rに代入する
OR r1,r2 r1←(r1)∨(r2)
OR r,adr[,x] r←(r)∨(adr+(x))
OR r,l r←(r)∨l
(r1)と(r2)、または(r)と(実効アドレス)ま
たはリテラル l との論理和を取り、r1または
rに代入する
EOR r1,r2 r1←(r1)⊕(r2)
EOR r,adr[,x] r1←(r1)⊕(r2)
EOR r,l r←(r)⊕l
(r1)と(r2)、または(r)と(実効アドレス)ま
たはリテラル l との排他的論理和を取り、r1
またはrに代入する
論理積(and)、論理和(inclusive or)、排他的論理和(exclusive or)は、2つの語の対応
するビット同士で取られる。
(例1)(GR1)=(0000 1111 1010 1100)2,
(GR2)=(1100 1010 1100 0101)2 のとき、
AND GR1,GR2 によって (GR1)=(0000 1010 1000 0100)16
OR GR1,GR2 によって (GR1)=(1100 1111 1110 1101)16
EOR GR1,GR2 によって (GR1)=(1100 0101 0110 1001)16
(例2)排他的論理和を使うと、否定(NOT)やゼロクリア(1語の全ビットを 0にすること)
もできる:
EOR GR1,GR1 によって (GR1)=(0000 0000 0000 0000)16 となる。
EOR GR1,=#FFFF によって、GR1の全ビットが反転する(0→1、1→0).
(例3) マスク
論理演算が使われる典型的な例は、1語の中の必要なビットだけを切り出すというもの
である。すなわち、切り出したいビット位置にだけ1が立ち、他のビットは 0 であるよう
な16進数との AND を取ればよい(必要なら、さらにビットを右または左にシフトして、
それにつづく処理がしやすいようにする)。上の例の、文字を数値に変換する部分を参照の
こと。
(問)いろいろな方法でプログラムを書け。
1.A番地の内容(整数)が正の数かどうか判定せよ(語の先頭の 1ビットが0)。
2.A番地に0を入れる(GR0をゼロクリアする)。
3.A番地と B番地の内容を入れ替える。
11
⑪ シフト命令 SLA (shift left arithmetic), SRA (shift right arithmetic),
SLL (shift left logical), SRL (shift right logical)
SLA r,adr[,x]
SRA r,adr[,x]
符号ビットを除き、(r)を実効アドレスで指定したビット数だけ左または右に
シフトする。シフトの結果空いたビット位置には左シフトのときは0、右シフ
トのときは符号ビットと同じものが入る(算術シフト)
SLL r,adr[,x]
SRL r,adr[,x]
符号ビットを含め、(r)を実効アドレスで指定したビット数だけ左または右に
シフトする。シフトの結果空いたビット位置には0が入る(論理シフト)
(例1)(GR1)=(0000 1111 1010 1100)2,
(GR2)=(1100 1010 1100 0101)2,
(GR2)=(0000 0000 0000 0100)2 のとき、
SLA GR1,4 によって (GR1)=(1111 1010 1100 0000)16
SRA GR2,4 によって (GR2)=(1111 1100 1010 1100)16
SRL GR2,4 によって (GR2)=(0000 1100 1010 1100)16
SLL GR2,4,GR3 によって (GR2)=(1100 0101 0000 0000)16
SRL GR2,16 によって (GR2)=(0000 0000 0000 0000)16 オーバーフロー
SRA GR2,16 によって (GR2)=(1111 1111 1111 1111)16 アンダーフロー
実効アドレスが示す番地に格納されている値ではなく実効アドレス(=絶対番地)その
ものがシフトすべきビット数を表すことに注意のこと。
なお、数値を k ビット左/右へシフトするとオーバーフロー/アンダーフローが生じな
い限り、2kを掛けた値/2kで割った値(商)に等しくなる(算術シフトの場合には、負の数
でもそのことが成り立つ)。
(注)オーバーフロー(overflow):左シフトしたとき、符号ビットと異なるものが失な
われる場合、2k倍したことにならない無意味な値となってしまう。
アンダーフロー(underflow):右シフトしたとき、符号ビットと異なるものが失なわれ
る場合、2kで割ったことにならなくなる(符号ビット=0、消失ビット=1 → 小数点以下の
桁の切捨てに相当する。符号ビット=1、消失ビット=0 → 小数点以下の桁の切り上げに
相当する)。
(例2)A番地、B番地に入っているデータを数値と考え、その積を C番地に格納する。筆
算と同様に、Aに Bの各桁(ビット 0/1)を下位の位から順に(20 → 215)掛けて、C(初期
値 0)に足していけばよい。繰り返しの各回、Bの各ビットに対応する 2の冪を Aに掛ける
のではなく、A を 1 ビットずつ左にシフトする。B の対応するビットが 0 だったときには、
12
0を掛けて足すのではなく何もしない。各回、Bは 1ビット右へシフトし、Bが 0になった
ら終了する。オーバーフロー、アンダーフローは起こらないものとする。
MULTIPLY START HAJIME
HAJIME LAD GR0,0 ; 積を GR0に求めるので、GR0←0
LD GR1,A ; 被乗数をロード
LD GR2,B ; 乗数をロード
LOOP CPA GR2,=0 ; 乗数が 0になったか?
JZE OWARI ; 乗数が 0になったら終了
AND GR2,=#FFF1 ; 乗数の 2kの位の1ビットを取り出す(k=0~15)
JZE NEXT ; それが 0ならループのインクリメントへジャンプ
ADDA GR0,GR1 ; A×2kを部分和へ足す
NEXT SLA GR1,1 ; Aに 2を掛ける(1ビット左にシフト)
SRA GR2,1 ; Bを 2で割る(1ビット右へシフト)
JUMP LOOP ; 次回の繰り返しへジャンプ
OWARI ST GR0,C
RET
A DC 123
B DC 10
C DS 1
END
5.サブルーチン
ほんの一部だけ異なるような類似した処理を別々のプログラムとして書くのは無駄であ
る。類似部分をパラメータ化して1つのプログラム部分とし、パラメータを変えて引用す
るだけで必要な処理ができるようにしたものが副プログラム(サブルーチン、subroutine)
である。
これまで書いてきたプログラムはそれぞれ1つの独立したプログラムであり、主プログ
ラム(メインルーチン)にもサブルーチンにもなりうる。サブルーチンを呼び出す命令が
CALL命令であり(実際の動作は、「サブルーチンへジャンプする」という方が合っている)、
サブルーチンから戻る命令が RET命令である。
CALL adr[,x] オペランド部で指定される実行アドレスに分岐する
RET 現在制御があるサブルーチンから、このサブルーチンを呼び出したル
ーチン内の呼び出した命令の次の命令位置へ制御が戻る
13
RET命令はオペランドが無いのに、なぜ呼び出したルーチン内の呼び出した命令の次の命
令に制御を戻すことができるのであろうか? この仕組みを理解するためには、スタック
という概念を知らなければならない。
スタック
複雑な構造を持ったデータ、あるいは、そのようなデータを持つ構造のことを一般にデー
タ構造(data structure)という。非常に有用なデータ構造としては、線形リスト、木構造、グラフなどがあるが、ここではスタックとキューについて述べる。 データ構造は、データの集合とその集合の上でどのような演算が定義されているかによ
って特徴付けることが出来る。 入 出 (1)スタック stack(pushdown stack) ↓↑ 順序を持った有限個のデータの集合 x1 [x1, x2, ..., xn] x2 で、これに属する要素の扱い方が以下のように制限 されているものをスタックという。 ...
直感的なイメージとしては、図のように、出し入れ xn 口が上部にしかないような構造を考えるとよい。 ←底
←スタックのトップ
このデータ集合に対して行なえること(すなわち、スタックの上の演算)は次のものだ
けである: ! スタックの先頭要素(topという) x1 を取り出すこと。この操作をポップアップまた
は単にポップという。 x1 をポップするとスタックの内容は [x2, x3, ..., xn] となる。
! スタックの先頭に要素を1つ追加挿入すること。この操作をプッシュダウンまたは単
にプッシュという。要素 y をプッシュすると、スタックの内容は [y, x1, x2, ..., xn] となる。
! スタックが空かどうか判定すること。 スタックにおいては、最後に入れられたデータが最初に取り出されることになるので、
スタックのことを LIFO (last-in first-out)ということがある。
14
(2)キュ- queue スタックがfirst-in last-outのデータ構造であるのに対して、FIFO (first-in first-out)のデータ構造をキューとか待ち行列という。窓口に人が並んだ行列をイメージするとよい(先
着順に受け付けられる)。 出口 ← x1 x2 ... xn ← 入口 先頭 末尾 ↓ ↓ [x1, x2, ..., xn] キュ-の上の演算 ! キューの先頭要素(frontという) x1 を取り出すこと。その結果キューの内容は
[x2, ..., xn] となる。
! キューの末尾要素(rearという) xn に要素を追加挿入すること。 y を挿入すると [x1, x2, ..., xn, y]
となる。 ! キューが空かどうか調べること。
CASLⅡには、次のような命令があり、主記憶装置上のスタック領域をスタックとして使
うことができる。
PUSH adr[,x] スタックポインタSPの値が1だけ減じられ、そのあと、SPの指す番地
にオペランド部で指定される実行アドレスの内容が格納される
POP r まず、スタックポインタSPが指している番地の内容がレジスタrにロー
ドされ、そのあと、SPに1足される
CALL命令によって、実際は次のような一連の動作が行われる:
① スタックポインタ SPの値を1だけ減らす。
② プログラムレジスタ PR の現在値(=次に実行すべき命令が入っている 2 語の先頭
アドレス)が、SPが指す位置(から始まる2語)に格納される。この値(戻り番地
(return address)と言う)は、サブルーチンから戻るときに使われる。(①②がス
タックへのプッシュ)
③ adr,[x]で指定される実効アドレスにジャンプする。
また、RET命令の実行によって次のような一連の動作が行われる:
④ スタックポインタ SPが指す番地の内容(=このサブルーチンを CALLした命令の直
後にある命令が入っているアドレス)を取り出す。
⑤ SPに1足す。(④⑤がスタックからのポップアップ)
15
⑥ ④で取り出した値をプログラムレジスタ PR へ格納する。これによって、このサブ
ルーチンを呼び出した CALL命令の直後の命令へ制御が移る。
(注1)CALL するルーチンと CALL されるルーチンの間での値の受け渡し(parameter
passing) PUSH命令によってサブルーチンへ渡すデータをスタック領域に格納し、サブル
ーチンではその値を使って(どのサブルーチンでも SPの現在値が分かるので、その値にア
クセスすることができる)処理を行い、処理終了後は、PUSH 命令を使ってスタックに格納
することにより、CALLしたルーチンへいくつかの値を返すこともできる。
呼ぶ側と呼ばれる側で値を遣り取りするもう一つの方法は、汎用レジスタを仲介にする
方法である(下記の例参照)。
(注2)サブルーチンとマクロの違い マクロでは、引用によってパラメータ部分を変え
たものが生成され、引用位置に挿入される(アセンブル時に)。これに対し、サブルーチン
は1つの独立したプログラムとして存在し、それを引用すると制御がそのサブルーチンへ
移り、サブルーチンでの処理が終わったときに、呼んだルーチンに制御が戻る。これがマ
クロとサブルーチンの違いである。
(例)既出の「2数の掛け算」を行う部分をサブルーチン化する。
EXAMPLE START BGN ; A×Bを AB番地に、C×Dを CD番地に求める
LD GR6,A ; GR6を介して Aの値をサブルーチンに渡す
LD GR7,B ; GR7を介して Bの値をサブルーチンに渡す
CALL MULTIPLY ; 掛け算ルーチンを呼び出す
ST GR0,AB ; GR0には積 A×Bが入っている
LD GR6,C ; 以下、同様に、C×Dを求める
LD GR7,D
CALL MULTIPLY
ST GR0,CD ; GR0には積 C×Dが入っている
A DC 12
B DC 34
C DC 123
D DC 456
AB DS 1
CD DS 1
END
16
MULTIPLY START HAJIME
HAJIME LAD GR0,0 ; 積を GR0に求めるので、GR0←0
LD GR1,GR6 ; 被乗数をロード
LD GR2,GR7 ; 乗数をロード
LOOP CPA GR2,=0 ; 乗数が 0になったか?
JZE OWARI ; 乗数が 0になったら終了
AND GR2,=#FFF1 ; 乗数の 2kの位の1ビットを取り出す(k=0~15)
JZE NEXT ; それが 0ならループのインクリメントへジャンプ
ADDA GR0,GR1 ; A×2kを部分和へ足す
NEXT SLA GR1,1 ; Aに 2を掛ける(1ビット左にシフト)
SRA GR2,1 ; Bを 2で割る(1ビット右へシフト)
JUMP LOOP ; 次回の繰り返しへジャンプ
OWARI RET ; 呼び出したルーチンへ戻る
END
(演習問題)
次のことを行うプログラムを書け。
1.(8000)16 番地の内容を(9000)16 番地へ格納せよ。
2.3つの数値 X, Y, Zを大きい順に並び替えて X,Y,Zへ入れ直せ。
3. 連続する 100語を文字の列として見て、その中の空白すべてを@記号で置き換えよ。
4.GR0の値を 0にする方法をいくつか述べよ。
5.DATABGN番地から DATAEND番地までにある数の最大値を MAXに求めよ。
6.DATA 番地からの 100 語にあるデータを数値と解釈し、そのうちの正のものだけの総
和を求めよ。また、偶数だけの総和と奇数だけの総和を求めよ。
7.DATA 番地からの 100 語の内容を文字とみたとき、その中の数(0~9)の個数、英
字(A~Z)の個数、それ以外の文字の個数を求めよ。1語には2文字入っていることに注
意のこと。
8.変換 数字(0~9) ⇔ 数値0~9 を行え。
9.DATA番地の1語 16ビットの内部表現において、1がいくつあるかを求めよ。
10.DATA番地からの 100語の内容を 1語ずつ後ろへずらせ。
11.問題5をインデックスレジスタを使わずに解け。1つの方法として、ADDA 命令のオ
ペランド部をループの中で変えることが考えられる。
12.足し算の繰り返しで掛け算を行え(オーバーフローは起こらないとする)。サブルー
チン化せよ。
13.DATA 番地から始まる 100 語に、昇順にソートされた整数値が入っている。この中に
17
18
M番地に入っている値と等しいものがあるかどうかを判定せよ。
14.DATA番地から始まる 100語に入っている整数値を昇順にソートせよ。
15.文字列として渡された 5桁以内の整数(負の場合には先頭文字が「―」)を CASLⅡの
内部表現(2進数)に変換するサブルーチンをつくれ。文字列の渡し方等の仕様は各自が決
めよ。