情報処理工学
NAGASAKA Yasunori
2006/04/10
|
http://edu.isc.chubu.ac.jp/naga/index.html で公開中
1 はじめに
1.1 目標
1.2 コンピュータに関する代表的な資格
2 コンピュータで扱うデータ
2.1 データの種類と 2 進数
2.2 文字データ
2.3 構造を持ったデータ
2.3.1 ベクトル
2.3.2 行列
2.3.3 レコード
2.4 数値データ
2.4.1 2 進数, 16 進数, 2 の補数
2.4.2 固定小数点形式
2.4.3 浮動小数点形式
2.4.4 IEEE754, 浮動小数点形式の国際標準規格
2.4.5 練習問題
2.4.6 2 進化 10 進数
2.4.7 練習問題
3 コンピュータのハードウェア
3.1 コンピュータを構成する装置
3.1.1 練習問題
3.2 コンピュータに関連する単位
3.2.1 練習問題
3.3 様々なコンピュータ
4 コンピュータのソフトウェア
4.1 プログラミング言語
4.2 言語プロセッサ
4.3 オペレーティングシステム, OS
4.4 コンピュータの使用形態
5 CPU、マイクロプロセッサの機能
5.1 機械語命令とデータサイズ
5.2 CPU の内部構成
5.2.1 CPU 内各部の機能
5.2.2 レジスタの役割による分類
5.3 CPU の動作原理
5.3.1 機械語プログラムの例
5.3.2 メモリ上のプログラムとデータの配置
5.3.3 プログラム実行時の CPU とメモリの通信
5.4 主記憶、メモリ
5.5 アドレシング
6 アセンブリ言語 CASL II
6.1 仮想 16 ビット CPU COMET II の仕様
6.2 COMET II の命令
6.2.1 データ転送
6.2.2 算術演算
6.2.3 論理演算
6.2.4 比較
6.2.5 桁移動
6.2.6 分岐
6.2.7 スタック操作
6.2.8 サブルーチンコール、リターン
6.2.9 練習問題
6.2.10 練習問題
6.3 条件判断の記述方法
6.3.1 練習問題
6.4 スタック
6.4.1 スタックの使用例
6.4.2 練習問題
6.5 CASL II によるプログラミング
6.5.1 アセンブリ言語でプログラムを作る時の考え方
6.5.2 CASL II のプログラムの書き方
6.5.3 プログラムの例
6.5.4 練習問題
1 はじめに
1.1 目標
ハードウェア、ソフトウェア、データの表現法、
ネットワークなどのコンピュータに関連する様々な事柄を学ぶことによって、
コンピュータシステム全般の理解を深める。
1.2 コンピュータに関する代表的な資格
経済産業省が監督する「情報処理技術者試験」がよく知られており、権威もある。
様々な試験区分があるが、
基本情報技術者試験及び初級システムアドミニストレータ試験が最も合格しやすい。
最初はこのどちらかの試験の合格が目標となる。
この講義では、過去に情報処理技術者試験で出題された問題を時々演習として解いてみる。
2 コンピュータで扱うデータ
2.1 データの種類と 2 進数
論理値、数値、文字などがコンピュータ上ではデータとして処理される。
コンピュータ内部ではすべて数値 (2 進数) として表現される。
2 進数の 1 桁を 1 ビット(bit)と呼ぶ。
コンピュータで 2 進数を扱う場合、
8 ビットのデータを一固まりのデータとすることが多い。
8 ビットを 1 バイト(Byte)と呼ぶ。
2 進数はバイトが単位として使われることが多い。
2.2 文字データ
コンピュータで文字を表すデータを考える場合、
文字集合と文字コードという二つの概念が必要となる。
文字集合とは、処理または表現の対象として、
どの文字を採用してどの文字を採用しないかということを規定する。
文字コードとは、一つ一つの文字に対してどのような数値を割り当てるかという対応関係を表す。
以下の日本語の文字の表現で出てくるように、一つの文字集合に対して、
複数の異なった文字コードが存在することもある。
文字は、アルファベット、数字、記号などは 1 バイトで表現される。代表的
なコード体系として、ASCIIコードがある。平仮名、漢
字など日本語で使われる文字は 2 バイトの数値で表現される。日本語の文字を表す
コード体系は JIS コード、Shift JIS コード、EUC コード、Unicode などがある。
以下でそれぞれの文字コードの特徴を簡単に示す。
- ASCII コード : 1 バイトでアルファベット、数字、記号などを表現する。
名前は American Standard Code for Information Interchange の頭文字を取って並べたもの。
英数字を表す際にもっとも広く使われている。1 バイトの取り得る値のうち、
文字が割り当てられているのは 0x00 〜 0x7F までで、0x80 以上は未使用。
- EBCDIC コード : 1 バイトでアルファベット、数字、記号などを表現する。
名前は Extended Binary Coded Decimal Interchange Code の頭文字を取って並べたもの。
大型計算機でよく使用される。ASCII とはコードの割当が異なる。
- JIS コード : JIS コードは 1 バイトコードと 2 バイトコードの 2 種類がある。
1 バイトコードは ASCII コードで未使用の領域にカタカナや記号を割り当てたもので、
英数字の表現は少数の記号を除き ASCII コードと同じ。
この場合の文字集合には JIS X 0201 という名前が付けられている。
2 バイトコードは平仮名、漢字を表現する。1, 2 バイトコードの切替位置に、
特定の制御コードを埋め込むことで区切りを表す。
平仮名、漢字を表すこの場合の文字集合には JIS X 0208 という名前がある。
JIS コードは電子メールで標準的に使用されている。
- Shift JIS コード : 文字集合は JIS X 0208 が対象。JIS コードでは1,
2 バイトコードの切替に制御コードが必要であるが、
Shift JIS では漢字を表すコードを JIS X 0201 の未使用領域に移動(Shift)させることで
制御コードを不要としている。パーソナルコンピュータでよく使用される。
- EUC コード : 文字集合は JIS X 0208 が対象。
JIS 2 バイトコードの 8 ビット目を 1 にしている。JIS コードでは1,
2 バイトコードで同じ値が存在するため制御コードが必要だが、EUC コードでは
8 ビット目を 1 にすることで値が重複しない。よって制御コードが不要。
UNIX ワークステーションで主に使用されている。
- Unicode : 新しく策定された体系で、2 バイトで各国語を表現する。
JIS, Shift JIS, EUC コードは基本的なコード割当の考え方が同じなので、
相互変換が容易である。しかし Unicode は考え方が全く異なるので、
前述の 3 コードとの変換規則を定めることができず、
全文字の対応表を用意する必要がある。最近では、Windows や Mac OS が対応しており、
Java では標準の文字コードになっている。
JIS X 0208 に含まれる文字 6879 個中、漢字は 6355 個で、
使用頻度により第一水準 2965 個と第二水準 3390 個のグループに分けられている。
文字コードに関する詳しい解説が http://www.kanzaki.com/docs/jcode.html にて公開されている。
2.3 構造を持ったデータ
2.3.1 ベクトル
数学でよく使われるデータ形式で、コンピュータ上でシミュレーション、数値
計算を行う場合には同じ形式で使われる。n 次元のベクトルは、n 個の数値を
並べて一まとまりのデータとして扱う。
一般的な表記法は、
(x1,
x2, x3, ... ,
xn) となる。
コンピュータ上では 1 次元の配列として表現される。
例として C 言語では int a[10]; といった表現になる。
2.3.2 行列
数学でよく使われるデータ形式で、コンピュータ上でも広く使われる。
m × n 行列は、m × n 個の数値を縦に m 個、横に n 個になるように 2 次元状に
並べて一まとまりのデータとして扱う。
一般的な表記法は以下のようになる。
x11 x12
x13 ... x1n
x21 x22
x23 ... x2n
x31 x32
x33 ... x3n
...
xm1 xm2
xm3 ... xmn
コンピュータ上では 2 次元の配列として表現される。
例として C 言語では int a[10][10]; といった表現になる。
2.3.3 レコード
ベクトルと行列は数学的な概念で、そこに含まれるデータは数値のみである。
数値に限らず、文字列や論理値なども対象として、
コンピュータ上であるまとまった概念を表現するために、
様々な属性のデータを集めたものをレコードと呼ぶ。
例 一人の人間を表現するためのレコード
属性 : 値 : データの種類
----------------------------------
名前 : 中部太郎 : 文字列
性別 : 男性 : 数値、論理値
身長 : 175cm : 実数
体重 : 65kg : 実数
年齢 : 20 歳 : 整数
住所 : 春日井市松本町 1 番地 : 文字列
電話番号 : 0568-51-1111 : 数値、文字列
趣味 : 読書、音楽観賞、テニス、スキー : 文字列の配列
コンピュータ上ではこのような複雑な構造を持ったデータをプログラムで表現
して処理できるように、専用の仕組みが用意されることが多い。 例として C 言語では
構造体として表現される。
上記の人間を表現するレコードを C 言語の構造体として表現すると以下のようになる。
struct human {
char name[20];
int sex;
float height;
float weight;
int age;
char address[100];
int tel[20];
char hobby[10][10];
};
コンピュータで何らかの情報処理をしようとする場合、単純な数値や文字列だ
けでは適切に処理対象のデータを表現できないことが多い。ベクトル、行列、
レコードなどの構造化されたデータが必要となる。
2.4 数値データ
2.4.1 2 進数, 16 進数, 2 の補数
次の計算をしなさい。
わからない問題がある場合は、1 年生の時に学んだ数の表現の部分をよく復習すること。
- (101000101110110)2 を 10 進数に変換する。
- (1234.123)5 を 10 進数に変換する。
- (101000101110110)2 を 16 進数に変換する。
- (101000101110110)2 を 16 桁の 2 の補数に変換する。
- (53.6875)10 を 2 進数に変換する。
- (123.45)10 を 5 進数に変換する。
コンピュータ上で数値を扱う場合、その表現法は大きく分けて
固定小数点形式と浮動小数点形式の
2 種類がある。
2.4.2 固定小数点形式
小数点の位置を常に一定の位置に仮定して数を表現する方法である。
場合によって小数点の位置が変化することがなく、
常に固定されているのでこの名前がついている。
次の例は 16 bit の固定小数点形式で整数を表現した場合の例である。
S, # は 2 進数 1 桁を表す。
S###############. (最上位ビット S は符号を表す)
固定小数点形式で数を表現する場合、
事前に特別な取り決めがなければ、
上の例のように通常は右端の位置に小数点があるものとされる。
別の言い方をすると、コンピュータで一般的に使用されている整数の表現は、
数の右端に小数点の位置を固定した固定小数点形式であるといえる。
整数を表現する場合、負数の表現は 2 の補数が用いられることが多い。
ただし、小数点の位置はプログラムを作成する者が用途に応じて決められるので、
別の位置にすることもできる。例として、小数点以下は 0.25 の精度で表現すれば十分な場合、
小数点以下を 2 進数で 2 桁だけ用意した固定小数点形式を使えば良いといえる。
このような取り決めをこのプログラムやデータを使う者すべての間で事前にしておけば問題ない。
ただし取り決めを知らない第三者にとっては、このデータは無意味となる。
2.4.3 浮動小数点形式
浮動小数点形式は、その名前のとおり小数点の位置が場合によって異なる表現である。
コンピュータで小数点以下の部分を含む実数を表現する場合、ほとんどの場合固定小数点形式ではなく、
浮動小数点形式が使用される。
実数を仮数部 M, 指数部 E の組合せで表現する方法である。
以下ではまず 10 進数を表現する浮動小数点形式により、その基本的な考え方を示す。
その後コンピュータで実際に使用されている 2 進数による浮動小数点形式を示す。
10 進数の場合の例
(0.000391)10 を表現したいとする。
この時浮動小数点形式では、もとの数を 0.391 × 10-3
と変形する。ここで 0.391 を仮数、10-3 を指数と呼ぶ。
変形後は 391 と -3 を記憶する。
もとの数は 0.MMMMM × 10EEEEE の M,
E に 391, -3 を代入することで再現できる。
浮動小数点形式は次のような場合に有効である。
(3910000000000000)10 や
(0.0000000000391)10 といった数を表現したい場合、
固定小数点形式では十数桁の精度が必要である。
一方、0.391 × 10n と変形して、
391 と n を記憶しておけば高々 5, 6 桁の精度で十分となる。
このように浮動小数点形式は絶対値が非常に大きくなる場合、
小さくなる場合でも記憶するデータ量がそれほど増えないという特徴がある。
正規化
上記の変形で、仮数を 10-1 <= M < 1 にすることを
正規化という。
コンピュータ内部で記憶できる数は有限の桁数しかないため、
仮数部の限られた桁数でなるべく精度良く数を表現するために行う。
正規化の例
0.000391 を表現する時に、仮数部が仮に 3 桁だけ使用できるとすると、
0.039 × 10-2 → 039, -2 を記憶するのは ×
0.391 × 10-3 → 391, -3 を記憶するのは ○
もし 039, -2 を記憶すると、
本来表現できるはずの 391 の末尾の 1 が誤った正規化により消えてしまうからである。
現実のコンピュータでは、内部で表現、記憶できる数は必ず有限の桁数であるので、
限られた桁数でなるべく多くの桁を正しく表現するためには、
正しい正規化を行なうことが必要である。
2.4.4 IEEE754, 浮動小数点形式の国際標準規格
上記 10 進数の場合の表現は、浮動小数点形式の概念を説明するための例であり、
現実のコンピュータでは以下に示す浮動小数点形式の表現が使用される。
コンピュータで実際に使用されている浮動小数点形式は国際標準規格となっており、
IEEE754 (アイトリプルイー 754)という名前が付けられている。
IEEE754 は 32 bit 版と 64 bit 版があるが、基本的な考え方は同じで仮数部、
指数部に割り当てる bit 数が異なる。以下では 32 bit 版を示す。
次の図で、S, E, M, . はすべて 1 bit を表す。
IEEE754 のビットの割り当て
S |
...E.... |
...........M........... |
- 最上位ビット S はもとの数を符号を表し、0 の時正数、1 の時負数を表す。
2 の補数と同じ値が割り当てられているが、2 の補数と直接関連はない。
- 指数部 E は 8 ビットの大きさで、-127 〜 +128 を表す。2 の補数は使わない。
- 仮数部 M は 23 ビットの大きさであるが、暗黙の 1 ビット(後述)があるため精度は
24 ビット分ある。
- 正規化は 1.MMMMM × 2EEEの形にする。
正規化の例
IEEE754 は先の 10 進数の例とは異なる特有の正規化を行なう。例として、
0.0001011 → 1.011 × 2-4
11011.11 → 1.101111 × 24
-0.0010111 → -1.0111 × 2-3
-1111.011 → -1.111011 × 23
などの例を挙げておく。
ポイントは小数点の左に 1 bit だけ残すことである。
また浮動小数点形式では 2 の補数は関係しないので、
負の数の表現は正規化の段階ではそのままマイナス符号を付けておけばよい。
暗黙の 1 ビット
仮数部の最初の 1 (小数点の左の1) は常に一定なので、仮数部 M には直接記録しないようにする。
M としては小数点以下を 23 ビット記録する。
よって記録しているのは 23 ビットであるが、24 ビットの精度がある。
指数部 E の表現
指数部 E は符号無し 8 ビットの整数で表現する 2 進数 0 〜 255 から 127 を減算した値で、
-127 〜 +128 を表す。2 の補数を用いないので注意する。
8 ビットの値と E の解釈の対応は以下の通り。
指数部 E の解釈
00000000 |
-127 |
00000001 |
-126 |
00000010 |
-125 |
00000011 |
-124 |
途中略 |
途中略 |
01111110 |
-1 |
01111111 |
0 |
10000000 |
1 |
10000001 |
2 |
10000010 |
3 |
10000011 |
4 |
途中略 |
途中略 |
11111110 |
127 |
11111111 |
128 |
(この形式では E の大小関係が 符号無し 8 ビットの 2 進数にそのまま対応するので、
指数部の処理が容易になる。すなわち絶対値の大小が、
そのまま 8 ビットの整数の大小として表現される。
もし 2 の補数を用いたとすると大小関係が途中から反転するため、扱いが難しい。)
問題
IEEE754 はこのままでは一つ困った問題を抱えることになるが何か ?
計算の例
例として 10 進数の 60.125 なら、
(60.125)10 → 2 進数に変換 →
(111100.001)2 → 正規化 →
1.11100001 × 25 → 指数部、仮数部を求める →
0 10000100 11100001000000000000000 → (指示があれば 16 進で書く) →
0100 0010 0111 0000 1000 0000 0000 0000 → 42708000
正の数なので、符号ビットは 0 になる。
指数部は 5 なので 127 を加えた 132 を 8 bit の整数で表し 10000100 となる。
仮数部は正規化した式の小数点以下 11100001 に 23 桁になるまで 0 を加える。
別の例として 2 進数の -11100111.01 なら、
(-11100111.01)2 → 正規化 →
-1.110011101 × 27 → 指数部、仮数部を求める →
1 10000110 11001110100000000000000 → (指示があれば 16 進で書く) →
1100 0011 0110 0111 0100 0000 0000 0000 → C3674000
負の数なので、符号ビットは 1 になる。
指数部は 7 なので 127 を加えた 134 を 8 bit の整数で表し 10000110 となる。
仮数部は正規化した式の小数点以下 110011101 に 23 桁になるまで 0 を加える。
2.4.5 練習問題
(1)
次の各数を IEEE754 にしたがって表現しなさい。答えは正規化した形と、
浮動小数点形式のビットパターンを 8 桁の 16 進数に変換して示しなさい。
- 53.687510
- -12710
- 10101010102
- 0.0000012
(2)
次の各数を 2 進数の正規化した形で示しなさい。
また浮動小数点形式のビットパターンを示しなさい。
- IEEE754 で表現可能な最大の数
- IEEE754 で表現可能な最小の数
- IEEE754 で表現可能な正数で絶対値最小の数
- IEEE754 で表現可能な負数で絶対値最小の数
2.4.6 2 進化 10 進数
2 進化 10 進数 (BCD, Binary Coded Decimal) は、2 進数 4 桁の 0000 〜
1001 までを使って 10 進数 1 桁の 0 〜 9 を表現する方法である。
演算を行う場合は通常の 2 進数とは異なり、4 桁毎に特別な桁上がりの処理が必要となる。
2 進化 10 進数は、その表現法の違いからゾーン形式とパック形式という 2 種類の表現がある。
ゾーン形式
ゾーン形式は 1 バイトのデータの下位 4 ビットのみを使って 10 進数 1 桁を表す。
上位 4 ビットの扱いは処理系により異なる。
値の範囲は ####0000 〜 ####1001 となり、0 から 9 までを表す。# は未使用ビットを表す。
パック形式
パック形式は 1 バイトを上位、下位の 4 ビットずつに分けて、それぞれで 10 進数 1 桁を表す。
よって 1 バイトで 10 進数 2 桁を表現できる。
上位 4 ビットに表す数がない場合の扱いは処理系により異なる。
00000000 〜 10011001 で 0 から 99 までを表す。
例
例としていくつかの数を 2 進化 10 進数のゾーン形式とパック形式で表現してみる。
ここでは使用していないビットはすべて 0 で埋めるものとする。
7 はゾーン形式では 00000111, パック形式では 00000111 となる。
23 はゾーン形式では 00000010 00000011, パック形式では 00100011 となる。
578 はゾーン形式では 00000101 00000111 00001000,
パック形式では 00000101 01111000 となる。
6625 はゾーン形式では 00000110 00000110 00000010 00000101,
パック形式では 01100110 00100101 となる。
2.4.7 練習問題
以下の数をゾーン形式とパック形式の両方で表しなさい。
未使用領域は 0 で埋めるものとする。
- 9310
- 15010
- 634510
- 2105010
3 コンピュータのハードウェア
3.1 コンピュータを構成する装置

