演算処理装置(CPU)の検討。

コンピュータ関連記事, 旧サイト記事

旧ブログ記事を更新し、再掲 2020年11月14日(初出2017年10月06日)加筆修正 2023年7月17日
Study of central processing unit.

第1章

フォンノイマン型のCPUは入力から受け取った決められた桁数の2進数の数値を先ずメモリに蓄える。このデータはプログラムの場合もデータの場合もある。次に、リセット入力などによって、プログラムの実行を開始する。大抵は、メモリの0番地等の決められた記憶領域からプログラムを実行する。その領域から続く二進数のデータはプログラムであると仮定されるわけである。

プログラムは命令制御ユニットで解析される。一つの命令が解析されたならば、次の命令を実行するようにする必要がある。それを実現するのが、プログラムカウンタ(PC)と呼ばれるレジスタである。

C言語のような関数型のプログラミング言語をサポートするために必要なのがスタックと呼ばれる仕組みであり、それを実現するのが、スタックポインタ(SP)である。

計算の値を保存するレジスタをアキュムレータ(ACC)と呼ぶ。そのようにレジスタを固定せずに複数のレジスタを計算の時に利用できるようなCPUもある。RISCタイプのCPUはレジスタの数が多いのが普通である。

一般的に、関数の変数は、2~3個程度なので、レジスタの数が16個程度あれば、関数呼び出しや割り込み処理時にレジスタに値を待避する事が可能である。レジスタのワンセットを複数用意して、主記憶上のスタックではなく、レジスタバンクのレジスタの切り替えで関数や割り込みを実行する事もできる。レジスタのミラーリングと言う。

ただ、関数の変数が多い場合は、スタックに保存する必要があるので、最初から変数の待避先はスタックと決めておくのと、変数の数によって、待避先を切り替えるように実装するのでは、スタック決め打ちの方が命令制御ユニットの構造が簡単になる。

計算結果や分岐命令の判断などの為にCPUの状態を判断するステータスレジスタも必要である。

最初の検討では、基本構成として以下のレジスタブロックを考える。

8本の汎用レジスタ:名称はR0~R7(バス幅:64 bit)
・64 bit長(ちょう)のパラレルレジスタとする。
・64 bitパラレルで任意の値を入出力できるようにする。
(各種データ代入命令に必要。R0~R7も全て同じ仕様。)

プログラムカウンタ:名称はPC(バス幅:64 bit)
・64 bit長(ちょう)のカウンタ機能付きレジスタとする。
・64 bitパラレルで任意の値を入力できるようにする。
(初期化、JUMP命令や実行制御に必要)
・レジスタの値を+1ずつカウントアップできるようにする。
・PCの値をアドレスとしてメモリに64 bitパラレルで出力できるようにする。

プログラムメモリ用スタックポインタ:名称はPSP(バス幅:64 bit)
・64 bit長(ちょう)のパラレルレジスタとする。
・64 bitパラレルで任意の値を入力できるようにする。
(スタック領域の設定に必要)
・PUSHという命令に対応するため、外部からの入力でレジスタの値を-1
できるようにする。
・POPという命令に対応するため、外部からの入力でレジスタの値を+1
できるようにする。
・PSPの値をアドレスとしてメモリに64 bitパラレルで出力できるようにする。
この仕様では、スタック領域は使えるメモリの最上位に設定し、プログラム中の関数(サブルーチン)読み出し・復帰毎(ごと)に、関数のアドレスをPUSH/POPする必要がある。

データメモリ用スタックポインタ:名称はDSP(バス幅:64 bit)
・64 bit長(ちょう)のパラレルレジスタとする。
・64 bitパラレルで任意の値を入力できるようにする。
(スタック領域の設定に必要)
・PUSHという命令に対応するため、外部からの入力でレジスタの値を-1
できるようにする。
・POPという命令に対応するため、外部からの入力でレジスタの値を+1
できるようにする。
・DSPの値をアドレスとしてメモリに64 bitパラレルで出力できるようにする。
この仕様では、スタック領域は使えるメモリの最上位に設定し、プログラム中の関数(サブルーチン)読み出し・復帰毎(ごと)に、関数のアドレスをPUSH/POPする必要がある。

ステータスレジスタ:名所はSR(バス幅:4 bit)
4 bit長(ちょう)のレジスタとする。
・4 bitパラレルで任意の値を入力できるようにする。
(初期化とALU計算結果ステータスの設定に必要)
・ステータスレジスタの値を4 bitパラレルで出力できるようにする。

