スティルハウスの書庫の書庫

はてなダイアリーで書いてた「スティルハウスの書庫」を移転してきました。

FPGAエクストリームコンピューティング第2回をやりました #fpgax

先日6/4、FPGAエクストリームコンピューティング第2回ニフティさんの会場で開催しました。今回もかなり濃ゆい内容でした:


・BBR/PIAX Inc.の吉田さん:異形の論理型言語システムをFPGAで!!
・本庄さん:MapReduce(Hadoop)のハードウェアオフロード
・アックスの浜田さん:FPGAでエクストリームなレトロコンピューティング
・@natsutanさん:速いぜ速いぜFPGA
・三好さん:FPGAでSSDの話
・@nishioさん:FPGA体験記(ライフゲームを作った話)
・きしだなおきさん:コンピューターサイエンスはオワコン
・安田豊さん:AristaのFPGAスイッチの話
・栗元さん:(次回の予告を簡単にお話いただきました)


しかし今回も時間が足りなくなってしまい、発表者の皆さんにご迷惑をお掛けしてしまいました。申し訳ありません!m(__)m 栗元さんには第3回でゆっくりお話いただきたいです。

まとめとust録画

会計など

  • ピザとビール:56260円
  • 集金:75000円
  • 次回繰越:18740円

今回は会場提供と運営でニフティの岡田様ほか皆様に大変お世話になりました。ありがとうございました!
この集まりはなぜか関西の方が多いので、第3回は関西で開催かなー。。数か月に1回くらいのペースでやりたいですね。発表をご希望の方いらっしゃいましたら @kazunori_279 までお知らせください!

appengine ja night #24 が終わりました

appengine ja night #24リクルートMTLで開催されました。今回はGoogleでAPAC地域のCloudセールスを統括するCory Frantzmeierがたまたま東京に来ててぜひ皆さんに挨拶したいというので簡単なキーノートをお願いしました。そこで「年内には台湾、香港、シンガポールにApp Engineのデータセンターを設置したい」っていう情報も飛び出してました(正式なところは私もよく分からないのですが...)。これが実現すると、いまよりぐっとレイテンシが短くなるはずで、App Engineエンジニアには嬉しいニュースですね。

今回のおしながきは以下のとおり。

セッション1:「Google Cloud Endpoints & BigQuery」
発表者:Ryo Yamasaki @vierjpさん
資料:こちら

セッション2 「Datastoreへのアクセスを楽してMemcacheアクセスに置き換えるライブラリ作った in GAE/J」
発表者:@vvakameさん
資料:こちら

ヤマサキさんのEndpointsセッション、この資料はGoogleのドキュメントよりもさらに実践的で、Endpointsを実際に使う人にはとっても価値のある内容になってます。私自身もEndpointsの使い始めのころはドキュメントも不足していていくつか何度かハマっていたのですが、そうしたハマりポイントが網羅されてます。さらに、AngularJSと組み合わせようとするとまずは初期化の順序や方法で悩むのですが、そのあたりもきちんと触れられてますね。これらの点でいちど慣れてしまえば、Endpointsはとっても快適で、もうサーブレットMVCをサーバー側で自前で用意する気にはなれなくなります。つい先ほど松尾さんもチャットで「もうEndpointsだけでいいじゃん」と言ってましたよ!

わかめさんのMemvache、ApiProxyにフックを入れてPBをいじって、、っていう手法は、ajnの初期にしばしば熱く議論されたテーマで、昔のajnが思い出されますねー(遠い目)Datastoreアクセスしてるコードを一行も変えずにMemcacheキャッシングを挟めるという便利ツールです。さらに自前でキャッシングStrategyを入れ替えたりできるのいいですね。というかこういうのをSDK標準に入れてPythonのndbみたいなAPIにしてほしい、、と思いました。わかめさんSlim3コミッター就任おめです!shin1さんを乗り越える日も近い。。

BeerTalk

今回のBeerTalkはこんな内容。いつものごとく、私とshin1さんのBTは時間が足りなくて次回持越しとなってしまいました。。

BeerTalk2:「Google App Engineを使って仕事をするということ」
発表者:塩瀬悠樹さん(吉積情報)

BeerTalk4:「Dig・基幹系でAppEngineを掘る」
発表者:清野克行さん
資料:こちら

吉積情報さんは大手のお客様向けの業務システム構築でたくさんのApp Engine実績をお持ちで、とくに印象深いのがApp Engineでは難しい事前の運用コスト見積もりのノウハウを蓄積されてる点(これができないと業務案件の見積もりは難しいですよね)、そして数万ユーザー規模の業務システムでも月額費用が驚くほど安い点(確か2万円くらい?)でした。すごーい。。

清野さんのセッションはブラウザのWebSQLとCloudSQLを組み合わせてオフラインファーストな業務アプリを構築する手法を解説したもので、BeerTalkには収まりきれない密度でした。時間が足りなくなってしまって残念です。。しかしデモでは入力に瞬時に反応してマスタ内容を引っ張ってくるUIとか、Channel APIでサーバーからクライアントに変更内容をプッシュ通知してブラウザ内容を書き換えとか、かっこよかったです!

皆さんのまとめ

いつもながらthorikiriさんのまとめの密度と素早さはすばらしい( ;∀;)

会計

今回はビールたのみすぎたーっ。。

  • ビール&ピザ:57880円
  • 集金:30000円
  • 前回繰越:30108円
  • 次回繰越:2228円

いつもいつも会場提供&運営でご協力いただいておりますリクルートの黒田さん、今回もありがとうございましたm(__)m

appengine ja night #23 が終わりました

(まとめを書くのがすっかり遅くなってしまいました。。)今回のappengine ja night #23はひさびさにGoogleオフィスで開催されました。今回はGoogle米国本社からProppyとBrianを招いてApp EngineとCompute Engineのセッションを開催しました。

  • App Engine アプリの最適化と Appstats
    • Johan Euphrosine (proppy), Developer Programs Engineer, Google Inc.
    • App Engine アプリ設計や Datastore 利用におけるアンチパターンとベストプラクティスをはじめ、Appstats による最適化の方法を紹介します。
    • 資料はこちら
  • Google Compute Engine 最新動向と App Engine 連携
    • Brian Dorsey, Developer Programs Engineer, Google Inc.
    • 昨年の Google I/O 2012 で発表された IaaS サービス、Google Compute Engine の最新動向を紹介するほか、Google App Engine との連携のテクニックを日本語で解説します。

Proppyのセッションでは中級程度のApp Engineノウハウがまとめられてましたが、とくに注目すべきはGlobal Queryのアンチパターン。つまり、Queryの結果得られるEntityの内容が古い場合があるってことです。これ、今までドキュメント等にわかりやすく書かれていなかったので、見落としている方も多いと思います。この問題によるトラブルを避けるためには、Proppyの資料にあるように、Keys-only QueryとMemcacheやローカルキャッシュを組み合わせることで、古い内容をつかんでしまうリスクをできるだけ避けます。ただ、この方法も完璧じゃないですし、依然としてQueryのeventual consistencyによる「直前にinsertしたEntityの取りこぼし」は起き得ます。よって必ず最新状態の取得が必要な用途には、やっぱりstrong consistencyが保証されるAncestor QueryとEntity Groupを使う必要がありますね。

