ブログの練習

ブログを書く練習です。
最近はレトロな計算機(電卓、マイコン、パソコンなど)
に関することを書き始めました。

Intel 4004 (その16) 周辺回路を現代の部品で作ってみる(EMUZ80(PIC)編)

2023-05-24 13:50:42 | マイコン(4004)
周辺回路を現代の部品で作る試みの第2弾、EMUZ80+4004メザニンボードです。
EMUZ80というのは電脳伝説さん設計によるワンボードマイコンです。詳細はこちら(EMUZ80が完成)。Z80の周辺回路(ROM, RAM, UART, クロック等)を全てPIC1つに実装して、CPU+PICという最少構成かつ低コストなシステムを実現しようという設計思想のもとに作られています。
レトロマイコン界隈でちょっとしたブームになっているようで、Twitterでは高速化したりCPUを別のもの(6502, COSMAC(1802), 68030等々)に改装したりしているのを見かけます。面白そうなのでその流れに乗って真似してみることにしました。

Z80やら68030が動いてるんだから4004なんて余裕だろう、と思っていたのですがそれがまず間違いでした。電脳伝説さんによる解説記事「EMUZ80の設計と製作」(私はboothでカラー版を購入しました。白黒より読み易いし読んでて楽しいです。)によると、どうやらMREQ_nを受けてからWAIT_nを出して待たせるところが割と重要なポイントのようで、WAIT信号の無い4004ではその手法が使えません。
COSMACはどうやったんだろうと思ってググったところ、やはりCOSMACもWAITが無いので200~300kHzが限界(EMU1802-mini の高速化に挑戦しました@COSMAC研究会)とのことのようでした。750kHzで動かすのは難しそうです。

要求条件を整理します。4004のインストラクション実行サイクルとデータアクセスの詳細なタイミングはこちら。


バスは時分割されていて、A1~A3の3サイクルで4bit×3の12bitのアドレスがCPUからメモリに渡され、続くM1,M2サイクルでデータがメモリからCPUに渡されます。
要は、A1~A3で受けたアドレスのROMデータを1350nsで用意してM1サイクル出力すれば良いわけです。あれ、意外に出来そうじゃん。と思ったのですが、計算してみるとかなり厳しいです。
PIC18F47Q43はクロックは64MHzとはいうものの、1命令4クロックなので1命令あたり最短62.5nsかかります。1350ns/62.5ns=21.6 なので、21命令しか使えません。
データシートによると、"Fixed interrupt latency of three instruction cycles"とあるので、割り込みは3サイクルなのですが、割り込みルーチン内でA1~X3の8種のサイクルの分岐をしているとそれだけで20命令は余裕で超えてしまうので、割り込みを使うのはやめました。
とにかく命令数を少なくするという方針で考えてみた結果、SYNCでA1サイクルを開始して、クロックをポーリングしてA1, A2, A3, M1, M2, X1, X2, X3, SYNC待ちとサイクルを進めて行きながら各サイクルの処理を実行するという方式にしました。
とりあえず書いてみたところ、4004の下限クロックの500kHzでも動かず、データシート仕様以下の300kHzまで下げてやっと動きました。動画がこちら。