割り込みレジスタ:名称はIR(バス幅:64 bit)
・64 bit長(ちょう)のパラレルレジスタとする。
・64 bitパラレルで任意の値を入力できるようにする。
(割り込み処理アドレス設定に必要)
・割り込みレジスタの値をアドレスとしてメモリに64 bitパラレルで出力できるように
する。最初の設計なので、割り込みは1つに限定し、アービトレーション回路や複数の割り込みを予(あらかじ)め登録しておく割り込みテーブル関連の設定は考えないことにする。

第2章

算術論理ユニット(ALU)について

ALUの役割は、データの処理を行うことである。最初の頃のCPUは固定小数点形式の整数の加算と、逆数の加算による減算が実行でき、データをバイナリーのビット列と見なして、ビット列に対する演算処理を実行する機能を実現していただけだった。すぐに、乗算器と呼ばれる論理回路が追加されて、固定小数点形式の整数の四則計算を高速に実行できるようになった。

当時は、科学計算に必要な浮動小数点形式の数値を計算する為の論理回路は、CPU単体の機能に必要とは思われていなかったので、浮動小数点形式の数値を計算する専用回路(FPU)はついていなかった。必要なユーザーがFPUを追加するという形式であった。しかし、すぐに、FPUの機能はCPUに統合された。

その後、グラフィック処理ユニット(GPU)と呼ばれる、ディスプレイ表示専用の機能を実現した半導体回路拡張基板が、専用のバス経由でCPUに接続されるようになった。この論理回路は、グラフィック処理に良く出てくる浮動小数点形式の計算に特化した論理回路がハードウェアで組み込まれた。現在は、GPU機能もCPUに統合されている。

また、金融計算等で必要な、何度計算しても誤差が蓄積されない形式の数値をプログラムではなく、論理回路で実現する必要もある。古くはBCD演算と呼ばれていたような形式の数値の事である。

表計算ソフトの関数機能で実現されている各種関数は、ソフトウェアで数値計算ライブラリを利用して実現されているのだろうが、計算能力が限られている組み込み用途のCPUでは、予め、三角関数を計算済みの表形式で内部のROMに保管しておいて、三角関数の計算結果が必要なときは、内部でその都度計算するのではなく、ただ、該当する位置の表に記録されている計算結果の数値を参照するような論理回路を用意してあるものもある。

それらを考慮すると、ビット演算論理回路、固定小数点演算論理回路、浮動小数点演算論理回路、金融計算演算論理回路、グラフィック専用計算論理回路、ハードウェアの論理回路で実現した数学関数ライブラリーがALUには必要であるように思われる。

第3章

記憶制御ユニット(MMU)について

MMUに必要な機能

パソコンは、ハードディスクやインターネットなどから、OSやアプリケーションプログラムを主記憶(メインメモリ)に読み込み、プログラムの操作対象となるデータも同様にハードディスクやインターネットからメインメモリに読み込んで、アプリケーションプログラムの実行開始ポイントから、CPUへの命令を実行する事でプログラムを実行する。そして、大抵の場合は、実行結果を逆にメインメモリからハードディスクやインターネットへ書き込んで、プログラムの実行を終了する。

そのため、メモリは大変重要な機能であると言える。また、現在のOSは、実際のメモリアドレス(物理アドレス)とは別に論理アドレスと呼ばれるアドレスでメモリを管理する事によって、マルチタスクを実現したり、メモリの保護を実現したり、ハードディスクの空き容量をメモリに利用する事で、実行速度は大幅に遅くなっても、テラバイトサイズのメモリを実装しているように見せかける事のできる仮想記憶機能を実現している。

また、CPUの演算処理部とは別に、メモリ間のコピーや移動、シリアルの通信機能とメモリ間で、まとまったデータを授受する仕事を実行する専用のハードウェアとしてDMAC(DMAコントローラ)を備える事が当たり前になっている。当然こうした機能も必要である。

現在パソコンのメモリはDDR SDRAMが用いられているが、それには歴史的な理由がある。半導体の論理回路はゲートと呼ばれるが、このゲートはCMOSと呼ばれる回路でできている。スタティックRAMと呼ばれるメモリ回路は、このゲートを二つ使用して、各々の出力を相手の2入力の内の一つに入力してフィートバックをかけた回路で実現されている。この回路の事をフリップフロップ(FF)と言う。FFは実際にはセット入力とリセット入力、同期式ディジタル回路を実現するために必要なクロック入力を備えている。RS-FFとかD-FFとか、様々な回路が考案されている。FF一つで1 BITのデータを保持する事ができる。