BrianのセッションではGCEの現状が紹介されました。App Engineとは異なり、GCEでは計画停止などによりインスタンスがダウンするとサービスもダウンしてしまいます。そのため、例えば計画停止前に別のゾーン内のインスタンストラフィックを移す等の対処が必要になります。GCEではグローバルIPアドレスと各インスタンスの割り当てを動的に変更できるようになったため、そうしたインスタンス切り替えも比較的簡単に実現可能となりました。

皆さんのまとめなど

会計など

なんと今回、ピザとビールはGoogle持ちでした!しかもいつものピザよりおいしかった。。ぐぬぬ
ふみさん、西村さん、横田さん、運営ありがとうございましたっ!

FPGAでジョインやソート

ストリームやデータベースにおけるジョインやマージやソートのFPGA実装って、いまどこまで研究が進んでいるんだろう…と気になってて、その道の専門家である筑波大の川島さんに参考になるpaperをいくつか教えてもらった。これからゆっくり読む。

  • How Soccer Players Would do Stream Joins
    • ストリームデータ同士を高速にwindow joinするhandshake joinという手法。これをベースに、三好さん+オゲさん+川島さんが世界最速のFPGA実装を作成されたとのこと。
  • FPGA: What’s in it for a Database?
    • こちらもFPGAでデータベースまわりをどう処理するか考えた短いpaper。Content-Addressable Memory(連想メモリ)のハード実装のあたり興味がある。

ハードウェアアルゴリズム一般の書籍

ところで、SIMDやシストリックアレイなどのハードウェアアルゴリズムについては、この本がなかなかわかりやすい感じ(現在読み中)。CAMやデータフロープロセッサのあたりが興味深い。

ストリーム処理一般

以下はFPGAとは直接関係ないけど最近気になるストリーム関連のリソースのメモ。川島さんには以前にストリーム処理の教科書も教えてもらったのだけど、これ高すぎて買うのを躊躇してるとこw

こっちはちょっと分野が違うけど、ストリームマイニングの本。こっちも高い割には俺が理解できるか自信がないw

あと、Self-Adjusting Computingなる技法で1日かかるMapReduceを数分に短縮したというpaper(via @tanakhさん)

文字通り「ネットワークがコンピューター」な金融HFTでのFPGAの使われ方

ここのところ重度のFPGA中二病にかかってしまい、冬休み中もDE0ざんまいな日々。気になっていた金融のHFT(high frequency trading:大手投資銀行等がμ秒単位の超高速で株式等を売り買いしてる恐ろしい市場)におけるFPGA利用状況について、HFT Reviewにこってりしたレポート(HFT業界のベンダー各社にインタビューしたもの)が載っていたので、勢い余って面白かった部分を超訳してしまった。

元ネタはこちら:

FPGA導入のはじまり:レイテンシのコントロール

そもそも、なぜ金融HFT分野でここ2年ほどの間にFPGAが急速に広まったのか? どんな用途から使われ始めたのか? その背景や歴史について。

Traditionally, we started out with FPGA on the NIC card a great place for putting logic such as market data feed parsing.
  • もともとは、NICに搭載されたFPGA上にアプリケーションロジックを載せ、マーケットデータのフィードのパースなどを行うところから始まった。
The first area is around low-latency connectivity for inbound and outbound data, where all network connections are possible candidates for an FPGA-enabled Network Interface Card (NIC) to give that extra latency boost. Such a card might be using the FPGA to run a TCP Offload Engine for example, which can both free up CPU cycles and reduce PCI traffic.

Other areas where FPGAs are starting to make a significant impact are market data feed handling, pre-trade risk controls and other processes where firms need to be able to take in data then run calculations or simulations on that data in-line at high speed. Applications are now increasing as people get more comfortable with the technology and firms are looking at pure acceleration of tasks that they would previously have done using CPUs or General Purpose GPUs.
  • FPGA搭載NICによるTCPオフロードエンジンTCPスタック処理をNIC側で実行しCPUやPCIバスの負荷を下げる)のようなネットワーク接続の低遅延化が、FPGA利用のはじまり。
  • もうひとつの用途は、マーケットデータのフィードハンドリングやリスク分析における各種演算やシミュレーションを実時間で実行する用途。
Most of them are doing some variation of ticker plant”, responds Durwood. “Some are just looking at a handful of stocks and absolutely hot-rodding those, others are trying to convert a 150-deep book into automated trading. It’s still at the immature phase where different people are trying different approaches and taking risks.”

Taking care of tasks like parsing, filtering, normalisation and session management is where FPGAs can add a real advantage, so market data delivery and distribution is ripe for this technology. 
  • FPGA利用事例の大半では、ticker plant(マーケットデータを投資家や各システムにリアルタイムかつ低遅延に配信する基盤)かそれに類する基盤の構築に利用している。また、複数の株価を監視してhot-rodding(?)したり、150-deep(?)のトレーディング・ブックを元に自動取引を実装しようとしているファームもある。
  • データのパースやフィルタリング、ノーマライズ、セッション管理などFPGAの得意とするところ。マーケットデータの配信はFPGAにいまもっとも適している用途だ。
Many times, Market Data Managers implement direct feeds in a 1:1 pairing with the most demanding clients.  But the explosion of low latency needs makes the 1:1 pairing of feeds and clients untenable. Most enterprises need to simultaneously feed dozens (even hundreds) of servers including: surveillance risk systems, historical tick databases and back up servers.  On top of all of this, they continue to experience ‘bursty markets’, a trend that is expected to continue with the increasing number of automated trading programs.

Recently, Market Data managers threw more CPUs at the problem.  They constructed multi-threaded programs, and tried to off load the CPUs.   But now, there is a type of recapitulation happening in the market.  The market is turning to new architectures, such as pure FPGA architectures to re-invent the market data infrastructure.  The FPGA architectures of tomorrow offer a highly parallelized approach to processing market data. This enables a deterministic latency infrastructure.  

