HOME  

SNES on FPGA


DE2-115 FPGA board (1 chip SNES)
 スーファミは遊ぶためのもので、開発するためのものではありません。

 SFC、つまりスーファミをFPGAで自作した、というお話。

 ファミコンの時代、チープな性能のため実現できなかったクリエイターたちの世界が、 スーファミの時代になり少しずつ実現しつつあった(それはもうICが火を噴かんがごとく)。 デザイナー、バトルプログラマ、ドッター、サウンドプログラマ… 彼らの歴史の中で紡がれてきたものはなんだったのか。 スーファミ互換機の製作。それはスーファミにおいて最後のゲームとなる。

▼ 開発環境

ハードウエア記述言語 SFL+、VHDL、VerilogHDL

・開発環境1代目
PC Windows2000、Athlon64 4000+、Mem 1GB /Cygwin、VC++6.0、sfl2vl、Verilator、Altera QuartusII 6.1
・開発環境2代目
dynabook RX3 WindowsXP、Core i5-520M、Mem 2GB /Altera QuartusII Free 9.1SP2
・開発環境3代目
dynabook R732 Windows7、Core i5-3320M、Mem 4GB /Altera QuartusII Free 12.1SP1
・開発環境4代目
dynabook R732 Windows7、Core i5-3320M、Mem 16GB /Intel QuartusPrime Lite 17.1

FPGAボード
Altera DE1 2005〜
 CycloneII 約18,000LEs、内蔵RAM 約30KByte
Altera DE2-115 2016〜
 CycloneIV 約115,000LEs、内蔵RAM 約500KByte
Altera DE0-CV 2017〜
 CycloneV 約49,000LEs、内蔵RAM 約380KByte


▼ 動作デモ

 SNES on FPGA (with original sound module)

 Chrono Trigger demo. YouTube

▼ SPC Player on FPGA
 SDカードのSPCファイルを演奏します。 APUのSPC700とDSPをAltera DE1に実装しました。
YouTube

▼ おとなりさんを覗いて見れば、文明開化の音がする

 2006年末、巷ではPS3、Xbox360、Wiiといったスーパー描画性能を持つコンシューマ機が出回り始め、 グラフィックやユーザインタフェースの進化とやらが少し見えてきました。 私の部屋にはそれらの次世代機はおろかテレビさえ無いけど。
 これまでのPS2やゲームキューブといったゲーム環境と違うところは、 単にゲームで遊ぶだけでなく、現実とのリンクがより強くなったということでしょうか。 とある職人はカスタムレースマシンをオークションに出品し現金を稼いだり、 またある医師はスポーツゲームで筋肉痛になったり。
 別に次世代機を持っていなくても羨ましくもなんともないのですが、 ある方から言われたのが「ゲームに遊ばれるな!」。 酒に呑まれたらおしまいだーとかそんなノリで、 まともにゲームを楽しむことができない体に改造されてしまいました (ここの処理は…という所に目がいってしまう)。ああ…たまにはゲームに遊ばれてぇ。
 要は、おもちゃといってもどうやって動いてるか分からないなんてくやしいっ!てことで、 じゃあ作りましょうかっていう流れになったのです。 家庭用ゲーム機としてメジャーなファミコンを! とは誰の言葉だったか…。理由なんて幾らでもありますがそれはおいときます。

▼ そんなベタなファミコンはいやだ!

 という心の叫びを実現したのがNES on FPGAであります。 ディジタル回路の復習とFPGAの練習もかねてかりかり実装したわけですが、 このときは「わあFPGAって便利なんだねぇ」程度にしか考えていなかったのがいまや FPGAに苦しめられる立場に…コンプライアンスってナンダー!
 ややもしながら、NES on FPGAは一応の完成を見たわけですが、 私としてはファミコンへの思い出以上に、スーファミへの愛着もあったわけです。 ちょっとアーキテクチャを調べてみると、やはり同じ会社が作ったわけで、 似たような部分もあるし、NES on FPGAの開発環境やノウハウもある。 まだ誰も作っていないのならば、作ってみようスーファミを! 今後の趣味の一つとしてSNES on FPGAの開発が始まったのでした。
 基本的な設計方針としてはNES on FPGAの時同様に、 実機に近いサイクルで動作させるようにします。 これは最終的に実カートリッジを使って動かすことを考えてのことですが、 FPGAボードの50MHzと豊富なリソースがあれば、 ほぼソフトエミュレータをベースにした設計で作ることも可能です。 しかしそれでは考古学的な意味合いがちょっとずれてしまいます。 当時のリソースを想定しながら実機に近いアーキテクチャで設計することで、 スーファミの設計者たちがどんな設計思想を持ち、 どんなところに苦労したのか、そんなことも少しは垣間見えるのではないか、 というところも今回の開発の醍醐味でもあるのですから。

▼ NEXT GENERATION

 用語の補足
  CPU (Central Processing Unit):65C816、メインの制御を司る。
  PPU (Picture Processing Unit):画面の描画を行う。
  APU (Audio Processing Unit):サウンドを生成する。SPC700プロセッサとDSPからなる。
  WRAM (Work RAM):CPUが使うメインメモリ。
  VRAM (Video RAM):PPUが使う描画用データが格納されるメモリ。
  DMA (Direct Memory Access):メモリからVRAMへCPUよりも速くデータを転送する。
  ROM (Read Only Memory):ゲームカートリッジにあるソフトデータが格納されている。
  PPU2:各機能のタイミングなどを制御する。
  HDMA:各ラインでちょっとしたDMAを行い、PPUレジスタを書き換えて画面効果を実現する。

 SNES on FPGAの開発環境としては、 開発プロセスをなぞりながら見ていきます。 ベースはNES on FPGAの開発プロセスです。 ただし規模が大きくなるためそれなりに効率的な検証方法を導入する必要があります。

