4 章 機械語の設計 ここでは 機械語の設計をしてみましょう 機械語の設計! そんなことができるのでしょうか 情報処理技術者試験の CASLⅡ 説明書の参考資料には 命令後の構成は定義しないが と記載されています アセンブラ言語を理解するためには機械語の理解が非常に大切になりますし 自分で設計してみれば格段に理解が容易になります そこで 定義されていないなら 定義してしまおう というわけです CASLⅡが動くコンピュータである COMETⅡは仮想のコンピュータですから どんな設計をしてもかまわないのです しかし 命令後の構成は定義しない とする一方で 次のような構成を想定する として 機械語が定義されています この章では 自分で最初から設計する ことで話を進め 最終的には 想定された構成 になるように考えてみましょう - -
4. 設計の手順 設計といっても どうすればよいのでしょうか その方法を考えてみましょう 4.. 機械語とはそれでは 今さらですが 機械語 とは何でしょうか プログラムは アセンブラ言語であれ 高級言語であれ ある程度人間が理解できるように書かれます コンピュータは もちろん理解できませんから これを機械のわかる言葉 (= 機械語 ) に変換 ( つまり アセンブルする コンパイルする ) してからコンピュータに命令を与えることになります 機械語は 実行時にはコンピュータのメモリーに置かれますから ビットの集合です しかし このビットの集合は 元はプログラムとして書かれたものですから 逆に機械語から元のプログラムが復元できるようになっていなければなりません 4..2 実際に設計設計してみる例えば LD GR,KINGAKU,GR2 という命令を機械語に変換することを考えてみましょう この命令を機械語に変換した結果として ( 機械語から ) 次の情報を読み取ることができなければなりません 命令 ( オペレーション ) が LD 命令であること 2 汎用レジスタ GR へロードする命令であること 3 ロード元としてアドレスが定義されていること (LD GR,GR2 というような ロード元が汎用レジスタではないこと ) 4 アドレスとして KINGAKU が指定されていること 5 インデックスとして汎用レジスタ GR2 が指定されていることそれでは 順に考えていきましょう オペレーション CASLⅡには全部で 38 種類の命令があります ( 命令の種類は 28 種類ですが バリエーションを含めると 38 個になります ) 38 種類の命令を区別するためには 少なくとも 6 ビット必要です (6 ビットで 64 種類表現できますが 5 ビットですと 32 種類しか表現できません ) 従って 命令のオペレーション部分として 最低 6 ビットが必要です 汎用レジスタ汎用レジスタは 0~7 までの 8 種類がありますから 最低 3 ビットが必要です アドレスアドレスは 0~65535 までありますから 6 ビットが必要です - 2 -
インデックスインデックスも汎用レジスタと同じく 3 ビットが必要です ここまで 必要なビット数は 28 ビットになりました さて COMETⅡは 語が 6 ビットですから 28 ビットというのはいかにも中途半端です そこで 少しもったいないのですが 6 ビットを 2 つ 合計 32 ビットを使用することにします ここで 再度 命令に必要なビット数を見ますと アドレス部はそれだけで 6 ビットですので これを 語として 残りの 語 6 ビットに他の部分を埋め込むことにします 他の部分は 2 ビットですから 6 ビットを使うと 4 ビットが余ることになります 余りは 未使用 でもかまわないのですが 将来拡張されることを考慮して オペレーションを 8 ビット 汎用レジスタとインデックスをそれぞれ 4 ビットとします そうすれば 将来オペレーションの種類が 256 まで増えても大丈夫ですし 汎用レジスタが 6 個まで増えても大丈夫です ここまでをまとめると次のようになります 最初の 8 ビットオペレーションの種類 語目次の 4 ビット汎用レジスタ最後の 4 ビットインデックスレジスタ 2 語目アドレス表 4- 語の割り振りそれでは LD r,r2 のような インデックスが無い代わりに汎用レジスタが 2 個あり アドレスも無い命令はどうなるでしょうか このような命令は アドレス部が不要なので 命令は 語となる インデックスの代わりに r2 を 語目最後の 4 ビットに設定するということにします では RET や NOP のように オペランドの無い命令はどうなるでしょうか このような命令は 語目の最初の 8 ビットのみであとは不要です この場合 命令は 8 ビットで済むのですが COMETⅡでは番地が 語単位にしか割り振られていないので 残りの 8 ビットをすべてゼロ とし 命令の長さを 語にします つまり 全ての命令は 語か 2 語になるというわけです オペレーション部分は 勝手に ( 同じ値にならないように ) 割り振っていけばよいのですが 想定され 特にゼロにする必要は無いが 通常このような場合はゼロにする - 3 -
る命令語の構成 にしたがってみましょう この構成では 命令後の上位 4 ビットで命令を大きく分類し 下位 4 ビットで細かく分けているようで す このようにして全ての命令を設計したのが次の表で 情報処理推進機構のホームページに記載され ています 4..3 宿題の答 命令 オペランド 語目 ( ビット位置 ) 5~8 7~4 3~0 2 語目 LD LoaD r,r2 000 000 r r2 - r,adr[,x] 000 0000 r x adr ST STore r,adr[,x] 000 000 r x adr LAD LoadADdress r,adr[,x] 000 000 r x adr ADDA ADD Arithmetic r,r2 000 000 r r2 - r,adr[,x] 000 0000 r x adr ADDL ADD Logical r,r2 000 00 r r2 - r,adr[,x] 000 000 r x adr SUBA SUBtract Arithmetic r,r2 000 00 r r2 - r,adr[,x] 000 000 r x adr SUBL SUBtract Logical r,r2 000 0 r r2 - r,adr[,x] 000 00 r x adr AND AND r,r2 00 000 r r2 - r,adr[,x] 00 0000 r x adr OR OR r,r2 00 00 r r2 - r,adr[,x] 00 000 r x adr XOR exclusive OR r,r2 00 00 r r2 - r,adr[,x] 00 000 r x adr CPA ComPare Arithmetic r,r2 000 000 r r2 - r,adr[,x] 000 0000 r x adr CPL ComPare Logical r,r2 000 00 r r2 - r,adr[,x] 000 000 r x adr SLA Shift Left Arithmetic r,adr[,x] 00 0000 r x adr SRA Shift Right Arithmetic r,adr[,x] 00 000 r x adr SLL Shift Left Logical r,adr[,x] 00 000 r x adr SRL Shift Right Logical r,adr[,x] 00 00 r x adr JPL Jump on PLus adr[,x] 00 00 0000 x adr JMI Jump on MInus adr[,x] 00 000 0000 x adr JNZ Jump on Not Zero adr[,x] 00 000 0000 x adr JZE Jump on ZEro adr[,x] 00 00 0000 x adr JOV Jump on OVerflow adr[,x] 00 00 0000 x adr JUMP unconditional JUMP adr[,x] 00 000 0000 x adr PUSH PUSH adr[,x] 0 0000 0000 x adr POP POP r 0 000 r 0000 - CALL CALL subroutines adr[,x] 000 0000 0000 x adr RET RETurn from subroutines - 000 000 0000 0000 - SVC SuperViser Call adr[,x] 0000 0000 x adr NOP No OPeration - 0000 0000 0000 0000 - 表 4-2 機械語一覧 ( 出典は 情報処理推進機構情報処理推進機構ホームページホームページ ) それではここで 宿題の回答をしておきましょう 宿題 汎用レジスタ 0 は なぜインデックスレジスタとして使用できないのか - 4 -
命令の説明で書いたように 命令を構成する 6 ビットのうちの最後の 4 ビットでインデックスレジスタとして使用する汎用レジスタの番号を設定します ただし インデックスレジスタが指定されていない場合はどうすれば良いでしょうか 通常は ゼロを設定しておきます すると インデックスレジスタとして汎用レジスタ 0 が指定された のか インデックスが指定されていないのか 区別がつかなくなります そこで エイッ とばかり 汎用レジスタ 0 はインデックスとして使用できない としたのです この設計では 汎用レジスタが 7 個しかないのにレジスタ設定部として 4 ビットを確保していますので 4 ビット中の最上位ビットは常に 0 となります ですから たとえば 最上位ビットが のときはインデックスを使用していない とでも定義しておけばよいのですが 将来汎用レジスタが 6 個に増えたりしたときには この手は使えなくなりますので 汎用レジスタ 0 はインデックスとして使用できない と決めたのです 4.2 アセンブルの仕組仕組み それではここで 定義した機械語を使って 実際にアセンブラ 2 がどのようにソースプログラムから機械 語を作り出していくかを見てみましょう 4.2. プログラム例 例として 次のようなプログラムを紙上でアセンブルしてみましょう このプログラムは SUCHI にある値と SUCHI2 にある値を加算して 結果を KOTAE へ格納すると いうもので 非常に単純なプログラムです 加算は 一旦 SUCHI の内容を汎用レジスタ へ持ってきて そこへ SUCHI2 の内容を加算し 結果を 6 進の X F0F0 で論理積をとって KOTAE へ格納します 論理積をとるのは あまり意味はないのですが リテラルの説明のためにあえてこの命令を入れまし た くどいようですが このプログラム自体は 特に何をするというものでもなく 単に命令を並べただえで すので どんな結果になるのか 何をしようとしているのか などを考えないでください SAMPLE START ; LD GR,SUCHI ;2 ADDA GR,SUCHI2 ;3 AND GR,=HF0F0 ;4 ST GR,KOTAE ;5 RET ;6 SUCHI DC 200 ;7 SUCHI2 DC 300 ;8 KOTAE DS ;9 END ;0 IBM メインフレームのアセンブラも同様です 2 くどいようですが アセンブラ が アセンブラ言語で書かれたソースプログラム を機械語に変換すること ( アセン ブルすること ) を アセンブリ と言います - 5 -
以下 順に説明します 説明 プログラム名を SAMPLE としています 2 SUCHI の内容を GR へロードします SUCHI は6で 200 と定義されていますので 汎用レジスタ には ( 命令実行前の無いように関係なく )200 が格納されます SUCHI の内容は変わりません 3 GR に SUCHI2 の内容を加算します SUCHI2 は7で 300 と定義されていますので 汎用レジスタ には 200+300=500 が設定されます 4 結果を 6 進の X F0F0 で論理積をとります 5 加算結果を KOTAE へ格納します 命令実行前の KOTAE の内容が何であれ 無視されて加算結果が格納されます 6 プログラムを終了して制御を OS へ返します 7 SUCHI という領域を 語確保し 初期値を 200 とします 8 SUCHI2 という領域を 語確保し 初期値を 300 とします 9 加算結果を格納する領域を 語確保し その領域に KOTAE という名前をつけています 初期値は未定です ( 何がはいっているかわかりません ) 0 プログラムの終わりを示します 4.2.2 アセンブルそれでは 上記プログラムをアセンブルしてみましょう アセンブルは 2つのフェーズに分けて行います まず 第 フェーズです 上記 は機械語の命令ではありませんから 変換しません 前に設計した 機械語一覧によれば 2は次のようになります 語目の 5~8 ビット目 000 000 これが 機械語で LD 命令になります 語目の 7~4 ビット目汎用レジスタは を使用しますので 000 語目の 3~0 ビット目インデックスは使用していませんので 0000 2 語目は まだ分かりませんので 仮に? としておきましょう ここまでで 語目は 0000 000 000 0000 となります 2 進数では見にくいので 6 進表示にすると X 20 になります これで命令ひとつが機械語になったわけですが ( まだ 2 語目は? のままですが ) プログラムは 0 番地から始まるとしてで 0 番地 X 0000 番地 X???? となります 以下 同様に6までアセンブルします ただし 6のように 語だけで構成される命令もあります では 7はどうなるでしょうか これは 単に 200 という数字です 200 は 0 進数ですので これを 6 進数に変換して X 00C8 になります - 6 -
同様に 8は X 02C ですね では 9はどうでしょうか これは 単に領域を確保するだけで 初期値は定義されていないのですが 機械語に変換するとき困りますので X 0000 とでもしておきましょう ここまでの変換結果をまとめてみます 語目ラベルオヘ レーションオヘ ラント アト レスビット表現 5~8 7~4 3~0 6 進 2 語目 SAMPLE START 00 2 LD GR,SUCHI 0 000 000 000 0000 20? 3 ADDA GR,SUCHI2 2 000 0000 000 0000 200?2 4 AND GR,=HF0F0 4 00 0000 000 0000 300?4 5 ST GR,KOTAE 6 000 000 000 0000 0?3 6 RET 8 000 000 0000 0000 800 ( なし ) 7 SUCHI DC 200 9 0000000000000 00C8 ( なし ) 8 SUCHI2 DC 300 0 000000000000 02C ( なし ) 9 KOTAE DS 0000000000000000 0000 ( なし ) 表 4-3 アセンブル結果 ( フェーズ ) 次に フェーズ 2 です フェーズ 2 では フェーズ で とりあえず? にしておいたところを解決します 上の表では 3 箇所 (??2?3および?4) の未解決部分があります まず?ですが これは SUCHI のアドレスが分からないので とりあえず? にした というものです ところがフェーズ が終わった段階で 上表を見ると SUCHI のアドレスは 9 番地 に決定していますので これを 6 進に変換して X 0009 がアドレスになります 同様に?2と?3はそれぞれ X 000A と X 000B になります 最後に?4が残りました これはリテラルですので プログラムに存在しませんから自動で作り出してあげる必要があります 作り出す場所は END 命令の直前 と定義されていますから 直前に DC #F0F0 という命令を作り出します このアドレスは 最後 (9) のアドレスの次になります - 7 -
これらの値を上表に埋め込むと 次のようになります ラベルオヘ レーション オヘ ラント アト レ ス 語目ビット表現 5~8 7~4 3~0 6 進 2 語目 SAMPLE START 00 2 LD GR,SUCHI 0 000 000 000 0000 20 0009 3 ADDA GR,SUCHI2 2 000 0000 000 0000 200 000A 4 AND GR,=HF0F0 4 00 0000 000 0000 300 000C 5 ST GR,KOTAE 6 000 000 000 0000 0 000B 6 RET 8 000 000 0000 0000 800 ( なし ) 7 SUCHI DC 200 9 0000000000000 00C8 ( なし ) 8 SUCHI2 DC 300 0 000000000000 02C ( なし ) 9 KOTAE DS 0000000000000000 0000 ( なし ) 2 00000000 F0F0 表 4-4 アセンブル結果 ( フェーズ 2) これでアセンブルが全て終了しました 完成した表から 機械語部分のみをとりだすと 6 進で 20 0009 200 000A 300 000C 0 000B 800 00C8 02C 0000 F0F0 となります これが このプログラムを機械語に変換した結果なのです 4.3 機械語でのでのコーディング それでは このプログラムを次のようにコーディングしたらどうなるでしょうか SAMPLE START 00 ; DC #030,#0009 ;2 DC #0B0,#000A ;3 DC #90,#000C ;4 DC #040,#000B ;5 DC #6600 ;6 DC 200 ;7 DC 300 ;8 DS ;9 DC #F0F0 ; END ;0 なんだかまったく分からないプログラムなのですが 機械語部分は変わりませんから立派に動作しそう ですが 実は動かないのです 理由は後で - 8 -
ところで このプログラムに RET 命令が無かったらどうなるでしょうか コンピュータは ST 命令の次にも命令があると思って 次の命令の実行にかかります 次の命令 ( と判断したもの ) は 6 進で X'00C8' ですから 命令のオペレーション部分は ビットで '00000000' となります ところがこんな命令はありませんから エラーとなり 実行が止まってしまいます しかし もし偶然に 先頭へ戻る ( ジャンプする ) というような命令になっていたらどうなるでしょうか このプログラムは先頭へ戻って また同じ事を繰り返しますから 永久に止まりません 4.4 アブソリュートタームとリロケータブルタームリロケータブルターム 今 次のようなプログラムを作成し 実行することを考えてみます SAMPLE START LAD GR,000 ST GR,KINGAKU RET KINGAKU DS END これをアセンブルして機械語に変換すると次のようになります アドレス命令 命令 2 コーディング SAMPLE START 2 0000 20 03E8 LAD GR,000 3 0002 0 0005 ST GR,KINGAKU 4 0004 800 RET 5 0005 0000 KINGAKU DS 表 4-5 アセンブル直後直後の機械語 CASLⅡ の説明書によれば プログラムは OS によって起動される プログラムがロードされる主記憶の領域は不定であるが プログラムのラベルに対するアドレス値は OS によって実アドレスに補正されるものとする とあります つまり プログラムをアセンブルしたときは そのプログラムは 0 番地 から始まるようにアセンブルさ れるが 実行時には 0 番地から始まるわけではないということです このとき OS が ラベルに対するアドレス値 を補正します 上記プログラムでは 3 の 命令 2 が ラベルに対するアドレス値 ですので この値が補正されるこ とになります なお 2 の 命令 2 は ラベルに対するアドレス値 ではないので 補正対象にはなりません 例えば このプログラムが 00 番地 (6 進で X 0064 ) からロードされたとします すると ラベルに対するアドレス値 を補正 (00 を加える ) されると 次のようになります - 9 -
アドレス 命令 命令 2 コーディング SAMPLE START 2 0064 20 03E8 LAD GR,000 3 0066 0 0069 ST GR,KINGAKU 4 0068 800 RET 5 0069 0000 KINGAKU DS 表 4-6 補正されたされた機械語 では 仮に 補正されない とするとどうなるでしょうか アドレス 命令 命令 2 コーディング SAMPLE START 2 0064 20 03E8 LAD GR,000 3 0066 0 0005 ST GR,KINGAKU 4 0068 800 RET 5 0069 0000 KINGAKU DS 表 4-7 補正されないされない機械語 本来は X 0069 番地へストアーしなければならないのに X 0005 番地へストアーすることに なってしまいます X 0005 番地はこのプログラムの 外 ですので 正しく動作しないのみならず 途中で異常終了 する可能性があります ところで 2はなぜ 補正 されないのでしょうか 2も3も実効アドレスのはずです 仮に 補正した とした場合 次のようになります アドレス 命令 命令 2 コーディング SAMPLE START 2 0064 20 044C LAD GR,000 3 0066 0 0069 ST GR,KINGAKU 4 0068 800 RET 5 0069 0000 KINGAKU DS 表 4-8 不必要に補正補正されたされた機械語 補正された結果 X 044C (=00) となり KINGAKU には 000 ではなく 00 がストアーされてしま います このように プログラムがロードされる時点で アドレスが補正されるものとされないものがあります 補正される アドレス( 項 ) を リロケータブル ターム といい 補正されない 項を アブソリュート ターム といいます 一般に ラベルはリロケータブルタームで 数値そのものはアブソリュートタームになります - 0-
ここで 4.3 の宿題の答えを出しておきます 宿題は なんだかまったく分からないプログラムなのですが 機械語部分は変わりませんから立派に動作しそうですが 実は動かないのです 理由は後で でした もうお分かりでしょうか このプログラムは すべてのアドレス部がアブソリュートタームとして定義されます したがって このプログラムが 0 番地 からロードされれば正しく動作しますが 0 番地以外からロードされた場合 リロケータブルタームの再配置が行われません ( アブソリュートタームばかりですから ) ので 正しく動作しないということになります - -