Deterministic latency, (keeping the same speeds regardless of data rates, number of venues or distribution points) is the new goal for Market Data Managers.  And it gives the Market Data Managers the ability to offer guaranteed service levels to their users.   Most importantly, the new FPGA architectures gives the algo trader a dependable ultra-low latency reaction time to changing market signals, under all market conditions.
  • これまでマーケットデータマネージャ(投資銀行や証券会社においてticker plantの構築を担当する部門?)は、大手投資家との間で1:1のネットワーク接続を行い、マーケットデータフィードを提供してきた。しかし(HFTの普及により)低遅延性が必須となったおかげで、1:1の接続は難しくなった。多くの投資家は、リスク分析システムや、時価履歴データベース、バックアップサーバーなど、時には数百台のサーバーを保有しており、それらに同時にマーケットデータを配信しなければならない。加えて、自動取引プログラムの増加によって、マーケットの動きのバースト性も高まりつつある。
  • つい最近まで、マーケットデータマネージャは、より多くのプロセッサをサーバーに搭載することで、この問題に対処しようとしてきた。例えばマルチスレッド・プログラミングによりCPU間で負荷分散する手法などである。しかしいま、ひとつの進化が起きている。FPGAのみをベースとするアーキテクチャによって、マーケットデータ配信のインフラを構築し直す動きである。FPGAの高度な並列性によって、マーケットデータの配信にともなうレイテンシの決定性を確保可能になる。
  • レイテンシの決定性とは、データの転送速度や配信先の数などによらず、データの遅延を一定以下に保証できる性質である。レイテンシの決定性は、顧客へのサービスレベルを保証する手段となるため、マーケットデータマネージャにとって現在もっとも重要な指標となっている。加えて、FPGAの利用によって、マーケットがどのような状況にあろうとも絶え間なく動くマーケットシグナルに応じて超低遅延で対応できる手段をトレーダーに提供することができる。

ここで示されてるように、HFTにおけるFPGA導入の動機はかなり特殊だ。この分野の情報を見ているとマイクロ秒や数百ナノ秒といったオーダーの数値がよく出てきており、もはやハードリアルタイム制御の世界である。こうなると既存のCPUやその上で動く一般的なOSではレイテンシの確実な予測が難しい。例えばマーケットが瞬間的に激しく動いてOS負荷が上昇し、オーダーを出すのが数ms遅れてしまった...では済まされない。実際に、マーケットデータ配信の数msの遅れによってNYSEが4億円の罰金を課せられたりしている。

こうした特殊環境のなかで培われたFPGA技術であるため、それがそのまま一般の用途(例えばWebやビッグデータ)にもすぐ広がるとは思えない。ただ、長期的にはFPGAコモディティ化によって一般用途でのFPGA導入のハードルがぐんと下がりつつあり、あるポイントでクリティカルマスに達するんじゃないかな〜と思ったり。

金融HFTにおけるFPGA利用の現状

つづいて、HFTファームがいま直面しているFPGA利用の課題について。

“There are maybe 25-30 end-user firms around the world that are fully capable of developing complete high performance applications in FPGA today”
  • (金融HFTの)高性能アプリをFPGAでフルに開発できるベンダーは25〜30社存在する。
Working with order and trade data brings additional complexities in development and testing however, because the order can go through so many state transitions.

Despite such complexities, FPGAs are now being used in FIX engines, rules engines, and even full-blown execution management systems. Ferdinando La Posta, Co-Founder of trading solutions vendor GATELab, explains his firm’s approach.
  • オーダーや取引データの処理となると、たくさんの状態遷移の取り扱いが必要となり、開発やテストの複雑さが増す。
  • そうした難しさはあるものの、FPGAFIXプロトコル(金融取引の標準プロトコル)エンジンやルールエンジン、さらには執行管理システム全体の実装までに利用され始めている。
“Firms realise they can buy FPGA-based solutions from vendors who have done the straightforward stuff like TCP offload, FIX/FAST translation, feed handling and so on,” says Keene. “But HFT firms also realise that the only way to gain an advantage now is to come up with better, more clever, more efficient, more productive and more profitable algorithms. That’s going to be their differentiator, but not many HFT firms have had much success putting their own trading algorithms onto FPGAs.
  • TCPオフロードやFIX/FASTプロトコル変換、フィードハンドリングといった簡単な処理を扱うFPGAソリューションであれば、いまやベンダーからすぐに購入できる。
  • 現在のFPGA活用の焦点は、より賢く効率的で、生産性と収益性の高いアルゴリズムFPGAで実装できるか。それこそが差別化要因だが、自社のトレーディングアルゴリズムFPGAに載せることに成功したファームはあまり多くはない。
Yes, you had ANDs, ORs and other arithmetic operators, but trying to build up logical or algorithmic expressions using individual components can end up being quite weighty and not really optimised. So to do anything clever like standard deviation, you were basically on your own and had to develop it yourself.”
  • FPGAでは、ANDやOR、その他の(簡単な)数値演算などの演算は簡単に記述できる。しかし、個々のコンポーネントを組み合わせて数式や論理式を構成しようとすると、すぐに規模が大きくなって、そのままでは(レイテンシの)最適化もなされていない。よって、標準偏差みたいなちょっと高度な演算を行うには、基本すべて自分で回路を組んで最適化していく必要がある。
But all of this means that there is now a growing demand in the financial markets for programmers and engineers who can work directly in VHDL and Verilog.

“Nobody knows how to write parallel code except the HPC guys,” asserts Keene. “A programmer writing an application to do financial transactions is unlikely to know how to write parallel code. FPGAs are still the realm of the electrical engineer as opposed to the computer science engineer. And those guys have now discovered that what they know is really valuable, so they’re charging an arm and a leg for it.”
  • 金融分野では今後もVHDLVerilogを直接書けるプログラマーのニーズが増え続ける? HPC分野のエンジニアじゃない限り、大規模並列なコードの書き方を知っている人はほとんどいない。金融取引のアプリを書いてたプログラマーは、FPGAの並列性を引き出すコードの書き方を知らないFPGAは未だに電子回路設計の世界であって、コンピューターサイエンスの世界ではない。そこにすごい価値があると知って、(回路を書けるエンジニアは)自分のスキルを高値で売りつけている。

FPGAはCPUではないので、ちょっと複雑なことをしようとするとすぐカベに突き当たる。現状ではHFTファーム各社はそのカベをいかにして超えられるか競っている状況のようだ。また、次に出てくる高級言語による高位合成はまだ普及しておらず、低レベルなハードウェア記述言語であるHDLをガリガリ書いて最適化できるデジタル回路設計者がモテモテな様子が伺える。

CやHaskell、データフロー言語による高位合成

金融以外のFPGA界隈で面白い話題のひとつは、高位合成だ。つまり、低レベルなHDLを地味に書いていくのではなく、C言語でフツーに書いたコードからHDLの順序回路や組み合わせ回路を合成するアプローチである。しかしHFT分野ではあんまり普及してないみたい。

“At one extreme, you give someone a low-level language, you give them all the detail they need, the data sheets, the specifications, an oscilloscope and a layout tool, so that they can build a board and develop it from there. At the other end of the spectrum is the claim that you can take a serial process, written in C for example, and somehow magically turn it into something that can run in a massively parallel way, which is what you need to do to put it on the chip.
  • FPGA開発のアプローチのひとつとして、HDLのような)低レベルの言語を使い、細かいところの作りこみをはじめ、データシートや仕様書、オシロ、チップのレイアウトツールなどを用いてボードの開発まで行なう(伝統的な)アプローチがある。
  • もう一方のアプローチとしては、C言語などの手続き型の高級言語を用いて、どうにかしてそこから高い並列性を引き出してFPGA上で動作させるという手法がある(高級言語による高位合成)。