コンピュータを構成する装置
3.1.1 練習問題
上の図に関して以下の問いに答えなさい。
- Central Processing Unit を日本語 1 単語で表す場合の名称 (〜装置) を答えなさい。
- Central Processing Unit の機能を 2 個答えなさい。
- Central Processing Unit を日本語 2 単語で表す場合の名称
(〜装置, 〜装置) を答えなさい。(前問の答えに関連がある。)
- Input Device を日本語で表す場合の名称を答えなさい。
- Input Device に該当する具体的な装置を一つ答えなさい。
- Main Memory Unit を日本語で表す場合の名称を答えなさい。
- Main Memory Unit は読み出しのみと読み書き可の 2 種類に分けられるが、
それぞれの英語の正式な名称と省略形の名称を答えなさい。
- Main Memory Unit で使用される読み書き可能な LSI は、
その仕組みの違いから 2 種類存在するが、
その名称とデータを記憶する仕組みを答えなさい。
- Output Device を日本語で表す場合の名称を答えなさい。
- Output Device に該当する具体的な装置を一つ答えなさい。
- Secondary Memory Unit を日本語で表す場合の名称を答えなさい。
- Secondary Memory Unit に該当する具体的な装置を一つ答えなさい。
- 次の表の空欄に適当な言葉を書き込みなさい。
違い
|
Main Memory |
Secondary Memory |
反応速度 |
? |
? |
記憶容量 |
? |
? |
電源を切ると |
? |
? |
- 「現在のコンピュータは人間があらかじめプログラムを作成し、
実行する時には ? に読み込んでおく必要がある。」
? に当てはまる適当な言葉を答えなさい。
- 「読み込まれたプログラムは、そこから順に 1 命令ずつ読み出して
CPU で実行される。」
この文章は現在のコンピュータの動作原理を表しているが、これを
? 方式と呼ぶ。? に当てはまる適当な言葉を答えなさい。
- 前問の方式で動作するコンピュータを ? 型コンピュータと呼ぶ。
? に当てはまる適当な言葉を答えなさい。
3.2 コンピュータに関連する単位
記憶容量
記憶容量を表す単位は以下のようなものがあるが、これらの単位は通常の単位と異なり、
10n で表す場合と、1024n
で表す場合の 2 種類の解釈があるので注意する。どちらの方式で計算されているかは、
単位を見ただけではわからないので、正確な値が必要な場合は確認する必要がある。
記憶容量の単位
単位 |
表す内容 |
1 kB |
103 または
1024 バイト |
1 MB |
106 または
10242 バイト |
1 GB |
109 または
10243 バイト |
1 TB |
1012 または
10244 バイト |
1 PB |
1015 または
10245 バイト |
1 EB |
1018 または
10246 バイト |
時間
時間を表す単位は以下のようなものがある。記憶容量とは異なり、
こちらは 10n だけである。1 秒より長い時間を表す場合は、
60 や 24 など不規則な値が単位の変化する区切りとして使用されるが、
1 秒より短い時間はすべて 10n が使用されるので、長さや重さと
同じように考えやすい。
時間の単位
単位 |
表す内容 |
1 msec |
10-3 |
1 μsec |
10-6 |
1 nsec |
10-9 |
1 psec |
10-12 |
1 fsec |
10-15 |
3.2.1 練習問題
- クロック周波数 2GHz の CPU のサイクルタイムを求めなさい。
- 反応時間が 60nsec の半導体メモリと 10msec の HDD は何倍の差があるか。
- 40GB の HDD には 1.44MB の FD 何枚分のデータが記録できるか。
- 40GB の HDD は何億ビット記録できるか。
- 1 人分のデータを 1KB で記録する時、40GB の HDD には何人分入るか。
- 光の速度を 30 万km/sec とする時、1nsec にどれだけの距離進むか。
3.3 様々なコンピュータ
ここでは、現在のコンピュータを価格、用途、性能等をもとにして分類してみる。
- スーパーコンピュータ : 数値計算を非常に高速に実行する。非常に高価である。
- 大型コンピュータ (汎用コンピュータ、メインフレーム) : 数値計算、
事務処理など幅広い用途で使用される。大規模なシステムで、
スーパーコンピュータに次いで高価である。
- ミニコンピュータ (オフィスコンピュータ) : 大型コンピュータと同様の用途で使用される。
規模は比較的小さく、安価で中小規模のシステムを構成する。
- プロセスコンピュータ : 大型コンピュータやミニコンピュータで、
特に工場の生産ラインの管理や制御に使用されるものを表す。
- ワークステーション, WS : 小型だが高度な演算性能を備えたシステムで、
最初は科学技術計算や研究用途で使用された。現在は幅広く事務処理等にも使用される。
- パーソナルコンピュータ, PC : 個人で利用する安価なコンピュータ。
ここ数年の性能向上の度合が著しい。
- マイクロコンピュータ : システムとしてのコンピュータではなく、
機械や電気機器等に組み込まれて制御用に使用される。
- マイクロプロセッサ : マイクロコンピュータと近い意味を表すが、
組み込み用途だけでなくワークステーションやパーソナルコンピュータの CPU
として使用されるものも表す。演算や他の装置の制御機能などの、
コンピュータの主要な機能を少数個の LSI にまとめている。
現在は WS, PC の能力が非常に向上しており、
単純な計算速度で比較すると上位のコンピュータとの差が小さくなっている。
CPU の能力は差が小さくなったが、その他の性能、
例えばファイルの入出力の速度や可用性など、
システム全体の性能は大規模なコンピュータと安価なコンピュータでは違いがある。
WS, PC の能力が向上したため、
従来メインフレームやミニコンで行っていた処理を安価な
WS, PC で行わせることをダウンサイジングと呼ぶ。
4 コンピュータのソフトウェア
4.1 プログラミング言語
プログラミング言語とは、プログラムを作成する(書く)ための専用の言語であり、
コンピュータの動作を指示するプログラムを記述するために人工的に作り出された。
プログラミング言語は様々な用途でこれまでに多数開発されている。
プログラムは最終的には CPU で実行可能なコードとして表現する必要がある。
人間がプログラムを記述する時の表現の仕方が、
コンピュータの動作に直結した内容を記述する(機械向き)か、
人間の思考方法に近い記述をする(人間向き)かで分類される。
前者を低級言語、後者を高級言語と呼ぶが、この低級/高級という表現は分類を表す名前であり、
低級言語が高級言語より劣っているという意味ではない。
低級言語から高級言語までは言語の記述内容のレベルにより大きく次の 3 段階に分けられる。
- 機械語, マシン語 : 低級言語で、最も機械向きの表現。
CPU の内部動作に直接対応したコード。
コンピュータの動作を一つ一つ厳密に指定したい場合に向いている。
反面、この言語で記述したプログラムは数値の並びになるので、
人間にとっては理解するのが難しい。
この数値の並びをコンピュータに入力するとそのまま実行できる。
表現の例 : 00 60 73 C5 91 26 ...
- アセンブリ言語 : 低級言語と高級言語の中間に位置する。
表現できる内容は機械語に完全に一致するが、
人間が理解し易いように数値の並びではなく記号の組み合わせで表す。
アセンブリ言語のプログラムは機械語と一対一の対応関係があるので、
変換が比較的容易である。
表現の例 : LD A, DATA1 や ADD A, B や JP LOOP など
- 高級言語 : 人間が理解し易いように、またプログラムを考え易いように作られた言語。
プログラムの記述能力や、抽象的な概念の表現力を考慮して作られており、
人間の思考過程をある程度自然に表現できる。その反面、
記述内容が機械語と一対一に対応しないため、機械語への変換は非常に複雑な処理になる。
高級言語には多くの種類があり、用途に応じて好みのものを選択できる。
高水準言語の例 : C, C++, JAVA, FORTRAN, COBOL, PASCAL, BASIC,
LISP, PROLOG, FORTH
表現の例 : DATA3 = DATA1 + DATA2;
以下は C 言語のプログラムの例である。
for (i = 0; i < 10; i++) {
sum += i;
}
機械語、アセンブリ言語、高級言語はそれぞれ多くの種類がある。
機械語は CPU のハードウェア 1 種類につき一つずつある。
機械語は世の中の CPU の種類だけあると言ってもよいだろう。
機械語一つにつきアセンブリ言語が一つある。
高級言語は用途やその言語の開発時の目的などに応じて多数作られてきたが、
CPU のハードウェアには直接関係しない。
4.2 言語プロセッサ
プログラミング言語で記述されたプログラムを、
実行可能な機械語のプログラムに変換するプログラムを言語プロセッサと呼ぶ。
- アセンブラ : アセンブリ言語で記述されたプログラムを機械語に変換する。
- コンパイラ : 高級言語で記述されたプログラムをアセンブリ言語または機械語に変換する。
- インタプリタ : 高級言語で記述されたプログラムを逐次機械語に変換して実行する。
対話的に利用できるため、実行を始めて間違いが見つかったところで中断し、
すぐにプログラムを修正、再実行することができる。
コンパイラとインタプリタは高級言語を機械語に変換するという点で似ているが、
プログラムを実行する方法が異なるので使い分けがされる。例として、
あるプログラムを実行する時に、どちらも 11 分かかるとする。