一方、ダイナミックRAMと呼ばれるメモリ回路は、原理的にはコンデンサーとセンスアンプと呼ばれるゲートだけで実現されている。コンデンサーに電荷を貯(た)めると論理1、コンデンサーに電荷がなければ論理0と判断する。こちらの回路はスタティックRAMと比べると約四分の一のゲートで実現する事ができる。しかし、原理的にプリチャージやリフレッシュと呼ばれる機能が必要になる。DRAMのデータは書き込むときは、ただ書き込むだけであるが、読み出すときはコンデンサーの電荷を取り出してしまうので、破壊読み出しになってしまうからである。そこで、再度書き込む必要がある。また、コンデンサーの電荷は自然放電で0になってしまうので、0になる前に値を読み出して、元の値を再度書き込む必要がある。この機能をリフレッシュと言う。

上記のような欠点があるものの、SRAMに比べてDRAMは同じ半導体プロセスルールで製造した場合、メモリの容量を約四倍にできるため、コストの面からパソコンのメインメモリはDRAMが使用されている。当初は、DRAMC(DRAMコントローラ)と言うハードを標準CMOSゲートで作成したり、CPUがDRAMC機能を取り込んだりしていたのであるが、現在主流のDDR3 SDRAMのようなメモリモジュールの場合、メモリーモジュール側にコントローラがあって、アドレスバスとデータバスを直結して直接メモリにアクセスするのではなく、DDR SDRAMへコマンドを送る事で、データを読み書きできるようになっている。また、SDRAMのSはシンクロナス=同期式という意味で、クロックに従って、内部の回路が動作するようになっているDRAMを意味する。MMUには、このようなDDR SDRAMとのインターフェース回路が必要である。

メモリ階層の問題

CPUの論理回路を高速化する事は、パイプライン処理を実現するなどの方法である程度上手(うま)くいってきた。一方、メモリの高速化はなかなか困難で、両者のスピードには、一桁以上の差がある。そこで、考え出されたのがキャッシュと呼ばれる機能である。メインメモリがCPUに比べて遅いので、CPUの内部バスに一次キャッシュと呼ばれる超高速のSRAMを用意する。そして、プログラムによって、メインメモリから読み出したデータをキャッシュに保持しておく。ノイマン型のコンピュータの場合、ほとんどの場合、プログラムの実行ステップの前後に制御が移る事が多いので、こうする事で、改めてメインメモリから読み出さなくてもキャッシュから読み出す事ができるわけである。

半導体プロセスルールの微細化でトランジスタが余り気味と言う事もあって、一次キャッシュ、二次キャッシュ、三次キャッシュと、CPUチップ上に実装されるのが普通になった。その下位にDDR SDRAMモジュールとコマンドでやりとりするメインメモリがある。メインメモリのデータを読み書きするハードディスクをSSDに置き換えると、SSDは周辺機器インターフェースを通じて、ハードディスクへの読み書きに使用されるSATAコマンド通じて、ハードディスクのように振る舞うのだが、中身はNANDフラッシュと呼ばれる不摘発性のメモリーモジュールによって構成されている。ハードディスク自体にもキャッシュがあるのは当たり前で、キャッシュを使って見かけ上の速さを実現している。

こんなにキャッシュがあって、大丈夫なのだろうか?コヒーレンス性を保つのが大変なのではないだろうか。次世代のメインメモリはNANDフラッシュのように不摘発性でSRAMのように高速でアクセス可能な性質を持つメモリの研究が進んでいるようなのであるが、そうした新メモリの活用を考える必要があるかも知れない。

独自な実装について

既存のコンピュータの構成に縛られないで検討すると、組み込みマイコンや、パソコン用CPUでもCPU内部バス構成ではそうなっている物もあるように、データとプログラムを分ける方式が正しいかも知れない。そうすれば、あらかじめプログラムとデータが混ざって置かれているメモリのスタック領域に、マルウェア(犯罪目的のプログラム)をデータとして書き込んでおいて、わざとスタックオーバーフロー起こすようなアプリケーションプログラムをユーザーの権限で実行させ、本来、プログラムではなく、データだった筈(はず)のマルウェアが実行されてしまい、パソコンへの侵入を許してしまうような事も原理的に起きなくなるからである。