“In the ASIC prototyping world, there have been attempts to get from C to gates for many years. And there have been any number of companies founded and failed on the basis of their C-to-gates technology, because it just doesn’t work out. From our point of view, as FPGA guys, we don’t understand how you can even begin to minimise latency in terms of clock cycles without designing as close down to the actual logic as possible. There are companies claiming you can do it in C or even in MATLAB, but we don’t agree,” he says.
  • ASICプロトタイピングの世界では、C言語からゲートレベルへの合成の手法が長年に渡って検討されてきた。Cベースの高位合成のベンダーがいくつも現れては、うまく行かずに消えていった。いまのFPGAに求められているのは低遅延性であることを考えても、ゲートレベルで設計せずにレイテンシを最適化できるとは考えにくい。CやMATLABで記述したコードをFPGAに落とせるといった主張には同意できない。

レイテンシや並列性の最適化が命のHFTでは、Cから生成したHDLでFPGAを使うなんて、もってのほからしい。あまり高位合成について知らないけど、Cで普通に書けば、そこから高度に並列化されたHDLが生成されるとは想像しにくい。たぶん順序回路だらけになるんだろうな。もっとも、コモディティ化したFPGAを用いる一般用途では高位合成の利用が主流になるんじゃないかな、と思う。なにせ高級言語デバッグラクだし。。

一方で、Cのような手続き型言語ではなく、データフロー言語や関数型言語を使って高位合成しようというアプローチもある。

“At Maxeler we take a very different approach. You shouldn't be thinking in terms of sequential C++ code, but instead think about the flow of data through your algorithm, which at the end of the day is all that matters. MaxCompiler does all the heavy lifting for you, like making sure the data is in the right place at the right time, and presents the programmer with a high level abstraction of the dataflow that is easy to conceptualise. Because of this you spend your time designing great algorithms rather than getting your hands dirty with all the messy details.” claims Spooner.
  • Maxelerでは、これらいずれとも違うアプローチをとっている。結局のところ、重要なのは欲しいアルゴリズムに基づいてデータの流れを定義することであって、必ずしもそれをC++のような手続き型言語を使って実装する必要はない。MaxCompilerでは、理解しやすく抽象度の高いデータフローをプログラマーが表現できる環境を提供し、かつデータが正しいタイミングで正しい場所に流れることをプログラマーに代わって管理する。(HDLのように)細かく面倒な詳細を記述する必要はなく、より多くの時間をアルゴリズムの設計に使える。

データフロー厨な俺はこういうの反応してしまうなぁ。。一方、Parallel ScientificというベンダーではHaskell FPGAコンパイラというものも作っている。

GPGPUFPGAの違い

ところで、FPGAのライバルであるGPGPUは使われてないの?

“GPUs have a stronghold in the parallel processing of graphics, but where they fall down is that they don’t help you with latency at all,” explains Spooner. “While they have a massive amount of parallelism, it’s coarse-grain parallelism, it’s not pipeline parallelism.”
 
“If you’ve got one message, you can only process it in one core. So it doesn’t matter how many different cores you have, it’s only in one of them. Which means that GPUs give you a throughput play rather than a latency play. If you want to reduce latency, you need fine-grain parallelism,” says Spooner. "At Maxeler we use Dataflow engines (DFEs), which provide the same fine grain parallelism, but are ready-to-compute rather than just blank chips.”

Another problem with GPUs is that they tend to be more prone to failures and errors in calculations. So although they can work well for certain parallel computing tasks like Monte Carlo simulations, they are unable to deliver the level of determinism offered by FPGAs.
  • GPUはグラフィクスの並列処理には強いが、低遅延の実現には向いていない。並列度は高いが、それは粒度の粗い並列度であって、パイプラインレベルの並列度ではない
  • 例えばGPUでは、ひとつのメッセージを受け取ったとき、それを1つのコアでしか処理できない。コアがいくつあっても意味がない。つまりGPUはレイテンシよりもスループットを重視した設計になっている。低遅延が必要なら、より細粒度の並列性が必要だ。そこでMaxelerでは、そうした細粒度の並列性をゼロから設計するのではなく、すぐに計算に使えるデータフローエンジン(DFE)を用いて実現している。
  • GPUのもうひとつも問題点は、演算中のエラーや障害に弱いところ。そのせいで、モンテカルロシミュレーションのような並列演算には向いてるものの、FPGAのようなレベルの(レイテンシの)決定性は実現できない。

インテルの主張

このレポートではインテルへのインタビューも掲載されてる。今のところインテルは、FPGAでもGPGPUでもなくCPUを使え!ってスタンスであることがよく分かる(社内じゃ研究してるだろうけど…)。

FPGA-based feed handlers are very common, but when people want to do more, they end up sending the data to a CPU socket. There were visions at one time about doing a lot of the calculation on the FPGA, but programming FPGAs are fairly challenging. It’s certainly not as easy as performant code with higher level languages.
 
We found that people started looking at using Cuda as an alternative for the math side of things, but this too can be a more challenging development environment. So, people take applications that were targeted at an FPGA for math, and attempt to run those computations on GPGPUs. But then they were losing the benefit of doing everything on the FPGA card and sending out the data as quickly as though that is possible, because once you leave the card, you incur a latency hit going across the bus.
 
Fragmentation of the code base is a bad thing, and this type of GPU + FPGA + CPU solution makes it worse.
  • FPGAベースのフィードハンドラはとても広く利用されているが、それ以上のことをやろうとすると、CPUにデータを送ることになる。かつてはFPGA上でさまざまな演算を行うという構想もあったが、FPGAのプログラミングは簡単ではない。高レベル言語のような生産性の高いコードに比べると難易度が高い。
  • FPGA上での数値演算をCUDAで記述する試みもあったが、これも開発環境に難点がある。そこで、FPGA向けに書いた数値演算アプリをGPGPUで動かそうとする人もいたが、すると「すべてをFPGAカード上で処理する」というメリットが失われ、カード外部とのデータのやり取りでレイテンシが発生してしまう。
  • GPU + FPGA + CPUを組み合わせるソリューションは、コードベースの分断をまねくダメなソリューションだ。

FPGA搭載アプリケーションスイッチの登場

金融HFTのFPGA界隈でのいまもっとも熱い話題は、FPGA搭載のアプリケーションスイッチ、具体的にはArista 7124FXの登場である。アプリケーションスイッチとはつまりレイヤ7スイッチのことで、ロードバランサーのようにアプリケーションレイヤの情報(URIとかクエリパラメータとかクッキーとか)を見てスイッチングしたりするネットワーク機器を指す。

With the announcement of the 7124FX switch from Arista, it’s now possible to put logic on a switch.  Of course, all data needs to cross a switch when it enters or leaves your cabinet, or travels inter-server in a co-lo location.  Some applications can really benefit if you can perform actions on the data as it’s making that mandatory switch.  Anything that could benefit from data transformation (a good example is normalizing market data, or filtering down a feed) or inspection with/without manipulation (for example risk checking) is a great application for the switch. 