・仕様を把握しろ!
 一言でいえば互換機の開発なので、 オリジナルの仕様を理解しなければ子供たち(ゲームソフト)との楽しいおしゃべり (ROMカートリッジアクセス)もままなりません。 絵筆が無いと芸術家は爆発し、楽器が無いと演奏家は旅に出たまま戻ってきません。
 すでに20数年前に発売されたゲーム機ということもあり、 資料からエミュまで多く存在しています。 それでもハードウエア実装を目的とした資料はあまりありません。 やはりそこは自分で確認するしかない。

・エミュレータ作成
 資料を読み解きながらリファレンスモデルとなるエミュを作成します。 開発はVC++6.0で行っています。 基本的にはリセットベクタから順繰りデータをフェッチして処理するCPUとメモリがあれば動く。 イニシャライズルーチンから垂直同期待ち、DMA、背景描画、スプライト描画。 デモのソフトを試しながら順次CPUの命令を追加。 ちゃんと実行しているかは描画して確認。 ちなみにサウンドに関してはエミュ実装が面倒で、 FPGA実装の方が容易だろうと踏んで音はでません。 やっぱり基本はマリオだろうということで、実行したがAPUアクセスで停止したり…。

・ハードウエア記述
 一般的にはVHDLとかVerilogHDLを使用する人が多いようですが、 生活環境上SFLを使用する流れに。 結果として機能記述が可能なSFLのおかげで、 仕様変更に柔軟に対応できたわけですが。 さらに、NESの開発環境を活用して開発効率を上げます。 特に独自拡張したSFL+はより大規模なSNESの開発に役に立ちました。

・シミュレーション
 SFLでのシミュレーションは行わず、VerilatorにてC++に変換しシミュレーションです。 一般的には波形を目視確認することが多いようですが、波形は見たくない。 しかも仕様が未確定な部分が多いためテストケースが作れず十分なシミュレーションもできません。 まあ、基本SFLって動作記述的なところがあるからシミュレーションしなくても大体動いちゃうんですが。

・SFLからVerilogHDLへの変換
 オーバートーン社のNSL Coreに付属するsfl2vlコマンドを使用してVerilogHDLへ変換します、これはいい。 Cygwinを使用しているので、makeコマンドで一発です。 ついでにverilatorも通すので、もしsfl2vlで変換不具合があった場合でもすぐにわかります。 そんな時はNSLの開発者様へ報告して、すぐに対応していただけました。感謝いたします。

・そのFPGAボードおいしいの?
 SNESのゲート規模をおおよそNESの4倍と想定してAltera DE1(Cyclone II EP2C20)を購入しました。 値段は$150+送料=約\17,000(2005年当時)でした。 本当はDE2(Cyclone II EP2C35)がほしかったんですが値段が3倍以上したので怖くて手が出ませんでした。

・FPGAでの動作確認
 AlteraのQuartusIIで論理合成・配置配線したのち、FPGAへコンフィグして動作確認です。 基本的にエミュで動作したものを検証するので、全く動かないことはまれです。 問題なのは動いてしばらくしてから、画面の描画がおかしいとき。 問題はCPUかDMAかPPUか、はたまたそれ以外の部分か? 不具合を発見するため問題の切り分けが必要です。

・不具合を見つけ出せ!
 問題の切り分けのために基本的にはエミュでCPUの動作ログを取得してにらめっこです。 HDLで記述したCPUのシミュレーションは、限られたデバッグ時間では現実的ではないのでできません。 CPUに問題が無さそうであればPPUを疑います。
 エミュで問題個所のスナップショットを取り、VerilatorでPPUのVerilogHDLをC++に変換したものをシミュレーションします。 1フレームの描画には約3秒かかります。 PPUの実装で問題があればここでFPGAでの不具合が再現され、描画に失敗した画像が出てきます。
 PPUにも問題が無ければDMAやそのほかの部分など、 仕様外動作が考えられるところに一つずつアサーション回路を埋め込んで、さらにFPGAで検証します。
 それでも不具合の原因が特定できなければ、 疑わしい部分をVerilatorでC++に変換してエミュに組み込んで協調検証です。 エミュの動作ログとC++に変換した部分の動作ログを比較することで、 不具合発見に至ります。
 厄介なのが、レジスタやメモリなどへの同時アクセスがエミュでは再現できないこと。 これらはHDLで記述する場合、しっかりと排他制御しなければいけません。 それを忘れたり実装をミスっていたりすると不具合原因の切り分けが難しくなります。

・はたして結果は…
 不具合発見に至ればあとは修正するだけです。 ただし仕様が不明確な部分は試行錯誤が必要ですが。
 SFLを修正したらmakeしてコンパイルして再度FPGAで動作確認です。 問題なのは、シミュレーションしない(できない)ので、果たして正しく修正できているか、 ちゃんとした結果が出るまでドキドキです! コンパイルしてFPGA検証するまで、心の落ち着きを取り戻すのに数日かかることもあります(単に別の事で忙しいだけ)。 その間はひたすら脳内シミュレーションで確認して心を落ち着かせます。
 そしていよいよFPGAボードの電源を入れ、データをコンフィグし、動作確認。 問題なく動いたときはあっさりと動くものです。 動かなかったらただ泣きます。 泣き疲れたら再度原因の調査、修正個所の確認です。

