放課後の電子工作 HOME > Mandelbrot集合描画ハードウェア [ Pyxis 2010 ]

2011年2月13日 更新

Mandelbrot集合描画ハードウェア [ Pyxis 2010 ]

Mandelbrot集合描画
ハードウェア

[ Pyxis 2010 ]

Pyxis 2010

製作中

製作過程
デモ動画
FPGAについての補足

オリジナル[ Pyxis ]

22年前に製作した
オリジナル[ Pyxis ]

マンデルブロ集合をとにかく速く表示したい」との想いから、丸2年の歳月をかけた『Mandelbrot集合描画支援ハードウェア [ Pyxis ] 』が完成したのは、22年前の1988年のことです。
 マンデルブロ集合についてはこちら
 Pyxisについてはこちら
TTL361個を手配線で繋いだそれは、まさしくロジック回路の塊です(右写真)。設計、製作共にとても手間暇のかかるものでしたが、当時はそれしか実現方法がありませんでした。

現在はFPGAという強力な武器があります。これを利用しない手はありません。『同じ作るなら思い切りやってみよう』ということで、大規模なFPGAを使ってどれだけ速くできるのか試してみることにしました。また、大きなFPGAを使おうとするとBGAパッケージからは逃れられないので、ついでにそれを手配線で動かすことにも挑戦してみました。結果は以下の通りです。

--

マンデルブロ集合を求める漸化式、
 Zn+1 = Zn2 + C (ここでZiは複素変数、Cは複素定数)
において、右辺の複素演算を毎秒12億回の速さで計算し、表示させることができました。
以下は実測値です。
 ・480×256=122,880ピクセルの全てがマンデルブロ集合に含まれ、上記漸化式を256回反復する場合で、所要時間26.2msec
これはつまり、
 (480×256×256)/0.0262=1.20×109
ですから、設計通り毎秒12億回で計算できていることになります。

数値データはPyxisと同じく、実部虚部それぞれ64ビット固定小数点にしました。
乗算器、加算器などの演算ブロックを独自に設計することで、内部クロック200MHzをクリアしています。
FPGA全体としては、64ビット加減乗算を毎秒84億回実行しています。

Pyxis 2010は、オリジナルPyxisと比べて、実に約3000倍も高速です。約20年前、一度は検討して挫折した完全なリアルタイム描画という夢が、ようやく実現できました。

--

》製作過程
使用するFPGA
使用するFPGA

AlteraのCycloneIII、EP3C120F484です。
パッケージサイズは23mm×23mm。

Digi-Keyにて46,446円でした。
万が一壊しでもしたら(汗)・・・経済的、精神的ダメージは計り知れません。
でも予算の都合により、これをユニバーサル基板に手配線で動かすことにします。

FPGA裏面
FPGA裏面

1mm間隔でびっしりと並んだ、484個のはんだボール。
これが今回の戦場です。

FPGA裏面-パスコンを実装した様子
パスコンを実装

電源ピンとグランドピンは概ねきれいに隣接して配置されているので、それらを繋ぐようにパスコンを直接実装します。
1mmピッチなので1005のコンデンサがちょうどぴったりです。

FPGA裏面-電源系の配線
電源系の配線

主な電源とグランドを配線したところ。
電源は1.2V、2.5V、3.3Vの3系統ですが、特にコア電源の1.2Vは電流が大きいので要注意です。
写真では見えませんが、何個かのプルアップ抵抗も直接実装してあります。

こういう“無責任でバカバカしく難しい”配線作業は本当に楽しいです。

配線の様子
配線の様子

配線は複雑に立体交差しています。
さながらジャングルジムのよう。

通電中にショートしたら終わりです。慎重に、慎重に・・・。

周辺回路
基板製作

FPGAを基板に組み込み、さらに主な周辺回路を実装したところ。
基板は秋月の表面実装用ユニバーサル基板です。その中央部分にFPGAがちょうど入る角穴を開けて落とし込み、周辺回路と接続しています。FPGAを角穴に落とし込んでいるのは、基板下のヒートシンクとFPGAを熱結合させるためです。
左下に延びている2本のFFCは開発環境との接続用です。太い方はJTAG、細い方はマイコン用です。

実行中の様子
動作確認

バラックで取り急ぎ動作が確認できた記念の1枚です。