コンパイラとインタプリタ
コンパイラはプログラム全体を一括して機械語のプログラムに変換する。
この例では 10 分かかるが、その間人間は待っている必要がある。
変換が終了すれば実行は 1 分でできる。
もし実行結果が間違っていた場合、
プログラムを修正して再度機械語に変換する必要があるが、ここでも 10 分かかる。
しかし一旦正しいプログラムが完成すれば、
その後は何回実行しても必要なのは実行に要する時間だけで、
10 回実行すれば 10 分で実行が終る。
インタプリタはプログラムを先頭から 1 命令ずつ機械語に変換して実行していく。
全体を変換、実行するには 11 分かかるが、
プログラムを実行し始めて 2 分のところで間違いが見つかれば、
そこで中断して修正に移ることができる。開発中で実行、中断、修正を繰り返す場合は、
コンパイラを使用するよりも効率が良い。しかしプログラムが完成した後も実行するには 11 分かかる。
10 回実行すれば 110 分必要となる。実行時間が問題となる場合はインタプリタは向いていない。
4.3 オペレーティングシステム, OS
オペレーティングシステムは、基本ソフトウェアと呼ばれ、
コンピュータを利用する上でいくつかの重要な機能を持っている。
- ハードウェアを管理、制御すること、
及び様々な処理のハードウェアに依存した部分をプログラムとして備えており
API を一般のアプリケーションプログラムに提供する。
-
二つめはコンピュータの様々な機能を人間が利用しやすいように、ユーザインタフェースを提供する。
-
複数のプログラムを並列に実行可能なシステムでは、
プロセス(プログラム)の優先順位を決めて各プロセスを実行する際のスケジューリングを行う。