A simple example: “Send this buy order when the price of MSFT drops below 27.42”.  Imagine if you could program this into the switch: you could go from tick-to-trade in nanoseconds, without even fully entering your cabinet!  This is exciting stuff and it will be reality very soon!”
  • (2012年の)Arista 7124FX(FPGA搭載アプリケーションスイッチ)の登場によって、スイッチ上にアプリケーション・ロジックを載せることが可能になった。
  • スイッチは、コロケーション(データセンター)内のサーバーやラックを出入りするあらゆるデータが通り抜ける場所。そこでさまざまな処理を実行できることで多大なメリットが得られる用途も多い。例えばマーケットデータのノーマライズやフィルタリング、データ内容の監視や加工(リスクチェックなど)は、このスイッチに最適な利用例だ。
  • 例えば「MSFTが27.42以下に下がったら買いを入れる」といったロジックをスイッチに組み込める。マーケットデータがサーバーのラックに届く前に、ナノセカンドの単位で取引が可能になる。こんなスゴいことがもうすぐ実現可能になる。

FPGAを載せたアプリケーションスイッチ、もはやロードバランサーなんてつまらない仕事はしていない。株価がサーバーに届く前に勝手に株の売り買いしてる(なにそれこわい)。俺もちょっと前にIPスイッチみたいなFPGAサーバーがあれば面白いだろうなぁ〜と妄想してたら、このAristaのFPGAスイッチはまさしくそのまんまの製品だった。まぁ誰でも考えるか。しかもAristaはSunのアンディ・ベクトルシャイムが設立してて、やっぱりベイエリアのコアな投資家の嗅覚は半端ないなぁと感心するなど。





このFPGAスイッチについてはHFT Reviewの別のインタビュー記事でもう少し詳しく解説されてて、こちらもたいへん興味深い。

With the goal of accelerating transactions as they pass through the network, it was crucial for us to find a truly in-line solution; rather than simply attaching the FPGA as a client of the switching chipset, the processor sits directly in line with the traffic flow, leveraging both the high functionality of the FPGA and the more traditional network forwarding, multicasting and filtering capabilities that are inherent to the ASIC itself.

このスイッチは10GbEが24ポートあるので、つまりは240Gbpsで流れるトラフィックにon the flyでアプリロジックを適用できる(訂正:FPGAがつながってるのは8ポートだけでした)わけだ。なんだそれは。。

Once you’ve got the ability to do this processing directly within the network, you can provide services that are leveraged across the pool of servers. Feed-handling (normalisation, translation), line arbitration, and symbol based routing are some of the obvious network-centric applications.

シンボルベースのルーティング、つまり、株価情報が流れてきたら、その企業コードを見てパケットをルーティングって面白い。@kibayos さんも指摘の通り、もはやオーバーレイネットワークがIPネットワークを置き換えつつあるような。例えばこれをMapReduceのkeyにあてはめれば、鬼のような超高速でshufflingしてくれるスイッチが簡単につくれる(もっともデータ受け取り側に大量にSSD並べないとボトルネックになるだろうけど)。MRに限らず、テーブルのプライマリキーになりそうなあらゆるIDでシャッフルやジョインしてくれるスイッチ...こんなのがクラウドにずらりと並んでたら楽しそうだな!

そんなわけで、ネットワークがコンピューターだという名言が現実のものとなりつつあるなぁ、という金融HFTの現状であった。

DE0で作った音源にエンベロープを付けた。

前回、DE0で作った音源をMIDIキーボードで鳴らしてみた。のつづき。ポリ化のつぎは、シンセになくてはならないエンベロープを付けてみる。つまり、一音一音の音量の調節、ADSRってやつだ。



これまではMIDIキーボードで指定された音程を固定の音量で鳴らしていたので、今回はADSRの各パラメータの大きさに応じて音量を調節するしくみを作る。デジタル音声信号の音量調節とは、つまりは掛け算だ。乗算器ってどんな仕組みだっけ、、と久々にパタヘネ本を引っ張りだして読み返したりしたけど、HDLでは乗算器を自分で書く必要はなくて、単にこんなコードを書くだけで済んだ:

wire [23:0] outvol = cur_vol * cur_velocity * 2 * wavedat;
assign DAT = outvol[23:16];

ここで、wavedatには正弦波のデジタル信号が8ビットの整数値として入る。これに、エンベロープで制御された音量cur_volと、MIDIキーボードを叩いた強さ(ベロシティ)cur_velocityを掛け合わせる。8ビットの値を3つ掛けるので答えは8 x 3 = 24ビットのデータになるけど、DAコンバーターには12ビットしか入らないので、24ビット中の上位12ビットだけを取り出してDAコンバーターへの出力DATに入れている(そのせいか小さな音の音質があんまりよくないのだけど。。これを直すには正弦波のビット数を上げるしかないのかな。。?)

乗算回路だって除算回路だって1行で書けるHDLって、便利だなぁ。。

カウンタでADSRをつくる

ADSRの各パラメータにしたがってcur_volを上下させるコードはこんなふうに書いてWaveGenに追加した。A, D/S, R, 無音のそれぞれにひとつずつ状態を割り当てて、ノートオン時にAを始め、Aが終わったらD/S、ノートオフでR、、って感じの状態遷移を行う。HDLプログラミングって、こういったカウンタや状態遷移ばっかりだね。それと、always文がどんどんでかくなってきて、アプリプログラマーとしてはリファクタリングしたくてたまらないのだけど、なかなかうまく小分けにできない。。

		case (env_st)
			0:;	// note off
			1:	// attack
				begin
					if (cur_vol == 255) begin
						env_st <= 2;
						env_cnt_speed <= dec_val;
					end else
						cur_vol <= cur_vol + 1;
				end
			2:	// decay/sustain
				begin
					if (cur_vol > sus_val)
						cur_vol <= cur_vol - 1;
				end
			3:	// release
				begin
					if (cur_vol > 0)
						cur_vol <= cur_vol - 1;
					else
						env_st <= 0;
				end
		endcase

シリアルUSBとDE0をつなぐ

こんな感じで、エンベロープ機能そのものはそれほど難しくなく実装できた。問題は、ADSRの各パラメータ(それぞれ8ビット)を設定するためのユーザーインターフェースをどうするかだ。DE0に付いてるボタンやLEDでちまちま入力するってインタフェースはとっても使いにくいしHDL書くのが面倒。PC上でGUIを作ってDE0と通信させることにした。

通信手段をいろいろ探してたら、こんな製品を見つけた。



FTDIのUSBシリアル変換ケーブルってやつ。一見すると単なるケーブルに見えるけど、USBコネクタの中にシリアル通信用のICであるFT232RLが内蔵されてて、PCからはシリアルポートとして認識される。このシリアルポートにデータを流すと、ケーブルの反対側からはMIDIやRS-232Cと同じUARTの非同期シリアル信号として出力される。前に作ったMIDIデコード用のHDLをそのまま使える!ってことで、さっそくこのケーブルを購入。MIDIデコードのコードをコピペして921.6kbps用にタイミング合わせたら、すんなり動いた。シリアルデータをバイト単位で切り出すSerialIfモジュールとして追加した。

