ブログの練習

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

Intel 4004 関連記事の目次

2099-12-31 23:59:59 | マイコン(4004)
goo blogでカテゴリ毎の記事一覧をうまく表示させる方法がよくわからなかったので、ここに4004関連の記事へのリンクをまとめておきます。

Intel 4004 (その1)
Intel 4004 (その2) クロックの巻
Intel 4004 (その3) 1702A EPROM用ライター(プログラマー)を自作する
Intel 4004 (その4) Lチカの巻
Intel 4004 (その5) Mask ROM 4001を読んでみる
Intel 4004 (その6) MCS-4 Evaluation Kit using the 4001-0009
Intel 4004 (その7) 実験用ボードの作成
Intel 4004 (その8) シリアル通信を実装する
Intel 4004 (その9) メモリ領域へのアクセス
Intel 4004 (その10) 電卓を作ってみる
Intel 4004 (その11) メモリ周りを改築する
Intel 4004 (その12) VTLインタプリタを作ってみる
Intel 4004 (その13) 8080エミュレータを作ってみる
Intel 4004 (その14) メモリ64KB化とプリント基板作成
Intel 4004 (その15) 周辺回路を現代の部品で作ってみる(Teensy編)
Intel 4004 (その16) 周辺回路を現代の部品で作ってみる(EMUZ80(PIC)編)
Intel 4004 (その17) 周辺回路を現代の部品で作ってみる(TangNano編)
Intel 4004 (その18) CPUを4040にしてみる
Intel 4004 (その19) VTLインタプリタを機能拡張する
コメント (3)
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Intel 4004 (その19) VTLインタプリタを機能拡張する

2024-03-21 14:53:08 | マイコン(4004)

4004で動くVTLインタプリタでStarTrekを走らせる話です。

去年作ったVTLインタプリタですが、このときの目標はとりあえずマンデルブロ集合を表示するプログラムASCIIART.BASを走らせることだったので、未実装の機能がいくつかありました。

 

Intel 4004 (その12) VTLインタプリタを作ってみる - ブログの練習

4004用のVTLインタプリタを書いてみました。当初はMITS_Altair_680_Very_Tiny_Language_VTL-2_Manual.PDFに載っている6800版のオリジナルのソースか、白石孝次氏による8080...

goo blog

 

しかし、メモリ空間をほぼギリギリまで使っていたため機能追加は難しい状況。4004で動く8080のエミュレータがあれば8080用の言語処理系が動かせるのではないかと思って作ったのがこちら↓です。これでPalo Alto Tiny BASICやGAME80を動かすことはできたのですが、ちょっと実用にならないレベルの遅さでした。

 

Intel 4004 (その13) 8080エミュレータを作ってみる - ブログの練習

電卓やVTLインタプリタを書いてみて、ずいぶん4004のアセンブラに慣れてきました。とはいえ、いろいろなものを4004のアセンブラで一から作るのは面倒です。8080のエミュレー...

goo blog

 

というわけで、VTLインタプリタの方をもう少しちゃんとしたものにすることにしました。メモリ空間はモニタプログラムの機能を削って確保しました。

今回実装した機能は下記の通り。

  • 乱数(疑似乱数)
  • 配列
  • サブルーチンコールのネスト
  • 高速GOTO(通常のGOTOとは別の独自仕様)
  • 二項演算子(剰余, 排他的論理和)

古典的なコンピュータゲームであるStarTrekが走るレベルの機能を目標にしました。

まずは乱数。

疑似乱数の生成アルゴリズムというのは結構奥が深い世界なのですが、そんなに真面目に実装する気は無いし、そもそも4004には計算パワーも論理演算命令も無いので、とりあえず線形合同法でいいやと思って実装してみました。下記のような単純なものです。

uint16_t rand(){
static uint16_t x=1;
x=x*16877; /* 16877=7^5 */
return(x>>4);}

x_nをそのまま使うと出てこない数があったので>>4して0~4095までの乱数にしました。試しにx_nをプロットしてみるとこんな感じ。

周期性がありますが、まあわりと乱数っぽいです。ゲームぐらいには使えるかなと思ったのですが、後述するStarTrekで星がいつでも斜めに並ぶという現象が発生。

(x_{2n}, x_{2n+1})をプロットしてみると・・・

これはダメです。ちょっと使い物になりません。

というわけで、もうちょっと真面目に実装することにしました。疑似乱数生成アルゴリズムをググっていたところ、16ビットマイコンボードの製作 というページにxorshiftというアルゴリズムが紹介されているのを見つけました。

16 bit xorshift rng (now with more period)