オペレーティングシステムの役割
オペレーティングシステムの機能のわかりやすい例として、
マウスを動かした時にマウスカーソルが画面上で移動することや、
キーボードから入力した文字が画面に表示されるといったことがある。
これらは、マウスやキーボードを制御して入力されたデータを読みとるプログラムや、
ディスプレイを制御してデータを画面に表示するというプログラムを OS が備えており、
これらがユーザインタフェースの一環として実行されているからである。
オペレーティングシステムがなければコンピュータは全く使用できないと言える。
4.4 コンピュータの使用形態
1 台のコンピュータを複数の使用者で利用する場合、以下のような使用形態がある。
- トランザクション処理 : 銀行の CD 機、鉄道や飛行機の座席予約など、
特定の業務における一定の処理を行う場合を指す。典型的な例として、
中央に大規模なコンピュータとデータベースがあり、
ネットワークで接続された端末からデータを操作する場合が相当する。
- バッチ処理 : 利用するプログラムをあらかじめ待ち行列に登録しておき、
自分の順番が来たらまとめて実行される。昔の大型コンピュータの主要な使用法で、
利用者はコンピュータが設置してある場所まで出向いて作業する必要がある。
- 会話型処理 : ネットワークで接続された端末からコンピュータに指示を送ることができ、
多数の人が同時に使用していても、
各使用者にはまるで自分がコンピュータを独占して使用しているように感じられる。
利用者はコンピュータが設置してある場所まで出向く必要がなく、遠隔地から利用できる。
会話型処理を実現するには、
多数のプロセスを高速に切替えながら並行して実行する機能が必要である。
会話型処理は TSS (Time Sharing System) とも呼ばれる。
5 CPU、マイクロプロセッサの機能
5.1 機械語命令とデータサイズ
機械語命令の種類として、算術演算、論理演算、順序制御、入出力、データ転送などがある。
n ビットの CPU という場合、一般にはレジスタ長が n ビットであることを表す。
またデータバスのサイズも n ビットであることが多い。
CPU のレジスタ長と直接扱える数値の範囲
ビット数 |
扱える数値の範囲 |
4 |
24 = 16 |
8 |
28 = 256 |
16 |
216 = 65536 |
32 |
232 = 4.295 × 109 |
64 |
264 = (232)2 |
5.2 CPU の内部構成

内部構成
ここでは例として代表的な 8bit CPU である Z80 を取り上げる。
Z80 はザイログ社が開発した CPU で、インテル社の 8080 の上位互換の機能を持っている。
Z80, 8080 は 30 年程前に広く使用されていた CPU で、
8 bit CPU の代名詞となっている。
当時から産業用でも広く使われており組み込みのコントローラとして使用されてきた。
これまでに開発されたソフトウェア資産が膨大であり、
コントローラの能力がそれほど必要でない場面では現在でも広く使用されている。
プロセッサの基本的な動作原理は 4 bit CPU でも、32 bit CPU でもほとんど同じである。
よって 8 bit CPU の Z80 についての知識でも、
最近の高性能な 32 bit CPU, 64 bit CPU の機能の理解に役立つ。
処理能力を上げるための特別な仕組みがないため、
CPU そのものの機能を理解するための教材としてちょうどよいといえる。
5.2.1 CPU 内各部の機能
CPU には、先に示した CPU の内部構成の図にあるように様々な要素があり、
相互にデータや信号をやりとりしてプログラムを実行していく。
- ALU : 2 個のレジスタから値を入力し、算術論理演算を行う。
- CPU レジスタ : プロセッサ内部でデータを記憶しておくところ、汎用レジスタとも呼ぶ。
現在の CPU ではほとんどの場合 CPU レジスタの用途は固定されておらず、
算術演算、論理演算、アドレスの計算、操作などに汎用的に利用できる。
もし用途が限定される場合は下の 2 種類の名前で呼ばれることもある。
- (演算レジスタ) : 算術論理演算を行う対象のデータを記憶しておくところ。
- (インデックスレジスタ) : メモリ、周辺装置のどこをアクセスするかを指定する数値
(番地, アドレス) を記憶しておくところ。
- PC : プログラムカウンタ : 次に実行する命令のアドレスを保持する。
- IR : 命令レジスタ : 実行対象の命令 (2 進数で表現される) を保持する。
- SP : スタックポインタ、スタックの一番上のデータの番地を示す。
- システム制御部 : プロセッサの動作を管理して、必要な信号を各部に送る。
制御信号を読み込んだり外部に出力する
- データバス(制御) : レジスタとメモリ、
周辺装置との間でデータの送受信をする時のデータの通り道。入出力可能。
- アドレスバス(制御) : メモリ、周辺装置のどれをアクセスするか、
番地を指定する時のデータの通り道。出力専用。
- システム制御信号 : プロセッサと周辺回路との間で互いの状態を通知する信号。
なぜ 8 ビット CPU なのに、AB は 16 ビットなのか ?
→ AB が 8 ビットではメモリ容量が少な過ぎる (256 Byte) から。
メモリが 256 Byte では実用的なプログラムは全く記憶できず、
コンピュータとして役に立たない。
同じ理由で 16 ビット CPU なのに、8086 では AB が 20 ビット、
68000 では AB が 24 ビット に拡張されている。
32 ビット CPU では AB も 32 ビットに拡張されており、
特別な工夫をしなくても 4GB のメモリが使用できる。
通常の用途では現在でも十分な広さのメモリアドレスの空間があるといえる。
5.2.2 レジスタの役割による分類
Z80 のレジスタはアルファベットの名前が付けられており、
プログラムで処理するデータを記憶するための汎用レジスタとして A,B,C,D,E,H,L がある。
A レジスタだけは下記にあるように多少特別な役割を持っている。
他にも F,I,R などの様々なレジスタがあるが、
これらは用途が決められていてプログラムで自由に使うことはできない。
また IX, IY, PC, SP レジスタはアドレスを処理対象として扱うため 16 bit 長となっている。
図中、白い部分は 8080 CPU にあるレジスタで、
薄いグレーの部分は Z80 で新たに加えられたレジスタである。
A' から L' までは「裏レジスタ」と呼ばれるレジスタで、8080 CPU との互換性を保ちつつ、
レジスタの少なさを緩和するための工夫である。

レジスタ
- A レジスタ : ALU への入力、出力を保持する。accumulator と呼ばれることもある。
- B,C,D,E,H,L レジスタ : 汎用レジスタ。演算対象のデータを保持する。16bit のデータを扱う時は、
BC, DE, HL が組になり、仮想的な 16bit レジスタとして使用できる。
- F レジスタ : フラグレジスタ。種々の演算の結果を 1 bit のフラグの組み合わせで保持する。
- I レジスタ : 割り込み処理ルーチンの先頭番地を表す。
- R レジスタ : DRAM の記憶内容保持のためのリフレッシュ動作の番地管理
- IX, IY レジスタ : メモリアクセスの際の番地指定専用、インデックスレジスタ
- PC : プログラムカウンタ、次に実行する命令の番地を保持する
- SP : スタックポインタ、スタックの一番上のデータの番地を示す
(ヒント):リフレッシュとは : DRAM, Dynamic RAM はコンデンサに蓄えた電荷でデータを記録する
ため、一定時間アクセスがないと放電により内容が消えてしまう。そのため記憶データを
使わない時でも時々読み出して同じ内容を書き込む操作が必要となる。この操作を
リフレッシュと呼ぶ。
算術演算、論理演算を行なう時はレジスタから値を取り出して ALU で必要な演算をした後、
A または HL レジスタペアに結果が記憶される。
また演算結果を表す様々な値が F レジスタに記憶される。これらの値としては、
結果が 0 になったか、
結果が負数になったか、
桁上がりが発生したか、などがあり、プログラム中の条件判断の時に参照される。

8bit 演算

16bit 演算
5.3 CPU の動作原理

