FC2カウンター FPGAの部屋 XSTでのVHDLインプリメントの注意点
FC2ブログ

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

XSTでのVHDLインプリメントの注意点

7セグLEDのダイナミック点灯でも使用した1KHzのタイミングを作るfreqdiv.vhdというモジュールを以前作成した。これはgeneric mapに動作周波数をkHz単位で書くと自動的に1kHzごとにイネーブル信号を出力する。
動作周波数によっては用意したカウンタのカウント値をオーバーしてしまうので、その時はstd_logic_vectorのビット幅を手で変更しなければ、ならなくなっていた。
ソースを示すと、
-- Frequncy Divider for Dynamic Lighting
-- 1KHz clock
-- マスタークロックを1KHzのlighting_enaに分周します。
-- クロック周波数をclk_frequencyにKHz単位で設定してください。defaultで25MHzです。
-- lcntが16ビットになっているので、clk_frequencyが65536以上の場合はビットを増やしてください。

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity FreqDiv is
 generic(
  clk_frequency : integer := 50000 -- KHz
 );
 port(
  clk, reset : in std_logic;
  lighting_ena : out std_logic
 );
end FreqDiv;

architecture RTL of FreqDiv is
signal lcnt : std_logic_vector(15 downto 0);
begin
 process(reset, clk) begin -- Lighting frequency is 1KHz
  if reset='1' then
   lcnt <= (others => '0');
  elsif clk'event and clk='1' then
   if lcnt = conv_std_logic_vector(clk_frequency, 16) then
    lcnt <= (others => '0');
   else
    lcnt <= lcnt + 1;
   end if;
  end if;
 end process;

 lighting_ena <= '1' when lcnt = conv_std_logic_vector(clk_frequency, 16) else '0';
end RTL;

signal lcnt : std_logic_vector(15 downto 0);で15 downto 0になっているが、66MHzになると16 downto 0にしなければいけない。最初から16 downto 0にすれば良いという選択肢もあるが美しくない。log2を使えればエレガントに書く事が出来る。
そこで、依然買ってもらったVHDLの本をよく読んで見ると。log2(x)はmath_realパッケージをuseすると使えるようだ。だが、xはrealなので、integerをrealに変換しなければいけない。log2(x)はrealなので、またintegerに変換して使う。
変更したソースは
-- Frequncy Divider for Dynamic Lighting
-- 1KHz clock
-- マスタークロックを1KHzのlighting_enaに分周します。
-- クロック周波数をclk_frequencyにKHz単位で設定してください。defaultで50MHzです。

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use ieee.math_real.all;

entity FreqDiv is
 generic(
  clk_frequency : integer := 50000 -- KHz
 );
 port(
  clk, reset : in std_logic;
  lighting_ena : out std_logic
 );
end FreqDiv;

architecture RTL of FreqDiv is
signal lcnt : std_logic_vector(integer(log2(real(clk_frequency)))-1 downto 0);
begin
 process(reset, clk) begin -- Lighting frequency is 1KHz
  if reset='1' then
   lcnt <= (others => '0');
  elsif clk'event and clk='1' then
   if lcnt = conv_std_logic_vector(clk_frequency, integer(log2(real(clk_frequency)))) then
    lcnt <= (others => '0');
   else
    lcnt <= lcnt + 1;
   end if;
  end if;
 end process;

 lighting_ena <= '1' when lcnt = conv_std_logic_vector(clk_frequency, integer(log2(real(clk_frequency)))) else '0';
end RTL;

ModelSimでシミュレーションすると、clk_frequencyを25000にすると15bitのlcntになり、66000にすると17bitのlcntになることが確認できた。やった出来た!!!エレガントに書く事が出来たと喜んだ。
実際にXSTで論理合成して、念のためView RTL Schematicで確認してみると、あれ?lcntカウンタが16ビットのはずなのに15ビットしかない???
View RTL Shematicで見たfreqdiv.vhdのRTL図はこれ
XST_freqdiv.png

念のため、Synplify Proで論理合成してみると、ちゃんと16ビットのlcntカウンタが合成されている。
Synplify ProのRTL Schematicのlcntはこれ
synplify_pro_freqdiv.png

XSTの合成結果はModelSimの結果やSynplify Proの合成結果と違うようだ。
Synplify Proで合成した物をコンフィギュレーションすると、SW0~4を31にするとちらつくが、XSTでやるとちらつかない。オシロで測ると1個当たり350us位になっているようだ。

もしかしたらrealからintegerに変換する時の丸め方が違うかもしれない。それでソースを変更してやってみた。
-- Frequncy Divider for Dynamic Lighting
-- 1KHz clock
-- マスタークロックを1KHzのlighting_enaに分周します。
-- クロック周波数をclk_frequencyにKHz単位で設定してください。defaultで50MHzです。

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
use ieee.math_real.all;

entity FreqDiv is
 generic(
  clk_frequency : integer := 50000 -- KHz
 );
 port(
  clk, reset : in std_logic;
  lighting_ena : out std_logic
 );
end FreqDiv;

architecture RTL of FreqDiv is
signal lcnt : std_logic_vector(integer(log2(real(clk_frequency))) downto 0);
begin
 process(reset, clk) begin -- Lighting frequency is 1KHz
  if reset='1' then
   lcnt <= (others => '0');
  elsif clk'event and clk='1' then
   if lcnt = conv_std_logic_vector(clk_frequency, integer(log2(real(clk_frequency)))+1) then
    lcnt <= (others => '0');
   else
    lcnt <= lcnt + 1;
   end if;
  end if;
 end process;

 lighting_ena <= '1' when lcnt = conv_std_logic_vector(clk_frequency, integer(log2(real(clk_frequency)))+1) else '0';
end RTL;
これだと、XSTもSynplify Proも両方コンフィギュレーションして確かめてみた結果OKだった。Synplify Proの方はlcntカウンタが17ビットになっているが、最上位ビットは0の時にlighting_enaが0になるようにしてある。これは後でオプティマイズされるだろう。
これで大丈夫だけど、丸め方の違いを覚えておかないとModelSimでOKだと思って1ビット幅を削ってしまった時にXSTで動かないということがありえる。これではまずいのでやめることにした。
というわけで、今回のソースコード・エレガント化計画は挫折してしまった。計算の丸め方のオプションが各ソフトにないのであろうか、知っている方がいらっしゃったらご一報ください。
  1. 2005年10月31日 11:47 |
  2. VHDLの書き方
  3. | トラックバック:0
  4. | コメント:3

コメント

最近、仕事で使うので勉強させて頂いてます。
動作周波数があがると・・・という記述がありましたが、型変換せずにそのままinteger型でカウントを作っては駄目なのでしょうか?
もしかしてデバイス使用率が膨大に膨れ上がるのかなと思ったのですが、レポート見る限りほとんど差が無かったので、気になりました。
(常識的な質問ですいません;)
  1. 2015/10/22(木) 14:49:01 |
  2. URL |
  3. FPGA初心者 #-
  4. [ 編集 ]

integer型で書いても、コンパイル時にビット長は無駄なビット長は削除されると思います。ですが、初心者こそ、カウンタが収まるビット長を意識して書くべきだと私は思います。
カウンタはいずれにせよ、integer型で実装しても出力ポートは32ビットあるとばかりは限らないのではないでしょうか?
飽和演算の必要性とかをよく考えて演算を実装する必要があるかもしれません。そういったバグは見つけるのが難しくなる可能性があります。
ビット長を考え、SIGNED、UNSIGNEDを考えながら、実装したほうが後々良いと思います。
512ビット長のデータバスとかも作ったことがありますよ。

あくまでも私の考えですので、integerで大丈夫だから、それで行くというのでも構わないと思います。その場合は、ビット長を必ず意識して下さい。
  1. 2015/10/22(木) 20:15:52 |
  2. URL |
  3. marsee #f1oWVgn2
  4. [ 編集 ]

管理人様>>
ご返信ありがとうございました。
今までビット長はあまり意識せず、ある程度適当な幅を取って、足りなければ増やせばいいという感じで作っていたことが多かったので大変勉強になりました。
まだそういった次元でしか触っていないので何とかなっていましたが、今後のことも考え、きちんとビット長を意識して設計していこうと思います。
ありがとうございました。
  1. 2015/10/26(月) 13:18:58 |
  2. URL |
  3. FPGA初心者 #-
  4. [ 編集 ]

コメントの投稿


管理者にだけ表示を許可する

トラックバック URL
http://marsee101.blog.fc2.com/tb.php/57-2004f0b6
この記事にトラックバックする(FC2ブログユーザー)