液晶パネルには初期型のPSP(PSP1000)用として販売されているものを使いました。
1個のFPGAの中に、演算回路と合わせてグラフィックRAM(フレームバッファ)、カラーパレットテーブル、キャラクタRAM、キャラクタジェネレータ、液晶用制御信号生成回路なども入れてあります。ですのでFPGA以外の主な部品は、FPGAのコンフィグレーションROMとマンマシンインターフェース処理用マイコン、電源類しかありません。

表示サンプル
実行速度の確認

マンデルブロ集合の全体像を表示してみました。
横480ピクセル×縦256ピクセル、実軸上の座標範囲(-2.5, +1.5)、最大反復回数256回です。
計算時間は5.84msecでした。

電源の実装準備
電源の実装準備

FPGAのコア電源(1.2V)には市販のPOL用DC/DCコンバータ(BellnixのBSV-3.3S8R0M)を使用しました。
写真は電源実装前の基板の裏側です。電源はFPGA左側のスペースに実装します。
この基板は裏側が全面ベタなので、それを電源の放熱用として有効活用します。FPGAの左に見える銅色の長方形は、電源の放熱用パッドをはんだ付けするためにレジストを削り取った部分です。

電源の実装とFPGA用ヒートシンク
電源の実装とFPGA用ヒートシンク

電源の放熱用パッドをベタにしっかりとはんだ付けして固定し、スズメッキ線を使って基板表側と入出力を最短で接続します。電源の周囲が緑色なのは、絶縁確保のために電源の下一帯にカプトンテープを貼ってあるからです。

さらにFPGA用のヒートシンクを貼り付けて、基板の裏側は完成です。
強制空冷の際に冷却風が電源の方へ流れるように、ヒートシンクのフィンは横向きにしておきます。

PSPへの組み込み準備(1)
PSPへの組み込み準備(1)

Pyxis 2010のケースはPSPです。
壊れたPSP1000をオークションで安く調達し、改造して組み込みます。

写真は液晶パネルと板金フレームを外した様子です。

PSPへの組み込み準備(2)
PSPへの組み込み準備(2)

メイン基板は写真の通りに惜しげもなく二分し、右側の細い方だけを使います。
こうしたのは次の3つの理由から。ひとつめは、ケースを元通り組み立てるためにはネジ部分の基板が必要なこと。2つめは、本体左側の方向スイッチやアナログスティックを構造的に受けるものとして、その部分の基板が必要なこと。3つめは、基板の剛性が全体の"しっかり感"に欠かせないこと。メイン基板は"かなりの"多層板なので剛性が高く、これだけ細く切ってしまっても相応の効果が期待できます。

PSPへの組み込み(1)
PSPへの組み込み(1) -放熱

いよいよPSPへ組み込みます。
UMDを取り外し、板金部品やプラスチックケースの一部も切り取って、できたスペースに製作した基板を納めます。秋月のユニバーサル基板はこのUMDのスペースにお誂え向き。ちょうどぴったりの寸法です。
UMDのふたには冷却用のファンを付けました。ヒートシンクとPOL電源を両方同時に強制空冷できる配置になっています。

PSPへの組み込み(2)
PSPへの組み込み(2) -基板の固定

基板は本体側ではなく、UMDのふた側にスタッドで固定します。
秋月のユニバーサル基板に付いている四隅のねじ穴をそのまま使いました。

PSPへの組み込み(3)
PSPへの組み込み(3) -基板と本体の接続

液晶パネルやスイッチ基板からは元々メイン基板と接続されていたFPCが出ていますが、それらは組み込んだ基板までは届きません。ですので、その延長も兼ねてFFCを"ごにょごにょ"っと接続します。
市販品の長さでちょうど良く接続でき、かつ繰り返しの開閉に耐えられるように、FFCの通し方や折り返しの位置を考えておきます。

PSPへの組み込み(4)
PSPへの組み込み(4) -FPCとFFCの接続

FPCとFFCを"ごにょごにょ"っと接続している部分です。
FPC用コネクタと市販の極薄エクステンション基板を介して、細い線材で両者を接続しています。ピッチは0.5mmです。さらにここで、ユニバーサル基板上での配線の都合に合わせて信号の並びを入れ替えました。

PSPへの組み込み(5)
PSPへの組み込み(5) -本体裏側の処理

UMDのふたの"PSP"ロゴが入っている部分を全てくりぬくと、40mm角ファンの開口にちょうど良い丸穴になります。
基板を固定しているネジですが、座面がふた両端の曲面の部分に掛かってしまうために、リューターで平ザグリを入れてあります。
なお、この裏面はまだ仮の姿です。