さらに、そこから流れてくるバイト列を解釈するUIControllerモジュールを追加。どんなプロトコルにしようかな?エンベロープ以外にも使えるよう汎用性持たせたいな?と考えて、まあとりあえず、

  • 1バイト目は0xFF
  • 2バイト目はコマンドを表す(今回はエンベロープ設定用の0x01だけ使用)
  • 3〜6バイト目には32ビットデータを入れる

って固定長のプロトコルにしておいた。デコード簡単だし。例えばADSRの各パラメータを送るには、FF 01 xx xx xx xx って感じの6バイトをUSBシリアルに流す(xx部分にはADSRのそれぞれが1バイトずつ入る)。するとUIControllerモジュール側でコマンドを解釈して、ADSRのパラメータを更新し、WaveGenに供給する仕組み。

ChromeのSerial APIでシリアル通信

あとはPC側のGUIだけど、シリアル通信できるGUIアプリってどう作るか。俺がすぐ作れるのってJavaアプリとかAdobe AIRとかだけど……今さら感が漂う。できればHTML5がいいな。最近ChromeってJSでなんでも書けそうな勢いなのでシリアル通信用APIもあるだろ?ってググったら、あった。さすがChrome。



もっとも、こういったネーティブリソースにアクセスするには、ChromeのPackaged Appsという形式でHTML5アプリを作る必要がある。manifest.jsonっていうファイルにアプリケーション情報を記述したりChromeに登録したりすると、Serial APIはじめネーティブアプリ的なAPIが利用できるようになる。Chromeのドキュメントを見ながらそのあたりの手順にしたがってPackaged Appを作成した。シリアルポート一覧を取得するサンプルコードを動かしてみたら、うまいこと一覧が取れた(でも、実はSerial APIってWindowsでは動いてないらしく、最初はWindows環境でテストしてて動かずしばらく悩んでた…)。



ここで、/dev/cu.usbserial-FTG3ZBV4っていうのがFTDIのUSBシリアル変換ケーブルのシリアルポート。ちなみに、UNIXでは古来よりシリアルポートへの送信に/dev/cu、受信に/dev/ttyというデバイスファイル名を使うのが習わしだそうな。

さて、このWebUIアプリにはADSRのそれぞれをコントロールするノブを4つ置きたい。いろいろ探して、Canvasベースのノブを簡単に作れるjQuery Knobってのを見つけた。



このノブを4つ並べて、値が変化したときにコールバックされるfunctionを以下のように記述。

function updateAdsr() {
  chrome.serial.open("/dev/cu.usbserial-FTG3ZBV4", {bitrate: 921600}, onOpen);
}

こんな感じで、USBシリアル変換ケーブルのポートをボーレート921.6kbpsでオープンする。開いたらonOpenが呼ばれるので、

var onOpen = function(connInfo) {

  // get conn id
  connId = connInfo.connectionId;
  console.log("opened: " + connId);

  // send env command  
  var buf = new ArrayBuffer(6);
  <ここで送信するデータをbufに入れる>
  
  // write and close the connection
  chrome.serial.write(connId, buf, function() {
    console.log("written.");
    chrome.serial.flush(connId, function() {
      console.log("flushed.");
      chrome.serial.close(connId, function() {
        console.log("closed.");
      });
    });
  });
}

といった具合にJSっぽいコールバックだらけのコードを書く。ポートがオープンしたらconnectionIdが取れるので、それを使ってwrite()を呼び出し、ArrayBufferに入れたバイト列を書きだすだけ。ちゃんと即時送信されるようにflush()も呼んでおく。それと今回は1回コマンドを送るたびにポートをclose()するようにした(この書き方だとclose漏れが起きるかも。。?)。

一方、write()に渡すArrayBufferはこんなふうにして作る。

  var bufView = new Uint8Array(buf);
  bufView[0] = 0xff; // header
  bufView[1] = 0x01; // enverope command
  bufView[2] = $("#env_a").attr("value");
  bufView[3] = $("#env_d").attr("value");
  bufView[4] = $("#env_s").attr("value");
  bufView[5] = $("#env_r").attr("value");

...いつのまにかJSにもバイト列をいじるAPIが完備されててびっくりしたよ。さきほどの4つのノブに付けたenv_a、env_d...というIDを使ってノブの値を読み出し、ArrayBufferに入れるだけ。

エンベロープ付きの音が出た!

そんなこんなで、DE0で作ってきた俺様音源にエンベロープが付いた!それっぽいデモを作ってみた(MIDIファイルはまたここからお借りした)。

おぉ、単なる正弦波なのに、エンベロープ付けるだけでそれっぽくなるなぁ。。しかしReleaseを長くすると8音じゃ足りなくなる。同時発音数増やしたい。

次の野望

フィルターは鬼門だなぁ。。デジタル信号処理の入門書がAmazonから届いたので、もし俺が数式等を理解できたならばもしかするとフィルタを実装してみるかもしれないがしないかもしれない。

現在のコード全体はこちら

DE0で作った音源をMIDIキーボードで鳴らしてみた。

これはWeb Music Developers JP Advent Calendar 2012の12月19日分のエントリです。Web Musicとちょっと違う話題ですが :)

これまでのまとめ

2〜3か月前にFPGAの入門用ボードDE0を買ったのがはじまり。



これでなに作ろうか?自作CPUもいいのだけど、中学のころ連日ヤマハ仙台店に通っては(鍵盤弾けないのに)PolysixDX7やJUNOに何時間もぶらさがって店員さんに煙たがられていた程度にはアナログシンセ好きの俺としては、まずは音!FPGAを使ったデジタル回路設計の練習がてらにDE0で音を出してみたかった。デジタル回路も電子工作もデジタル信号処理も素人なんだけど。。

ここまでやってきたこと:

  • DE0で音を出してみた。 まずDE0って音だせるの?どこに何繋げばいいの?ってところから。440Hzで0と1を繰り返す信号をスピーカーにつないだらブザーみたいな音が出た。
  • DE0で正弦波を出してみた。DE0のデジタル信号をオーディオのアナログ信号に変換するためのDAコンバーターを使うのに手こずった。なんとか440Hzの正弦波を鳴らせた。
  • DE0でMIDIをデコードしてみた。 音が出たら、キーボードで弾いてみたいね。となるとMIDIでつなげるか。そもそもMIDIってどんなプロトコルなんだっけ?なんとかMIDIキーボードから出てくるノートナンバーを読み取るとこまでできた。

次の野望はMIDIキーボードで正弦波を鳴らすこと。その本題に入る前に、なぜいま俺がFPGAにハマっているのか書いておきたい。

FPGAってなに?

FPGAは、見た目はCPUみたいなチップだけど、中身はまったく違う。簡単に言うと大人の電子ブロックだ。子供の頃、ブロック10個くらい入った電子ブロックを買ってもらっていろんな回路組んで使い倒したけど、ブロック50個くらいぎっしり詰まったフルセットを持つ友人がうらやましかった。



その電子ブロックみたいな電子部品(ロジック・エレメントって言うもの)が、例えばDE0に載ってるAltera Cyclone III 3C16だと1万5000個ほど詰まってて、それをハンダゴテ使わずともPCからのプログラミングで自由自在に組み替えて回路を組めるという、子供の頃の俺からすると未来の世界すぎて鼻血が出そうなおもちゃだ。FPGAといえば昔は一般人が趣味に使えるようなものではなかったけど、それが今や1万円ちょいで買える!これは大人買いするしかない。しました。

