CPU実験室

誰も見向きもしない古いCPUをいじって動かしてみようというプロジェクトです

回路図入力

プログラムカウンタMC14516×3をEPM7128に置き換えたICU基板の回路図入力を始めました。

CPLDとプログラムメモリ、データメモリ周辺

f:id:O3I:20210424153101j:plain

間接アドレッシングを実現するのが難しいため、アドレスバスとデータバスを結ぶブリッジを置けばいいのではと考えてもみました。例えばデータを8ビット分ラッチするレジスタをプログラム空間にマップするような。ただそこまでICUアーキテクチャを拡張するのも如何なものかと思うし、それならばFPGAの中にICUの機能も含めた好きなアーキテクチャのCPUを構成すればいい訳であまり欲張らないようにします。

 

間接アドレッシング

バイト演算も1ビットごとにばらしてビット演算を繰り返せば実現可能であることは容易にわかります。8ビットCPUに比べ同クロックで単純に8倍時間がかかるかもしれませんが。レジスタ間であればAND,OR,XOR,NOTといった論理演算SHR,SHL,ROTなどのシフト演算、ADD,SUB,MULなどの算術演算も実装できるでしょう。SUBができれば比較CMPもでき、既存のスキップ命令SKZと組み合わせれば条件分岐ができるはずです。

従来のCPUでできていたプログラミングをどのように移植できるか、いろいろ試していたのですが悩んだのが間接アドレッシングでした。

例えば以下のようなプログラムのLD C,(A)に当たる部分でテーブルデータ参照とか7セグデコーダとか絶対必要な処理です。

f:id:O3I:20210422221501j:plain

問題なのはレジスタの内容を単なるビットパタンではなく本当に「数値」としてみなければならないこと、データ領域にある数値を実効アドレス=コードとして処理しなければならないこと。ということになります。特に後者はアーキテクチャ的に普通は「できない」となってしまいます。

 

それでも無理くりコーディングしたらこんな感じになりました。Aレジスタに入った値をビットパタンでみて2分木で全分岐先をデコードし、それぞれ所定のテーブル値を持ち帰ってくるという力技です。もちろんAレジスタの任意の値に応答するのは無理なんで下位4ビット分0~15のみです。

f:id:O3I:20210422221515j:plain

これで一応動作しました。ただしたったこれだけのことをするのにメイン・サブルーチン、データテーブル合わせて396wordものコーディングになってます

CPLD差し替え

スタック段数を増やすためにCPLDEPM7128に交換してロジックをインプリメントしました。ピンアサインは指定せずコンパイラに任せた結果、並びはぐちゃぐちゃになりましたがロジックサイズが抑えられ、スタック段数DEPTH=7まで入りました。きりが悪いですが7レベルあればもう十分でしょう。この時のレポートを見ると

   Total macrocells 123 / 128 ( 96 % )

   Total pins 35 / 68 ( 51 % )

パッケージが大きくなるのでピンは相当余りますがマクロセルはいい感じに有効利用してます。

これでサブルーチンが7段まで使えるようになったので、8ビット加算ADD_A_Bをサブルーチン化しメインルーチンを書き直しました。

f:id:O3I:20210421225559j:plain

処理部分はそっくりCALLする形ですが見た目は8ビットCPUのコードと何の遜色もありません。

さて実機確認です。CPLD基板に84ピンPLCCのEMP7128を載せ、ICU基板とジャンパケーブルで結んでいます。またまた配線がすごいことになってますが期待通りに正常動作しました。

 

f:id:O3I:20210421225629j:plain

 

VHDL修正

プログラムは正常動作しているのでMC14500周囲のハードはだいたいOKと見てよいでしょう。あとはスタックを深く取ってサブルーチンを自由に使いたいところです。

現状のカウンタ記述はスタックポインタがうまく動作してなかったのですがもう一度見直すことにしました。

いろいろなVHDLの記述例を見てみるとFIFOとかテーブル参照とかインデックスを変数で動かす場合、インデックスが適正な範囲にあるかのチェック、外れていたらどうするかをちゃんと記述してあげないといけないようです。それがないと余計なロジックを生成してしまうのか理由はよくわかりませんが、念のためこのカウンタ記述にも入れ込みました。

f:id:O3I:20210420190332j:plain

