TJD4 vol.7 命令セット 汎用ロジックicだけで作るcpu制作記録
masudaですー.
命令セットについてニチニチ書いていきますよー.
よろしくお願いします.
進捗
前回の記事を書いたまま今回書いているので進捗に更新はありません.
CPUの命令に必要なもの
CPUの命令のデッキのことを命令セットと言います.
現在この世にはx86だとか,ARMだとか,RISC-Vだとか,いろんな命令セットがありますが,TJD4にそんな高級な命令セットを持ち込むことはできません.
徹底的に命令の数を少なくしていきます.
いらない命令はTJD4には不要です.
...って考えた時に,どんな命令さえあれば,CPUとして成り立つのかを考えていきます.
考えても分からないときは,インターネットの母Wikipediaを拝見します.
wikiさん曰く,
「移動,計算,制御フローの変更」が必須らしいです.(https://ja.wikipedia.org/wiki/%E5%91%BD%E4%BB%A4%E3%82%BB%E3%83%83%E3%83%88 より)
ひとつずつ説明していきます.
移動,これは情報の参照元(source)と,情報の格納先(distination)が指定でき,sourceからdistinationへの情報を移動ができることを指します.
Aレジスタの情報をBレジスタに移動する命令,RAMnn番地の情報をXレジスタに移動する命令,Aレジスタの情報を出力ポートに移動する命令,,,これらは移動にあたります.
計算,これは文字通り情報と情報の足し算や,論理積を求める命令がないとCPUとしては成立しないことを記述しています.
制御フローの変更,これは簡単に言うと,ジャンプ命令についての説明と言えます.もし~~だったらこうしよう,そうじゃなかったらああしよう,といった命令を指します.
TJD4はそのハードウェア制約により,ジャンプ命令がかなり使いづらいものとなっていますが,一応実装されているので問題ありません.
TJD4の命令セット
これらを踏まえてTJD4の命令セットはどんなものにしましょう.
結論から書きますが今回の命令は以下のようになります.
まずOPECODE,OPERANDがROMに格納されている情報です.
それらとフラグよってデコーダ出力が変わります.
信号がxであるところはそれが0でも1でも出力に変化はありません.
順番に説明していきます.
LD(s), (d) (LoaD)
この命令.(s)や(d)にはABXYのいづれかが当てはまります.
先ほど説明した移動命令の一種で,(d)レジスタに(s)レジスタの値4ビットをコピーします.
今書いてて思ったけどこれ(s)と(d)反対の方が絶対文法的に誤解を生まなかった気がします.
IM(d), n (IMmediate)
この命令は(d)レジスタに即値4ビットをコピーします.即値4ビットはROMのオペランド領域を参照します.
AB(d), n (ABsolute)
この命令は(d)レジスタにRAMn番地の値4ビットをコピーします.
IN(d), n (INput)
この命令は(d)レジスタに入力ポートの値4ビットをコピーします.
ST(s), n (STore)
この命令はRAMn番地に(s)レジスタの値4ビットをコピーします.
ちなみにROMは書き込み不可なのでROMに書き込む命令はありません.
ADD (ADD)
この命令はAレジスタとBレジスタの値を二進法で加算します.
演算結果はAレジスタに格納されます.
加算後の値が十進数で15を超えたら,Caフラグが立ちます.
SUB (SUBtract)
この命令はAレジスタとBレジスタの値を二進法で減算します.
演算結果はAレジスタに格納されます.
Aレジスタ - Bレジスタを行います.
値が0より小さくなる場合は,Caフラグが立ちます.
ORA (OR)
この命令はAレジスタとBレジスタの値の論理和を計算します.
演算結果はAレジスタに格納されます.
この命令によってフラグレジスタは変化しません.
AND (AND)
この命令はAレジスタとBレジスタの値の論理積を計算します.
演算結果はAレジスタに格納されます.
この命令によってフラグレジスタは変化しません.
ROR (ROtate Right)
この命令はAレジスタの値を右方向にシフトします.
演算結果はAレジスタに格納されます.
Aレジスタの値4ビットabcdは,ROR命令を実行するとdabcになります.
ROL (ROtate Left)
この命令はAレジスタの値を左方向にシフトします.
演算結果はAレジスタに格納されます.
Aレジスタの値4ビットabcdHa,ROL命令を実行するとbcdaになります.TRA (ThRough A)
この命令はALUの入力Aに手を加えないままAレジスタに格納します.
この命令がなんの役に立つのか,いまさらですが考えてもわかりません.
TRB (ThRough B)
この命令はALUの入力Bに手を加えないままAレジスタに格納します.
この命令がなんの役に立つのか,いまさらですが考えてもわかりません.
JMP (JuMP)
この命令は,フラグがいかなる状態であっても,絶対にジャンプします.
ジャンプ先のアドレス8ビットは,上位4ビットにXレジスタの値,下位4ビットにYレジスタの値が代入されます.
JCA, JEQ, JCM, JIN (Jump CArry, Jump EQual, Jump CoMpetition, Jump INput)
この命令は,それぞれのフラグ(CA, EQ, CM, IN)が立っている場合はJMPと同じ動作をし,フラグだ立っていない場合はLDA, Aと同じ動作をします.
また,命令でフォーカスされていないフラグの影響は受けません.
例えばJCA命令はCAフラグによって動作が変化しますが,EQフラグ,CMフラグ,INフラグの値は考慮する必要がありません.
命令の補足説明
分かりづらい点について説明していきます.
まず,移動命令は理解するのに時間はかからないと思います.例外的な動きはしないし,説明したことがすべてです.
次に算術命令.ADD命令は素直に加算してますが,SUB命令はどのようにして実現しているのでしょう.
二進数の引き算には,補数を使った計算をしています.
簡単に言うと,A-Bをするときには,Bに論理否定をかけて,それに1を加算し,それをAと加算するといった手法です.
だから結果的に値がマイナスになるとキャリーフラグが立つんですね.
次にローテート命令,右方向と左方向があります.
ローテートにもいろいろあります.
あふれた桁は循環させるのかとか,0を入れるのかとか,フラグに格納するとか.
TJD4のローテ―ト命令は循環命令になります,その方が都合がいいし.
他のローテート命令はだいたい命令の工夫で実現できます.
最後にジャンプ命令です.
多くの機械語では,JMP xxxxxxxx みたいに,とび先を直接指定できるのですが,基本設計が4ビットのアーキテクチャですので,8ビットの値をオペランドに指定することはできません.
よって,XレジスタとYレジスタに事前にジャンプ先を格納しておく必要があります.
例えば00110101番地にジャンプしたい場合は,
LDX, 0011
LDY, 0101
JMP
と3回に分けて記述する必要があります.
それから,大抵の命令セットにはHLTとNOPがありますが,これらは実装していません.
NOPはLDA, Aで代用可能ですし,HLTも単純なJMP命令で代用できるはずです.
デコーダ設計
入力6ビット(フラグを足すと10ビット)に対して,12ビットの出力を考えるときに,なるべくANDORを少なくしたいと考えるのは自然です.
今回は,レジスタに書き込む信号が,なるべく二進数で変換の少なくなるように設計しました.
http://www.ee.t-kougei.ac.jp/tuushin/lecture/lcircuit/7/index1.html
こんなサイトにいくと人力で計算しなくても正確に論理式に変換してくれます.
で,論理式が分かったらユニバーサル基板にANDとORとNOTを大量に埋め込んで配線していきましょう.
大体どこかで間違えているのでテスターにあてて地獄のデバッグを行いましょう.
感想
マジで前回からコンスタントにいじって一か月弱かかった作業なので文字数がえぐいことになってしまいました.
次回は入力コントローラとフラグレジスタをつくっていこうと思います.
ではまた.
この記事が気に入ったらサポートをしてみませんか?