この場合は、仮想記憶の利用をプログラムメモリ側だけに適用するのか、データメモリ側にも適用するのか、など様々な検討課題が出てくると思われる。

演算処理部とメインメモリ間のデータ交換をなるたけ高速化するという機能を考えると、データはユニークであるので、再利用したり、あらかじめ用意しておく事はできないけれども、プログラムは、あらかじめ演算処理装置の近くにまとめて用意しておく事はできると思われる。

大昔は、プログラムは行き当たりばったりで書かれていて、スパゲッティのように混ざり合っていたので、書いた本人以外には解読するのが困難で、保守性が低いと言われていたのが、構造化プログラミングの時代になって、どんなに曲がりくねったプログラムも逐次実行文や、制御文、繰り返し文の組み合わせで実現できることが数学的に証明されて、プログラムの保守性が上がったのであった。

次にオブジェクト指向言語の時代になると、予め決まったデザインパターンを利用する事で、毎回車輪を再発明しなくてもプログラムが作成できるという考え方が広まった。例えば、リンク付きのリストを実現するようなプログラムは、誰が書いても同じようになるだろうから、高水準言語のライブラリーのような物を利用して実装し、プログラマーは独自の部分のみをコーディングするようにする事でプログラムの生産性を向上できるという考えである。

そうしたライブラリーをCPUと遅延無しでつながる階層に用意したROMに入れておいて、ユーザーのアプリケーションプログラムはそうしたライブラリーの利用を前提にした中間言語のようなものが、プログラム開発アプリケーションのコンパイル済みの実行プログラムとして出力されるようにすると、プログラムのサイズが小さくなり、実行は早くなり、メモリ階層の多さもクリアして、CPUの性能が向上するかも知れない。

第4章

入出力制御装置(IOP)と必要な機能

バスコントローラ機能

グラフィックコントローラを内蔵したCPUが標準的になってきたが、昔はCPUの取り付けられたマザーボードにある拡張用スロットに、グラフィックカードという名称の基板を差し込む方式だった。グラフィック処理は大量にデータを使用するので汎用の拡張スロットではデータ転送帯域が確保できない為、グラフィックカード専用のユーザーインターフェースが用意されている。こうした機能を実現する必要がある。

CPUや、コアが複数になると主メモリとの接続に工夫が必要になる。単純に全てのコアを同じバスに接続すると性能を上げられないボトルネックになることがある。それを避けるためにはCPUの側(がわ)にメモリを配置してハイパーキューブ型のネットワークにしたり、電話交換網のようなクロスバースイッチを配置して接続したりする必要がある。

そうした構造のCPU周りの高速バスと、CPU外の周辺機器に接続することを前提に考えられた低速バスを用意する必要がある。この二つのバスは転送速度に差があるために、直接接続する事はできない。中間にバッファーを入れて、フロー制御で速度差を吸収する必要がある。

バスコントローラはこれらの処理を適切に実行する必要がある。

シリアル・パラレル変換機能

周辺インターフェースは半導体チップの外部へ接続され、プリント基板を介して、他の半導体チップと接続されたり、バッファーやレベル変換用の半導体チップや電子回路保護用の部品を介して、パソコンの外部インターフェースソケットと接続されたりする。

そのため、64 bit並列(パラレル)伝送方式で64本の信号線を引っ張るようなことは実用性が低く、64 bitの情報を数本の信号線で送受信できるような直列(シリアル)伝送方式が採用される。こうした伝送方式を実現するためには、相互にシリアルとパラレルを変換できる回路が必要であり、実装できる限り高速に変換できる必要がある。

各種周辺インターフェース規格への対応

USB等の周辺インターフェースは、従来は、CPU周辺チップとして実現する例が多かったのだが、最新のCPUでは、機能として内蔵されていく傾向にあるようだ。バグ無く実装できれば、ソフトウェアでOSのドライバ等として実現するよりも、高速、かつ、安定的に動作するだろう。その規格が周辺インターフェースとして必要性が高く、規格が確定している周辺インターフェース規格は内部機能として実現する必要がある。

第5章

命令制御ユニット(IU)と必要な機能