つまりスタックに積むとき(push)はポインタptrがスタックの深さDEPTH未満であること、スタックから取り出すとき(pop)ptrが1以上であることの判定を追加し、これをCPLDにダウンロードしたところ正常にスタックにアクセスできるようになりました。でもこれでコンパイル結果は

 

  Total macrocells 64 / 64 ( 100 % )

  Total pins 35 / 36 ( 97 % )

・・・リソースを完全に使い果たしました。というかこんなにきれいに使い切るのも気持ち良いです。スタックを増やすにはEPM7128に移行するしかありませんが同じソースコードDEPTHの定義のみ変えればうまくいきそうです。

多ビット演算(2)

 

メインルーチンは以下のようなコーディングになります。8ビットレジスタ同士の加算はサブルーチン化して再利用できるようにしたいところですが1ビットづつ処理をキャリを伝搬させながら8回繰り返すベタ書きになっています。

f:id:O3I:20210419205703j:plain

これはメインルーチン→8ビット加算処理→全加算器→半加算器と階層構造にするとスタックの深さが3段必要になってしまい現状のハードには乗らないためです。MC14500は単純な処理しかできないからスタックは2段もあればいいんじゃないかと思ってましたが、逆に言えばある程度まとまった動作をさせるには十分なスタックを持ちサブルーチンを多用しなければいけない、ということです。

このプログラムを実行させるとLEDがバイナリ的にカウントアップしました。実行中のLEDの最下位ビット(ch.1)とシステムクロック(ch.2)を観察してみます。システムクロックを1kHzに設定すると、

f:id:O3I:20210419213108j:plain

 

LEDは約1.4Hzでチカチカします。つまりこのレジスタのインクリメントするだけの処理に700クロックも要していることになります。

f:id:O3I:20210419213127j:plain

 

多ビット演算

サブルーチンが使えるようになりメモリアクセスの問題も解決したので少し長いプログラムを書いてみました。

MC14500はもともとリレー制御の代替なので数点のセンサ入力と数点の接点出力が制御できればいいわけですが、あえて「数値」を扱う方法を考えてみます。このプロジェクトの最初のころに数のインクリメントはやってみましたが、それを一般化してみます。

例題としてはこのような感じ。Z80風のニーモニックで書きましたがレジスタ内容を加算してパラレルのLEDに出力するLチカテストです。

f:id:O3I:20210418084241j:plain

8ビットCPUで書けばこのように数行で済んでしまいますが、これをMC14500でやったらどうなるか、ということです。

先ずはレジスタですがMC14500のデータ幅は1ビットしかないので例えば8ビット幅レジスタをつくるにはビットをばらしてデータメモリ上の8アドレスへ割り付けることになります。そのほか使いそうなワーキングレジスタ(ビット)も定義しておきます

f:id:O3I:20210418084705j:plain

OUT命令は簡単。レジスタ内容を1ビットづつLEDがつながっているI/Oアドレスへコピーするだけです。困るのがLD A,0といったレジスタへの即値代入で、ハーバードアーキテクチャのためコード領域にデータが書けず、レジスタ経由で渡せたとしても「1ビット」なので、あらかじめLD A,0LD A,1、・・・・LD A,255とすべてのパタンを用意しておき名前で呼び出す必要があります。もっとも必要なものだけつくればいいのでここら辺はコンパイラの仕事ですね

f:id:O3I:20210418084731j:plain

つぎは加算処理です。当然ADD命令なんてないのでANDXORの論理演算によって加算器を構成します。

まず半加算器HADDRをつくり全加算器FADDRは半加算器をサブルーチンとして呼び出します。これだけの長さでやっと加算ができますがあくまでもこれは1ビット分です。8ビットレジスタ同士の数値演算はこれを8回呼び出す必要があります

f:id:O3I:20210418083647j:plain

 

クロック遅延

CR積分回路を組み込んでみました。ここはプログラムカウンタのクロックを整形してから入力したのと同じ部分なのでブレッドボード上で部品追加できます。シミュットトリガ2段直結していた所にCRを挟むだけなので簡単です。なんか初めから仕込まれていたようなトラブルです。

f:id:O3I:20210412190155j:plain

 

 

波形を実測します。クロック1kHz設定とし、上からクロック入力、コンデンサの電圧、クロック出力ですがわずかに遅延しているのがわかります。

f:id:O3I:20210412190227j:plain

 

クロック立上り部分を拡大すると、シミュレーション結果そのまま10usの遅れになっています

f:id:O3I:20210412190314j:plain