法政大学国際文化学部
情報システム概論
担当 重定 如彦
2008年11月11日
第7回 機械語によるプログラミング その3
1. 前回の課題の答え
1 START
2 LD GR1, A
3 LEA GR2, 0
4 LOOP SUB GR1, B
5 JMI ANS
6 LEA GR2, 1, GR2
7 JMP LOOP
8 ANS ST GR2, C
9 ADD GR1, B
10 ST GR1, D
11 EXIT
12 A DC 10
13 B DC 3
14 C DS 1
15 D DS 1
16 END
まず12、13行目で10と3をメモリのA番地とB番地に格納し、14、15行目で答えを格納する場所をメモリのC番地とD番地に用意します。2行目でA番地の内容をGR1に代入し,3行目でGR1からB番地の内容を何回引いたかを数えるGR2の内容を0で初期化します。4〜8行目がループで、4行目でGR1からB番地の内容を引き算し、結果が負であった場合は、5行目で答えを代入する ANS 番地へジャンプします。結果が負でなかった場合は、引いた回数を数えるGR2に1を足し8行目で4行目へ無条件でジャンプし、繰り返しを続行します。ループが終了した時点で答えが計算されているはずなのですが、GR1の値は余分に一回B番地の内容が引かれたているため9行目でB番地の内容を足し算し、答えを格納しプログラムは終了です。このプログラムではループの最初でループを抜けるための条件分岐を行っている点に注意して下さい。
2. アドレッシング
これまでの解説した機械語の命令のオペランドの部分には、(LEA命令と条件分岐命令を除いて)すべて計算する値が格納されているレジスタ又はメモリのアドレスを記述しました。実際の機械語では、このオペランドの部分にこれ以外の様々な方法で計算する値を指定する方法が用意されています。この命令コードが計算する値を指定する方法をアドレッシングと呼びます。アドレッシングには以下のような種類があります。
·
即値アドレス指定方式
オペランドの部分にアドレスではなく、命令コードの計算の対象となるデータを直接記述する方式です。CASLの場合、LEA命令の第2オペランドがこれに相当します。
LEA GR1, 20
例えば上記の命令はGR1に20という数値そのものを代入するという意味を持ちます。
·
直接アドレス指定方式
オペランドの部分に命令コードの計算の対象となるデータが格納されているメモリのアドレスを記述する方式です。CASLの場合、ロード・ストア命令、加算、減算命令など多くの命令の第2オペランドがこれに相当します。
ADD GR1, 20
例えば上記の命令はGR1にメモリの20番地に格納されている数値を加算します。
アセンブラ言語によっては、即値アドレス指定方式と直接アドレス指定方式を区別するために、直接アドレス指定方式の場合、アドレスの数値の前後に()を以下のように記述する場合があります。(注:CASLではこのような記述は行いません)
ADD GR1, (20)
·
(自己)相対アドレス指定方式
命令コードが記述されているメモリのアドレスに、オペランド部分で記述されている数値を加算したアドレスの内容を命令コードの計算の対象とする方式です。
例えば命令コードに対応する機械語命令が2000番地に格納されており、オペランドに20という数値が記述されていた場合、相対アドレス指定方式では、2000+20=2020番地の内容を計算の対象とします。相対アドレス指定方式は、リロケータブルなプログラム(メモリの任意の場所にプログラムを置くことができるプログラムのこと)を作成する際に用いられます。なお、CASLには相対アドレス指定方式を使用する命令コードはありません。
〜なぜ相対アドレス指定方式を使うとリロケータブルなプログラムになるのか?〜
例えば、メモリのA番地の内容を汎用レジスタ1に読み込むというプログラムを直接アドレス指定方式で記述し、アセンブルした結果、下記の番地に機械語のプログラムが作成されたとします。
0番地 LD GR1, 2 ; メモリの2番地の内容をGRに代入
2番地 DC 10
このプログラムをメモリの別の番地、例えば100へ移動させると以下のようになります。
100番地 LD GR1, 2 ; メモリの2番地の内容をGRに代入
102番地 DC 10
プログラムを格納する場所を移動させるとそれに伴い元々2番地に格納されていた10というデータが102番地に移ってしまいますが、プログラムの中ではGR1に代入するメモリの番地をそのまま記述しているので、このプログラムでは依然として2番地の内容をGR1に格納することになってしまい、元のプログラムと違う動作を行ってしまいます。
一方もし、このプログラムの LD GR1, 2 の 2 の部分が相対アドレス指定方式で記述されていた場合、これは、自分のアドレス+2番地のアドレスの内容をGR1に格納するという意味を持ちます。この命令が記述されているメモリのアドレスと、GR1に格納したいデータが記述されているメモリのアドレスの差は一定(=2)なので、このプログラムをどこへ移動させてもこのプログラムは正しく動作するのです。
·
レジスタアドレス指定方式
オペランド部に汎用レジスタの番号を指定し、そのレジスタに格納されているアドレスの内容を命令コードの操作の対象とする方式です。例えば、GR1に 2000 という数値が記述されていた場合、レジスタアドレス指定方式では GR1 を指定することで、メモリの2000番地の内容を計算の対象とします。レジスタアドレス指定方式をアセンブラ言語で記述する場合、一般的に以下のようにアドレスを格納するレジスタの部分を直接アドレス方式の場合と同様に()で括って記述する場合があります。
LD GR2, (GR1) ;GR1番地の内容をGR2に代入
なお、CASLにはレジスタアドレス指定方式を使用する命令コードはありません。
·
間接アドレス指定方式
オペランド部分にメモリのアドレスを指定するところまでは直接アドレス指定方式と同じですが、間接アドレス方式では、指定したメモリのアドレスに格納されている数値をさらにメモリのアドレスとみなし、その数値のアドレスの内容を計算の対象とします。
例えばメモリの1000番地に2000、2000番地に3000という数字が格納されていた場合、間接アドレス指定方式で 1000 と指定することで、まずメモリの1000番地の内容を調べ、次にその内容である2000をメモリのアドレスとみなし、その内容である3000を計算の対象とします。間接アドレス指定方式をアセンブラ言語で記述する場合、一般的に以下のように2重に()で括って記述する場合があります。
LD GR1,((1000)) ;(1000番地の内容)の番地の内容をGR1に代入
なお、CASLには間接アドレス指定方式を使用する命令コードはありません。
·
指標アドレス指定方式
直接アドレス指定方式に似ていますが、指定したアドレスに特定の汎用レジスタの内容を加えたアドレスの内容を計算の対象とします。この時に使われる汎用レジスタのことを指標レジスタと呼びます。指標アドレス指定方式は、隣り合ったメモリの内容の計算を行う場合などに使われます。CASLでは指標アドレス指定方式を使うことができます。
3. 指標アドレス指定方式を使ったプログラム例
CASLでは、多くの命令コードの第3オペランドに指標レジスタとして汎用レジスタを記述することで、指標アドレス指定方式でアドレスを指定することができます。
LD GR1, A, GR2
例えば上記のプログラムはメモリの(A+汎用レジスタ2の内容)番地の内容を汎用レジスタ1に代入するという意味を持ちます。
なお、CASLでは、指標レジスタにとして汎用レジスタ0(つまりGR0)を使用できないという仕様になっているので注意して下さい。また、第3オペランドを省略した場合は、直接アドレス指定方式で記述されたものとみなされます。
それでは、例としてメモリのA番地からA+4番地までの5個のアドレスに格納されている数値を足し算し、メモリのB番地に格納するという動作を行うプログラムを指標アドレス指定方式使って記述してみましょう。
1 START
2 LEA GR1,0 ;GR1に0を代入
3 LEA GR2,4 ;GR2に4を代入
4 LOOP ADD GR1,A,
GR2 ;GR1にA+GR2番地の内容を足す
5 LEA GR2,-1,GR2 ;GR2から1を引く
6 JPZ LOOP ;演算結果が負でなければLOOPへ
7 ST GR1,B ;GR1の内容をB番地に格納
8 EXIT ;プログラム終了
9 A DC 1 ;A番地に1を代入
10 DC 2 ;A+1番地に2を代入
11 DC 3 ;A+2番地に3を代入
12 DC 4 ;A+3番地に4を代入
13 DC 5 ;A+4番地に5を代入
14 B DS 1 ;結果を格納するB番地を用意する
15 END
まず、9〜13行目で、メモリのA番地からA+4番地までにそれぞれ1,2,3,4,5という数値を格納します。このようにCASLでは隣り合った行にDC命令を記述するとそのデータは隣り合ったメモリの番地に格納されることになっています。また、14行目で計算結果を格納するメモリのB番地を用意しています。
プログラムでは、計算の途中結果をGR1に格納し、GR2指標レジスタとして使用することにします。そして、GR2の内容を4から0まで1ずつ減らすことによって、A+4番地からA番地の内容の合計を計算することにします。
まず、2行目でGR1の内容を0で初期化し、GR2の内容を4にします。4〜6行目がループになっており、ループでは
4行目 GR1の内容に A+GR2 番地の内容を加算する
5行目 GR2の内容を1減らす
6行目 GR2の内容が0以上ならば4行目に戻る
という動作が繰り返し行われます。このループを一回行う度に、GR2の値が4,3,2,1,0,−1と一つずつ減っていき、−1になった時点でループを終了するので、結果としてGR1の中にはメモリのA番地からA+4番地の内容の合計が格納されることになります。そして7行目で答えであるGR1の内容をメモリのB番地に格納しています。
4. その他の命令
これまで解説しなかった命令について解説します。
·
比較演算命令
比較命令は、第一オペランドで指定した汎用レジスタの内容と第二オペランドで指定したメモリのアドレスの内容を比較し、その結果をフラグレジスタ(FR)に反映させる命令です。比較演算命令は数値の比較のみを行なう命令で、結果はFRにのみ反映されます。従ってレジスタやアドレスの内容は変化しない点に注意して下さい。なお、この命令を実行後のフラグの状態の覚え方は、SUB命令と同じであると覚えればよいでしょう。
命令 |
命令コード |
オペランド |
意味 |
算術比較 |
CPA |
GR、 adr |
GRとadr番地の内容の算術比較を行う |
論理比較 |
CPL |
GR、 adr |
GRとadr番地の内容の論理比較を行う |
|
GR>adr |
GR=adr |
GR<adr |
FRの値 |
(00)2 |
(01)2 |
(10)2 |
算術比較と論理比較の違いは、算術比較では数値を2の補数で表現される−32768〜32767の範囲の数値とみなすのに対し、論理比較では数値の符号ビットを無視して、0〜65535の16ビットの正の整数とみなす点です。慣れない内はとりあえず論理比較命令のことは無視して、算術比較命令のみ使えばよいでしょう。
先ほどのプログラムを算術比較命令を使ってA番地からA+4番地の順番で計算するプログラムになおすと以下のようになります。前と変わった部分を灰色で表示しています。
1 START
2 LEA GR1,0 ;GR1に0を代入
3 LEA GR2,0 ;GR2に0を代入
4 LOOP ADD GR1,A, GR2 ;GR1にA+GR2の内容を足す
5 LEA GR2,1,GR2 ;GR2に1を足す
6 CPA GR2,
C ;GR2とC番地の内容を比較
7 JNZ LOOP ;GR2<C番地であればLOOPへ
8 ST GR1,B ;GR1の内容をB番地に格納
9 EXIT ;プログラム終了
10 A DC 1 ;A番地に1を代入
11 DC 2 ;A+1番地に2を代入
12 DC 3 ;A+2番地に3を代入
13 DC 4 ;A+3番地に4を代入
14 DC 5 ;A+4番地に5を代入
15 B DS 1 ;結果を格納するB番地を用意する
16 C DC 5 ;繰り返しの回数を格納
17 END
·
シフト演算命令
シフト演算命令は第一オペランドで指定した汎用レジスタの内容を第二オペランドで指定した内容の数だけビット数をずらすという動作を行います。
命令 |
命令コード |
オペランド |
意味 |
算術左シフト |
SLA |
GR、 数値 |
GRの内容を符号部を残して数値ビットだけ左にシフト |
算術右シフト |
SRA |
GR、 数値 |
GRの内容を符号部を残して数値ビットだけ右にシフト |
論理左シフト |
SLL |
GR、 数値 |
GRの内容を符号部を含めて数値ビットだけ左にシフト |
論理右シフト |
SRL |
GR、 数値 |
GRの内容を符号部を含めて数値ビットだけ右にシフト |
1ビット左にシフトすると数値は2倍になり、1ビット右にシフトすると数値は1/2倍になるので、2のn乗(2,4,8,16,32...)の掛け算や割り算を行う場合はビットシフト命令を使うと便利です。なお、算術シフトと論理シフトの違いは算術比較と論理比較の場合と同様で、算術シフトは符号部分のビットを残したままシフト、論理シフトは符号部のビットも含めてシフトするという意味を持ちます。
例えば
SLA GR1, 3
と記述するとGR1の内容が2の3乗倍、すなわち2*2*2=8倍になります。
5. 課題
以下のプログラムを作り実行せよ。また、作成したプログラムをGドライブにkadai3という名前で保存し課題のメールとして添付ファイルでta080017@mail.edu.i.hosei.ac.jpへ送ること。
メモリのA番地からA+4番地までに正の数字を入力し、その中で最も大きな数をみつけ、メモリのB番地に格納するプログラムを作りなさい。
A〜A+4番地に5,7,3,6,2を代入し、作成したプログラムを実行し、メモリのB番地に正しい答えが格納されていることを確かめよ。
ヒント:基本的なプログラムの構造はA〜A+4番地の合計を求めるプログラムと同じ。GR1を答えを格納する汎用レジスタとして利用する場合、最初にGR1に0を代入する。そして、繰り返し部分ではGR1とA〜A+4番地を比較しGR1のほうが小さければGR1にアドレスの中身を代入すればよい。
6. 授業で説明した全命令
以下に授業で解説したCASLの命令を表にまとめます。それぞれの命令の意味についてはこれまでのプリントを参照して下さい。表のオペランドの部分の記号は以下の意味を持ちます。また、FRの欄に○が記述されている命令は、その命令を実行した結果、フラグレジスタの内容が変化することを意味します。[,XR]と記述されている部分はその部分を省略できることを表します。
命令 |
命令コード |
オペランド |
FR |
アドレッシング |
ロードストア命令 |
||||
ロード |
LD |
GR,adr[,XR] |
× |
直接アドレス指定 |
ストア |
ST |
GR,adr[,XR] |
× |
直接アドレス指定 |
ロードアドレス命令 |
||||
ロードアドレス |
LEA |
GR,数値[,XR] |
○ |
即値アドレス指定 |
算術、論理命令 |
||||
算術加算 |
ADD |
GR,adr[,XR] |
○ |
直接アドレス指定 |
算術減算 |
SUB |
GR,adr[,XR] |
○ |
直接アドレス指定 |
論理積 |
AND |
GR,adr[,XR] |
○ |
直接アドレス指定 |
論理和 |
OR |
GR,adr[,XR] |
○ |
直接アドレス指定 |
排他的論理和 |
EOR |
GR,adr[,XR] |
○ |
直接アドレス指定 |
比較演算命令 |
||||
算術比較 |
CPA |
GR,adr[,XR] |
○ |
直接アドレス指定 |
論理比較 |
CPL |
GR,adr[,XR] |
○ |
直接アドレス指定 |
シフト演算命令 |
||||
算術左シフト |
SLA |
GR,数値[,XR] |
○ |
即値アドレス指定 |
算術右シフト |
SRA |
GR,数値[,XR] |
○ |
即値アドレス指定 |
論理左シフト |
SLL |
GR,数値[,XR] |
○ |
即値アドレス指定 |
論理右シフト |
SRL |
GR,数値[,XR] |
○ |
即値アドレス指定 |
分岐命令 |
||||
正分岐 |
JPZ |
adr[,XR] |
× |
即値アドレス指定 |
負分岐 |
JMI |
adr[,XR] |
× |
即値アドレス指定 |
非零分岐 |
JNZ |
adr[,XR] |
× |
即値アドレス指定 |
零分岐 |
JZE |
adr[,XR] |
× |
即値アドレス指定 |
無条件分岐 |
JMP |
adr[,XR] |
× |
即値アドレス指定 |
記号 |
意味 |
実際に記述する値 |
GR |
汎用レジスタ |
GR0〜GR4 |
adr |
adrで指定されたアドレスの内容。 XRが記述されている場合はXRの部分で指定された指標レジスタの内容をadrに加算したアドレスの内容。ただし、分岐命令の場合のみ即値アドレス指定な点に注意。 |
アドレスを表す数値またはラベル |
数値 |
数値。XRが記述されている場合はXRの部分で指定された指標レジスタの内容を数値に加算した値。 |
数値またはラベル |
XR |
指標レジスタとして使用する汎用レジスタ |
GR1〜GR4 |
アドレッシングの部分に「直接アドレス指定」と書かれているものは、[XR]を省略した場合です。[XR]を記述した場合は、指標アドレス指定となります。
出席、課題のメールはta080017@mail.edu.i.hosei.ac.jpにお願いします。
質問のメールなどは、sigesada@edu.i.hosei.ac.jpまでお願いします。
授業の資料の最新版はhttp://www.edu.i.hosei.ac.jp/~sigesada/にあります。