CPUは命令を読み込んでそれに従って処理を実行する。命令制御ユニットは命令の解析を行う解析部と、解析した結果にもとづいて処理の実行に必要な各種機能モジュールを制御する制御部とから構成される。分岐命令で順番が代わらない限り1命令ずつ順に実行して行く。1命令を細かい単位に分解して同時に実行する事で、分割した単位の数に応じて処理速度を倍加する事もできる。そうした機能をパイプライン方式と言い、現在の市販されているCPUは殆ど全て、パイプライン方式である。命令体系はCPUを左右するほど大切なものであり、いろいろな処理を似たような形式で処理できる命令体系の方が、分かり易くて良い命令体系と言われる。

ハードワイヤ方式とマイクロプログラミング方式

命令の解析と制御を行う機能モジュールをハードウェアで実現する方法と、CPUの中に更に小さなCPUのような機能モジュールを用意して、普通のCPUの命令とは異なって、人間にとても分かりづらい1命令の長さがすごく長い形式の命令の実行でCPUの命令解析と実行を制御する方法がある。前者の方式をハードワイヤ(回線が固定されているの意味)方式と呼び、後者の方式をマイクロプログラミング方式と呼ぶ。

一般に命令体系が複雑なCPUはマイクロプログラミング方式で実現され、命令体系が単純なCPUはハードワイヤ方式で実現される。当然、ハードワイヤ方式の方が実行速度は速くなるが、開発するのは難しく、単純な命令しか実現しにくいので、アプリケーションから見た場合、結局上位のソフトウェアで複雑な処理を実行する事になる。

複雑な命令を持ったCPUならば、アプリケーションから見て同じ処理が少ない命令で実現できる場合があり、どちらが速くなるかは一概には言えない。ただ、パイプライン方式を導入する場合は、命令体系が単純で、個々の命令が高速でかつ、どの命令もできる限りほぼ同じ実行時間で処理を実行するような命令体系の方がCPUは高速に動作する。

パイプライン方式

命令実行時の内部処理を細かい単位に分解して、その単位毎に、独立して実行できるような機能モジュールとして設計し、できるだけ、それぞれの機能モジュールの実行時間を一緒にして、平行して動作できるようにし、細かい単位の処理をそれぞれのモジュールに行き渡らせて、一斉に実行させるようにすると、最初の命令の実行にはクロックに応じた時間が掛かる事には変わりは無いのだが、二つ目以降の命令は、最初の命令の実行時に次の命令の細かい単位の処理が処理済みになっているので、すぐに、次の命令を実行する事ができる。

このようなやり方をパイプライン方式と言い、理想的な状況ではパイプラインの段数が多ければ多いほど見かけ上、段数分の一にCPUの命令処理時間を向上させる事ができる。実際には、命令を実行して、その結果が分からない限り、どちらへ制御を移して良いか分からない分岐命令と言う問題があって、理想的な状況が常に成立するわけではない。

パイプラインが無効にならないための回避策

パイプライン方式で分岐命令を処理しようとすると、パイプラインが無効になって、最初からパイプラインの中へ細かい単位の処理を詰め込んでいくことが必要になることがある。

この問題の回避方法の一つは、資源をたくさん使って、二組、あるいはそれ以上、細かい単位の処理を実行できる機能モジュールを用意しておき、分岐命令の結果によって分かれる分岐1と分岐2のそれぞれの処理を、両方とも同時に実行してしまうという方法がある。この方法の場合は、分岐命令の処理が終わると同時に正しい分岐先の処理結果を有効として、その続きからパイプラインを使った実行を続け、正しくない分岐先の処理結果は破棄する。

もう一つの回避方法は投機的予測と呼ばれる手法で、分岐命令の結果が分岐1と分岐2のどちらになるかをギャンブルのように予想する。過去の傾向などから予測を立てるので、公営ギャンブルなどと比較してはるかに良くあたる。この方式は資源を浪費しないメリットがある。ほとんどの場合は予測が的中してパイプラインは引き続き有効だが、たまに予測が外れると、パイプラインの中の途中処理した細かい単位の処理は全部無効になり、分岐命令の直後から、正しい分岐先の処理をパイプラインへ入れていく必要がある。

第6章

割り込み処理ユニット(INTU)と必要な機能

周辺機器にはキーボードのような、低速な周辺機器もある。こうした周辺機器に対応する場合は必須の機能となる。割り込み処理機能が存在しないと、もっとも低速な周辺機器をポーリングで監視し続ける必要が生じて、CPUの性能が著しく低下する。割り込み処理機能があれば、一度、割り込み処理を設定しておけば、CPUは割り込まれるまで別の命令を実行する事ができる。