・再現性を上げる!
 確かに、ゲームが動いて、音も画像も出て、プレイもできるようにはなりました。 しかし、エミュレータでは再現できない、ハードウェアだからこそ発生する不具合というものがあります。 トリガ発生タイミングの問題、メモリアクセスの問題、各プロセッサ協調動作の問題など、 ほんのちょっとの本来の仕様と実装のズレによって発生する不具合。 それも、ほとんどゲームプレイに影響しないような、描画のちょっとしたゴミ、遅延など。 それらの原因を、FPGAの内部信号をプローブできるSignalTapIIで観測したり、 資料を読み込んで推測したりして、原因を究明し修正して、ひとつひとつ不具合を解消していきます。
 また、資料に見つからない仕様に関して。 世にある解析資料はソフトウェア開発者目線のものが多く、 ハードウェアで実現するために必要な仕様が不明な部分があります。 そういったパラメータを決めてやらなければいけない所は、 複数のソフトを使って範囲を絞り込む必要があります。 各ソフトでパラメータを変えながら動作する範囲を確認し、 全ての範囲が重なった部分を仕様として決定するのです。

 こうしてSNES on FPGAは完成に近づいてゆくのでした。

▼ 開発履歴


SFC cartridges over 1,000
1990/11/21 スーパーファミコンが発売される。
1994/11/11 祖父からスーファミを買ってもらう。
2005/04〜 資料集め。エミュやデモソフト、スーファミカートリッジも集める。
2005/05〜 エミュ作成開始。 資料から、まず簡単なデモが動作するまでのエミュを作る。 イニシャライズルーチンまで動作VBlank待ちDMAを実装する必要がある。
2005/06/02 タイルデータからキャラクタアドレスを求め、 ピクセルデータからカラーデータを取得するロジックを確認。
2005/06/14 自作エミュで「Hello World !」を表示できた。
2005/06/21 「DEMOROM」が動作、mode1のbg1を実装。
2005/07/02 「HDMADEMO」のためにHDMAとColorWindowを実装。 ColorWindowのために描画をパレットからRGBデータへ変更。 CPU命令を順次実装。 スプライトを実装。 BGを複数面実装。 「スーパーマリオワールド」など、APU通信を使用しているためハング。
2005/07/15 APU(SPC700)を実装。
2005/08 バックグラウンド各モード実装。 各種サンプルROMを動作させ、アドレッシングモードでのインクリメントやインデックスの様子を観察。
2005/11/12 FPGA向けにSPC700を実装。 DBNZ、MOV_MA、MOV各種、BBS、BBC、MOVW、CMP、MUL、CLRC、RETなど。

