DotToriKun on FPGA

またやってしまいました。誰得プロジェクト。


プロトタイプ1で自作 DotToriKun を動かす (クリックで別ウィンドウ表示)

トップページへ戻る



ドットリ君のゲーム基板

概要

「ドットリ君」というゲーム基板を FPGA で再現してみました。

動機

CPU, ROM, RAM および標準ロジック IC という基本部品のみで構成されているシンプルなゲーム機から、 ゲームハードの基本を学ぶことができるのではないかと考え、回路図化および FPGA による動作検証を行いました。 (回路図の公開は若干問題がありそうなのでしません。欲しい方は個人的にメールください。)

ゲーム基板の紹介

ドットリ君とは、SEGA が 1990 年頃に販売していたゲーム筐体に同梱されていたおまけ(?)ゲーム基板です。 どうもゲーム筐体のみの販売は法律で認められていないらしく、 その対策としてドットリ君という必要最小限のゲーム基板が入れられていたということのようです。

このような事情から、ゲーム基板としては、必要最小限のものを製作したと思われます。 一言で言ってしまえば、「安物の○ックマン」です。'>' が自機で、 これを操作して画面のドットを拾っていきます。'X' が敵で、 ぶつかるとゲームオーバーです。

ゲーム基板の入手性

簡単でシンプルな上、ゲームとしての価値はさほどないと思われるため、 Yahoo Auctions 等では 500円 〜 1000円 で手に入ると思います。私は 1000円 (+送料失念) で入手しました。

海外での呼称

海外では "dottori kun" と呼ばれているようですが、英語圏の人には dottori kun の意味はわからないと思われます。英語だと "dot picker" とか。。。 あと "kun" をどう訳すかですが、とりあえず思いつくのは "dot picking dude" とかですかね(笑)。

バージョンの違い

実はバージョンが2種類あり、初期バージョンは画面の背景の色が白で、 キャラクタが黒であるのに対し、後期バージョンは背景とキャラクタの色が反転されています。 あと後期バージョンはテストモードも追加されているらしいです。 初期版か後期版かを見分けるには、ROM の "MPR-14479" の後に 'A' の文字が入っているかどうかのようです('A' 付きが後期版)。 私のは 'A' 無しで、確かに初期バージョンでした。

主なスペック

主なスペックは CPU: Z80 @4MHz, ROM: 16kB, RAM: 2kB です。 ROM は 16kB (27128) が使用されていますが、ドットリ君ではこのうちのわずか 2kB 強しか使われていません。

画面解像度は 128 x 96 で、冒頭の画面写真からもわかるように、 この表示領域が画面の中央にくるようにタイミング生成回路が組まれています。 また、色数は全景と背景それぞれ1色(合計2色)しか出せませんが、色は (r,g,b) 各1ビットの組み合わせから選択できます。具体的には black (0,0,0), white(1,1,1), red(1,0,0), green(0,1,0), blue(0,0,1), cyan(0,1,1), magenta(1,0,1), yellow(1,1,0) から背景と前景を1色ずつ選べます(ドットリ君では白と黒の2色を使用)。

RAM の用途は 000h-5FFh (128x96/8 bytes) が表示パターン、 600h-7FFh が CPU のワーク RAM です。CPU は RAM 000h-7FFh の全領域に対して読み書き可能で、表示回路は 000h-5FFh を read-only でピクセル情報を読み出し、これを画面に表示します。


ドットリ君のゲーム基板をテキトウにジャンク LCD に接続して動かしてみた


ついでにドットリ君エミュレータも作ってみた (画面は 128x96)


[Mar.10 2012] Z80 IP を自作し VGA にも対応してみた

ハードウエアの特徴

CPU と表示回路が同じ RAM にアクセスする設計になっているため、表示期間中は CPU と表示回路間でアクセス競合が発生します。 これを回避するために、表示回路が RAM から読み出しを行っている間は CPU が RAM にアクセスしている/していないに関わらず、CPU のクロックが停止されます。 本当に CPU を停止する必要があるのは、表示回路と CPU が同時に RAM にアクセスした場合のみですが、このハードウェアではとにかく表示回路が RAM から読み出しを行っている間は CPU クロックを有無をいわさず停止させてしまいます。 また、Z80 は CPU を停止する目的で /WAIT 入力端子を持っているのに、 これを使わずにクロック自体を停止してしまうところから、機能よりもコスト(省部品) が重視された設計であることが伺えます。

Z80 の RAM 565h への書き込みと、表示回路の RAM 092h からの読み出しが衝突した場合の波形を以下に示します。表示回路が RAM にアクセスするときは Z80 のクロックが停止され、表示回路の RAM アドレスおよび制御信号(nRamOE, nRamWE)に切り替わります。表示回路が 092h から読み出しを完了した後 Z80 の RAM アドレスに切り替わり、クロックが停止が解除され、 Z80 による 565h への書き込みが完了します。


図1 表示回路が RAM にアクセスするたびに Z80 は停止させられる(赤で囲った部分)

表示期間中は 8 クロックサイクルごとに1回、表示回路が RAM にアクセスします。 これによって Z80 のクロックが 2 クロック間停止されます(立ち上がり 2 個分が H に保持される)。 よって表示期間中は Z80 は実質 4[MHz]*6/8 = 3[MHz] で動作していることになります。