PSPへの組み込み(6)
PSPへの組み込み(6) -動作確認

取り急ぎ動作確認。無事に動きました。
期待通り、PSPのスイッチ類を利用した操作性は抜群です。
スクロールやズームイン、ズームアウトも思いのまま。

でもまだ完成ではないので、保護フィルムの"除幕式"はしばらく先になりそうです。

開発環境との接続
組み込み後の開発環境との接続

FPGA用とマイコン用のそれぞれの開発環境と接続している様子です。
作業をやりやすくするため、UMDのふたが通常よりも大きく開くように追加工してあります。

オーバレイによる文字表示
オーバレイによる文字表示

座標値などの各種情報表示用に、キャラクタジェネレータ方式による文字のオーバレイ表示ができるようにしました。
このキャラクタジェネレータとキャラクタRAMも、フレームバッファと同様にFPGA内のメモリを利用しました。小容量なので問題なくFPGA内に納まります。

フォント作成
フォント作成

文字サイズは8ピクセル×8ピクセルにしてみました。行間と文字間に1ピクセルずつ空けるため、実際は7×7です。
キャラクタジェネレータのフォントデータはオリジナルで作成しました(写真)。その際にQuartusIIの"In-System Memory Content Editor"を使ったのですが、これは超便利なツールですね。JTAG経由で実際の表示を確認しながら作業できたので、あっという間にできあがりました。
その昔、机上でフォントをデザイン→バイナリファイル作成→EPROM書き込み→結果確認、気に入らなければ殺菌灯でROM消してデータ修正を繰り返すという経験をしているので、このお手軽さはまさに天国です。良い時代になりました。

デモ画像(1) -起動画面
デモ画像(1) -起動画面

電源オン後、最初にタイトル「Pyxis 2010」を表示する起動画面を作ってみました。

バックライト駆動ICにPWMをかけて、スムースなフェードイン/アウトができるようにしました。
○ボタンを押すと、次の動作画面に移ります。

デモ画像(2) -動作画面
デモ画像(2) -動作画面

画面上部に各種ステータスを表示するようにしました。
1行目はとりあえずタイトルです。
2行目は画面中央の複素座標と、FPGAに取り付けた温度センサの検出値です。
3行目は1ピクセル分の座標幅、発散と見なす最大反復回数、パレット番号が表示されます。

デモ画面(3) -パレット変更(1)
デモ画面(3) -パレット変更(1)

Mandelbrot集合のグラフィクス表示は、Z0 = 0 および各ピクセルの複素座標を C として漸化式 Zn+1 = Zn2 + C を反復計算し、その値が発散すると判定された時点での n の値に対応した色でそのピクセルを描画することで実現されます。したがってこの n の値と色の対応付けが、出力画像の見え方を左右する重要な要素になります。
Pyxis2010にはこの対応付けのためのパレットと呼ぶ色データテーブルが組み込んであります。パレットの実装によって漸化式の計算と色付けを分離することができ、パレット変更だけで見え方を変えることができます。

現在は9種類のパレットを定義してあります。左右ボタンでいつでも切り替えられるようにしてあります。
左の写真は連続サイクリック型(全体にスムースに色が変化し、かつ周期的に同じ色パターンが繰り返されるタイプ)のパレットのひとつです。

デモ画面(4) -パレット変更(2)
デモ画面(4) -パレット変更(2)

これは不連続サイクリック型(色の変化に不連続な箇所があり、かつ周期的に同じ色パターンが繰り返されるタイプ)のパレットです。
表示している座標範囲は上の(1)と同じです。パレットを変えるだけでこんなに見え方が変わります。

デモ画面(5) -パレット変更(3)
デモ画面(5) -パレット変更(3)

これは連続非サイクリック型(スムースに色が変化し、かつその変化が周期的でないタイプ)です。
Mandelbrot集合周辺部などの入り組んだ箇所でも、なめらかな色の変化が得られるパレットです。

デモ画面(6) -パレット変更(4)
デモ画面(6) -パレット変更(4)

これは(1)と同じ、連続サイクリック型の別のパレットです。色の変化の仕方が異なると全然印象が違ってきます。

パレットの定義は奥が深くて面白い作業です。

》デモ動画

現在の動作の様子です。