DE1 + original APU module
2005/11/26 「FF5」のSPCを元にSPC700の命令を順次実装。 MOV各種、DEC、INC、ADDW、INCW、JMP、PUSH、POP、EOR、XCN、SETP、BCS、CBNE、 CPUとの通信ポートレジスタ。
2006/01/04 SPC演奏部分初期実装。
2006/02/03 SPCのDIV実装によりFPGAで再生可能。 再生速度が速かったため動作周波数を修正した。
2006/05/04 「46億年物語」のキャラクタがPPU->CPUのDMAを行っているのでサポート。
2006/05/08 エミュでSRAMサイズチェック対策。 「カービィボウル」が動作した。
2006/07/02 PPU2 符号無し16bit除算実装。 「STRDEMO」の使用命令実装完了。
2006/09/24 FPGAにてHello World!を表示。→
2007/02/10 「ニューロでファジーなシューティング」にて 処理速度が極端に落ちていたのはSBCのfcが反対だったため。 演算命令チェックを実施。
2007/02/17 FPGA向けMPUの命令実装、わにわにクラブの各サンプルについて実行しながらの実装。 「ロックマンX」についての実装、 APUへのアクセスが入ってきてから命令のトレースがエミュと合わなくなったため、 実機のAPUモジュールを接続する。 それでもコアAPUと変わらないのでとりあえず実装したところ実行できた。
2007/03/11 「ロックマンX」が動作しない不具合の検証のため、 VerilatorでC++にしてエミュに組み込み協調検証を行う。 実行速度は速い。どうやらIRQが入っていなかった模様なのでこれを修正。 FPGAにて「ロックマンX」がプレイできた。 (It is playable MegaManX on FPGA)→
2007/03/17 エミュにてXBA,TSB,TRBのフラグミスを修正。
2007/05/01 APU、DMA、MPUの優先順位でNMI中のDMAが間に合わずハングしていた不具合。 DMAの転送レートが遅かったため、readとwriteをパイプライン化して解消した。
2007/05/04 「カオスシード」でキーが反応しなかったのは21モードSRAMへのアクセス方法を変更していたため。 8kBのSRAMをマップして解消した。
2007/06/07 SDカード読み込み実装。そしてFAT16実装。 これによりSDカードからのROMブートが可能になった。
2007/07/01 エミュにBG mode7実装。
2007/08/27 FPGAにDSPを実装して音色が出る。 波形メモリはSPC700と同じなのでアービトレーションが大変。 BRRのフィルタは必要。 符号付>>が面倒、>>>の実装が待たれる。 8チャンネルにする必要がある。
2007/09/28 SPC700のTCALLを修正。
2007/09/30 エミュとFPGA実装のAPUタイマのタイミングを合わせた(だいたい)。 サウンドSPC700の検証で難しいのはsflのログとエミュのログをあわせること。 SPCとタイマの動作比をあわせることで大体のログの一致が見られた。 「バハムートラグーン」Boss.spcにてSPC700のDBNZ、JMPMを修正した。 さらにJMPMは16bit加算に修正。
2007/11/11 シリアルポートでSPCファイルを転送して演奏できるようにした。
2007/12/30 「FF6」戦闘.spcなど、 シンバルのホワイトノイズ成分を線形補間しようとするとインパルス雑音が混じる。 補間間隔をゆるくすれば大丈夫だが、できればガウシアンフィルタを実装したいところ。 :線形補間演算部の符号拡張ミスが原因だった。
2009/12/20 HDMA初期実装。 ラスタスクロールによる画像効果が可能になった。
2009/12/27 BG mode7実装。回転、拡大、縮小が可能になった。 HDMAとの組み合わせで飛空挺画面。
2010/12/12 BRRデコーダのバグ修正。 「FF6」仲間を求めて.spcが正常に演奏されるようになった。
2011/05/04 SRAMサイズをROM情報に合わせてマスク。 これによりSRAMチェックを行っている「ルインアーム」や「カービィボウル」が正常に動作。
2011/05/05 HiROM(21mode)をサポート。
2011/06/04 「カービィボウル」の軌道がおかしかったのでPPU1の乗算器を符号拡張演算に修正。 ちゃんと転がるようになった。
2011/06/05 PPU2のV_IRQを修正。1フレーム内で何度でもIRQが出るように修正。 「FF4」のメニューがちゃんと表示された。
2011/09/11 SubScreen演算、ColorWindow実装により、透過処理をサポート。
2011/09/18 スプライトフェッチの終了条件を修正。 大きなサイズのスプライトが並ぶと表示されなかったものをちゃんと表示できた。
2011/09/19 HDMAの終了条件を修正。 エミュでバグ再現があっさりできたので簡単にバグトラッキングできた。
2011/09/25 65C816のIndexAddressingを修正。あと命令を全部実装。
2011/10/02 SpritePriorityRotationを修正。左上のマリオが表示された。→
2012/03/04 IRQ生成方法の修正で「風来のシレン」が動作した。
2012/06/28 $2180のメモリリードでデータバスが接続されてなかった所を修正。
2012/07/05 VBlank中でもHBlankingFlagが立つよう修正。 「クロノトリガー」「カオスシード」が動作した。
2013/03/24 PPUのHVカウンタラッチを実装。 「クロノトリガー」のバトル中にハングする不具合が解消された。
2013/04/21 DMA中にHDMAが発生した場合DMAを一時中断するよう修正。
2013/05/06 PPUのOffsetPerTileを実装。 「クロノトリガー」のタイトルが波打つような表現や、 「す〜ぱ〜ぷよぷよ」のゲームオーバー時の落下を再現。
2013/05/19 TileSize16を修正。 「JellyBoy」「アダムスファミリー」を正常に描画できるようになった。
2013/05/26 モザイク機能初期実装。
2013/06/02 キー入力を修正。 「風来のシレン」「タクティクスオウガ」でキーが効くようになった。
2013/06/09 「バハムートラグーン」でフレームの途中でもHDMAをdisableするケースがあったのでこれに対応。
2013/06/16 HDMAの終了条件を修正し「バハムートラグーン」が点滅しなくなった。
2013/06/23 HDMAの終了条件をさらに修正し「バハムートラグーン」のOPデモをパスした。
2013/06/29 windowの範囲条件にleft<rightを追加。
2013/07/07 DMAでROM→WRAMへのバスを実装した。 両方ともSDRAMにマッピングしているため仕様例外としてこの場合に限りパイプライン動作を解除。 これにより「クロノトリガー」「天地創造」などで画像がバグっていたものがちゃんと表示されるようになった。
2013/07/18 PPU2のHVカウンタソフトラッチをリセットイネーブルに修正。 「エナジーブレイカー」が動いた。
2013/07/27 65C816のアドレッシングモードSTACK_RELATIVE_INDIRECT_INDEXを修正。 「DQ6」「DQ3」が動作した。
2013/07/28 VRAMアドレスリマップを実装。 「DQ3」「DQ6」のメッセージが正常に表示された。
2013/09/08 HDMAがフレームの途中でenableされることに対応して「エナジーブレイカー」の背景グラデーションがちゃんと表示された。
2013/09/16 PPU1のH Counter Software Latchを修正。 「海腹川背」「シルヴァサーガU」が動作。
2013/09/29 PPU1_Mode7_DirectColorModeを実装。 「アクトレイザー2」「エアーマネジメント」のマップが正常に表示された。
2013/10/05 DMAとHDMAで同じチャンネルを同時にEnableできるよう修正。 「悪魔城ドラキュラXX」が正常に表示された。
2013/10/14 BG mode7の領域外処理(透過 or Char0)を実装。 「バットマン フォーエバー」のOPが正常に描画された。
2013/10/19 モザイク機能の修正で、開始タイミングを特定した。透過領域も考慮。 これで上部、左部の表示が正常になった。
2013/10/20 セーブデータ(.srm)を読めるようにした。
2013/11/17 BG mode7のExtBGモードを実装。 「きぐるみ大冒険」のワールドマップの色がきれいに表示された。→
2013/11/27 WAI命令を修正して「ミスティッククエスト」が動作した。
2013/12/23 NES方式のキー読み取りをサポート。 「バトルテック3050」「レディストーカー」がプレイできた。
2014/01/22 65C816のBIT命令(Immediate)を修正。 「ガイア幻想記」のスプライトが正常に表示された。
2014/02/16 HDMAの開始タイミングの調整とクロック数削減、PPUレジスタ2重化の解除により「クロノトリガー」のOPデモをパス。
2014/02/23 VRAM_adrsセット時にVRAM_Dummy_readするようにして「ワギャンパラダイス」などいくつかのnamcot製ソフトでBGがちゃんと表示された。
2014/03/01 スプライトアドレスのリロードを実装。 「スーパードンキーコング」「摩訶摩訶」などでスプライトがちゃんと表示された。
2014/03/16 スプライトフェッチをアップカウントからダウンカウントに修正。 「クロノトリガー」の異次元ゲート表示時の不具合を解消。
2014/03/23 スプライトフェッチ最大34個までをサポート。 「FF5」のバッツが表示された。(32個まで制限しているとバッツが表示されない)→
2014/03/30 BG mode2,4,6のOffsetPerTileでTileSize16と64x64tilesをサポート。 「クロノトリガー」の名前付ける画面やメニュー画面が正常に表示された。
2014/04/05 OffsetPerTileを修正。 「シルヴァサーガU」のネーム画面やフィールドが正常に表示された。
2014/04/20 HDMAでチャンネルごと転送→次アドレス、としていたものを、 転送ステージと次アドレスステージと分離させることで、 PPUへのアクセス時間をHSYNCまでに間に合わせるようにした。 これによりHDMAの開始タイミングを確定できたが、少しちらつきが発生する所があって要調査。 :転送方向切換の実装ミスが原因と判明。
2014/05/24 DSPのエンベロープジェネレータで先発継続としていたものを後発優先 (下村陽子氏のインタビューより)に修正。
2014/08/24 DSPでエンベロープの途中でパラメータが変更された時に、タイムカウント値をクリアするよう修正。 「DQ6」の街のテーマでスタッカートが効くようになった。
2014/08/31 DSPのエコーが浅いというコメントがあったため、エコー実装のクリップ処理を修正。 ノイズもなくエコーが効くようになった。
2014/09/07 DSPのMVOL(MainVolume)を実装してエコーとのバランスが取れるようになった。 またクリップ処理やエコーバッファの有効ビット幅を見直して、ノイズが乗らないようにした。
2014/09/14 DSPのBRRデコードをOldADPCMからより実機に近い方式に修正した。 これによりエナジーブレイカーなどいくつかのサウンドでクリップノイズが乗っていたものが解消された。 また、「FF6」の雨の街ゾゾの雨の音が再現できた。
2014/09/21 DSPのエコー後段にFIRフィルタを実装。 エコーの効き過ぎが少し抑制されてサウンドがまろやかになった感じ?
2014/09/27 DSPのエンベロープジェネレータでサスティンレベルの解釈を間違えて実装していたものを修正。 「天地創造」のジャングルのテーマでドラムが正常に演奏されるようになった。
2014/09/28 DSPのエンベロープジェネレータで急峻アタックをサポート。 「FF4」のエンベロープゲインが安定した。
2014/10/11 IRQの終了条件を修正して「FF6」のダンジョンがちらつかなくなった。
2014/10/12 CPU速度可変機能を初期実装。 「Final Fight」でロゴ表示画面のごみが消えた。 「FF6」で表示中にVRAMアクセスが発生していたタイミングを遅らせることで右下の微妙なごみが消えた。 「ワイルドガンズ」がちらつくようになった(後に解消)。
2014/10/13 モザイクの保持条件を修正。 「FF5」「FF6」でエンカウント時のエフェクトが正常になった。
2014/10/18 疑似的なDRAMリフレッシュを実装した。 リフレッシュの間、CPUにウェイトをかけることで「FF6」の右下に出ていたゴミを画面外に追いやることができた。
2014/10/25 PPU1のForceBlackを実装。 「スーパードラッケン」のOPデモで雲が描画されていた不具合を強制黒にできた。
2014/10/28 CPUのブロック転送命令(MVN/MVP)のサイクル数を修正。 「エナジーブレイカー」のロゴ表示時に一瞬ちらついていたものが解消された。
2014/11/01 CPUのDirectPageAddressing関係で仕様に合わせてサイクルを修正。
2014/11/15 HDMAの改良に伴いバスの切り替え実装が不十分だった箇所を修正。 「バハムートラグーン」のOPデモでの一瞬のちらつきが解消された。
2014/12/07 DMAが範囲外バーストリードすることに対してPPUへのReadをガードするように修正。 「スーパーテトリス3」のタイトル画面やプレイ画面が表示されプレイできるようになった。
2014/12/23 モザイクでY方向の処理を修正し 「エナジーブレイカー」で上部に下部のモザイクが表示されていた不具合について解消した。
2014/12/30 疑似横512ドットモードを実装。 「シルヴァサーガU」の水面の半透明が表現できた。
2015/01/04 BG mode5,6の横解像度512ドットを初期実装。 「聖剣伝説3」「ときめきメモリアル」などBGmode5を使用しているゲームの文字が読めるようになった→
2015/01/30 BG mode7の水平反転を実装。 「Battle Grand Prix」のメーカーロゴを正常に表示できた。
2015/02/01 模擬OpenBusを実装。 「スーパーファミスタ2」などが動作するようになった。
2015/02/07 BG mode5でのパターン水平反転を実装。
2015/02/11 BG mode5でのタイルサイズ16の時の挙動を修正。 「ロマンシング・サガ3」のメニュー背景を正常に描画できた。
2015/02/15 タイミング解析で警告があったのでDMAレジスタアクセスをステージ分離してfmaxを満たした。
2015/02/16 V_IRQのトリガをコメントアウトしていた件について修正。 以前のバージョンでプレイできていた「カオスシード」を再び正常に描画できた。
2015/02/28 画面描画時のVRAMへのWriteアクセスを無視することで 「スーパーテトリス3」のスパーク時のゴミ表示が消えた。
2015/03/01 ForceBlankフラグを即時反映させるように修正し「アウターワールド」のゴミ表示が消えた。 ただしこれにより「ヴァルケン」が点滅するようになった(後日解消)。 また、DMAコアで転送タイプを全て実装した。
2015/03/08 スプライトアドレス指定をバッファリングするように修正し 「デザエモン」のスプライト表示不具合が治った。
2015/03/18 スプライトアドレスのリロード条件を修正し 「エアーマネジメント」のOPデモ時の飛行機が表示された。
2015/04/05 BGmode5の固定カラー演算をサポート。 「ルドラの秘宝」「ときめきメモリアル」での表示が改善された。
2015/04/14 HiROMのSRAM21に対してバンク指定を修正 「バハムートラグーン」のテンポラリセーブデータが壊れる不具合を解消。
2015/05/20 DMA中にNMIが発生した場合の処理を追加 「ワイルドガンズ」がちらつかなくなった。
2015/06/20 DE2-115ボードにCPU、PPU、DMAなどを移植。 とりあえずサウンドなしのサンプルが動作した。
2015/06/24 DE2-115ボードでAPUを追加して全てのモジュールの結合テスト。 が、サウンドが鳴らなくてCPUとの通信に失敗し動作せず。
2015/06/27 APUのエコーバッファ書き込み有効無効フラグを修正。 結合テストで動作しなかったのは、エコーからのAPUメモリへの書き込みが、 CPUからのサウンドプログラム書き込みを阻害していたため。 無事、CPU,PPU,DMA,APUの全てのコアを動作させることができ、 スーファミがFPGA 1chipで動作した。
2015/08/14 ForceBlankフラグを即時反映させるようにしたことに伴い、 Blank中でも描画回路を動作させるように修正(ただしVRAMアクセスはしない)。 「ヴァルケン」の画面が点滅したりラインごとに描画がずれる現象が解消した。
2015/09/06 BGメモリアクセスとスプライト探索・パターンフェッチのタイミングを、 ForceBlankフラグのライン同期時に反映させるように変更。 「ヴァルケン」の上部ゴミと「バハムートラグーン」上部のスプライトのゴミが表示されなくなった。
2015/09/21 APUのノイズ生成機能実装。 「クロノトリガー」の効果音や「デザエモン」のBGMのハイハットなどが鳴るようになった。
2015/09/22 APUのピッチモジュレーション機能実装。 「FF6」OPの崖の風の音や「クロノトリガー」のカエルの鳴き声が再現できた。
2015/10/11 CGRAMアクセスガードの修正で「バハムートラグーン」のラストステージの背景色がおかしくなる不具合を修正。 また、Brightnessがゼロのとき黒を出力することで、画面切り替え時のゴミ表示が消えた。
2015/10/12 APUのミュートフラグを実装。 「アラビアンナイト〜砂漠の精霊王〜」開始時などの雑音が消えた。
2015/11/07 DE2-115ボードでUSBゲームパッドを使えるようにした。 USBコンバーターを使えば純正SFCパッドやプレステパッドも使用可能。
2015/11/08 APUのリセットを修正。
2015/11/12 エミュにCx4を実装して動作を確認。
2015/12/20 エミュにSuperFXを実装して動作を確認。
2016/04/20 APUメモリをゼロフィルして「エルファリアU」のサウンドがましになった。 しかしサウンド切り替えで止まる現象あり。
2016/09/10 HDMAでAPUへのwriteを実装して「N-Warp大作戦」が動作した。
2016/09/24 CPUのデータフェッチ時のアドレス桁上げを修正。
2016/11/26 8MB ROMのメモリマッパサポートと、 リザーブ領域のアクセスをROMアクセスに修正して「Bad Apple」を完走した。 HDMAサウンドストリームでたまに音飛びする症状があるが、これは実機でも発生するため問題なし。
2016/12/04 SNES core内にあったセーブメモリのアドレスマップをcore外に移動。
2016/12/10 スーファミパッド×2 to USB変換器を使えるようにして対戦プレイできるようになった。
2017/05/07 VBlankの開始ラインを224から225に修正して、Burn-InテストのV224/V239をPASSした。
2017/05/08 Y位置(scanlineレジスタ)の更新タイミングと、X位置(view_xレジスタ)が256越えてもカウントするように修正し、 Burn-InテストのEXT_LATCHテストをPASSした。
2017/05/12 オブジェクトのレンジオーバーフラグとタイムオーバーフラグのセット条件を修正し、 Burn-InテストのOBJ_L_OVERテストをPASSした。 これでBurn-Inテストについて全てPASS。
2017/05/13 前に(2015/09/13)HBlank時にCGRAMへのアクセスをしないようにしたが、 255ドット目のCGRAMアクセスができなくなっていた。 HBlankフラグのタイミングを修正しこれを解消。
2017/05/18 50MHzから生成した約10.738635MHzのサイクルをCPUやDMAの動作速度に使用することで、 「クロノトリガー」のOP終わりがサウンドと一致した。 一部魔王城の所でちらついたが、HDMAのクロック削減で解消。
2017/05/23 LoROMとHiROMを判別するロジックを追加。これまでは手動スイッチで切り替えてた。 チェックサム値が正常に設定されていない同人ソフトの判別には弱い。
2017/08/02 DE0-CVボードが入手できたので移植。 キー入力はボタンで、サウンド出力は1bitΔΣDAC。
2017/08/12 PS/2キーボードで操作できるようにした。
2017/09/17 SPC700のRETI命令でIフラグとBフラグが逆になっていたものを修正。
2017/09/18 WAI命令でIフラグが立っていてもIRQが来たらWAI解除するよう修正。
2017/10/05 SPC700のADDW,SUBWが4クロックだったものを5クロックに修正。
2017/10/07 オートキー取得のロジックを修正して「す〜ぱ〜ぷよぷよ通」がプレイできるようになった。
2017/11/05 65C816のADCとSBCでのVフラグの論理を修正。
2017/11/14 65C816でIRQとNMI時にDフラグをクリアするよう修正して 「聖剣伝説3」でプレイ時に強制リセットがかかっていた現象が改善しプレイできるようになった。
2017/12/16 BG mode7のスクロール値とセンター座標の差をクリップするよう修正して 「RPGツクール2」の飛空艇画面や「キャッツラン」のレース画面の描画が改善した。
2018/01/01 エンベロープジェネレータでDecay時間が長かったのを短く調整。
2018/06/21 MiSTerシステムに移植。せっかくなのでHDMIから映像出力できるようにしたい。