CPU とメモリ
プログラム記憶方式に基づいて作られている CPU は、
次の手順にしたがってメモリの先頭から順に命令を読み出し、実行していく。
この動作原理は、特殊な CPU の場合を除いて、すべての CPU に共通する。
- PC に実行開始番地をセットする。
- AB に PC の内容を出力して番地を指定する。
- DB から、指定した番地の内容を読み取り、IR にセットする。
これをフェッチと呼ぶ。 PC ← PC + 1
- システム制御部により IR の内容が解読される。これをデコード
と呼ぶ。
- 命令を実行する。
- 2 に戻る。
Z80 の制約として、DB が 8 ビットなので、
メモリからは一度に 1 Byte しか読み込むことができない。
また、Z80 では 1 Bytes 〜 4 Bytes の可変長の機械語命令を採用している。
(機械語命令の例 : 01111000 = 78H : LD A, B
B レジスタのデータを A レジスタに転送するという命令)。
このため上記の手順は、読み出しの部分が場合によって複数回に分かれるため、
下記のようになる。
- PC に実行開始番地をセットする。
- AB に PC の内容を出力して番地を指定する。
- DB から指定した番地の内容を読み取り、IR にセットする。
PC ← PC + 1
- システム制御部により IR の内容が解読される。
1 バイト命令なら 6 へ進む。
- 2 バイト以上の命令については、(2),(3) を必要な回数繰り返す。読み込んだ
データは CPU 内部のバッファに保持する。
- 命令を実行する。
- 2 に戻る。
5.3.1 機械語プログラムの例
例 (2000) のデータと (2001) のデータを加算して (2002) に格納する機械語のプログラムが
1000 番地から配置されている場合
※ (2000) という表現は、機械語プログラムの内容を記述する場合に、
メモリの 2000 番地という意味でしばしば用いられる。
ここでもこのような意味で ( 数値 ) という表現を用いる。
したがって上記のプログラムは、メモリの 2000 番地と 2001 番地のデータの和を 2002 番地に
記録するという動作になる。
※ Z80 ではメモリへの入出力、算術論理演算はA レジスタでしか行えない
という制約があるため、多くの場合データは A レジスタを介して操作される。
このプログラムは、次に示す一連の命令の組み合わせとして記述する。
- メモリの 2000 番地からデータを A レジスタに読み込む。
- そのデータを一旦 B レジスタにコピーする。(A レジスタを空けるため)
- メモリの 2001 番地からデータを A レジスタに読み込む。
- A レジスタと B レジスタの和を A レジスタに記録する。
- A レジスタの内容をメモリの 2002 番地に記録する。
- 終了。
5.3.2 メモリ上のプログラムとデータの配置
このプログラムを機械語で記述してメモリの適切な位置(仮に 1000 番地とする)に記録すると、
次の図に示すようなイメージになる。
この図では左に 0000, 1000, 1001, 1002 などの数値が付けられているが、
横 1 行が一つの記憶場所を表しており、1 バイトの容量がある。

プログラムとデータの配置
メモリ中のプログラムとデータに関して、次のような特徴がある。
- メモリの 0000 番地からは、通常 BIOS (Basic Input Output System)
と呼ばれる特別なプログラムが置かれるので一般のアプリケーションプログラムは置けない。
- データが 2000 -- 2002 番地まで置かれるので、プログラムは他の番地に置く必要がある。
ここでは 1000 番地としたが、他の番地でもよい。
- 1000 番地から始まる最初の命令は 3 バイトの長さで、最初の 1 バイトが命令の内容
(指定したメモリの番地からデータをレジスタに読み込む) を表し、
続く 2 バイト 00, 20 が合成されて 2000 番地を表す。1004, 1007 番地の命令も同様。
- 1003, 1007 番地の命令は番地指定がないので 1 バイトで完結している。
- 最後にはプログラムを終了または停止させる命令を置く。
- この図では、プログラムとデータが区別できるように描いているが、
実際にメモリに記録されている値を見ただけではプログラムなのか、
データなのかはわからない。メモリ上では単なる数値でしかない。
5.3.3 プログラム実行時の CPU とメモリの通信
上記のプログラムを実行する時には、
次に示すように CPU と メモリ間で様々なデータが送受信される。
1000 → AB ; LD A, (2000) ; 2000 番地のデータを A レジスタに読み込む。
IR ← DB ; 参考までにこの命令の最初の 1 バイトは 3A である。
; 命令の最初の 1 バイトを解読すると 3 バイト命令とわかるので残り 2 バイトを読む
1001 → AB
バッファ ← DB (00)
1002 → AB
バッファ ← DB (20)
2000 → AB
A ← DB ; (Q.1)
1003 → AB ; LD B, A ; A レジスタの内容を B レジスタにコピーする。
IR ← DB
B ← A ; (Q.2)
1004 → AB ; LD A, (2001) ; 2001 番地のデータを A レジスタに読み込む。
IR ← DB
; 同様に (1005), (1006) から 01, 20 を読む
2001 → AB
A ← DB ; (Q.3)
1007 → AB ; ADD A, B ; A レジスタと B レジスタの内容の和を求め A レジスタに書きこむ。
IR ← DB
A ← A + B ; (Q.4)
1008 → AB ; LD (2002), A ; A レジスタの内容を 2002 番地に書きこむ。
IR ← DB
; 同様に (1009), (100A) から 02, 20 を読む
2002 → AB
A → DB ; (Q.5)
100B → AB ; HALT ; プログラムの実行を停止する。
IR ← DB
; 終了
5.4 主記憶、メモリ
メモリには場所を指定するために一定の記憶容量毎に固有の番地(アドレス)が割り当てられている。
番地の割り当て方には以下の 2 種類がある。
- バイトマシン : 1 バイト毎に番地を付ける。
- ワードマシン : 1 ワード(16, 32, 64, ... ビット)毎に番地を付ける。
ワードとは、CPU が一度に扱える自然なデータの大きさで、
32 bit CPU であれば 32 bit が 1 ワードとなる。
32 bit CPU はデータバスも通常 32 bit あるので、
メモリの番地は 32 bit (4 Byte) に一つ割り当てれば問題はないが、
慣例として現在でもほとんどすべてバイトマシンが採用されている。
32 ビット CPU などビット数の大きな CPU を採用していて、
かつバイトマシン形式の番地割当を採用している一部のコンピュータでは、
4 の整数倍の値 (0, 4, 8, 12, ...)
から始まるメモリの番地しか指定できないという制約がある。
その場合、メモリは 1 バイト毎に 1 個番地の値が存在するが、4 の整数倍以外の
途中の値を指定するとメモリアドレスに関する特有のエラー (Alignment Error) になる。
具体的な例として、上記の制約があるコンピュータでは、
図中のグレイの部分のように 4 の整数倍の値の番地から始まる連続した 4 バイトのアクセスは許される。
もし 2 番地から始まる連続した 4 バイトを読みだしたい場合、
この制約がなければ番地の値として 2 を指定すれば 1 回のメモリアクセスで完了するが、
制約がある場合は 0 番地からと 4 番地からの 2 回に分けてデータを読み出して、
その後で必要部分を取り出して合成する必要があり効率が悪い。

メモリアクセス上の制限
このような問題もあるが、その一方で
指定可能な番地の値に制約を設けることによって、
メモリアクセスに関連するデータバス、アドレスバスの回路設計が、
必要以上に複雑になるのを避けられるというメリットもある。
5.5 アドレシング
CPU が処理対象のデータをどこから取ってくるか、
場所を指定することをアドレシングという。
以下のような種類がある。
下の図では、グレイの部分のデータが参照したいデータを表している。
参考までに、少し前に出てきた内容の CPU の動作原理、
CPU の動作例で示した機械語プログラムの例では、
処理の一部にメモリアクセスを含んでいた。
その部分の機械語命令の一部分に、参照するメモリの番地が直接含まれていたが、
この場合のアドレシングは直接番地方式を使用していたといえる。
- 直接番地方式 : 番地部の値そのものがメモリの番地を示す

直接番地方式
- 間接番地方式 : 番地部で示される番地のメモリの値が実際にデータが
入っている場所の番地を示す。

間接番地方式
- 相対番地方式 : 番地部の値と PC の和がメモリの番地を示す。
番地部は PC からの偏位、ずれを表す。

相対番地方式
- インデックス修飾方式 : 番地部の値とインデックスレジスタの和が
メモリの番地を表す。

インデックス修飾方式
- 即値方式 : 番地部の値をそのままデータとする方式。

即値方式
- レジスタ指定方式 : レジスタ番号を指定してそのレジスタの
値をデータとする。