水平表示タイミング生成回路

ゲームハードの設計を考えたとき、最大の関心事の一つは画面表示の仕組みではないでしょうか。 ドットリ君の場合、水平表示タイミングは 74LS161 を2個使用して、4[MHz] クロックを 1/2 〜 1/256 に分周した信号を取り出し、これを AND や OR などのゲートで合成して生成しています。 ここでは、74LS161 を2個使用して構成している 8 ビットカウンタを「H カウンタ」と呼ぶことにします。


   図2 H カウンタの回路図(相当)

水平表示タイミング生成ロジックを以下に示します。


      図3 水平表示のタイミングチャート

ドットクロックは 4[MHz] をそのまま使用しています。 水平表示1ラインの周期は 4[MHz]/256 の時間で、64[us] になっています。 また、水平パルス幅は 4[MHz]/32 パルスの半周期分を取り出して 4[us] になっています。 最終的に F に示される波形を得るために A 〜 E を使っているということもできると思います。

もう一つ、この水平表示タイミング生成ロジックで重要なのは、H カウンタがどの値のときに水平パルスが出力されるかです。 これが、ドットリ君の水平表示開始位置に関わってくるためです。上のタイミングチャートをみると、 H カウンタが 10110000 (注: 4M/128 は反転されているので) つまり 0xB0 のときに水平パルスが 出力されていることがわかります。また、水平パルスが L に戻るのは 4[MHz]/32 の半周期後なので、H カウンタが 0xC0 のときということになります。 ここが、いわゆる水平ブランク期間の終了ポイントであり、この信号を受信した映像機器は、 この直後から画面の左端にドットを表示可能とする動きになるはずです。

しかし、ドットリ君の場合は、この時点でドットを表示開始しません。 実際には、H カウンタが 0x00 〜 0x80 の 128 クロックの期間にドットを表示します。 このように、水平パルスとドット出力のタイミングをずらすことによって、横 128 ドットの範囲が画面のほぼ中央に位置するように設計されています。このタイミングも H カウンタの信号を AND や OR などのゲートで合成することで生成されています。

ちょっとわかりにくいかもしれませんが、水平パルス(Sync)とドット出力(SR)の タイミングを以下に示します。ドット出力期間が2つの水平パルスのほぼ真ん中に配置されていることがわかると思います (実際には真ん中より少し右寄り、冒頭の写真からも確認可能)。


      図4 水平表示のタイミング

垂直表示タイミング生成回路

垂直表示タイミングの生成も水平の場合と考え方は同じです。 垂直表示タイミング生成ロジックを以下に示します(一部正論理/不論理が実際の回路と異なります)。


      図5 垂直表示のタイミングチャート

こちらも 74LS161 を2個使用して、4[MHz] クロックを 1/512 〜 1/65536 に分周した信号を取り出し、これを AND や OR などのゲートで合成して生成しています。 このカウンタを「V カウンタ」と呼ぶことにします。


   図6 V カウンタの回路図(相当)

V カウンタも 8 ビットのカウンタで、1水平周期ごとに +1 します。よって 256 水平周期=1フレームとなります。 垂直表示つまり1フレームの周期は 4[MHz]/65536 の時間で、16.384[ms] になっています。 垂直パルス幅は 4[MHz]/4096 パルスの半周期分を取り出して 512[us] になっています。 1フレーム周期の逆数をとると、61.035[Hz] つまりドットリ君は 61.035FPS で動作するゲーム機であることがわかります。

水平表示タイミングのところで、実際にドットリ君が表示を開始するタイミングについて述べましたが、 垂直方向についても表示を開始するタイミングがあります。つまり縦方向にも画面のほぼ真ん中に 表示領域がくるようにタイミングが生成されています(生成ロジックは省略)。

図4に水平表示のタイミングを示しましたが、実はこの図は、フレームの最初のラインの表示を取り出したものです。 このときの V カウンタ (CntH) の値は 0x40(=64) です。垂直ブランク期間の終了は 0x20(=32) ライン目なので、ドットリ君の垂直表示開始位置は画面の上端から 32 ライン目です。垂直方向は 2 ライン 同じ内容を繰り返し表示するため、96x2=192 ラインの表示を行い、その後 32 ラインの期間は何も 表示しません。

最後に

後半が駆け足になりましたが、要は H カウンタと V カウンタでドットクロック(ここでは 4[MHz]) を分周して、これをロジックで合成して必要なタイミングを作り出しているということですね。

表示回路が RAM にアクセスするアドレスはどうやって生成しているのかについて説明していませんが、 これも H カウンタと V カウンタをごちゃごちゃと AND/NAND, OR/NOR して作り出します。 ドットリ君の VRAM は 1 バイトで 8 ドットなので、8 ドットクロックごとに 1 バイトを VRAM から読み出す必要があります。なので 4M/8 を使うことは容易に想像できますね。 興味のある方は調べてみてください。

あと、ドットリ君の基板はほぼ知り尽くした&ゲームで遊ぶ気はないので、欲しい方にあげます。 ROM を一度ぶっこ抜いてソケット付きにしたので、自作 ROM に差し替えて自作ゲームを 遊ぶこともできると思います(やろうと思えば)。欲しい方はご連絡ください。

トップページへ戻る


謝辞


(C) Ki 2010