▼ ScreenShot

 DE1ボードのVGA出力をモニターに接続してデジカメで撮影したものです。


Rockman X

Super Mario World

BIO METAL

Gradius III

Final Fantasy IV

Gundam Wing

Final Fantasy V

Ruin Arm

Fire Emblem Trachia 776

The Great Battle III

Rendering Ranger R2

BUSHI 青龍伝

カービィボウル

Super Tetris 3

す〜ぱ〜ぷよぷよ通

R-Type III

悪魔城ドラキュラ

超時空要塞マクロス

46億年物語

Bahamut Lagoon

HAGANE

Romancing SaGa 3

聖剣伝説3

Super Street Fighter 2

風来のシレン

Chrono Trigger

CHAOS SEED

Final Fantasy VI

Jelly Boy

Tactics Ogre

Wonder Project J

天地創造

極上パロディウス

Nage Libre

すごろクエスト++ダイスニクス

Assault Suits Valken

Wild Guns

Dragon Quest VI

Dragon Quest III

Energy Breaker

海腹川背

Silva Saga II

ActRaiser 2

悪魔城ドラキュラXX

Arabian Knights 砂漠の精霊王

バスタード!!

超兄貴-爆裂乱闘編-

バトルZEQUE伝

ヘラクレスの栄光IV

