Radix-8、周波数間引き、改良型アルゴリズムの「Hyper FFT回路」がようやくZYNQの7Z030に入りそうという見通しが立ってきました。
このFFT回路は、216個の乗算器がクロック400MHzで一斉に動作し、Radix-8のバタフライ演算を1クロックで処理します。32768ポイントのFFTが51μ秒しかかからないという恐ろしい速度のFFT回路です。
しかし、クロック400MHzだといろいろな箇所で論理合成が通りません。タイミングエラーが出てしまいます。
わかてきたことは、Block RAMって意外と遅いってことです。普通にXILINXのCoreGeneratorでBRAMを作ると、400MHzで通りません。XILINXのデータシートではBRAMは400MHzで動くはずなのに、困ってしまいますよね。
どうすればよいかというと、CoreGenのオプションで、下のところをチェックを入れればいいようです。
BRAMのプリミティブの中にある出力レジスタを有効にしたり、ユーザ回路部分にSLICEを使ってレジスタを入れてくれるようです。今まで、レイテンシが増えるだけじゃん・・って思っていたのですが、なんと、これを入れるとタイミングエラーが解消しました。
レイテンシと引き換えに周波数を上げられるのですね。
あと、256→32にビット幅を変換するBRAMを作ったりすると、ユーザロジックが使われるので遅くなる場合があるようです。その場合もこのオプションで改善できました。
これをZYNQに実装して、パイプラインを入れまくってクリティカルパスを緩くしたところ、なんとかタイミングエラーが出ないようになりました。クロック-クロック間が2.5nsって思った以上に厳しいですね。
さて、論理的な検証のほうですが、シミュレーション上は51μ秒で計算できるのが確かめられました。
しかし、計算結果が正しくありません。
細かいところを波形を見ていてもわかりにくいので、textioを使って、結果のテキストに書き出すようにしてみました。
やりかたは、まずtextioを読み込みます。
use ieee.std_logic_textio.all;
use std.textio.all;
それから、適当なところでfile型のオブジェクトと、line型の変数を宣言します。
file wf_x : text open write_mode is "read_x.txt"; --出力ファイル
variable wl : line;
ファイルに書き込むには、まずline変数(以下の例ではwl)に文字列をセットして、writelineでファイルに書き出す、という形になります。
write(wl,"x read data",left);
writeline(wf_x,wl); --行をファイルに書き出し
write(wl,"stage raddr x0 x1 x2 x3 x4 x5 x6 x7",left);
writeline(wf_x,wl); --行をファイルに書き出し
このとき、writeという関数を使うと、line変数に""で囲った文字列や、VHDL上の信号、変数などを書き出すことができます。writeは万能です。
16進数で書き出したいときにはhwriteという関数を使います。
if(x_valid = '1') then
write(wl,f_tmp(14 downto 12),left,6);
hwrite(wl,f_tmp(11 downto 0),left,6);
hwrite(wl,x0_o,left,9);
hwrite(wl,x1_o,left,9);
hwrite(wl,x2_o,left,9);
hwrite(wl,x3_o,left,9);
hwrite(wl,x4_o,left,9);
hwrite(wl,x5_o,left,9);
hwrite(wl,x6_o,left,9);
hwrite(wl,x7_o,left,9);
writeline(wf_x,wl); --行をファイルに書き出し
end if;
上のような書き方をした場合、アドレスと、x0_o~x7_oまでの信号の値が書き出されます。
x read data
stage raddr x0 x1 x2 x3 x4 x5 x6 x7
000 000 00000000 00001000 00002000 00003000 00004000 00005000 00006000 00007000
000 001 00000001 00001001 00002001 00003001 00004001 00005001 00006001 00007001
こうして生成されたファイルと波形を見ると、一致しているのがわかります。
テキスト出力は便利ですので、長いデータのデバッグが必要になったらぜひ試してみてください。
C言語のソフトで作った計算途中経過と、シミュレータが吐き出した結果を見比べてみて、いろいろ直しました。
まだシミュレーションだけど、HyperFFT回路動きました!計算結果も正しいようです。
普通にFFT回路をFPGAに作ると、アドレスの計算とか、ステージ(ループ)間での無駄な待ち時間が生じてしまうのですが、私のアルゴリズムはそういう無駄が一切なく、20480クロックで結果が出ます。
最近のコメント