奇数割の分周器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)の両方で行い、カウンタはインクリメントするものでした。ダイジェスト版を以下に示します。

clk_n <= not clk;
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)はジッタフリーでなく、クロック源として使うには問題があるとの指摘をうけました。シミュレーション上問題なかったので見落としていたようです。リンクは最新版で既にこの問題が解消されています。

April 21, 2009 09:33 fenrir が投稿 : 固定リンク | | このエントリーを含むはてなブックマーク | この記事をdelicious.comでブックマーク

コメント

コメントする