コンパイラの出力を見たところ、romの配列を読むためのアドレス計算で結構無駄なことをしてそうなのでそのあたりを直すことにしました。
まず、EMUZ80の高速化事例を調べていたところ、
const byte rom[ROM_SIZE]  __at(0x10000) = {...
のように、配列をキリの良い固定アドレスに配置する手法があったのでそれを真似しました。
また、インラインアセンブラは必須のようなのでデータシートを読んでPICのインストラクションを調べたり、コンパイラの出力を見ながら見様見真似で書いてみました。
コンパイラの出力を見たところ、ポーリングはポート値による分岐命令(btfsc)とジャンプ命令(goto)の2命令なので、理想的には125nsの遅延なのですが、オシロで観測したところ、どうもクロックエッジから250nsぐらいの遅延がありそうでした。2相クロックのHが960ns, Lが384nsなので、250nsというのはちょっと無視できない遅延です。
なのでちょっと汚いのですが、CLK2↑で読むべきアドレス値はCLK2↓で読んだりしています。また、A3→M1がクリティカルパスなのですが、そこではCLK1↑をトリガにしてNOPで時間調整して読むとか突貫工事で作りました。
主要なループはこんな感じ。
※ここにソースの一部を貼ろうとしたのですが、うまく貼れないのでmain.cを見て下さい。
実は、まだ^(0+1280)とか,cとか付いているおまじないが理解できていません。RAM bankに関係ありそうで、データシートでa={0,1}とか書かれているRAM access bitみたいなんだけど、なぜ"c"なのかが謎。

話が前後しますが、2相クロック生成の話も書いておきます。Teensy, PIC, TangNanoの3つを試してみて、PICが一番簡単だったのは2相クロックのマスターになる5.185MHzのクロック生成です。NCO(Numerically Controlled Oscillator)なるモジュールを使って簡単に作れました。

しかし!そこから2相クロックにするのが大変でした。PWMはduty比は制御できたとしても位相制御が(そもそも出来るのかどうかすら)わからなかったので諦めました。TMRレジスタも違うよなあと思いながらいろいろ調べていたところ、EMUZ80ではWAIT信号の生成に使われていたCLC(Configurable Logic Cell)が使えそうなことに気がつきました。
4004の2相クロックは7進カウンタで作ります。CLCを3つJK-FFにしてカウンタを作りました。ただこのFF、クリアが非同期だったのでクリア条件とクリアを同期化するためのFFにCLCを2つ追加しました。さらにCLK1, CLK2の生成に2つ使って、合計7個のCLCで2相クロックを作ることができました。CLCの1つがこれ。こんな感じのものを7個、マウスをポチポチしながら作るのは結構面倒くさかった。


あまり納得のいく作り方ではなかったのですが、とりあえずブレッドボード上でLチカが740kHzで動くようになりました。

余裕があればRAMとUARTも載せたかったのですが、PICはもう性能的に無理だと感じたので諦めました。
CPU以外をPIC1個に載せるというEMUZ80の設計思想を実現できなかったのは残念ではありますが、"EMUZ80-4004"を名乗るために、EMUZ80に接続できる基板を作ることにしました。
回路図はこんな感じです。4002は電卓を動かすのに最低限必要な2つです。5V→15VのDCDCのおかげで電源はEMUZ80から供給する5Vで動きます。-15VをGNDにしたので、通信部分はレベル変換用のCMOSで代用可能だと後から気がついたのですが、前と同じフォトカプラ2つを使っています。



回路図通り、左側にレベル変換、右にCPUとRAMを配置する方が配線が楽なのですが、CPUは本来のZ80の位置に置く方が絵的に美しいので頑張って配線しました。コネクタからの信号が一旦右に行ってから左のCPUに戻り、CPUからの信号も右に行ってから左に戻るということになるので結構大変でした。



今回は10cm×10cm以下だったこともあり、配送方法にOCSのネコポスが選べたので送料込みで$3.5。激安です。$7クーポンを使ってMCLZ8の4層基板もタダで作ってもらっちゃいました。


さっそく部品を載せて動作確認。メモリ(4002)が2つしか無いので電卓プログラムは若干の修正が必要でした。ついでに起動画面のメッセージもちょっと修正しました。


クロックドライバに秋月で入手可能なSOT23パッケージのMPT1402をDIP変換基板に載せて使ったのですが、ちょっと格好悪いですね。次に作るときはDIPで2回路入っているMIC4427にしようと思っています。あと、フォトカプラも普通のCMOSのバッファに変更かな。

電卓が動いた動画がこちらです。


とりあえず作ってみましたが、PICはもう使わないかなあというのが正直な感想です。PICはCPUコアそのものに仕事をさせるんじゃなくて、周辺モジュールを働かせて何かを作るためのものだと感じました。あと、開発環境のMPLAB X IDE とMCCも高機能すぎて難しかった。

GitHubに回路図、基板製造データ、プログラム等一式を置いてあります。
GitHub - ryomuk/EMUZ80-4004: 4004 mezzanine board for EMUZ80

GitHub - ryomuk/EMUZ80-4004: 4004 mezzanine board for EMUZ80

4004 mezzanine board for EMUZ80. Contribute to ryomuk/EMUZ80-4004 development by creating an account on GitHub.

GitHub

 

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Intel 4004 (その15) 周辺回路を現代の部品で作ってみる(Teensy編)

2023-05-10 11:08:50 | マイコン(4004)
できるだけ当時の部品で作るという当初の目標は達成できたので、次は現代の部品を使ったらどうなるかを試してみました。候補としては、
(1)Teensy 4.1+4004
(2)EMUZ80+4004メザニンボード
(3)TangNano9K+4004
あたりを考えたのですが。まずはread4001(Intel 4004 (その5) Mask ROM 4001を読んでみる)で4001を読んだ実績があるTeensy4.1で試してみることにしました。

read4001のときは3.3V→15Vの変換はFETの2N7000を使っていたのですが、これでいいのか若干気になっていたので別の部品も探してみました。見つけたのがこちら。
CD40109B Low-to-High Voltage Level Shifter (datasheet)

実際の信号で2N7000と比べてみました。
上から、入力(3.3Vパルス)、40109、2N7000(4.7kプルアップ)です。(100ns/div)

40109は立ち下がりの遅延が2N7000の倍の100nsぐらいありますが、それ以外はかなり良い特性です。出力制御(OE)も備えているのでこれを採用することにしました。

この他に、CD4504B(Voltage-Level Shifter)も候補にあったのですが、全ての点で40109の方が勝っていたので不採用です。
上から、入力(3.3Vパルス)、40109、4504。(50ns/div)


次に15V→3.3Vです。4004のデータシートによると、HはVss-0.5~Vss(今回の場合は+14.5~15V)、LはVss-12~Vss-6.5V(+3~8.5V)です。実際の信号を観測してみると、Lは+3~+5Vぐらい。

read4001の時と同じように、1段目をVcc=15VのCMOSで受けて、2段目をVcc=3.3VのCMOSで受ければ良さそうです。1段目は閾値を高くするためにVcc=15Vにする必要があるので標準CMOS、2段目はVcc=3.3Vでいいので高速な74HC4049(入力耐圧は+15V)を使うことにしました。

クロックドライバの3.3V→15Vは秋月で売っているMicrochipのMCP1402(datasheet)を使ってみることにしました。最初は5.185MHzのクロック源(MCLK)を外部に用意して、ソフトで2相クロック(CLK1, CLK2)を生成するという構成を試したのですが、Teensyの内部カウンタ(600MHz)でわりと安定したMCLKまで作れてしまいました。

完成した回路図がこちら。


次にプログラムです。
速度が要求されるので、ポートレジスタ直叩きとかやる必要があるかなあ、面倒だなあと思っていたのですが、digitalWriteの速度を測ってみたところ驚愕な速さだったのでデータバスを1ビットづつ読み書きするというお子様的なプログラミングで済ませてしまいました。
こんな感じのコードで、
#define digitalWrite digitalWriteFast
  digitalWrite(DOUT0, data & bit(0));
  digitalWrite(DOUT1, data & bit(1));
  digitalWrite(DOUT2, data & bit(2));
  digitalWrite(DOUT3, data & bit(3));

この速度。Teensy4.1の性能恐るべしです。(これ5ns/divですよ)



プログラムはクロックを生成しながら4004の命令サイクルにあわせてバスを読み書きするだけなので特筆すべきことは無いかな。

Lチカが動きました。


回路図やプログラムはGitHubに置きました。
GitHub - ryomuk/Teensy-4001: Intel 4001 (MCS-4 mask ROM) emulator using Teensy 4.1

GitHub - ryomuk/Teensy-4001: Intel 4001 (MCS-4 mask ROM) emulator using Teensy 4.1

Intel 4001 (MCS-4 mask ROM) emulator using Teensy 4.1 - GitHub - ryomuk/Teensy-4001: Intel 4001 (MCS-4 mask ROM) emulator using Teensy 4.1

GitHub

 

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする