まごころせいじつ堂

浜町庄金 研究開発  マイコンで遊んでばっかりで

QuartusII

バレルシフタ 2段にして改善(お詫び 大きな間違いあり)

追記:@ikwzmさんから。https://gist.github.com/ikwzm/5558633 
バイト単位でシフトすべきところを4bit単位でやってました。あああ
ご指摘ありがとうございました。

※前段の 8byteシフト間違ってる気がしてきた。多分3bit分を<<5した時点ですべて'0'になってしまってるはず

(1)組み合わせ回路のシフトについて、下xx bitを削っていくような間違いをしていました。書きなおしたのは以下。
https://gist.github.com/houmei/5555418

(2)<<演算子を使ったbyte shiftは、いったん幅[6:0]の下位3bitを'000'とし、上位にシフト量を入れることで書き直しました。
比較結果:
349LE/214.92MHz (Megafunction)
343LE/214.55MHz (シフト演算子)
291LE/335.46MHz (組み合わせ回路)
ただし、組み合わせ回路によるものは(1)の間違いあり。

反省:見積もりに検証していない回路を軽い気持ちで使うと大失敗

以下は間違いありです。


 扱うbit幅が大きくなるとLE数は増え動作周波数は落ちていくバレルシフタ。ここでシフト量を制限したらどうなるか傾向を見てみた。例えば1bitシフトする/しないだけなら大幅にセレクタ数が減るはず。
以下の様なコードでシフト量を1,2,4,8...と変えながら試してみる。上位モジュールからは
sll64_partial #6 SLL(source,value,sftout); // partial shift
の様に呼び出す。
module sll64_partial (indata,val,outdata);
	parameter width=6; //[6:0]
	input [63:0] indata;
	input [width:0] val;
	output [63:0] outdata;
	assign outdata=indata<<val;
endmodule
結果は以下のとおり。
 64bitを部分シフト
[0:0] 129LE/615.38MHz
[1:0] 136LE/413.56MHz
[2:0] 143LE/357.65MHz
[3:0] 210LE/270.71MHz
[4:0] 285LE/250.38MHz
[5:0] 384LE/223.31MHz
[6:0] 390LE/220.17MHz

では、最初にバイト単位でシフトして次にビット単位で8つまでシフトするようにしてみる。
シフト量のnnnnxxxのうち、nnnnはバイトでのシフト量、xxxはビットのシフト量とする。nnnnについてはシフトする量がデータ幅をあふれたらall0とする。


ソースはこちら:https://gist.github.com/houmei/5541783 

コンパイル結果は207LE/284.41MHzとなった。組み合わせ回路でべたに書いた283LE/105.06MHzよりよい。

※以下も怪しい
 もし、もっと追求するとしたらbit幅の組み合わせを変える(4-3を3-4)、段数を増やす(2-2-3)、一部組み合わせ回路にしてみる、など。やりだすときりがなくなるけど構造的な改善である程度の性能が出たらしばらく放置して他に着手したほうがいいかも。

 あと、QuartusIIにはMagawizard Plugin Managerというのがあって、用途に合わせたライブラリが使える。今回の用途にはGates→LPMCLSHIFTというのが使えた。verilogやVHDLのインターフェース部分がソースとして出力されるのでこれを呼び出して使用する。

QuartusII 12.1 バレルシフタの記述比較

 前回、メモ:QuartusII 12.1 バレルシフタの記述とTimeQuestによる速度評価の続き。

 バレルシフタの入力、出力を64bitとすると、シフト量は0~64になる。つまりシフト量の指定に6bit+1必要。これらをfunction文による自前の組み合わせ回路と<<演算子による記述で比較してみた。

ソースはこちら:https://gist.github.com/houmei/5522404 

 function文によるRTLはこのようになる。(8bit幅)
sll8_15LE3 
 コンパイル結果は以下。27LEで3段。
62MHz


 <<演算子によるRTLはこんな表示。
sll8shiftop

 コンパイル結果。32LE4段。
33MHz


 このような感じで4~64bitまでの組み合わせ回路によるバレルシフタと演算子によるバレルシフタについて、LE数と動作周波数で比較した。
  barrel

 横軸は4,8,16,24,32,48,64が等間隔に並んでいるのに注意。組み合わせ回路はLE数が少なくて済むが、8~16bitのあたりで速度が逆転する。これを配置配線後の回路でみると、こうなっている。

組み合わせ回路によるもの:
06MHz

<<演算子によるもの:
05MHz
 <<演算子でコンパイラに任せたほうが、LEがまんべんなく散らばっているようにみえる。LE自体のディレイよりも配線のディレイが大きいように思える。
16bitくらいの大きさまでなら組み合わせ回路で手書きしたほうがいいが、回路をケチる必要がなければコンパイラに任せたほうがいい。


 <<の演算子で書くならparameter文で指示したら良さそうと思うでしょう?実験した。上位モジュールからは
 sllp #(63) SLL(source,value,sftout);
の様に書いてparameter文を使ったsllp.vを呼び出すようにコンパイルしてみる。すると、24bitで以下の様な結果となった。 
24bitでの<<演算子 / parameter文によるもの
128LE,295.33MHz / 133LE,280.74MHz

 bit幅によってはまったく同じではないことがあり得る。なんでわざわざこれを試したかというと、20年くらい前に論理合成ツールを使った時に怪しい挙動を経験したため。なので、ギチギチに詰める必要がある場合はいろいろ疑ってみたほうがいいかもしれない。

追記:@ikwzmさんにfor文を使った書き方を教えてもらいました。https://gist.github.com/ikwzm/5523178 398LE/199.76MHz
ちょっと8byteシフト&8bitシフトの組み合わせで64biシフタを構成したら210LE/310.95MHz

メモ:QuartusII 12.1 バレルシフタの記述とTimeQuestによる速度評価

 ALTERAのFPGA開発環境 QuartusII 12.1、Verilog HDLでバレルシフタを記述し、組み合わせ回路の動作速度をQuartusIIの機能であるTimeQuestで計ってみた。ターゲットはCycloneIII EP3C16F484C6(Terasic DE0)。I/Oのアサインはせずコンパイルのみ。

 バレルシフタは組み合わせ回路なので、最初はI/Oから入出力をとってそのまま接続していた。しかしこれではTimeQuestで評価されない。前後をFFではさむとfmaxが計算された。
 
sll64_rtl

 これに気づいたのはTimeQuestによるタイミング解析を学ぶ (1/3) 、FPGAの動作スピードを改善するポイントとは? (1/2)を読んでから。ディレイ計算はゲートの出力側から入力側に向けて積算して求めるものと思っていた。

ソースはこちら:https://gist.github.com/houmei/5510474 

 コンパイル後、[Tools]→[Netlist Viewers]以下のツールで回路を見ることができる。
→[RTL Viewer]でRTLの、→[Technology Map Viewer(Post-Fitting)]で配置配線後の回路を表示する。

[RTL Viewer]
sll4_rtl 

[Technology Map Viewer(Post-Fitting)]
76MHz

 Compilation ReportのTimeQuest Timing Analyzerの項目に最大動作周波数が載っている。ここのSlow 1200mV 85C Modelを開く(電圧が低く、温度が高い方が厳しい条件となる)。 ここのFmax Summaryを見ると712.76MHzとあり、これが最大動作周波数。

QuartusIIでCADRのソースをコンパイル 2

QuartusIIでCADRのソースをコンパイル 続き
i_DRAMの中身をカラ(reg 宣言を削りassign DO=DI; とする)にして再度コンパイルしてみた今回は5時間を越えてどんどん進むが停まる気配がない。10時間で打ち切り、すべてのRAMについて同様に中身をカラにしてみた。どうもreg宣言ばかりで明にRAMに割り当てていないようで、これがLE数を消費する原因と思われた。
結果は以下のとおり。
Flow Status Successful - Fri Feb 22 01:17:37 2013
Quartus II 64-Bit Version 12.1 Build 177 11/07/2012 SJ Web Edition
Revision Name caddr
Top-level Entity Name caddr
Family Cyclone IV GX
Device EP4CGX150DF31I7AD
Timing Models Final
Total logic elements 2,929 / 149,760 ( 2 % )
Total combinational functions 2,860 / 149,760 ( 2 % )
Dedicated logic registers 471 / 149,760 ( < 1 % )
Total registers 471
Total pins 27 / 508 ( 5 % )
Total virtual pins 0
Total memory bits 0 / 6,635,520 ( 0 % )
Embedded Multiplier 9-bit elements 0 / 720 ( 0 % )
Total GXB Receiver Channel PCS 0 / 8 ( 0 % )
Total GXB Receiver Channel PMA 0 / 8 ( 0 % )
Total GXB Transmitter Channel PCS 0 / 8 ( 0 % )
Total GXB Transmitter Channel PMA 0 / 8 ( 0 % )
Total PLLs 0 / 8 ( 0 % )
  2929LEですと?ちょっと少なすぎるみたいだけどもここからRAMを盛っていく。
i_DRAM については外付けのDRAMと勘違いしていたのだがDispatchRAMで17bit幅☓11bitアドレスのStaticRAMだった。主記憶はCADRマシンの外にある。caddrではすでにパリティ用の1bitについては削減してあった。
 あとはクロック周り。osc50mhzを外部からの入力として、以下の接続。
osc50mhz-->○--osc0-->○--hifreq1,hifreq2-->○--hfdlyd-->○--hftomm(未使用)
hifreq1,hifreq2は実質同じ、hfdlydはさらに位相の遅れたクロックのつもり。
これらを元にディレイラインで30ns,70nsの遅れを作りRAMのサイクル用などに使っている。
また、NAND2個のたすきがけで制御を行なっている場所が5箇所あり、図面のCLOCK DISTRIBUSIONとMASTER CLOCKはPLLを使用したクロック制御モジュールとして起こしてやらなければならないだろう。これに合わせて非同期SRAM部分も合わせるか。

QuartusIIでCADRのソースをコンパイル

LISPマシンCADRの回路図とVerilog-HDLに変換されたソースリストを見て、これ今のFPGAに収まりそうじゃないかなと思って試しにコンパイルしてみた。もともとはすべてTTLで構成されていて、それをそのままVerilogの記述に変換したものと、きちんと書きなおされたものがある。後者はCADDR Reviced CADR Verilogとして公開されているのでこちらを使った。
Retrocomputing - MIT CADR Lisp Machines
 すでに@natsutanさんが三年前に試されているけど、最近のはどうかな?
[Lisp][Verilog][FPGA]cadrのVerilogソースのコンパイル その1

環境:Windows7 PRIMERGY TX100S1(Core2Quad 2.67GHzに差し替えたもの)
QuartusII 12.1 Build 177 64-bit

新規プロジェクトを作成し、ターゲットデバイスを一番LE数の大きそうなものにする。今回はCycloneIV GXにした。制約条件などのオプション指定はなにもなし。コンパイルにかかった時間は4時間23分、結果はFittingに失敗(113%)、LE数は169,005と出た。

Flow Status Flow Failed - Wed Feb 20 18:15:59 2013
Quartus II 64-Bit Version 12.1 Build 177 11/07/2012 SJ Web Edition
Revision Name caddr
Top-level Entity Name caddr
Family Cyclone IV GX
Device EP4CGX150DF31I7AD
Timing Models Final
Total logic elements 169,055 / 149,760 ( 113 % )
Total combinational functions 109,428 / 149,760 ( 73 % )
Dedicated logic registers 136,714 / 149,760 ( 91 % )
Total registers 136714
Total pins 27 / 508 ( 5 % )
Total virtual pins 0
Total memory bits 787,040 / 6,635,520 ( 12 % )
Embedded Multiplier 9-bit elements 0 / 720 ( 0 % )
Total GXB Receiver Channel PCS 0 / 8 ( 0 % )
Total GXB Receiver Channel PMA 0 / 8 ( 0 % )
Total GXB Transmitter Channel PCS 0 / 8 ( 0 % )
Total GXB Transmitter Channel PMA 0 / 8 ( 0 % )
Total PLLs 0 / 8 ( 0 % )

ソースは以下の修正が必要。

・caddr.v 74181.v 74182.v busint.v  memory.v rom.v を新規ファイルとしてプロジェクトに追加。(New Files... でVerilog-HDLを指定してコピペ) lm2clock.vは多分いらない。