Breath of Fire II

ドカポン外伝

ELFARIA

Darius Twin

Demon's Blazon

ときめきメモリアル

F-ZERO

美食戦隊 薔薇野郎

はしれ へべれけ

実況パワフルプロ野球3

実況ワールドサッカー2

かまいたちの夜

LIVE A LIVE

MYSTIC ARK

▼ 実装した機能

・プロセッサ
  65C816コア 16bit
   動作周波数:1.79MHz、2.68MHz、3.58MHzの三段階切り替え
   各種アドレッシングモード、割り込み:NMI、IRQ、BRK、COP
   16bitBCD加減算含むALU
  メモリ:WorkRAM 128KByte

・グラフィック
  解像度:横 256 or 512、縦 224 or 240、ノンインターレース
  表示色:32768色中から選択
     BG面の枚数とパレット数の組み合わせをモード0〜7から選択。モードにより各BG面は4色、16色、256色パレット
  バックグラウンド:4面、タイルサイズ8×8 or 16×16、1面あたり最大1024×1024(内部)
  スプライト:最大128個、サイズ8×8、16×16、32×32、64×64、縦反転・横反転
        1ライン当たり8×8サイズで最大34個
  エフェクト:BGモード7による拡大縮小回転と拡張BGモード、ダイレクトカラーモード、半透明、モザイク
        ウインドウ2面、ラスタースクロール、8ピクセルごとの縦スクロール、疑似横512ドットモード
  その他:HVタイミングカウンタ、8×8bit乗算器、16÷8bit除算器、HV_IRQ
  メモリ:VideoRAM 64KByte