最近の工学部の学生さんは実習でFPGAを使ってる人も多く、「FPGAでCPU自作した」とか「ファミコンエミュレーター作った」とか、さらりとおっしゃる。つまりスノボと一緒だ。ある一定の年代以上の人はまったく使ったことない。おじさんの時代にはそんなのなかったぞ!うらやましすぎる!ハンダゴテで自作CPUなんてハードル高すぎたよ。。

ファミコンやMSX等のレトロCPUをFPGAで再現してる人も多いけど、FPGAはCPU以外にもいろんなデジタル回路を組むことができる。今回みたいに「俺はシンセっぽい何か作る」でもいいし、「将棋AI用のめちゃ速い探索回路」「株取引用のスパコンっぽいの」「Lispを直接実行するプロセッサ」「デジタルFMラジオ」「脳を再現」...皆さんいろんなことに使ってる。それらのデジタル回路をPC操作だけでさくっと組めて、なにか動きがヘンだったらすぐ直せるのが電子工作的には画期的。今どきのmakerムーブメントっぽいノリなのだ。ほしいチップがなければ自分で作る!

HDLプログラミングがスゴい

最近流行りのArduinoやRaspberry Piも見た目はDE0に似てるけど、それらはどれもCPUが載っているボード。CPUで動かすプログラムコードを書いて使うので、パソコンやサーバーのプログラミングと基本はあまり変わらない。一方で、FPGAはCPUではないので、いわゆる普通の「プログラム」はそのままでは動かない。FPGAのプログラミングとはつまりデジタル回路の設計のこと。Verilog HDLやVHDLといった専用の言語でデジタル回路を設計して、FPGAボードに付属するツールで実際の回路にコンパイルする。例えば reg [7:0] foo; って書くと、8ビット幅のデータを記憶してくれるレジスタ(変数みたいなもの)の回路が生成される。




大人の電子ブロックなのだ


このHDLのコーディングがとってもおもしろい。普通のプログラミング言語みたいに頭から順番に実行されるわけじゃなくて、回路なので、コードの一行一行がすべて同時並列に動く(はぁ?)。例えばa = b + c;って書くと、bとcを足し算し続ける回路ができる。CPUみたいに気が向いたときに1回だけ足し算してくれるんじゃなくて、昼も夜もいつでも常時足し算中。なのでbやcに流れるデータが変われば、aの結果もデジタル回路的に可及的速やかに変化する。この足し算回路を1000個並べることも簡単で、すると1000回分の足し算が1クロックで完了する。ループなんていうセコいものは書かなくてよい。

いわばこれは光の速さで動くExcelだ。やりたいことをExcelの式の数珠つなぎで書いてそこに大量のデータを流してやると、数万個の演算器がすべて同時に、かつ常時フルスピードで動作して答えを出してくれる。ある意味スパコン。だから画像処理や暗号化など大規模な並列計算が必要な用途によく使われる。やりたいことをどこまで並列化できるかはプログラマのアイディア次第。CPUで動く言語ではなかなか味わえない、この脳みその裏側の筋肉が鍛えられるようなパラダイムシフト感が新鮮だ(でもやっぱり初学者の俺には扱いが難しくてCPUの方が全然ラクだ〜って思うことも多いのだけど。詳しくは後述)。

MIDIキーボードで正弦波を鳴らす

すっごく前置きが長くなった。話を本題に戻して、前回やっと拾えたMIDIキーボードからのノートナンバー、例えば「30h」(鍵盤の真ん中のC)のような数字を周波数に変換して、これまで440Hz固定で鳴らしていた正弦波の音程を変える仕組みをつくる。

前々回に正弦波を鳴らした仕組みは、サインテーブルを使うもの。つまり正弦波の波ひとつ分の時間(440Hzなら2.3ms)を128分割(17μs)して、17μsごとにどんな電圧の信号を出力すればいいかを表にして回路に組み込んでしまう(sin関数を演算で求める回路を組むのはめんどい)。イメージ的にはこんな感じ:



17μsごとに順番に表から電圧の値を読み取ってDAコンバーターに送ると、アナログ信号に変換されて440Hzの正弦波として聴こえる。

この正弦波の周波数を変えるには、同じ表を使いつつ、読み取るスピードだけ変えればよい(今どきのシンセはこんな単純な仕組みじゃないと思うけど)。では、この読み取りの時間間隔をノートナンバーから求めるにはどうすればいいか。「MIDIノートナンバー 周波数」でググったら、いい感じの変換式が出てきた(g200kgさんのサイト!)。



この式を使うのだけど、これも割り算やらべき乗やらをわざわざ演算回路で組むのは大げさなのでテーブルで済ませてしまおう。今度は「ノートナンバーとサインテーブル読み取り間隔の対応表」をこんな感じで作る。



例えばノートナンバー0hならば、DE0の50MHzのクロックを47778回数えるごとに1回サインテーブルから値を読み取る、、って具合だ。この対応表をコピーして、HDLの関数stepsをこんなふうに書いた(コード全体はこちら)。

function [15:0] steps;
	input [7:0] note;
	case (note)
		0: steps=47778;
		1: steps=45096;
		2: steps=42565;
		...

さらに、MIDIステータス90hのメッセージが飛んできたらそのノートナンバーをstepsに渡してサインテーブル読み取り間隔を得るコードを書く。