レジスタ指定方式
6 アセンブリ言語 CASL II
6.1 仮想 16 ビット CPU COMET II の仕様
- 16 ビット CPU であり、ワードサイズ 16 ビット、レジスタサイズ 16 ビット、
データバス 16 ビット、アドレスバス 16 ビット
- ワードマシン形式のアドレスの割り当て方で、アドレス空間 64KW、
アドレスの取り得る値 0000 〜 FFFF
- 機械語は 1 語または 2 語の可変長と規定されているが、
機械語表現の詳細は規定されていない。
- 16 ビットの符号無し整数と符号付整数(2の補数)を扱うことができる。
浮動小数点形式の表現は未対応。
- レジスタは、汎用レジスタ GR, スタックポインタ SP,
プログラムレジスタ(プログラムカウンタ) PR, フラグレジスタ FR がある。
- 汎用レジスタは GR0 〜 GR7 の 8 個があり、
GR1 〜 GR7 はインデックスレジスタとしても使用可
- フラグレジスタは、演算結果の溢れを表す OF (Overflow Flag),
符号を表す SF (Sign Flag), 結果がゼロになったことを表す ZF (Zero Flag) がある。
- 算術演算には符号無し整数として演算を行う論理加算、
論理減算と符号付整数として演算を行う算術加算、算術減算がある。
COMET II の命令の構成
- OP : 命令コード
- GR : 演算対象汎用レジスタ
- ADR : 番地
- XR : インデックスレジスタ
OP をオペコード(動作の内容「どうする」を表す部分)、
GR, ADR, XR をオペランド(動作の対象「何を」を表す部分)と呼ぶ。
オペランドは最大で 3 個指定する。同じ種類のオペランドを複数個指定することはない。
すなわち、1 命令の中に GR を 2 回指定したり、ADR を2 回指定することはない。
命令の書き方は以下の 4 種類がある。命令により必要とされるオペランドが異なる。
[, XR] は省略可能で、命令を記述する時に書くか書かないかを決められる。
OP GR, ADR [, XR]
OP ADR [, XR]
OP GR
OP
6.2 COMET II の命令
6.2.1 データ転送
データ転送を行なう命令は LD (Load), ST (Store), LAD (Load Address) の 3 種類がある。
LD はメモリからレジスタへの転送、ST はレジスタからメモリへの転送、
LAD は数値をレジスタに転送する。レジスタ間のデータ転送は LD 命令で行なえる。
LD, ST はオペランドの書き方は同じであるが転送の向きが逆、
また LD, LAD は見た目がよく似ているが機能が異なるので注意する。
LD は番地部で指定した値がメモリのアドレスを表し、メモリの指定した場所からデータを取り出す。
LAD は番地部で指定した値そのものをレジスタに書き込む。
以下は具体的な記述の例である。
- LD GR0, GR1 ; ----- GR1 の内容を GR0 に転送(コピー)する
- LD GR0, 1000 ; ----- メモリの 1000 番地の内容を GR0 に転送する
- LD GR0, 1000, GR1 ; ----- メモリの (1000+GR1) 番地の内容を GR0 に転送する
- ST GR0, 1000 ; ----- GR0 の内容をメモリの 1000 番地に転送する
- ST GR0, 1000, GR1 ; ----- GR0 の内容をメモリの (1000+GR1) 番地に転送する
- LAD GR0, 1000 ; ----- 1000 という値を GR0 に転送する
- LAD GR0, 1000, GR1 ; (1000+GR1) という値を GR0 に転送する
6.2.2 算術演算
算術演算の命令は、算術加算 ADDA (Add Arithmetic), 論理加算 ADDL (Add Logical),
算術減算 SUBA (Subtract Arithmetic), 論理減算 SUBL (Subtract Logical) の 4 種類がある。
算術加算/減算は計算対象の数を2 の補数として扱う。
論理加算/減算は計算対象の数を符号無し整数として扱う。
使えるアドレシングは LD 命令と同じで、レジスタ同士の演算か、
レジスタとメモリ内の数値の演算となる。結果は最初に書いたレジスタに入る。
注意する点として、レジスタと直接数値の演算は指定できない。
以下は具体的な記述の例である。
- ADDA GR0, GR1 ; ----- GR0 ← GR0 + GR1
- ADDA GR0, 1000 ; ----- GR0 ← GR0 + メモリの 1000 番地の内容
- ADDA GR0, 1000, GR1 ; ----- GR0 ← GR0 + メモリの (1000+GR1) 番地の内容
- ADDL GR0, GR1 ; ----- GR0 ← GR0 + GR1
- ADDL GR0, 1000 ; ----- GR0 ← GR0 + メモリの 1000 番地の内容
- ADDL GR0, 1000, GR1 ; ----- GR0 ← GR0 + メモリの (1000+GR1) 番地の内容
- SUBA GR0, GR1 ; ----- GR0 ← GR0 - GR1
- SUBA GR0, 1000 ; ----- GR0 ← GR0 - メモリの 1000 番地の内容
- SUBA GR0, 1000, GR1 ; ----- GR0 ← GR0 - メモリの (1000+GR1) 番地の内容
- SUBL GR0, GR1 ; ----- GR0 ← GR0 - GR1
- SUBL GR0, 1000 ; ----- GR0 ← GR0 - メモリの 1000 番地の内容
- SUBL GR0, 1000, GR1 ; ----- GR0 ← GR0 - メモリの (1000+GR1) 番地の内容
6.2.3 論理演算
論理演算は 2 個の数に対して指定した論理演算を施す。論理積 AND, 論理和 OR,
排他的論理和 XOR がある。使えるアドレシングは算術演算と同じである。
以下は具体的な記述の例である。
- AND GR0, GR1 ; ----- GR0 ← GR0 AND GR1 -----
- AND GR0, 1000 ; ----- GR0 ← GR0 AND メモリの 1000 番地の内容
- AND GR0, 1000, GR1 ; ----- GR0 ← GR0 AND メモリの (1000+GR1) 番地の内容
- OR GR0, GR1 ; ----- 論理和 OR -----
- OR GR0, 1000
- OR GR0, 1000, GR1
- XOR GR0, GR1 ; ----- 排他的論理和 XOR -----
- XOR GR0, 1000
- XOR GR0, 1000, GR1
6.2.4 比較
比較命令は、2 個の数に対して CPU 内部で減算を行なう。
ただし、その結果はどこにも保存されず捨てられる。
比較命令の結果はフラグレジスタに反映され、2 個の数の大小関係を調べることができる。
算術比較 CPA (Compare Arithmetic) と、論理比較 CPL (Compare Logical) がある。
CPA は 2 個の数を 2 の補数として扱う。
CPL は 2 個の数を符号無し整数として扱う。
したがって同じビットパターンの数を比較しても、CPA と CPL では結果が異なる場合がある。
使えるアドレシングは算術演算と同じである。
以下は具体的な記述の例である。
- CPA GR0, GR1 ; ----- 算術比較 -----
- CPA GR0, 1000
- CPA GR0, 1000, GR1
- CPL GR0, GR1 ; ----- 論理比較 -----
- CPL GR0, 1000
- CPL GR0, 1000, GR1
6.2.5 桁移動
桁移動(シフト)命令は、指定したレジスタの値を、
番地部(インデックスレジスタを含む)で指定したビット数分だけ、右または左にずらす。
シフト命令には算術シフトと論理シフトがあり、ずらした後の空白の埋め方が異なる。
ずらした結果押し出されたビットは OF (Overflow Flag) に入る。
左にずらして右端のビットが空白になる場合は 0 で埋められる。
右にずらして左端のビットが空白になる場合は、
算術シフトの場合は符号ビットと同じ値で埋められ、
論理シフトの場合は 0 で埋められる。
以下は実行例である。
GR0 = 1111000011110000 の場合、
SLA GR0, 2 を実行すると、
GR0 = 1100001111000000
SRA GR0, 2 を実行すると、
GR0 = 1111110000111100
SLL GR0, 2 を実行すると、
GR0 = 1100001111000000
SRL GR0, 2 を実行すると、
GR0 = 0011110000111100
になる。
シフト命令の副次的な効果として、左に算術シフトすると 2, 4, 8, ... 倍、
右に算術シフトすると 1/2, 1/4, 1/8, ... 倍することができる。
GR0 = 0000000000001111 (15) の場合、
SLA GR0, 2 を実行すると、
GR0 = 0000000000111100 (60)
SRA GR0, 1 を実行すると、
GR0 = 0000000000000111 (7)
になる。
以下は具体的な記述の例である。
- SLA GR0, 1 ; ----- GR0 を 1 ビット算術左シフトする
- SLA GR0, 2, GR1 ; ----- GR0 を 2+GR1 ビット算術左シフトする
- SRA GR0, 3 ; ----- GR0 を 3 ビット算術右シフトする
- SRA GR0, 4, GR1 ; ----- GR0 を 4+GR1 ビット算術右シフトする
- SLL GR0, 1 ; ----- 論理左シフト -----
- SLL GR0, 2, GR1
- SRL GR0, 3 ; ----- 論理右シフト -----
- SRL GR0, 4, GR1
6.2.6 分岐
分岐命令は、次の命令ではなくて指定した番地の命令を実行する
(指定した番地の命令にジャンプする)命令である。
それを指定した条件が満たされたときに実行する条件付ジャンプと、
条件を指定しないで常に実行する無条件ジャンプがある。
条件付ジャンプが実行されない場合は次の命令が実行される。
アドレシングはジャンプ先の番地(インデックスレジスタも使用可能)を指定する
演算命令や比較命令と条件付ジャンプ命令を組み合わせることで、
条件判断を行ない、プログラムの処理を場合分けすることができる。
命令の種類は、
演算結果について FR (フラグレジスタ) が正数を表す場合にジャンプする正分岐 JPL (Jump On Plus),
負数を表す場合にジャンプする負分岐 JMI (Jump On Minus),
演算結果が 0 でない場合にジャンプする非零分岐 JNZ (Jump On Non Zero),
演算結果が 0 である場合にジャンプする零分岐 JZE (Jump On Zero),
演算結果がオーバフローした場合、
または OF (Overflow Flag) がセットされている場合にジャンプするオーバフロー分岐
JOV (Jump On Overflow),
無条件でジャンプする無条件分岐 JUMP がある。
- JPL 1000 ; ----- 正分岐で 1000 番地にジャンプする
- JPL 1000, GR1 ; ----- 正分岐で 1000+GR1 番地にジャンプする
- JMI 1000 ; ----- 負分岐 -----
- JMI 1000, GR1
- JNZ 1000 ; ----- 非零分岐 -----
- JNZ 1000, GR1
- JZE 1000 ; ----- 零分岐 -----
- JZE 1000, GR1
- JOV 1000 ; ----- オーバフロー分岐 -----
- JOV 1000, GR1
- JUMP 1000 ; ----- 無条件分岐 -----
- JUMP 1000, GR1
6.2.7 スタック操作
スタックとは保存しておきたい値を一時的にメモリの特定の場所に記憶させておく仕組みである。
スタックの詳細は後述する。
CASL II ではスタックを操作する命令として PUSH と POP が用意されている。
PUSH は数値(インデックスレジスタも使用可能)をスタックに退避する。
POP はスタック最上部の値をレジスタに復帰する。
以下は記述例である。
- PUSH 1000 ; ----- 1000 という値をスタックに退避する
- PUSH 1000, GR1 ; ----- 1000+GR1 という値をスタックに退避する
- POP GR1 ; ----- スタック最上部の値を GR1 に復帰する
6.2.8 サブルーチンコール、リターン
サブルーチンコール命令 CALL は JUMP と似ており、指定した番地の命令を次に実行する。
JUMP との違いは、CALL 命令の次の命令の番地をスタックに退避してから JUMP する点であり、
後に RET を実行した時に CALL を実行したもとの場所に戻ってこられるようになっている。
サブルーチンとは、
プログラム中でメインの処理から一時離れて別の処理をさせたい時に使う仕組みであり、
プログラムをメインとサブの処理に分けて構造化することができる。
RET はサブルーチンから復帰するための命令であり、スタックから戻り番地を取り出して
その場所の命令を次に実行する。
以下は記述例である。
- CALL 1000 ; ----- 1000 番地からのサブルーチンに処理を移す
- CALL 1000, GR1 ; ----- 1000+GR1 番地からのサブルーチンに処理を移す
- RET ; ----- スタックから戻り番地を取り出してサブルーチンから復帰する
6.2.9 練習問題
次の機能を実現する命令を書きなさい。
1 命令で実現できない場合は複数の命令を組み合わせて実現しなさい。
(####) はメモリの #### 番地の内容を表す。
演算命令で指定がない場合は算術演算、算術比較とする。
- GR1 ← GR2
- GR1 ← (1000)
- GR1 ← (1000 + GR2)
- GR1 ← (GR2)
- (1000) ← GR1
- (1000 + GR2) ← GR1
- (GR2) ← GR1
- GR1 ← 1000
- GR1 ← GR1 + 1000
- GR1 ← GR1 + GR2 ; (論理加算)
- GR1 ← GR1 + (1000)
- GR1 ← GR1 + (1000 + GR2) ; (論理加算)
- GR1 ← GR1 - GR2
- GR1 ← GR1 - (1000)
- GR1 ← GR1 - (1000 + GR2) ; (論理減算)
- GR1 を GR2 と比較、符号付
- GR1 を (GR2) と比較、符号付
- GR1 を (1000) と比較、符号付
- GR1 を GR2 と比較、符号無
- GR1 を (GR2) と比較、符号無
- GR1 を (1000 + GR2) と比較、符号無
- GR1 を 2bit、左、算術シフト
- GR1 を GR2 で表される bit 数、右、算術シフト
- GR1 を 4bit、左、論理シフト
- GR1 を 3bit、右、論理シフト
- 演算結果が 0 でなければ 1000 番地にジャンプ
- 演算結果が 0 なら 1000 番地にジャンプ
- 演算結果 >= 0 なら 1000 + GR2 番地にジャンプ
- 演算結果 < 0 なら GR2 番地にジャンプ
- 1000 + GR2 番地にジャンプ
- GR1 をスタックに退避する
- GR1 + 10 をスタックに退避する
- GR1 にスタックから値を戻す
- 1000 番地のサブルーチンへジャンプ
- サブルーチンから戻る
6.2.10 練習問題
GR1 が #A0F5 (1010000011110101B), GR2 が 1 のとき、
次のシフト命令を実行した時の GR1 の値を答えなさい。
- SLA GR1, 1, GR2
- SRA GR1, 2
- SLL GR1, 2, GR2
- SRL GR1, 0, GR2
6.3 条件判断の記述方法
アセンブリ言語で条件判断の処理を記述したい場合は、
比較命令と条件付ジャンプ命令を組み合わせることで実現できる。
以下では具体的な命令の組み合わせ方、記述の仕方を示す。
例として GR1, GR2 を調べて、GR1 == GR2 なら 1000 番地からの命令、
そうでなければ (GR2 != GR1 なら) 2000 番地からの命令を実行する。
(※ == は等しい、!= は等しくないことを表す)
CPA GR1, GR2 ; GR1 と GR2 を比較する
JZE 1000 ; GR1 == GR2 なら 1000 番地に行く
JUMP 2000 ; そうでなければ 2000 番地に行く
ちょっとひねった書き方だが、条件判断を逆にして次のように書くこともできる。
CPA GR1, GR2 ; GR1 と GR2 を比較する
JNZ 2000 ; GR2 != GR1 なら 2000 番地に行く
JUMP 1000 ; そうでなければ 1000 番地に行く
次の例として GR1, GR2 の大小関係を調べて、GR1 < GR2 なら 1000 番地からの命令、
そうでなければ (GR2 <= GR1 なら) 2000 番地からの命令を実行する。
CPA GR1, GR2 ; GR1 と GR2 を比較する
JMI 1000 ; GR1 < GR2 なら 1000 番地に行く
JUMP 2000 ; そうでなければ 2000 番地に行く
条件判断を逆にして、次のように書くこともできる。
CPA GR1, GR2 ; GR1 と GR2 を比較する
JPL 2000 ; GR2 <= GR1 なら 2000 番地に行く
JUMP 1000 ; そうでなければ 1000 番地に行く
気をつける点としては、JPL には二つの値が等しい場合も含まれるので注意が必要である。
逆に、JMI には二つの値が等しい場合は含まれない。
例として GR1, GR2 の大小関係を調べて、GR2 < GR1 なら 1000 番地からの命令、
そうでなければ (GR1 <= GR2 なら) 2000 番地からの命令を実行する。
これを次のように書くのは間違いである。
CPA GR1, GR2 ; GR1 と GR2 を比較する
JPL 1000 ; GR2 <= GR1 なら 1000 番地に行く
JUMP 2000 ; そうでなければ 2000 番地に行く
この場合、GR1 と GR2 が等しい場合も 1000 番地にジャンプしてしまうので正しくない。
JPL を使いたい場合、正しくは次のように書く。こうすれば等しい場合は先に 2000 番地に
ジャンプするので問題ない。
CPA GR1, GR2 ; GR1 と GR2 を比較する
JZE 2000 ; GR1 == GR2 なら先に 2000 番地に行く
JPL 1000 ; GR2 < GR1 なら 1000 番地に行く
JUMP 2000 ; そうでなければ 2000 番地に行く
または、次のように比較命令のオペランドを逆にすることで命令を減らすことができる。
CPA GR2, GR1 ; GR2 と GR1 を比較する
JPL 2000 ; GR1 <= GR2 なら 2000 番地に行く
JUMP 1000 ; そうでなければ 1000 番地に行く
JMI を使うと次のようになる。
CPA GR2, GR1 ; GR2 と GR1 を比較する
JMI 1000 ; GR2 < GR1 なら 1000 番地に行く
JUMP 2000 ; そうでなければ 2000 番地に行く
6.3.1 練習問題
次の条件判断を実現する命令列を示しなさい。
条件に合わなければ L2 にジャンプするようにしなさい。
L1, L2 はある特定の番地を表すものとし、解答中ではそのまま書きなさい。
演算命令で指定がない場合は算術演算、算術比較とする。
- GR1 と GR2 を比較して GR1 < GR2 なら L1 にジャンプする。
- GR1 と GR2 を比較して GR1 <= GR2 なら L1 にジャンプする。
- GR1 と GR2 を比較して GR1 == GR2 なら L1 にジャンプする。
- GR1 と GR2 を比較して GR1 != GR2 なら L1 にジャンプする。
- GR1 と GR2 を比較して GR2 < GR1 なら L1 にジャンプする。
- GR1 と GR2 を比較して GR2 <= GR1 なら L1 にジャンプする。
- 符号付数として GR1 + GR2 を計算した時、あふれがあれば L1 にジャンプする。
- 符号無数として GR1 + GR2 を計算した時、あふれがあれば L1 にジャンプする。
- GR1 を 1 ビット右に算術シフトした時、はみ出したビットが 1 なら L1 にジャンプする。
- GR1 を 1 ビット左に論理シフトした時、はみ出したビットが 0 なら L1 にジャンプする。
6.4 スタック
スタックとは、レジスタを別の用途に使いたい時に、
現在のレジスタの値を一時的にメモリに退避するための仕組みである。
- スタックにレジスタの値を退避する時は、
COMET II では 16 ビットを単位として処理する。
- スタックを操作する命令には PUSH と POP がある。
PUSH でレジスタの値、または数値をスタックに退避、
POP で退避してあった値をレジスタに戻す。
スタックを使う時には、使い始める前に SP (スタックポインタ) を初期化する必要がある。
SP はスタックの領域をどこまで使ったか管理するためのアドレス
(=最後に使った領域を指す) を保持する。
- PUSH を実行すると SP=SP-1 となり SP 番地に値が書き込まれる。
- POP を実行すると SP 番地からデータが読み出され、SP=SP+1 となる。
スタックの領域はアドレスの大きい方から使われ始めて、
使用量が増えるにしたがってアドレスの小さい方に増えていく。

スタック
アドレスの値の小さい領域は通常 ROM, OS, ユーザのプログラムが配置されるため、
スタックはアドレスの値の大きい領域に配置されることが多い。
6.4.1 スタックの使用例
- 最初の時点で GR0, GR1, GR2 にはそれぞれ 10, 20, 30 が入っているとする。
- PUSH 0, GR0 を実行すると、
GR0 の値が SP の指す上の場所のスタックに書き込まれる。
- その後続けて PUSH 0, GR1, PUSH 0, GR2 を実行すると各値が記録される。
SP はスタックが消費されるのにつれて、
アドレスの値の小さい方を指し示すように変更される。
- この時点で各レジスタの値はスタックに記録されているので、
他の用途にレジスタを使用して値が変化してしまっても、
後から復活させることができる。
- レジスタの値を戻す時には
PUSH を実行した順番と逆に POP を実行する。
POP GR2 を実行するとスタックの最後に使った領域から値が取り出されて
GR2 に値が代入される。
SP は値を取り出した領域の前の領域を指すように内容が変更される。
- その後続けて POP GR1, POP GR0
を実行すると各レジスタに値が代入されてスタックは元の状態に戻る。
6.4.2 練習問題
各レジスタの初期値が GR0=10, GR1=20, GR2=30 となっている状態で、
次のスタック操作を行なった後に各レジスタの値がどうなるか答えなさい。
(1) PUSH 0, GR0
PUSH 0, GR1
PUSH 0, GR2
POP GR0
POP GR1
POP GR2 の一連の操作を ★ とする。★ を 2 回繰り返す。
(2) ★ を 3 回繰り返す。
(3) PUSH 0, GR0 (4) PUSH 0, GR0
PUSH 0, GR1 PUSH 0, GR1
PUSH 0, GR2 POP GR2
PUSH 0, GR0 POP GR1
POP GR2 POP GR0
POP GR1
POP GR0
6.5 CASL II によるプログラミング
6.5.1 アセンブリ言語でプログラムを作る時の考え方
- どのレジスタをどういう用途に使うか決める
- 必要なデータをレジスタに読み込む
- 計算をする、結果がレジスタに入る
- レジスタにある結果をメモリに書き込む
以下は注意すべき点である。
- レジスタは有限個で少数しかないので使い方をよく考える
- 1 命令では単純な機能しか実行できないので組合せを工夫する
- 存在しない命令を使わない、アドレシングに気をつける
6.5.2 CASL II のプログラムの書き方
以下はプログラムの書き方を示すためのサンプルプログラムである。
EX0 START ; 最初に必ずラベルと、疑似命令 START を書く ---(1)
LD GR0, A ; A 番地のデータを GR0 に入れる ---(2)
ADDA GR0, B ; B 番地のデータを GR0 に加算する
ST GR0, C ; GR0 を C 番地に記録する
RET ; 実行部分の最後には RET を書く ---(3)
A DC 5 ; データを置く領域 ---(4)
B DC 3 ; データを置く領域
C DS 1 ; 答を置く領域、初期値は不定 ---(5)
END ; プログラムの最後には疑似命令 END を書く ---(6)
(1), (3), (6) について。
CASL II のプログラムは 3 個の命令、疑似命令 START, RET, END を、
次に示すように必ず所定の位置に書く必要がある。
ラベル START
…
プログラムの実行部分
…
RET
…
データの定義
…
END
プログラムの先頭には、そのプログラムを表すラベルと疑似命令 START,
プログラムの実行部分の後に命令 RET,
通常は実行部分に続けてデータの領域が置かれるが、その後(プログラム全体の最後)に
疑似命令 END を書く。
疑似命令とは通常の命令のように CPU で実行されるものではなく、
アセンブラに必要な指示を与えるための記述である。
この場合、START, END はアセンブラにプログラムのはじめと終りを伝える。
COMET II のプログラムは OS から CALL されて実行されるので、
RET の実行後は OS の管理下に戻ることになる。
したがって RET がないと適切なタイミングで OS の管理下に戻ることができず、
暴走した状態となるので RET は必ず必要である。
(2) について。
上記のプログラムで EX0, A, B, C は「ラベル」と呼ばれる記述法である。
ラベルとはプログラム中で命令やデータの番地を参照する必要がある場合に、
番地の値を直接書く代わりに使われる表現で、番地を表す仮の名前といった意味合いを持つ。
例として LD GR0, A ではラベル A が付いている番地からデータ 5 が読み込まれるが、
この番地はアセンブラで機械語のプログラムに変換した後、実行時にメモリに読み込むまで確定しない。
このような値が確定しない番地については、仮にラベルを付けておくことで、
ラベルの名前を使ってプログラムが記述できるようになる。
(4), (5) について。
データの定義は DC, DS という 2 種類の疑似命令で行なう。
DC はその場所に 1 ワードの領域を確保して、指定した値が初期値として代入される。
DS はその場所に必要な大きさの領域を確保する。
DS に指定した値は領域のワード数と解釈される。
DS 10 と指定したら 10 ワードの大きさの領域となる。
DS には初期化の機能はないので領域にどのような値が入るかはわからない。
DC と DS の使い分けは、初期化が必要なら DC、
複数ワードの領域が必要で初期化が不要なら DS となる。
6.5.3 プログラムの例
1. A と B の大きい方を C に記録する
EX1 START
LD GR0, A ; A 番地のデータを GR0 に入れる
CPA GR0, B ; B 番地のデータを GR0 と比較
JPL L1 ; B <= A なら L1 に行く
LD GR0, B ; A < B の時は B 番地のデータを GR0 に
L1 ST GR0, C ; GR0 を C 番地に記録する
RET
A DC 5 ; データを置く領域
B DC 3 ; データを置く領域
C DS 1 ; 答を置く領域
END
解説
EX1 : プログラムの先頭にはこのようにラベルを付ける
START : プログラムの先頭には START を書く
L1 : ジャンプする先にラベルを付けると、番地を指定する代わりに使える
RET : 実行部分の最後には RET を書く
A,B,C : データにもラベルを付けると参照するのが楽
DC : 1 ワードの領域を確保し、指定した定数で初期化する
DS : 指定した定数分のワードの領域を確保する、初期化はなし
END : プログラムの最後には END を書く
2. A × B を求める (A + A + A + ... + A, B 回 A を足す)
EX2 START
LAD GR0, 0 ; GR0 を 0 にする、答が入る
LAD GR1, 0 ; GR1 を 0 にする、足した回数を数える
JUMP L2 ; B=0 でも正しく動作するように L2 に行く
L1 ADDA GR0, A ; GR0 に A の内容を足す
LAD GR1, 1, GR1 ; 回数カウンタの GR1 に 1 を足す
L2 CPA GR1, B ; GR1 が B になったか比較する
JNZ L1 ; まだ B になってなければ L1 から繰り返し
ST GR0, C ; 答を C に記録する
RET
A DC 5 ; データを置く領域
B DC 3 ; データを置く領域
C DS 1 ; 答を置く領域
END
3. A × 10 を求める (シフト命令を使う)
EX3 START
LD GR0, A ; GR0 に A 番地のデータを読み込む
SLA GR0, 1 ; 左に 1 bit シフト、× 2 になる
LD GR1, GR0 ; その結果を一旦 GR1 に記録する
SLA GR0, 2 ; 左に 2 bit シフトで × 4、全体では × 8
ADDA GR0, GR1 ; 8 倍の結果にさっきの 2 倍の結果を足す
ST GR0, B ; 10 倍の結果を B に記録する
RET
A DC 5 ; データを置く領域
B DS 1 ; 答を置く領域、初期値は決まっていない
END
4. A 回の繰り返しのプログラムの考え方
EX4 START
LAD GR1, 0 ; 回数をカウントする GR1 を 0 にする
; GR0 はこの用途には使用不可、インデックス
; レジスタに指定できないため
JUMP L2 ; 繰り返し 0 回でも対応できるよう L2 へ
L1 ;
; 実際はここに繰り返したい内容を書く
;
LAD GR1, 1, GR1 ; カウンタ GR1 を +1 する
L2 CPA GR1, A ; A 回繰り返したか回数をチェックする
JNZ L1 ; まだ A 回になってなければ L1 から繰り返す
RET
A DC 10
END
5. A 番地から並んでいる B 個のデータの和を求める
EX5 START
LAD GR0, 0 ; 答を入れる GR0 を 0 にする
LAD GR1, 0 ; 回数をカウントする GR1 を 0 にする
JUMP L2 ; 繰り返し 0 回でも対応できるよう L2 へ
L1 ADDA GR0, A, GR1 ; GR0 に (A + GR1) の内容を足す
LAD GR1, 1, GR1 ; GR1 を +1 する
L2 CPA GR1, B ; GR1 が B になったか調べる
JNZ L1 ; なってなければ L1 から繰り返す
ST GR0, C ; 答えを C に記録する
RET
A DC 3 ; ここから足す対象のデータが並んでいる
DC 5
DC 7
DC 2
B DC 4 ; 足す個数が 4 個なので 4 を書く
C DS 1 ; 答えを記録する領域
END
6. A 番地から並んでいる B 個のデータを昇順(小さい順)に並べ換える
EX6 START
LD GR4, B : B-1 を GR4 に書き込む
LAD GR4, -1, GR4 :
LAD GR2, 0 ; 外側のループ i
L1 LAD GR3, 1, GR2 ; 内側のループ j = i + 1
L2 LD GR0, A, GR2 ; (A + GR2) を GR0 に読み込む
CPA GR0, A, GR3 ; それを (A + GR3) と比較する
JMI L3 ; (A + GR2) < (A + GR3) なら L3
LD GR1, A, GR3 ; ここからの 3 行で
ST GR0, A, GR3 ; (A + GR2) と (A + GR3) を
ST GR1, A, GR2 ; 入れ換えている
L3 LAD GR3, 1, GR3 ; 内側のループ j を +1 する
CPA GR3, B ; B になったか調べる
JMI L2 ; なってなければ L2 から繰り返し
LAD GR2, 1, GR2 ; 外側のループ i を +1 する
CPA GR2, GR4 ; B-1 になったか調べる
JMI L1 ; なってなければ L1 から繰り返し
RET
A DC 3 ; 並べ換える対象のデータの先頭
DC 5
DC 7
DC 6
B DC 4 ; 個数が 4 個なので 4 を書く
END
このプログラムは以下のプログラムとほぼ同じ内容になる
void sort(void)
{
int A[B], tmp;
for (i = 0; i < B - 1; i++) {
for (j = i + 1; j < B; j++) {
if (A[j] <= A[i]) {
tmp = A[j]; A[j] = A[i]; A[i] = tmp;
}
}
}
}
6.5.4 練習問題
次の機能を実現するプログラムをアセンブリ言語で作成しなさい。
A, B, C, D は必要に応じてデータ領域を確保しなさい。
演算命令で指定がない場合は算術演算、算術比較とする。
- A + B, A - B をそれぞれ C, D に記録する
- A * 3 を C に記録する
- A, B の小さな方の値を C に記録する
- A == B なら 0 を、A != B なら 0 以外の値を C に記録する
- A の 0/1 を反転して C に記録する (排他的論理和を使う)
- A の 2 の補数を求めて C に記録する
- A * 7 を C に記録する
- 1 + 2 + 3 + ... + A を求めて C に記録する
- A, B, C の最小値を D に記録する
- A 番地からの B 個のデータを降順(大きい順)に並べ換える