オレ仕様のゲーム機を作ろう(その13)
前回は,オレ仕様ゲーム機の機能アップについて,その内容を決めました。
オレ仕様のゲーム機を作ろう(その12)
今回は,CPU と音源機能を含む基板「CPUボード」を作っていきます。
マルチ CPU
前回,簡単に説明しましたが,2 つの Z80 を搭載して,それぞれ独立したメモリ空間のプログラムを同時実行させたいと思います。
うまく,処理を分散できれば,高速化とかできそうですよね。
ゲーム機なので,画像処理回路や,音源制御回路,入力制御回路などが,CPUのバスに接続されることになりますが,どちらの CPU からもアクセスできるようにすると,そのタイミング制御がとても大変で,部品数も多くなり,現実的じゃありません。
そこで,今回は,役割をある程度決めて,バスに接続するデバイスを明確に割り当てたいと思います。
画面制御回路と,入力制御回路を接続する CPU を「メイン CPU」とし,音源回路を接続する CPU を「サブ CPU」とします。
メイン CPU は,音源の制御をすることはできませんし,サブ CPU は,画面制御をすることはできません。
ただ,サブ CPU は,音源専用の CPU というわけではなく,メイン CPU での計算処理を肩代わりできる形にします。
ちなみに,今回使用した Z80 は,6MHz で動かします。
Z80-B って言うんですかね?
割り込み
ゲーム機なので,当然,CPU の割り込み機能を使うのですが,今回は,Z80 の「割り込みモード 2」 を使うことにしました。
単純なものだと,割り込みモード 1 を使うことが多いと思います($0038 番地がコールされるやつですね)
この割り込みモード 2 は,Z80 ファミリのデイジーチェーン用に用意されたと思いますが,割り込みベクタテーブルを使うことができるので,複数種類の割り込みを処理する時に,割り込みルーチンアドレスをソフトウェア側で管理できて,効率よく処理できそうです。
複数割り込みと言っても,垂直ブランク割り込みと,水平ブランク割り込みの 2 つですけどね。
水平ブランク割り込みは,割り込ませたい走査線(ライン)を専用のレジスタにセットして,別のレジスタで,水平ブランク割り込みを許可状態にすると,該当ラインで水平ブランク期間に入る時に,CPU に割り込みを掛けることができます。
割り込みルーチンで,走査線レジスタの値をインクリメントしてやると,次のラインでもまた割り込みが掛かり,結果,ラスタースクロールとかできます。
共有メモリ
サブ CPU 側に計算処理の肩代わりをさせるには,双方の CPU でデータのやり取りができないと,うまく機能しませんよね。
このデータのやり取りができる共有のメモリを双方の CPU バスに接続します。
この共有メモリは,普通の SRAM を使いますので,当然,2 つの CPU が同時にアクセスすることはできませんよね。
いろいろと方法はありますが,今回は効率重視ということで,片方の CPU がアクセスしている間は,もう片方の CPU にアクセスを待ってもらう方法を取ることにしました。
CPU がこの共有メモリにアクセスするタイミングというのは,LD 命令で読み書きした時や,演算命令でレジスタ間接参照したときなど,必ず命令実行の中で行われます。(共有メモリにプログラムコードを置いた場合は,命令フェッチサイクルでもアクセスされます)
命令(オペコード)フェッチサイクルは,通常 4 ステートあり,メモリの読み書きサイクルは,通常 3 ステートになります。
2 つの CPU が共有メモリに対して,頻繁に同時アクセスしても,メモリの読み書きサイクルでアクセスタイミングが互いにずれて,その後に,命令フェッチサイクルが入ったりするので,多分,うまく分散されると思います(ホントか?)。
このアクセスタイミング制御ですが,先に共有メモリにアクセスした側が優先権があり,後からアクセスした側が,先にアクセスした側のアクセスが終了するまで,待たされることにします。
あれ?でも全く同じタイミングでアクセスした場合は,どうするんでしょう?
その場合は,メイン CPU が優先されることにします。
複数音源
今回の音源は,前回と同じ YMZ294 を 2 つ搭載します。
矩形波 6 音同時再生ですね。
PSG の AY-3-8910 と比較して,チップの大きさが小さいので,もっと数を増やすこともできるのですが,制御するプログラムが大変そうなので,やめました(笑)。
作成した基板
今回のチャレンジとして,少し大きめの基板を作ってみたいと思い,2 つの CPU とその周辺メモリ,音源を 1 枚の基板に入れてみました。
そして,こちらが作成した CPU 基板です。(クリックで拡大します)
なんか,ザイログのロゴがカッコいいです!
では,大まかに説明します。
電源は,AC アダプターを使います。(左下にある DC ジャック)
左側中央にある USB コネクタでホスト PC と接続し,プログラムやデータを送信します。
ホスト PC から,メイン CPU,サブ CPU それぞれのバスに接続できるようにしたので,かなり,使用する IC が多くなってしまいました。
プログラムエリアを EPROM にすると,この辺りを省略できるので,かなり基板面積を小さくできると思います。
上の方にある Z80 が,メイン CPU です。
メイン CPU 側のメモリには,128KB のプログラムエリアと,8KB のワーク RAM,4KB の共有 RAM が接続されています。
プログラムエリアは,16KB のバンクメモリで,8 バンクあり,電気二重層コンデンサで内容がバックアップされます。
128KB は,1Mbit なので,メガロム級です(笑)。
また,右下に DSUB 9 ピンのコネクタがあり,MSX 互換のパッドやジョイスティックを繋げることができます。
この辺りはいつもどおりですね。
そして,下の方にある Z80 が,サブ CPU です。
サブ CPU 側のメモリには,32KB のプログラムエリア,8KB のワーク RAM,4KBの共有 RAM が接続されています。
ワーク RAM と プログラムエリアは同じチップにしても良かったかな…と思いました。
また,サブ CPU のすぐ右隣に YMZ294 が 2 つあり,サブ CPU のバスに繋がれています。
2 つあるのですが,出力はステレオではなく,モノラルにしました。
右上の方に,デバッグ用の発光ダイオードとディップスイッチがあり,それぞれ,8bit の出力と入力に使います。
左下にあるタクトスイッチがリセットスイッチでシステムをリセットします。
右下にあるタクトスイッチが,NMI 割り込みスイッチで,どちらか一方の CPU に対して NMI 割り込みを掛けることができます。
やっぱり一発では動かない
はんだ付け箇所は,2000 箇所以上あって,結構大変なのですが,プリント基板なので,一つ一つきちんとはんだ付けすれば,この辺は特に問題ありません。
やはり,元々の回路設計に結構ミスが見つかるんですね…。
ユニバーサル基板で作っている時は,接続している配線を取り除けたりするのですが,プリント基板では,パターンカットしたり,結構面倒だったりします。
空いているエリアに蛇の目パターンを作ったり,IC のフットプリントを入れておけば後の修正が多少楽になったりしますが,何故かいつも忘れてしまうんですよね。
…んで,基板裏側の空いているエリアで修正した結果がこちらです。
う〜ん,結構ひどいですよね(笑)。
水平カウンタと垂直カウンタの接続先の間違いを発見した時は,「うへぇ〜」ってなります。
メイン CPU には,電気二重層コンデンサを付けておいて,サブ CPU 側に付けるのを忘れたりとか…。
修正しても動かない時は,かなりやる気パワーが取られるのですが,修正後はなんとか一発で想定した動きになりました!
この CPU 基板だけでは,画面表示とかできないので,今回は,動作している映像とかはありません。
次回は,画面に背景を表示する基板「ビデオボードその1」を作成します。
それでは,次回に続きます…。