if (midi_status == 8'h90) begin
	note_on = 1; 
	current_steps = steps(midi_data1);
end

新しい間隔はcurrent_stepsっていうレジスタに入るので、こんなふうな50MHzクロックCLKを数えるカウンタcntを書いて、サインテーブル読み取り用クロックstepclkを作る。このstepclkのタイミングでサインテーブルを読みだしていく。

// clock for each step
reg [15:0] cnt;
wire stepclk;
always @(posedge CLK) begin
	if (cnt == 0)
		cnt = current_steps;
	else 
		cnt = cnt - 1;
end
assign stepclk = cnt == 0;

ここで、DE0内蔵のロジック・アナライザを使ってcurrent_stepsやcnt、出力データにどんな値が出ているか確かめてみる。



いい感じ。MIDIノートナンバー3Chに対応したcurrent_stepsとして05D5hがセットされて、その間隔でstepcntの値が0〜127まで増え、それを使ってサインテーブルから読み取った値DATがきちんと正弦波を描いている。

こんな仕組みで、意外とあっさりMIDIキーボードで叩いた音程で正弦波を鳴らすことができた。いえい!



...和音を出したいね?

しかし現状では単音しか出ない。ここまで来ると欲が出て、和音を出したくなる。横文字で言い表せばポリフォニック・シンセサイザーだ!(正弦波のみ・フィルター・エンベロープ他なんにもなし)

しかし実はこのポリ化でハマって半日くらい悩んでた。何が難しいか。正弦波を出す回路(WaveGenって名前のモジュールにした)をそのまま10や20ほどコピーするのは、あっという間にできる。なにせ1万5000個も部品あるし。問題は、それらに個々の音を割り振る仕組みだ。MIDIキーボードでいくつかの鍵盤を同時に叩くと、それぞれに対応するMIDIメッセージが飛んでくる。その瞬間に、いま空いているWaveGenを順番に探していって、空いているものが見つかったらそれにメッセージを渡す。

こういう順序だった処理って普通のプログラミング言語で書けばあっという間なのだけど、デジタル回路で実装するには慣れが必要。すべてが並列に動いており「順番にやる」という概念のない世界なので、レジスタやカウンタで状態を保持する仕組みを作ってあげて、それらの状態遷移図を頭のなかに描けなければならない。Node.jsやSAXみたいな非同期プログラミングしかない世界を思い浮かべてほしい。ややこしい。デバッグもやっかい。人類にはまだデジタル回路は早すぎたんや。。フォン・ノイマンさんやっぱ天才。もう二度とCPU様のことは裏切りませんすみません申し訳ありませんともがき苦しむことしばし(俺が単に初学者なだけなんだけど)。

結局はこんなふうにした。8個のWaveGenを作って、最初のひとつにMIDIメッセージを渡す。もしそれが発音中で忙しければ次のWaveGenにMIDIメッセージをバケツリレーするという、ソフトウェアにおけるChain of Responsibilityパターンっぽい動きだ。

// generates 8 polyphonic waves
WaveGen wg0(CLK, MIDI_MSG, MIDI_MSG_RDY, midi_msg_thru[0], wg_dat0);
WaveGen wg1(CLK, MIDI_MSG, midi_msg_thru[0], midi_msg_thru[1], wg_dat1);
WaveGen wg2(CLK, MIDI_MSG, midi_msg_thru[1], midi_msg_thru[2], wg_dat2);
WaveGen wg3(CLK, MIDI_MSG, midi_msg_thru[2], midi_msg_thru[3], wg_dat3);
WaveGen wg4(CLK, MIDI_MSG, midi_msg_thru[3], midi_msg_thru[4], wg_dat4);
WaveGen wg5(CLK, MIDI_MSG, midi_msg_thru[4], midi_msg_thru[5], wg_dat5);
WaveGen wg6(CLK, MIDI_MSG, midi_msg_thru[5], midi_msg_thru[6], wg_dat6);
WaveGen wg7(CLK, MIDI_MSG, midi_msg_thru[6], midi_msg_thru[7], wg_dat7);

ここで、wg0が忙しかったらmidi_msg_thru[0]フラグが立つので、wg1がMIDI_MSGを読んで発音する。もしwg1が忙しかったらmidi_msg_thru[1]が立って...という具合。大まかにはこんな構成だけど、各WaveGenの中での状態遷移とロジックの組み立てとデバッグがむずかった。。(実際のコードはここ

こんな仕組みでいいのかな?なにせ、このあたりの組み方を詳細に説明してるようなページが見つからなかったので、思いつくまま実装してみた。もっと勉強すればよりよい実装方法があるかもしれない。「FPGAでデジタルシンセを作る本」ってあったらほしい!

音のミックスってどう書くの?

もうひとつちょっと悩んだのが、音のミックスのしかた。デジタル音声のミックスって単純な足し算でいいんだよね?WaveGenから出力された波形はwg_datという8ビットのデータとして出てくるので、それらを足し算した値をDAコンバーターに送る。

assign OUTDAT = wg_dat0 + wg_dat1 + wg_dat2 + wg_dat3 + wg_dat4 + wg_dat5 + wg_dat6 + wg_dat7;

これでとりあえず試しに和音を出してみたら、最初ものすごっく歪んだ音がでてきた。足し算で出てきた答えが8ビットをオーバーフローして信号がぐちゃぐちゃになったからだ...しかしこれはこれでアリかな?ウィンターライブの教授のソロみたいにぎゅうううんとディストーションが効いてるすてきな音!と一瞬思ったものの、やはり透き通ったきれいな正弦波の和音をまずは出さねば。

本当は足し算する前にwg_datに定数で乗算してボリュームを落とし、合計して8ビット超えないようにする必要があるはず。あとは8ビット超えてもオーバーフローせずにFFhで頭打ちになるような足し算(飽和演算ってやつ?)とか。しかしラッキーなことに、今回使ってるDACは12ビット入るので、単純に足し算結果を入れるOUTDATを12ビットにしてそのままDACに入れたら歪まなくなった。

8音ポリ正弦波シンセができた〜

そんなこんなでポリフォニック化がいちばんの障壁であった。しかしなんとか和音が出せたよ!



見た目のギーク感を高めるために各WaveGenの発音状態をLED表示する回路も入れといた。さらに、キーボードが弾けない俺ではかっこよくデモできないので、バッハ様にデモしてもらった様子も入れておいた(MIDIファイルはこちらのサイトからお借りした)。

和音が出ているところをUSBオシロスコープで波形を観測してみると、なんだかうねうねっとしている。



ところで、手弾きでは問題なく動いてたのに、パソコンからMIDIファイルを流してみると最初は全然ダメダメだった。発音はするけど、うまくノートオフを拾えてないようす。調べてると、ノートオフの代わりに「ベロシティ(鍵盤を叩く強弱)が0のノートオン」を流すというMIDIの使い方もあることを知った。さらにはRyoya KAWAIさんがRunningStatusについて教えてくれて、なんだMIDIメッセージって3バイト固定じゃなくて可変長なのかぁ〜こりゃHDLじゃめんどいな!とCPUのありがたみを再度思い知った次第。

こんな構成になった

ここまで作ってきた回路のまとめ。DE0の開発ツール使うとこんなふうなオシャレな図を作ってくれる。



MIDI入力の非同期シリアル信号はMIDIモジュールによって3バイトのMIDIメッセージに変換される。それを受けてPolyWaveGenが上述の数珠つなぎによってMIDIメッセージを各WaveGen(サインテーブルによる正弦波生成モジュール)に割り振る。WaveGenから出てきた波形信号を、DAコンバーターへのインタフェースとなるSPIに渡す。一番下のNoteDisplayはMIDIノートナンバーをDE0の7セグLEDで表示するモジュール。

これまで書いたコード全体はここに置いておいた。

次の野望

シンセっぽくするなら、あとはやっぱりフィルタとエンベロープ、さらにはサンプラーかな。サンプラーはわりと簡単にできそう。A/DコンバーターのICが手元にあるので、そのデータをDE0のSDRAMに読み込んで、サインテーブル同様に読み出せばいいかな。あとFM音源はもしかして割と簡単にできるかな?サインテーブルを読み出すスピードを、別のサインテーブルでモジュレーションする。一方で、フィルタは難しそう。加算や乗算を組み合わせたFIRだのIIRだの謎回路を組まないとデジタルフィルタにならない。その辺りでググると数式がいっぱい出てくるので萎える。。こっち方面のいわゆるデジタル信号処理の方向には数学苦手な俺は向いてる気がしないなぁ。。