奇数割の分周器VHDL
以前、猫カメラ向けにSDRAMのコントローラ等をVHDLで作成したことをお伝えしましたが、その際に紹介したVHDLに含まれていた分周器(divider.vhd)が論理合成不可能なコードを使っていたため、修正しましたのでお知らせします(リンクは修正済みの最新版です)。
もともと分周器のコードは偶数割(例えば1/2とか1/4とか)と奇数割(1/3とか1/5とか)で違うインスタンスが生成されるようにgenerate構文で制御していたのですが、シミュレーションでは偶数割、奇数割の両方を行ったにもかかわらず、CPLDやFPGAに実装するために必要となる論理合成は偶数割しか試していなかったことが問題発覚が遅れた原因です。シミュレーションで実証できても全てが論理合成できるわけではないという基礎を疎かにしていました。
というわけで問題があったのは奇数割のコードなのですが、修正前(r3008.divider.vhd)はエッジの検出を立上り(L to H)と立下り(H to L)の両方で行い、カウンタはインクリメントするものでした。ダイジェスト版を以下に示します。
gen_odd: if (divide_value mod 2 = 1) generate
process(clk, clk_n, reset) begin
if reset = '1' then
timer <= (others => '0');
elsif (clk'event and clk = '1') or (clk_n'event and clk_n = '1') then
if timer < conv_std_logic_vector((divide_value * 2) - 1, required_bits) then
timer <= timer + 1;
else
timer <= (others => '0');
end if;
end if;
end process;
clk_out <= '1' when timer < conv_std_logic_vector(divide_value, required_bits) else '0';
end generate;
timerは指定した分周比の2倍まで数えられるカウンタです。このコードで論理合成を行うと、立上りと立下りのエッジをorでつなぐことができないと文句を言われてしまいました。orでつなぐことができないなら、と、elsifで分離したり、processを分けて試行錯誤してみましたが、両方のエッジで同じレジスタの値を変更することができないという別のエラーが発生しました。こういった両方のエッジで論理合成を可能にするためには、立上りと立下りでカウンタを2つ用意するのがよいようです。
しかし何とかレジスタ数を減らしたかったので、カウントの方法を工夫しカウンタを1つにした結果できたのが今回のコードです。立上りでは最下位ビットのみをコントロールします。立下りでは最下位以外のビット列の加算を行います。このようにすることで、立上りと立下りで同じレジスタをいじることを防いでいます。
もしかしたら論理合成を行う際の最適化によって、カウンタが2つの場合でも変わらないコードが生成されているかもしれません。とりあえずは、奇数割の際にも機能を達成できたということで満足しています。
※(2010/7/6)以前公開していたコード(r3383)はジッタフリーでなく、クロック源として使うには問題があるとの指摘をうけました。シミュレーション上問題なかったので見落としていたようです。リンクは最新版で既にこの問題が解消されています。
コメント
コメントする
- 匿名でのコメントは受け付けておりません。
- お名前(ハンドル名可)とメールアドレスは必ず入力してください。
- メールアドレスを表示されたくないときはURLも必ず記入してください。
- コメント欄でHTMLタグは使用できません。
- コメント本文に日本語(全角文字)がある程度多く含まれている必要があります。
- コメント欄内のURLと思われる文字列は自動的にリンクに変換されます。
- 投稿ボタンを押してエラーがでなければ、投稿は成功しています。反映されるまでには少し時間がかかります。