主な操作法は:
・アナログスティック:スクロール(可変速)
・○ボタン:ズームイン
・□ボタン:ズームアウト
・△ボタン:最大反復回数を+100する
・×ボタン:最大反復回数を-100する
・Rボタン:ズームイン/ズームアウトの加速
・Lボタン:上下スクロールを加速
・>ボタン:次のパレットに変更
・<ボタン:前のパレットに変更
です。

最後の方で内部の様子をご紹介しています。

FPGAについての補足説明

*リソース利用状況
QuartusIIのFlow reportからの抜粋です。

Total logic elements ; 34,337 / 119,088 ( 29 % )
Total registers ; 31405
Total memory bits ; 2,439,816 / 3,981,312 ( 61 % )
Embedded Multiplier 9-bit elements ; 576 / 576 ( 100 % )
Chip Planner

外付けのメモリを使用せず、フレームバッファやパレットテーブルなども詰め込んであるので、メモリの使用量が相応にかさんでいます。
エンベデッドマルチプライヤの利用率は100%。全て使い切りました。

右はChip Plannerのイメージです。

*数値データの表現法
数値データのフォーマットは実部、虚部共に、2の補数による64ビット固定小数点(符号1ビット、整数部3ビット、小数部60ビット)にしました。これはオリジナルPyxisと同じフォーマットです。
マンデルブロ集合の計算において演算回路を自作する場合、浮動小数点表現を採用するメリットはほとんどありません。漸化式の計算の中で表現される数値は、およそ-2から+2の間をまんべんなく変動する感じになるからです。拡大率がどんなに大きくなっても、例えば10-10などという非常に小さな数値になることはまずありません。従ってデータビット(64ビット)のうち整数部を必要最低限とし、小数部のビット数をできるだけ多くした固定小数点にするのが有利といえます。この辺の詳細についてはこちらもご参照ください。

*描画の高速化
描画性能を向上させるためには次の2つが鍵になります。
 (1)演算回路のクロック周波数の向上
 (2)処理の並列化

趣味の作品と割り切れば『動けばOK』という考え方もアリですが、達成の正否をちゃんと評価したいので、『QuartusIIのTiming Analyzerでタイミング要件を満足すること』を条件としました。
目的の回路は、Mandelbrot集合の漸化式に基づいて、64ビットの加減算器と乗算器を繋げば基本的にはできてしまいます。でもそれでは高速化は望めません。実際、最初に試してみた時には、80MHzにも届きませんでした。
データサイズが64ビットにもなると、遅延の影響でクロック周波数を上げることが難しくなります。その対応として当然パイプライン化が必要になりますが、メガファンクションのパイプラインパラメータと最適化パラメータをどう調整しても動作周波数が思うように上がりませんでした。調べてみると、メガファンクションの自動生成回路において、パイプラインの効果が上手く出ていないことがわかりました。そこで加減算器と乗算器を独自に設計し、その他いろいろ改良を加えることで、150~160MHzくらいまで出るようになりました。
ここまで来ると200MHzの大台に乗せたくなります。RTL ViewerやTechnology Map Viewerを参考にしながらロジックを改良したり、インスタンスのLocationをアサインしたり、Design Space ExplorerでRandom seedほか各種パラメータの最適値を探したりを地味に続けて、現在の結果に至りました。その間、180MHzくらいまでは順調だったのですが、200MHzのクリアにはかなりの調整を要しました。例えば9ビットダウンカウンタのキャリー出力生成においてロジック的な一工夫が必要になったり、などです。
次はタイミングアナライザレポートからの抜粋です。

Type : Slow Model Clock Setup: 'altpll0:(中略)clk[0]'
Slack : 0.108 ns
Required Time : 200.00 MHz ( period = 5.000 ns )
Actual Time : 204.42 MHz ( period = 4.892 ns )
Failed Paths : 0

条件の厳しいSlow Model解析において、204.42MHzが得られました。

最終的に、独自に設計した加減算器のパイプラインステージは3段、乗算器は10段です。それらを組み込んだ漸化式の全演算ループは22段のパイプラインになっています。さらにそのパイプラインを6回路、並列に動作させる構成としました。つまり132ピクセル分のデータが同時に計算されていることになります。実質的には200MHz1クロック毎に6ピクセル分、したがって200×106×6で毎秒12億回の漸化式演算となります。
FPGA全体で考えると、加減算器は24個、乗算器は18個が並列で動いていますので、64ビット演算を毎秒84億回実行していることになります。

--


HOME