・サウンド
  SPC700:制御用MPUコア 動作周波数:1.024MHz
  DSP:サンプリング周波数32kHzに準ずる
   最大同時発音数:8チャンネル
   BRRデコード16bit PCM音源 ステレオ(ADPCM)、ADSRゲインと各種線形ゲイン指定
   エコー最大240ms、8タップFIRフィルタ、周波数適応線形補間(独自実装)
   ノイズ生成、ピッチモジュレーション
  メモリ:SoundRAM 64KByte

・メモリアクセス
  DMA、HDMA
   どちらかの選択で8チャンネル使用可能
   HDMAダイレクトモード or インダイレクトモード
  DRAMリフレッシュ模擬、OpenBus模擬


未実装のものとその言い訳のようなもの

・グラフィック
  インターレース:使用しているゲームがごく稀。またVGAで出力するためタイミング的に合わず。
  長方形スプライト:仕様外のため。また使用している場面も見つけられない。
  Mode7のモザイク:さぼり。
・サウンド
  ガウシアン補間:こもり過ぎのため、周波数適応型の線形補間で代用。
  APU速度可変:今の所不要そう。
・その他
  PALモード:現在はNTSCモードのみサポート。

▼ Fitting Report

DE2-115 CycloneIV E (EP4CE115F29C7)
 行数はSFL+で約13,000行。

▼ DE2-115用コード

ISP1362_ctrl.sflp
 USBホストコントローラです。 HIDジョイパッドをNiosIIレスで使うためのものです。 SuperSmartJoy(SFC Pad to USBコンバータ)、 SANWA JY-PSUAD1(PlayStation Pad to USBコンバータ)、 BUFFALO BSGP801 USB Padをサポートしています。

