ユニット構成続き
インストラクションセット(再掲載)
DecoderROM詳細
DecoderROMから出る制御信号を1つづつ解説します。
アキュムレータにデータを取り込むかどうか:1ビット
この信号です。
データをアキュムレータに転送する命令、演算命令(ADD,SUB,AND,NOR)の時(演算命令はどれもアキュムレータに演算結果を書き込むので)1です。LD、LDA命令はメモリから、IN命令はI/Oから、演算命令の時ははALUから、そしてMOV命令はオペコードの下位8ビットからアキュムレータに転送します。アキュムレータの入力につながっている線をたどると、この3つのうち1つがマルチプレクサで選択されているのが判ると思います。
メモリに出すアドレスを3種類のうちどれにするか(又はどれでもないか):2ビット
この2ビットでメモリに向けて出すアドレスを選択します。 この2ビットが00の時は、ALUの出力が選択されます。これはLDA命令の時にオペコードの下位8ビットとアキュムレータを加算するからです。 01の時はオペコードの下位8ビットです。LDA以外でメモリの読み書きが発生する命令は、オペコードの下位8ビットがアドレスなので、これを出せるようにOPECodeレジスタの出力から下位8ビットを分けて取り出してあります。 10の時はCodePointerの内容を出します。Fetch Stageですね。アキュムレータの内容をデータバスに出すかどうか:1ビット
同様に信号をたどってみてください。この記号はLogisimではControlled Bufferと表記されています。(5)のセレクタの所で触れた tristate bufferです。下に生えてる制御信号が0の時は出力が電気的にどこにもつながっていない状態になります。これは、メモリがデータを出力している時にアキュムレータの出力とぶつからないようにするためです。ST命令とOUT命令の時に1になります。
※MOV命令の時に1なのは、アキュムレータもメモリも出力になって無い時にデータ線が「どこにもつながってない」にならないためです。プルアップ抵抗入れたので必要ないですが、直し忘れという事でどうかひとつ。
I/Oかメモリアクセスか:1ビット
メモリアクセスかI/Oアクセスかを、MEMORYとI/Oに伝えるための信号です。MEMORY部はこの信号が1の時はイネーブらないようにしてあります。これはMEMORYの枠の中にあるGATEが処理します。I/O部もこの信号が0の時は反応しません。
メモリへの書き込みかどうか:1ビット、メモリからの読み出しかどうか:1ビット
メモリ、I/Oへの書き込みか、読み出しかを指定する信号です。メモリもI/Oも、どちらかが1にならないと反応しないように作ってあるので、命令の実行が内部だけで完結する時(例えばJMP命令)は、どちらも0です。
ALU
Arithmetic Logic Unitの略で、不思議の国の略 算術・論理演算ユニットです。P08では、加算、減算、AND、NORの4種類の命令をサポートしています。
左側上から演算結果が0の時1を出すユニット、ZeroFlagを保存するDFF、CarryFlagを保存するDFFです。
このALUの入力は、片方はアキュムレータ固定、もう片方はメモリから読むか、又はオペコードの下位8ビットです。オペコードの下位8ビットはLDA命令でのみ使用されます。
SUB/ADDは(5)の加算の項で作った回路を並べて8ビットにしてあります。なので加算か減算か選択する信号が必要です。このSUB/ADD回路、それから8ビット同士の論理演算のANDとNORの4種類(というか3種類)の出力のうち1つを選択するマルチプレクサがあります。図の中央上ですね。演算命令は上位2ビットが01で、その次の2ビットが演算の種類なので、このマルチプレクサはオペコードから引いて来た信号を使っています。
このへんにはもう1つ、オペコードの上位2ビットが演算命令を示す01の時に1を出力するANDがあります。ANDの入力に付いてる白丸は反転の意味で、ここにInverterが付いてます(NOTも白丸ついてましたね。三角がNOTの意味ではなく白丸が本体です)。オペコードが演算命令の時ここから1が出ます。そして、この信号が1の時はアキュムレータはALUの出力を取り込みます。線をたどってみてください。また、Zフラグ、Cフラグを取り込むかどうかも、この信号で制御するので演算命令以外の時にフラグが変化しません。
JUMP制御部
制御信号はOPECodeの上位4ビットと、ALUからCarry FlagとZero Flagがつながっています。
左側、ANDが2つあります。上がオペコードの上位3ビットが100の時、つまりJCかJZ命令の時に1になります。分岐条件がCarryを見るのかZeroなのかは、オペコード上位4ビットのうち一番下ですから、それとALUから来た信号とで分岐するかどうかが右中央のANDから出てきます。左下のANDはオペコードの上位4ビットが1010の時に1を出します。JMP命令ですね。
どちらかが1なら分岐するのですが、Code PointerはFetch Stageの時は自分に1足した値を取り込みます。ですから、分岐先のアドレスを取り込むのはDecode&Execute Stageの時、という事になります。それを制御しているのが右下のANDです。
アキュムレータ周辺
アキュムレータに入力される信号は2つのマルチプレクサで選択されます。
アキュムレータに近い方は、選択信号が1の時にALUの出力が出てきます。遠いほう、図の左下はメモリかオペコードかの選択信号です。
メモリからアキュムレータにデータが転送されるのは、LDA命令、オペコードからの場合はMOV命令です。LDAはオペコード上位4ビットの一番下が0、MOVは1なので、それを利用します。
Code Pointer周辺
CP++と書いてあるのが、入力に1を出して出力するユニットで、それの出力とOPECodeの下位8ビットの選択をJUMP処理部からの信号で切り替えます。
だいたいこんな感じです。
それぞれのユニットやGATEは入力に応じた出力をいつも垂れ流しています。取り込む機能があるユニットがそのうちどれを取り込むかを制御する事で処理が進んで行きます。
取り込みのタイミングがクロックのQとEの↑エッジか↓エッジかの違いや、Fetch StageとDecode&Execute Stageのどちらで取り込むかの違いがありますが、基本は選択信号で選り分けられた信号を取り込むという事です。そして取り込んだ信号はその瞬間、組み合わせ回路を通って出力側に結果を垂れ流す、の繰り返しです。
P08は説明用に作ったシンプルなプロセッサですが、必要な事は全部ここに詰めました。Logisimは良く出来たシミュレータです。ぜひ、ステップ実行しながらお手々ツールで信号を追いかけて見てください。
プロセッサの動作詳細は続けていくと「ボクが作った最強筋肉超人」になってしまうので、このへんでひと段落です。