聞いたこと無いなあと思って見てみたところ、どうやら2003年に提案されたアルゴリズムのようです。とてもシンプルなアルゴリズムです。

uint16_t rnd_xorshift_32() {
static uint16_t x=1,y=1;
uint16_t t=(x^(x>>5));
x=y;
return y=(y^(y>>1))^(t^(t>>3));
}

これが21世紀になるまで発見されていなかったというのは逆に驚きでした。

y_nをプロットしてみると、

この範囲では周期性っぽい模様は見えません。(y_{2n}, y_{2n+1})を見ても、

ちゃんと乱数っぽくなっています。良さそうなのでこれを実装することにしました。

しかしここで問題が。4004にはxorを計算する命令がありません。8080エミュレータのときに書いたコードをベースにして作ってみました。長いですが他に方法も無いのでこれを使うことにしました。

4004で16bitのxorを計算するプログラムです。

乱数生成部のルーチンはこんな感じになりました。

データRAMを16bitのレジスタとして使うためのサブルーチン群が既にあるのでこの程度に収まってます。ビットシフトは乗除算に使っているサブルーチンを流用しています。

これにより、システム変数 ' で0~32767までの乱数が得られるようになりました。0~99の乱数が欲しいときは、最初、

R=' / 100 R=%

のようにして求めていたのですが、見た目が悪いので剰余を求める二項演算子 % を実装して、

R='%100

と書けるようにしました。'(100)という記法にするより実装しやすいのでこうなりました。あと、せっかく排他的論理和のルーチンも作ったので二項演算子 ^ も実装しました。

乱数が作れたことにより、最古の経営シミュレーションと思われる「イスカンダルのトーフ屋ゲーム」を走らせることができました。動画はこちら。

8080エミュレータでは激遅でとても遊べない速度でしたが、今回はちゃんとした速度で動きました。

次に配列です。とりあえず1次元配列を1つだけ実装。記法は、@(x)にしました。TK-80BSのLevel 1 BASICをリスペクトしています。最初これをPEEK、POKEの機能にしようかとも思ったのですが、4004の機械語を書いてもそこにジャンプして実行できるわけではなく、データ格納以外に使い道が無いので、変数と同じ16bitの整数として読み書きします。

これでStarTrek走るかな?と思ってエンサイクロペディアASCIIのStarTrek特集を眺めてみると、多段のGOSUBが使われています。サブルーチンが1段だけのVTL用に移植されたもの(マイクロTREK)もあったのですが、配列に返り番地を積むとか、あまり美しくない移植だったので、多段のサブルーチンを真面目に実装することにしました。

GOSUBは現在実行中のコンテクストを退避してGOTOでジャンプするだけ、RETURNはコンテクストを復帰させるだけなので、それほど難しくはありません。退避するコンテクストは、

  • 実行中の行の先頭アドレス
  • 実行中のプログラム位置(GOSUB文!=xxxの直後)を示すアドレス
  • 実行中の次の行の先頭アドレス

としました。本質的なのは実行中のプログラム位置だけですが、今回の実装ではその前後もある方が作りやすかったのでコンテクストに含めています。

実行中の行の先頭アドレスは、後述の高速GOTO用のシステム変数 # のため、次の行の先頭アドレスはIF文不成立時に文末まで舐めずに次の行に飛ぶためのものです。

これでどうにかStarTrekを動かせるレベルの言語処理系が準備できました。

StarTrekのプログラムは結構長いので、どこかに転がってないかとググってみたところ、こちらのサイト(Bequest333のページ)で電大版StarTrekが入ったパッケージを入手。どうやら電大版Tiny BASICにはFOR文が無いようで、GOTOを#=に、PRを?=に、IFを;=にのように機械的に置き換えるだけでほぼそのままVTL-4004に移植できました。

さっそく実行してみましたが何かがおかしく、いろいろ調べてみたところどうやらエネルギーが0で何も出来無いという状態。安田寿明著「マイ・コンピュータをつかう」に載っているソースと比べてみたところ、なぜか330行目のGOSUB 1600が存在せず、エネルギーや光子魚雷の数が設定されなくなっていたのが原因でした。

そこを修正したところ無事ゲームで遊べるようになったのですが、速度がかなり遅いです。Short Range Sensorの表示に1分ぐらいかかっていました。