・caddr.vのソース修正 `includeをすべてコメントアウト。プロジェクト内のモジュールを多重に読み込むことになるので。
・memory.vのソース修正 initial begin~end部分をコメントアウト。
・busint.vのソース修正 initial begin~end部分をコメントアウトし、always@(posedge clk)部分とalways@(rst_n)部分をalways@(posedge clk or negedge rst_n)として合体させる。

 あとはメモリを外に出す、caddr.vが大きすぎるのである程度のモジュールに分割し面積を減らせるか検討。特にパリティ回路はまるっと削除しても問題なさそう。あとはALUをまとめてしまう、など。

DE0 QuartusIIのMegaWizardでPLLを使う

DE0の基板上のクロックは50MHz。搭載されているSDRAMは100MHzか133MHz動作なのでこれなんか必要だよなあPLLがあるはずだがどうやって使うんだろうと悩んでいたが解決した。
 これはメーカー/デバイスごと固有の設定であり、Verilog-HDLの記述でどうこうできる話ではない。 QuartusII(12.1sp1)では[Tools]→[MegaWizard Plug-in Manager]で呼び出す。
2013pll1
新規作成を選んで次へ。
2013pll2
ここでは出力する言語をverilog HDL、ファイル名はapll、使用するmegafunctionはI/O→ALTPLLを選択。
 2013pll3
ここからALTPLLの詳細設定画面。入力クロックは50MHzにする。
2013pll4
resetやlock信号は今回使わないのでチェックを外す。後はいくつか飛ばして以下の画面へ。
2013pll5
 c0~c4まで出力を設定できるが、ここではc0だけ。100MHzに設定。あとは飛ばす。
2013pll6
最終確認。[Finish]

メインの画面に戻って[File]→[Open...]でapll.bb.vを開く。以下の内容のダミーモジュールができる。

module apll (
	inclk0,
	c0);

	input	  inclk0;
	output	  c0;

endmodule
 これをつないでやれば良い。トップモジュールで定義したクロック入力をclk_50、PLLの出力をclkで分配すると
apll apll_0(clk_50,clk);
とすればよい。なおトップモジュールでクロック入力の名前を変えるとピンの対応付けが再度必要になるのでPinPlannerで定義する。これでチカチカ表示するのが二倍速になるのを確認した。

参考:
http://www.emb4fun.de/fpga/nutos1/

昔話:
昔はのう、クロック入力を分周してデューティ50%で使ってたんじゃ。例えば内部50MHz動作だと100MHzの発振器が必要で、当時CMOSでそんな出力のはなかったんでECLレベルの発振器を使っておったんじゃ……

DE0 QuartusIIでのコンパイル結果をちょっと見る

QuartusII 12.1 Windows 32bit

 ゼロサプレスのデコーダ作ってて、どんな回路が作られてるのだろうと覗いてみた。QuartusIIの[Tools]→[Netlist Viewers]→[RTL Viewer]

追記:
※この回路はゼロサプレス部分にミスがあります。 

入力がすべて0の判定を三項演算子でやると、コンパレータになってる。
 assign bout=(bcd==4'b0000)?1'b1:1'b0;
2013decoder_eq0
Flow Status Successful - Sat Jan 26 18:40:00 2013
Quartus II 32-bit Version 12.1 Build 177 11/07/2012 SJ Web Edition
Revision Name fizzbuzz
Top-level Entity Name fizzbuzz
Family Cyclone III
Device EP3C16F484C6
Timing Models Final
Total logic elements 112 / 15,408 ( < 1 % )
Total combinational functions 101 / 15,408 ( < 1 % )
Dedicated logic registers 67 / 15,408 ( < 1 % )
Total registers 67
Total pins 57 / 347 ( 16 % )
Total virtual pins 0
Total memory bits 0 / 516,096 ( 0 % )
Embedded Multiplier 9-bit elements 0 / 112 ( 0 % )
Total PLLs 0 / 4 ( 0 % )
 

ゲートレベルで考えるとちゃんとゲートになっている。
assign bout=(~(|bcd));
2013decorder_or0
 Flow Status Successful - Sat Jan 26 18:37:14 2013
Quartus II 32-bit Version 12.1 Build 177 11/07/2012 SJ Web Edition
Revision Name fizzbuzz
Top-level Entity Name fizzbuzz
Family Cyclone III
Device EP3C16F484C6
Timing Models Final
Total logic elements 110 / 15,408 ( < 1 % )
Total combinational functions 99 / 15,408 ( < 1 % )
Dedicated logic registers 67 / 15,408 ( < 1 % )
Total registers 67
Total pins 57 / 347 ( 16 % )
Total virtual pins 0
Total memory bits 0 / 516,096 ( 0 % )
Embedded Multiplier 9-bit elements 0 / 112 ( 0 % )
Total PLLs 0 / 4 ( 0 % )

 LEが2個少なくなった。差はないと思っていたんだけど、記述での最適化は効くということだろうか。 
記事検索
プロフィール

hardyboy

カテゴリ別アーカイブ
月別アーカイブ
QRコード
QRコード
  • ライブドアブログ