CPUよもやま話(プログラムカウンタのお仕事)
今回は、プログラムカウンタが動作する様子を見てみましょう。
プログラムカウンタのお仕事は、実行すべきプログラムが格納されているメモリアドレスを指し示すことです。もう少し具体的にいうと、プログラムの開始位置となるアドレスから始まり、クロックに合わせてカウントアップしていく・・・・・・という簡単なお仕事です。1命令が1アドレスに収まっているなら1ずつカウントアップし、1命令が2アドレスにまたがるなら2ずつカウントアップする・・・・・・、といった具合にです。
前回、レジスタについて触れましたが、レジスタにカウントアップ機能を付加したものだと思えばよいと思います。
- ~Loadが1なら、クロックの立ち上がりでOutputの値を1つカウントアップ
- ~Loadが0なら、カウントアップを止め、Dataの値を読み込む
- 再び~Loadが1になれば、読み込んだDataの値からカウントアップしていく
勘のいい人ならピンと来たかもしれませんが、Dataからはプログラムの開始位置となるアドレスやジャンプ先のアドレスが読み込まれることになります。
※本記事中のプログラムカウンタはすべて0000番地からスタートするものとします。
では、上の回路を部品化して、メモリに繋いでみましょう。
このように、プログラムカウンタのOutputをメモリのアドレスバスに接続すれば、該当のアドレスに格納されたプログラムがデータバスから出力されます。(プログラムカウンタが4ビットなので、1111番地の次に0000番地に戻るのは無視して下さい)
しかし、これだけでは面白くないので、好きなタイミングで指定アドレスにジャンプできるような回路を追加してみたいと思います。
追加する回路をアセンブリ言語で表現するならば
- JMP 即値 '即値をプログラムカウンタにセット
です。
即値(すなわちジャンプ先アドレス)に0000を指定しておき、プログラムカウンタが1000まで進んだところで、手動でJMP命令(すなわち~Loadを0にする)を与えてみます。
現在アドレスが1000から0000に変わり、再び0000からカウントを開始していることが分かると思います。
でも、手動で命令を出すなんてのは原始的な発想ですね( ̄q ̄;)。ここは、プログラムから自動的にJMP命令を与えるようにしてみましょう。
っと、その前にプログラムのフォーマットについて説明しとかないと意味が繋がらなくなってしまいます。CPUによって異なりますが、本回路では1命令を8ビットとし、下のような割り振りにしたいと思います。
オペコードはMOV A,BとかJMPとかのアレで、即値はプログラム中に直接書く値です。
メモリの各アドレスには、下のようなプログラムが事前に格納してあるものとします。
んで、メモリのデータバスからプログラムカウンタへ向けて、最上位ビットを~Loadに接続し、下位4ビットをDataに接続します(複数ビット・単数ビットのいずれも単線で表現されているので注意して下さい)。
これにクロックを与えて動作させると
0000番地から1000番地を無限ループします。
1000番地に格納された、01110000というプログラムはアセンブリ言語で表現するならば、
- JMP 0 '0000をプログラムカウンタにセット
です。この回路の場合、オペコードの最上位ビットが0になれば、プログラムカウンタに即値の0000がロードされるので、プログラムは0000番地に戻るという訳です。
上位4ビットのうち残りの3ビットは配線がどこにも繋がっていないので、この場合は無意味です。つまり、この回路で実行できる命令はJMP(オペコード 0XXX)のみです。
次回は、MOVやADDなどの命令も実行できるように配線を繋いでいきたいと思います。