また、割り込みは、周辺インターフェースに接続されたタイマー機能などと組み合わせてハードウェア的な一定期間毎の割り込み処理を発生させて、マルチユーザー・マルチタスクシステムOSを実装するときのシステムタイマーに利用されたりする。

割り込みを理解するためには、まず、サブルーチンや関数と呼ばれるプログラミング言語の文法を理解する必要がある。フォンノイマン型の言語のプログラムは、基本は命令逐次処理型であり、命令が羅列されている文字列で構成される。そのようなプログラムには同じ手続きの繰り返しが現れる事がしばしばある。

昔はメモリが貴重だったのでプログラムをメモリに収めるためにサブルーチンの仕組みが考え出された。メモリが安くなって来たり、仮想記憶方式が開発されてきたりした結果、プログラムの格納サイズに対する制限は大幅に緩和されたがサブルーチンや関数という考え方はプログラム言語の仕様に残った。

サブルーチンや関数を実現するためには、スタックマシンと呼ばれるハードウェアの仕組みがあった方がより望ましいと言える。IBMのごく初期のメインフレームはスタックマシンの仕組みを持たなかったので代わりにレジスタブロックを複数持ち、サブルーチン実行時はレジスタブロックを切り替えて対応していた。現在のCPUはスタックマシンの仕組みを持たないものは多分無いであろう。

サブルーチンや関数はプログラムの中から呼ばれる。サブルーチンコールや関数コールの書式に基づいて必要な引数を与えられて呼び出され、実行が終了すると制御がプログラムに戻ってくる。OSを持たないプログラムやシングルタスクOSのプログラムの場合は、サブルーチンや関数の実行が終了するまで、メインのプログラムの実行は停止され、実行終了まで待たされる。こうした動作を同期式と言う事もある。通信プログラムのように、プログラムの実行が停止されては困るような場合は、非同期式の動作ができるようにコーディングしたり、マルチタスクモニタやマルチタスクOSを使用したりする。

こうした非同期式サブルーチンの実行のきっかけが、CPU内部のプログラムからのコールではなく、CPU外部のハードウェア要因による仕組みが割り込み処理という機能である。つまり、CPUの外部から、CPUが実行中のプログラムの実行を中断させ、予め与えておいたサブルーチンを実行するようにできる機能の事を言う。割り込み処理で重要なのは、割り込みからの復帰と割り込み処理の優先順位付けの調停機能である。

割り込みから復帰するには元のプログラムを実行していたときのレジスタの内容を復元する事が必要だ。そのためスタック領域というメモリ領域にレジスタの値を待避しておく。割り込みプログラムの実行が終了したならば、待避しておいたレジスタの内容をスタック領域からレジスタに設定し直す。レジスタにはプログラムカウンタ(PC)も含まれているため、そうすると、割り込み復帰後、直ちにプログラムの続きを実行する事ができる。

割り込み処理ユニットに必要であり、重要な機能が割り込み処理の優先順位付けと割り込みの調停機能である。

リセット(RESET)はもっとも優先順位の高い特殊な割り込みと理解する事ができる。殆どのCPUでリセット入力検出後の動作はハードウェアで固定されていて、例えば、プログラムカウンタ(PC)の0番地から実行を開始する事、CPU固有のリセット後のメモリ状態が実在し、メモリの内容も0クリアされていて、ヒープ領域やスタック領域が、初期値でCPUが想定しているメモリマップに基づいたメモリ領域に存在していると仮定して、リセット直後の実行を開始する。

容易に思いつくように、予め、リセット実行時の状況が適切になるようにハードウェアを用意したり、リセット直後に実行されるブートプログラム(BOOT)でメモリの初期化や各種内部レジスタの初期値の設定などをきちんと設定したりする必要がある。そのようにしておかなければ、リセットしただけでCPUは暴走してしまう。

ノン・マスクド・インタラプト(NMI)と呼ばれる割り込み入力もあるNMIの特長はプログラムからNMIの割り込みの有効・無効を変更できない事である。そのため、NMIに周辺ICのインターバル・タイマからの周期パルスを入力する事で、モニタやマルチタスクOSを実現するような目的に使われる。

通常の割り込み入力(INT)は割り込まれたときの割り込み処理実行用のサブルーチンのアドレスを設定したり、割り込みの有効・無効の設定も特定のレジスタにセット・リセットの値を書き込んだりする事で自由に設定する事ができる。

