なでしこさんで 1bit CPU エミュレータ
頭が悪いので、今週もやろうと思う作業ができなかったのだ。
今回もなでしこで簡単なプログラムを書いてごまかすのだ。
今回やったこと
1bit CPU のエミュレータを作ってみた。
プログラム
1bit CPU エミュレータ (なでしこ3貯蔵庫)
使い方
「ROM」内のチェックボックスを操作して、プログラムを設定する。これは 1bit CPU のディップスイッチに相当する。
「電源」のチェックボックスにチェックを入れると、電源を投入したことになり、プログラムが実行される。
「リセット」ボタンを押すことで、状態をリセットできる。
プログラムのポイント
UI作成の補助用関数の用意
●(LABELの)グループボックス作成とは
定数のグループボックスは「fieldset」のDOM部品作成。
それの「display」に「inline-block」をDOMスタイル設定。
定数のラベルは「legend」のDOM要素作成。
それにLABELをDOMテキスト設定。
グループボックスにラベルをDOM子要素追加。
グループボックスを戻す。
ここまで。
●(部品を)クリック無効設定とは
部品をクリックした時には
対象イベントのDOMイベント処理停止。
ここまで。
ここまで。DOM部品操作系命令による部品の作成に似たインターフェイスで fieldset を作成する「グループボックス作成」関数と、「DOMイベント処理停止」命令を用いてチェックボックスの操作をできなくする「クリック無効設定」関数を用意する。
UIの大枠の作成
ラッパーは「div」のDOM部品作成。
それにDOM親要素設定。
それに{
display: "inline-grid",
gridTemplateColumns: "auto 1fr auto",
alignItems: "center",
}をDOMスタイル一括設定。
状態ボックスは「状態」のグループボックス作成。
それに{
gridRow: "1",
gridColumn: "1 / span 3",
textAlign: "center",
marginBottom: "0.5em",
}をDOMスタイル一括設定。
ROMボックスは「ROM」のグループボックス作成。
それに{
gridRow: "2",
gridColumn: "1 / span 3",
textAlign: "center",
marginBottom: "0.5em",
}をDOMスタイル一括設定。
電源スイッチは「電源」のチェックボックス作成。
それに{
gridRow: "3",
gridColumn: "1",
}をDOMスタイル一括設定。
リセットボタンは「リセット」のボタン作成。
それに{
gridRow: "3",
gridColumn: "3",
}をDOMスタイル一括設定。グリッドを用いて、状態表示エリア・ROMエリア・電源スイッチ・リセットボタンを配置する。
UIの各エリアの中身の作成
状態ボックスにDOM親部品設定。
「A:」のラベル作成。
Aレジスタは空のチェックボックス作成。
それをクリック無効設定。
「 PC:」のラベル作成。
プログラムカウンタは空のチェックボックス作成。
それをクリック無効設定。
「 クロック:」のラベル作成。
クロックは空のチェックボックス作成。
それをクリック無効設定。
ROMボックスにDOM親部品設定。
「0:」のラベル作成。
ROM00は空のチェックボックス作成。
ROM01は空のチェックボックス作成。
「 1:」のラベル作成。
ROM10は空のチェックボックス作成。
ROM11は空のチェックボックス作成。
ROMは[[ROM00, ROM01], [ROM10, ROM11]]。状態表示エリアおよびROMエリアの中身を作成する。
状態表示エリアのチェックボックスは、用意した「クリック無効設定」関数を利用し、直接変更できないようにした。
リセットボタンの処理
リセット中はオフ。
リセットボタンをマウス押した時には
もし、対象イベント$buttonが0ならば
対象の「setPointerCapture」を[対象イベント$pointerId]でJSメソッド実行。
リセット中はオン。
Aレジスタ$選択状態はオフ。
プログラムカウンタ$選択状態はオフ。
ここまで。
ここまで。
リセットボタンをマウス離した時には
もし、対象イベント$buttonが0ならば
リセット中はオフ。
ここまで。
ここまで。リセットボタンが押されたとき、状態をリセットして動かないようにする。
「クリック時」命令ではクリックされた瞬間しかとれないので、「マウス押時」命令と「マウス離時」命令を用いていつからいつまで押しているかがわかるようにした。
「押ボタン」では複数のボタンを同時に押したときの処理に難があり、また「マウス離時」のイベントでは正しくボタンの情報が得られないようなので、button プロパティを用いて左クリックかどうかの判定を行うようにした。
さらに、setPointerCapture メソッドを用いて、押したままマウスカーソルがボタンから出ても離した判定をできるようにした。
状態を更新する処理
●状態更新とは
命令とは変数。
もし、プログラムカウンタ$選択状態ならば
命令はROM@1。
違えば
命令はROM@0。
ここまで。
定数の命令種類は命令@0。
定数の命令オペランドは命令@1。
もし、命令種類$選択状態ならば
プログラムカウンタ$選択状態は命令オペランド$選択状態。
違えば
もし、命令オペランド$選択状態ならば
Aレジスタ$選択状態はAレジスタ$選択状態の論理NOT。
ここまで。
プログラムカウンタ$選択状態はプログラムカウンタ$選択状態の論理NOT。
ここまで。
ここまで。
●クロック処理とは
クロック$選択状態はクロック$選択状態の論理NOT。
もし、(クロック$選択状態)かつ(リセット中の論理NOT)ならば
状態更新。
ここまで。
ここまで。「クロック処理」関数では、クロックの状態をトグルし、立ち上がりで「状態更新」関数を呼び出す。
「状態更新」関数では、「チェックボックス作成」命令の解説にある「$選択状態」を用いて、ROMの内容を取得し、それによってAレジスタやプログラムカウンタの状態を進めている。
電源スイッチの処理
クロックタイマーはNULL。
電源スイッチの変更時には
もし、電源スイッチ$選択状態ならば
クロックタイマーは「クロック処理」を0.5秒毎。
違えば
Aレジスタ$選択状態はオフ。
プログラムカウンタ$選択状態はオフ。
クロック$選択状態はオフ。
クロックタイマーのタイマー停止。
ここまで。
ここまで。電源スイッチがオンになったときは、クロックの発生を開始する。
0.5秒ごとにクロックの信号をトグルすることで、1Hzで動かすようにしている。
電源スイッチがオフになったときは、クロックの発生を停止し、状態をリセットする。
まとめ
なでしこで、1bit CPU の動作を再現することができた。


コメント