SDカードコントローラ(SDバスモード)
 SDカードコネクタとFPGAでDAT信号線が4本とも接続されているため、 SDバス4bitモードが使用できます。 SNESのデータ読み込み高速化のため、SDバスモードを実装しました。

▼ 配布

SNES on FPGA feat. DE0-CV
 Terasic社製FPGAボード「DE0-CV」向けSNES on FPGAのsofファイルです。 操作はキーボードで。映像はVGA出力。サウンド出力回路はDIYです。
 Ver.20180103 USB経由のROM転送サポートとSPC再生機能追加。 Support ROM transfer via USB. Added SPC playback function.
 Ver.20170912 FAT16コアを修正してLinux環境でフォーマットしたSDカードをサポート。
 Ver.20170816 初期リリース。

SPC Player on FPGA feat. DE0
 Terasic社製FPGAボード「DE0」でSPCファイルを再生します。 SPCファイルはUSB経由で転送、もしくはSDカードから読み込みます。 標準IOピンから出力しますので、ローパスフィルタを付けてアンプに接続してください。
 Ver.20180102 エンベロープのDecayを調整。
 Ver.20171224 SPCをUSB経由で転送できるようにした。
 Ver.20170416 DE0ボードに移植。逆位相サラウンド実装。

SPC Player on FPGA feat. DE1
 Terasic社製FPGAボード「DE1」でSPCファイルを再生します。 SPCファイルはUSB経由で転送、もしくはSDカードから読み込みます。

SNES on FPGA feat. MiSTer (WIP)
 MiSTer FPGAボード向けSNES on FPGAのsofファイルです。 操作はStartとAボタンのみ。映像はVGA出力。サウンドはオーディオジャック出力です。
 Ver.20180714 初期リリース。

▼ 所感

・ファミコンでは主にサウンド拡張チップがカートリッジに搭載されていた。 しかしスーファミでは(ドライバさえ良ければ)サウンド面では本体のもので十分であったため、 グラフィック拡張チップがカートリッジに組み込まれた。 コンシューマ機でありながら拡張できるシステムとして面白いところのひとつである。 NES on FPGAでは音源チップまで実装したが、 SNES on FPGAでは拡張チップの実装までできるだろうか?

・SNES on FPGAはDE1ひとつに収まらない。 このため、DE1を2つ使用し、ひとつはCPU+PPUなどなど、もうひとつはSPC700+DSPのサウンド、 という構成でon FPGAを実現することになる。 DE2だと収まるんだろうけど高いし。 回路規模削減のポイントとしては、 現在アドレスデコーダをロジックでべた書きしている65C816とSPC700を、 マイクロプログラム方式にすること。 そしてDSPの8チャンネルをパイプライン化する事。 これらによりもしかしたらぎりぎりDE1に収まるかもしれない可能性は残っている。

 2014/07 DE2-115を手に入れてしまった…。規模的にはスーファミが3つくらい実装できます。 このボードにはIRレシーバ(赤外線通信)がついているので、 赤外線のワイヤレスゲームパッドで操作できるようにしてみました。 しかししばしば反応しなくなることがあるためこれはあきらめて。 結局、USBホスト機能を実装して、 USBゲームパッドやスーファミパッドUSB変換器をサポートしました。

・SPC Player on FPGAも、音質向上、サウンド効果など修正して、ほぼ実装は完了しました。 ただし、XMSNESで作成したSPCの一部について、エコーバッファが実機演奏を想定していないものについては、 実機同様に演奏できません(回避策としてエコーをOFFにすれば演奏できる)。 エコーバッファを別に用意すれば対応できるのですが、 約30KBの内蔵RAMが確保できません。 将来的にはFPGA内の内蔵RAMに余裕ができれば対応は可能かと思われます。

・「聖剣伝説3」をプレイ中に強制リセットがかかる現象に悩まされていたけど、 自作エミュでCPUログを追いかけて、数年越しにようやく原因を突き止め修正することができた。 原因は「65C816の割り込み時にDフラグクリア」という実装が抜けていたこと。 これに気付くのにずいぶんと時間がかかってしまったのは、
 ・NESの6502をベースに実装したため。
 ・これまでテストしたソフトでは問題なかった。
 ・タイミング関連の実装が問題だと思い込んでいた。
 ・解析資料通りに実装しているか確認不足だった。
と、色々あるけど、 NESの6502ではDフラグクリアしていない(NESはDフラグを立ててもBCD演算はできない)こともあって、 65C816でもクリアしないとの思い込みが大きかったと思う。 よく考えると65C816のNES互換を考えると、Dフラグクリアするのが妥当なんだけど…。 検証中は自作エミュでも同様の現象が出ていたため、仕様の実装が不十分だということは薄々感じていた。 その段階で解析資料(ある意味これが仕様のベースになるが、完全には信じない) と実装を徹底的に比較すればもっと早く気付いていたかもしれない。 今回の反省を今後に活かしたい。

 最初に「実機に近いアーキテクチャで」と啖呵を切っていますが、 結局、初期実装ではまだまだ潤沢なリソースに頼っているところもあって、 リソース削減のために改善すべきところはたくさんあります。 このあたり、アーキテクチャを実機に近い形で実装するのは、 まだ今後の楽しみにとっておきたいと思います。

▼ 参考資料など

 というよりコレクターズアイテム?

ROM吸出し機


*スーパーファミコン、スーファミ、SuperNES は任天堂の登録商標です。

E-mail

Copyright(C)2005-2018 pgate1 All Rights Reserved.