割り込みには調停機能が必要である。ハードディスク(HDD)コントローラとDMAコントローラーを割り込み処理で非同期にアクセスしようとしたとする。もしかすると、HDDコントローラはDMAコントローラーが割り込み処理を終了するのを待機中かも知れない。と同時に、もしかすると、DMAコントローラはHDDコントローラーが割り込み処理を終了するのを待機中かも知れない。こうした状態になってしまうと、いわゆるデッドロック状態になってしまう。

そこで、調停機能の出番である。何らかのルールに基づいて、割り込みに優先順位をつける。すると、デッドロック状態を解除する事ができる。例えばRESET > NMI > INTとし、NMIやINTはよく考えて、どのようなルールで優先順位を付けるか決める。割り込みディスクリプタのような、割り込み処理サブルーチンのアドレスや割り込み専用のメモリ領域の大きさやアドレスなどをまとめて登録できる一覧表のようなものに優先順位が高い割り込み処理と、優先順位が低い割り込み処理を登録する。

すると割り込みが競合するような場合に、調停機能モジュールが介入して、上位の方の割り込み処理サブルーチンを優先的に実行して、下位の割り込み処理サブルーチンは後回しに実行される。後回しされる割り込み処理は時間が掛かってもかまわない処理を選択しておく必要がある。

第7章

その他、基本構成で必要な機能

CPUの初期設定モジュール

CPUはリセットされると、プログラムの0番地から実行を開始する。これを正しく実現するには、半導体の初期値をそのような実行が可能なように初期設定しておく必要がある。半導体は製造時の誤差によって、電源が入れられると、レジスタの各bitの初期値が、0又は1のどちらかに偶然によって決まってしまう。

そのため、CPUの初期設定を実行するモジュールが必要になる。このモジュールは、パワーオン・リセット回路と入力リセット回路を必要とする。割り込み回路と似ているが、実行に必要な動作はより多くなる。初期設定モジュールはマイクロプログラムで実行するか、ステートマシンのようなハードウェアで実現する。

第8章

エイトリーフCPU命令セット・アーキテクチャ仕様書0.2版について。

エイトリーフCPUの命令セット・アーキテクチャ仕様書の基本構成版の第1.0.2版」がダウンロードページで公開されています。旧Webサイトで公開していた0.2版とは大幅に変更されています。

独自CPUの命令セットとアーキテクチャをまとめた。
基本構成と上級構成の2タイプに分けて検討する。まず基本構成を検討する。上級構成はかなり難しくなるので当面は検討を先送りにする。

前提条件として、キャラクターと数値を表現するコードのbit長を64 bitに決める。もう一つ前提として、クロックで動作する同期式論理回路で実現する。論理回路には非同期式と呼ばれる回路もあるのだが、同期式に比べると安定的に動作させることが飛躍的に難しくなるからだ。

固定長か可変長か

命令を決める場合には、固定長命令とするか、可変長命令とするかを検討しなければならない。固定長命令とは命令のサイズが決まっているもので、RISCプロセッサによく採用されている。理由は、命令解析の論理回路が簡単になることと、プログラムキャッシュに格納しやすくなるからである。しかし、必要な命令体系の最大サイズに合わせると、メモリの無駄が生じる。短い命令だけで構わない場合も、空きスペースを追加して、サイズを統一する必要があるからである。

一方、可変長命令の場合は、命令のメモリ利用効率がよくなる。また、命令体系の柔軟性が増す。理由は、命令だけで済むものは、命令だけでよく、命令+データや、命令+アドレス+データ、命令+アドレス+アドレスのようにすることができるからだ。その代わり、命令解析の論理回路が複雑になるし、プログラムキャッシュにも格納しにくくなる。

■結論

・仮想記憶や保護のない物理メモリーでフラットな構造にする。
・入出力はメモリマップ方式として、専用の命令や仕組みは用意しないことにする。
・サブルーチンコールができるようにスタックマシンの仕組みを用意する。
・割り込み処理は1レベルの単純な物にする。
・メモリ管理はプログラム専用メモリーとデータ専用メモリーに分離する方式とする。
・プログラムは2バイト(16 Bit)のUTF-16コードで記述することにする。
・データ長とアドレス長は64 bitの数値として扱うことにする。
・クロックで動作する同期式論理回路で実装されることを想定する。
・可変長命令形式を採用する。

以上

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

CAPTCHA


関連記事一覧