考えられる原因はGOTO文(#=)の処理です。今の実装では#=は飛び先の場所をプログラムの先頭から行番号を探してジャンプします。一応行番号の隣に次の行へのポインタを格納しているので、プログラムの文字列を全部舐めているわけではないのですが、それでもプログラムの後ろの方に

5000 I=I+1 ;=I<10 #=5000

みたいな行があると、#=5000でプログラムの先頭から順番に見ていって5000の行まで探すので大規模なプログラムだとかなりのオーバーヘッドになります。

ジャンプ先を行番号ではなくプログラムの場所のポインタで指定できれば即座にジャンプできます。というわけで、システム変数 # を、現在実行している行の行番号ではなく、現在実行中の行の先頭アドレスに変更することにしました。

さらに、実行するプログラムの位置を変更するための記法として、>= を実装しました。さきほどの例は、

5000 I=I+1 ;=I<10 @(I)=0 >=#

のように書き直します。16bitの値で普通に変数に格納できるので、ループを多重にしたい場合は A=#のように保存しておいて、>=Aでジャンプすることもできます。

ループで何度も実行されるGOTOをこれに書き直すことによってかなり高速化され、Short Range Sensorも30秒ほどで表示できるようになりました。

ゲームの様子です。まだ遅いと言えば遅いですが、ギリギリ耐えられる遅さにすることができたかなと思います。

インタプリタのソースコード等一式はGitHubに置きました。

 

GitHub - ryomuk/VTL4004: VTL Interpreter for 4004 Evaluation Board

VTL Interpreter for 4004 Evaluation Board. Contribute to ryomuk/VTL4004 development by creating an account on GitHub.

GitHub

 

 

 

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

Intel 4004 (その18) CPUを4040にしてみる

2024-03-04 14:27:10 | マイコン(4004)

1年前にeBayで買ったまま積んであった4040があったので、これを使った基板を作ってみることにしました。4040は4004と互換性が高く、ピンの配置を変換するアダプタでも作ればそのまま4004実験ボードに搭載してそのまま動かすことができるはずなのですが、せっかくなので拡張された機能も使えるようにします。

ハードウェアに関連する主な拡張機能は次の3つ。

  • 割り込み機能
  • プログラムメモリ領域が2倍(4KB→8KB)
  • シングルステップ実行

割り込みに関しては、通信ポートをポーリングではなく割り込みにするということも考えましたが、8251や6850のような通信用のLSIがあるわけでもなく面倒なので割り込みボタンを1つつけるだけにしました。

ROMのバンクを切り替えるための信号線CMROM1により、プログラムメモリ領域が2倍になりました。4004のときには8080エミュレータにしてもVTLにしても4KBのプログラム領域を使い切って足りなくなっていたのでかなりうれしいです。

シングルステップ実行は、アドレスやデータをラッチして表示したりしないと実用的じゃないし、使い道がいまいちイメージできなかったので信号線だけ出して未実装です。

ソフトウェアに関連する拡張機能には次のようなものがあります。

  • サブルーチン用スタックが3段→7段に増加
  • RPM命令によるプログラム領域のRAMの値の読み出し
  • 論理演算命令(AND, OR)

4004ではサブルーチンのネストが3段しか出来ず、プログラムを書く際の大きな制約になっていたのですが、少しはマシになりそうです。とはいえ、7段では構文解析みたいながっつり再帰的なプログラムには足りそうもないので使い道は限定されますが。

4004では256byteバンク内のメモリ値しか読めなかったので、4004実験機ではあらかじめ全部のバンクの末尾にメモリ値を読むためのサブルーチンを書いておいてそこをコールして読むという曲芸的なことをやっていました。4040ではRPM命令によって4289配下のプログラム領域のメモリの値を読めるようになります。

論理演算も4004ではえらい長いプログラムでなんとか実装していましたが、4040では少しマシになりそうです。

基板を設計するにあたり考慮した点を順不同で書き連ねます。

  • データRAMに4002-1を4つ使う構成はプログラムが書き難いので、4002-1と4002-2を各2つづつ使用。(切り替えジャンパは削除)
  • UARTのインターフェース部分はフォトカプラではなくTTLに変更。
  • 4201を使うとクロックとステップ実行の回路が簡単になるが、入手性が悪く、ステップ実行は実装しないので4004と同様にTTLを使用。
  • プログラム領域のRAMはHM62256は入手性が悪いのでHM628128に変更。
  • せっかくなので4004を搭載する用のソケットも用意しておく。

こんな方針で回路図を描いて基板を作ってみました。

さっそく組み立てて電源を入れてみたのですが、動かず。デバッグ開始です。

とりあえずクロックを見てみます。SYNC信号と2相クロックが綺麗に出ています。

次はメモリ回り。OEやCSはちゃんと出ていることが確認できたので、新規設計部分の拡張ROM領域関連が怪しい気がしてきました。

とりあえずA0とA12を見てみると、A12の幅が短い気がします。

A12は拡張ROM領域用のアドレス信号で、CMROM0=0のメモリアクセスのときに0、CMROM1=0のメモリアクセスときに1です。とりあえずCMROM0をそのまま出しておけばいいやと思って作っていたのですが、データシートを確認したところ、CMROM0はCPUサイクルのM1でしかアサートされないのでそこでラッチする必要があったのでした。

運良くNANDゲートが2つ余っていたので、CMROM=0で0、CMROM1=0で1になるようなRS-FFを作って修正。空中配線で配線しました。

電源を入れてみるとモニタプログラムが起動。4004に作ったVTLもそのまま動きました。

次は拡張機能部分の動作確認です。段階的に確認していきましたが、最終的に、

  • プログラム領域のRAMの読み込みにRPM命令を使用。
  • 割り込み時に拡張ROM領域に配置したプログラムにジャンプしてメッセージ表示。

というプログラムが動きました。動画はこちらです。VTLインタプリタでカウント表示ループを実行中にINTボタンで割り込みをかけて、拡張ROM領域に配置したプログラムで"*INT!*"というメッセージを表示しています。

回路図とガーバーデータはとりあえずGitHubに置いてあります。

 

GitHub - ryomuk/SBC4040: Single Board Computer using Intel 4040

Single Board Computer using Intel 4040. Contribute to ryomuk/SBC4040 development by creating an account on GitHub.

GitHub

 

最後に一言。

4040は確かに4004より強力で、プログラムも書き易そうではあるのですが、いろいろ作っていて感じたのは、4004のときほどのワクワク感は無いなあということでした。

というわけで、4040はこれでクローズして4004に戻ろうかと思います。

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

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

2023-06-14 18:03:16 | マイコン(4004)
4004の周辺回路を現代の部品で作る試みの第3弾、TangNano編です。やっと完成したのでブログにまとめることにしたのですが、かれこれ1ヶ月以上前からやっていて、最初の頃のことは自分でもすっかり忘れているので、twitterで自分のツイートを読み返しながら書きます。トラブったことや部品選定の話をとりとめもなく書くだけなので、技術的な話はGitHubの回路図やソースを見てもらう方がいいと思います。
GitHub - ryomuk/tangnano-MCS4memory: Memory system for Intel 4004 using Tang Nano 20K

GitHub - ryomuk/tangnano-MCS4memory: Memory system for Intel 4004 using Tang Nano 20K

Memory system for Intel 4004 using Tang Nano 20K. Contribute to ryomuk/tangnano-MCS4memory development by creating an account on GitHub.

GitHub

 


Tang Nanoというのは、Gowin SemiconductorのFPGAを使ってSipeedが製造販売しているFPGA評価ボードです。
当初Tang Nano 9Kというボードで試しており、64KBのメモリを実装するにはリソースがギリギリ足りないので実機と完全コンパチには出来ず、ブレッドボードでVTLを走らせるところまで試してさてどうしたものかと思っていたのですが、つい先日20Kという新製品が発売され、64KBのメモリを実装できるようになり、実機と完全互換のものが作れました。
9Kでブレッドボードで試していたときの写真がこれ。


この実験をしているときに、3.3V→15Vのレベル変換IC(CD40109)のGNDを継ぎ忘れていたせいでTangNano9Kを1つ壊してしまいました。40109にGNDを継げずに15Vと3.3Vだけ継げて検証実験をしたところ、入力端子(TangNano側の出力端子)に4.2Vの電圧が発生。


結構な時間こんな状態が続いていたのでまあ壊れるのも納得です。で、すぐに予備の9Kを2つ秋月に発注したのですが、なんとその日の夜にSipeedがtwitterで新製品の20Kの発売開始を発表。
とりあえず20Kの方もコントローラー付属のゲームキット1つとピンヘッダー無しを2つ注文しました。巷では5月25日頃に到着の報告を見かけたのですが、どうやらゲームキットもいっしょに注文したのがまずかったようで、発送が遅れて6月1日にやっと届きました。(しかも1個足りなくて、再送してもらいました。)


初物なのでいろいろトラブルがありました。主なのは2つかな。
1つ目はpin25とpin26がデータシートで逆に描かれているという問題。pin25に継げたスイッチが全く反応しないので何がおかしいのか調べていたらどうやらpin25とpin26が逆の様子。これは6月8日のアップデートで修正されました。
2つ目はpin75から信号が出ない、信号入力もできないという問題。当初全く動かないので、twitterでSipeed宛てにpin75が動かないよ~と下記画像を付けてツイートしてみました。

いろいろ調べているうちに、なぜか手動で信号をGNDと+3Vに切り替えると0、1はちゃんと入力できることがわかり、これはもしかしてと周波数を変えて試してみたところ、高い周波数がカットされているらしいという現象を見つけて追加でツイート。

これに対して別の人から、pin75はコンデンサにつながってるとのリプライがあり、原因がわかりました。

Sipeedからも、そのcapを外せばいいというツイートがあったので外して試してみたところ無事直りました。


pin75が使えないと基板作り直しだなあと思っていたので作り直さずに済んで良かったです。(今は未使用のCMRAM1_nの信号につなげているので実害は無いのですが気持ちが悪いので。)
同様の信号がpin51にもあるのですが、こちらのコンデンサはパターンだけあって実装されていません。pin75のコンデンサも次期ロットあたりから外されるのかな。

今回の試作でもうひとつトラブったのが電源周りの話です。(こちらはTang Nanoとは無関係な話です。)
周辺回路をほとんどTangNanoに入れてしまったので、15Vの電源が必要なのは4004とクロックドライバだけになります。4004のデータシートを見ると、平均消費電流は最大40mA、絶対定格で1Wとあり、クロックも4004にしか供給されないので、多く見積っても全部で50mAもあれば良さそうです。
5V→15V、1WのDCDCでいけるだろうと思ってブレッドボードで試していたのですが、電圧が14Vぐらいまでしか上がらないという謎な現象に遭遇しました。
3WのDCDCにとりかえて電流を測定してみたところ、なんと最初に90mAぐらい流れています。

15V1Wは67mAなので、これは過負荷です。14Vまでしか上がらないのも納得。
これが1分ほどで想定通りの33mAぐらいに落ちつきます。

最初は温度の問題かと思ったのですが、電源を入れなおすとまた90mAぐらい流れるので温度の問題では無さそう。4004とクロックドライバを疑って個別に計測してみたのですが特に問題無し。
CMOSゲートの4049を測ってみたところなんと1つあたり30mA流れていることが判明。これが犯人でした。いや、犯人は私なんですけどね・・・
4049の未使用入力をオープンにしていたのが原因でした。基板を作るときはちゃんとVCCかGNDに継げますが、ブレッドボードでは面倒なのでサボっていました。ごめんなさい。

電源がらみでもう1つ。DC/DCの選定にあたり、秋月で売ってるMINMAXにするか、ワールドワイドで入手性がいいRECOMのどちらにするか試してから決めようと思っていろいろ買ってみたのですが、RECOMの3WのRI3-0515Sがばかに電圧高めに出るなあと思っていたところ、DC/DCにはregulatedとunregulatedがあるということに気がつきました。

全部regulatedだと思ってたのですが、
MINMAXは1WのMAUはunregulatedで3WのMCWIはregulated。RECOMもROEやRI3はunregulated。regulatedが欲しければRS3なのでした。
3Wのunregulatedを0.5Wぐらいで使うと電圧は高くなってしまうというのは仕様通りの挙動。いろいろ買って試してみてやっと気がつきました。

1Wを0.5Wぐらいで使うのは丁度いいようなので、今回はワールドワイドで入手性のいいRECOMのROE-0515Sを採用することにしました。

最後に部品選定の話をもう1つ。クロックドライバについてです。
昔の4004の回路では、DS0026というドライバが使われていました。若松でしか売ってないレベルの昔の部品です。現行品を使う方がいいかなと思い、teensyやPIC版では秋月で売ってるMicrochipのMCP1402に変えてみたのですが、やっぱりSOT23+変換基板というのは美しくないのでいろいろ調べた結果、同じくMicrochipのMIC4427というのがDIPの現行品らしいのでこれを使うことにしました。


これについて調べてたときに、Microchipのこの表を見て途方に暮れていたのですが、


TIが作ってくれたこの表に助けられました。


これに限らず、TIの資料は本当にわかりやすいです。

で、なんやかんやで完成した基板がこれ。

部品のほとんどはレベル変換用IC(15V←→3.3V, 15Vクロックドライバ, UART用5V耐圧バッファ)です.

ほとんど昔の部品で作った基板はこちら。この赤で囲んだ部分が全部Tang Nanoに入ったことになります。


一定の成果が得られたので、4004の周辺回路を現代の部品で作る試みはひとまずこれでひとくぎりにします。当たり前ですが、ハードウェアをエミュレートするのはCやアセンブラよりverilogの方が簡単でした。
次は何をやろうかな。
コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

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でシェアする