Immediate Values – LEGアーキテクチャー版【Turing Complete編】
はじめに
いつもブログをご覧いただきありがとうございます。
コーストFIRE中のIPUSIRONです😀
Immediate Valuesステージ
過去にも"Immediate Values"という同名のステージがありましたが、本ステージではLEGアーキテクチャーにImmediate(イミディエイト)モードを追加します。
追加するImmediateモードの仕様は次の通りです。
・命令語の1バイト目(操作コード)において最上位ビット(8番目)がONなら、引数1は転送元ではなく、即値(計算対象のバイトデータそのもの)を意味する。
・命令語の1バイト目(操作コード)において上から2番目のビット(7番ビット)がONなら、引数2は転送元ではなく、即値(計算対象のバイトデータそのもの)を意味する。
Immediate Valuesステージを解く
1:既存のLEGアーキテクチャーの回路を見直す
これまでに作ってきたLEGアーキテクチャーが引き継がれているはずです。
※「Switch schematic」で既存の回路をバックアップし、コピーしたものに使って回路を組むとよいでしょう。
Immediateモードの回路を組み込むことになりますが、最初は各種演算回路(ALUに相当)の右側にスペースが空いているので、いったんはここに組むことにします。
ただし、処理の流れとしては、演算の転送元の処理なので、本来は各種演算回路の左側にあった方が自然といえます。そのため、最終的には、各種演算回路部と入れ替えるように配置します。
2:Immediateモードを識別する回路を検討する
操作コードの上位2ビットによって、操作がImmediateモードかどうかが決まります。
操作コード | 従来のCPUアーキテクチャーのモードに例えると | 操作 |
---|---|---|
0000 xxxx | Calcutationモード (Computeモード) | 第1引数と第2引数はレジスター群(追加で入出力ポート、プログラムカウンター)が対象。 保持するバイトデータを扱う。 |
1000 xxxx | Immediateモード | 引数1が即値。引数2はレジスター群。 |
0100 xxxx | Immediateモード | 引数2が即値。引数1はレジスター群。 |
1100 xxxx | Immediateモード | 引数1と引数2の両方が即値。 |
この4パターンを識別する回路は、命令語の1バイト目を8 Bit Splitterコンポーネントでビットごとに分離します。そして、8番ピン(あるいは7番ピン)のON・OFF状態で、計算対象データの取得元を切り替えます。レジスター群から取得するか、第2引数(あるいは第3引数)から直接取るかのどちらかになります。
多入力から1本を選択するには、マルチプレクサーがもってこいです。今回はバイトデータ用のワイヤー(8ビット幅)が2本あり、それを1ビットで切り替えればよいので、8 Bit Muxコンポーネントを使うことになります。
3:命令語の2バイト目のための回路を組み込む
命令語の2バイト目と3バイト目についての回路を組み込む必要がありますが、まずは前者の回路だけを考えます。これが完成さえすれば、後者も同様な回路になるはずだからです。
まずはオペコードがADDのときの処理だけについて、2バイト目の回路を組み込みます。
ステップ2の考え通りにやれば、8 Bit Muxコンポーネントの入力まではできるでしょう。
あとは出力がどうつながるのか考えます。演算の転送元の候補は2つあり、マルチプレクサーで切り替えられました。つまり、「AddコンポーネントのInput 1ピン」のワイヤリングを解除して、「8 Bit MuxコンポーネントのOutputピン」と「AddコンポーネントのInput 1ピン」を接続すればよいことがわかります。
回路は次のようになります。
次に、オペコードがADDについて、3バイト目の回路を組み込みます。
もう1つ8 Bit Muxコンポーネントを用意します。今度は8 Bit Splitterコンポーネントの7番ピンを使うことになります。それ以外については、2バイト目の回路の実装とほど同様です。
オペコードADDについての回路は完成しました。後は、他のオペコードについても回路を組むことになります。
Immediateモード用の回路がどの程度のスペースを使うのがわかりましたので、この時点で各種演算回路部の左側にスペースを作りましょう。そして、その後で他のオペコードに対する回路を完成させることにします。
Multi Selectボタンで右側をまとめて右にスライドさせてから、Immediateモードの回路を隙間に入れます。スライドした時点でワイヤリングが重なって不正な状態になるかもしれません。
下に警告文が出て、不正なループが発生しているところはワイヤーが赤くなっているので修正します。
また、ワイヤリングが曲がったり重なったりして見にくくなっていれば、この時点で修正しておきましょう。
※画像では、ProgramコンポーネントのAddressピンにつながっているワイヤーを余分に消してしまいました。最後まで気づかず、テストでようやく気づきました。
さらにワイヤリングを調整して、隙間を空けます。そして、Multi Selectを使って、Immediateモードの回路を間に移動します。
ワイヤリングを調整します。全体を見直してワイヤリングミスがないことも確認してください。
特に、演算コンポーネントの入出力ピンのつながりをチェックします。
きれいにワイヤリングし終えた例が次になります。
4:演算コンポーネント周辺の回路を修正する
残りの演算コンポーネントについても、Immediateモードの回路に接続します。
演算コンポーネントの出力に変化はありません。入力ピンに接続するワイヤーを修正します。
下から回ってきているレジスター(あるいは入力端子)からくるワイヤーを外して、8 Bit MuxコンポーネントのOutputピンから伸びたワイヤーに接続するのです。
5:演算回路内の一致回路を修正する
残念ながら、まだ修正する必要があります。
これまではEqualコンポーネントを使って、演算結果を1つだけ流すように制御していました。本ステージからはオペコードの上位2桁が00固定でなくなったことに対応させる必要があります。
そこで、Equalコンポーネントを止めて、従来の「8 Bit Splitterコンポーネント+3 Bit decorderコンポーネント」の手法に戻します。これであれば、任意の上位2桁であっても、出力すべき演算が確定できます。
※命令語の1バイト目にはすでに8 Bit Splitterコンポーネントを接続済みなので、これを流用します。
※ProgramコンポーネントのAddressピンのワイヤーもこの時点で修正する必要があります。
最初回路ができあがったときに、テストがパスできず30分以上悩み続けました。
原因は、プログラムカウンターとProgramコンポーネントのワイヤリングが途中で外れてしまっていたからです。
メイン回路側に問題があるのではないかという先入観があったため、プログラムカウンター周辺に目が行きませんでした。
6:テストする
テストにパスすると、ステージクリアになります。
一致回路のために上位2桁を無視する場合【別解】
上記の回路では演算回路内の一致回路を削除しましたが、一致回路を残したまま対応させる方法があります。
マスクビットのテクニックを使えばよいのです。1バイト目と0011 1111bをAND演算すると、上位2桁を00bにできます。
マスクビットのテクニックを活用すると、次の回路が得られます。