-1

VHDL で VGA ドライバを作成しようとしています。

640x480 @ 60 Hz を使用するので、25 MHz と 31.5 KHz のクロックが必要です。divider_hプロセスは 50 MHz クロックで駆動され、結果として 25 MHz クロックになります。25 MHz クロックの各ティックでh_counter、プロセスによってインクリメントされ、ある値 ( )h_syncに達すると、プロセスが開始され、短時間の間 1 に設定されます。H_FRONT + H_SYNC - 1divider_vclock_v

Quartus II のタイミング解析が失敗し、次の警告が表示されます。1 つのパスに沿って最小セットアップおよびホールド要件クロックを達成できませんコンパイル レポートのクロック ホールドv_counterセクションは、最小スラック タイムが -0.050 ns のMSB が原因であると指摘しています。2 番目に低いスラック タイムは 0.218 ns で、問題ありません。

短い 0 状態に対して長い 1 状態を使用しようとしましたがclock_v、最小スラック時間が -0.019 ns に増加しましたが、これはまだ許容できません。

私が理解しているように、ホールドクロックの問題は、入力が正しく処理される前に変更されることを意味するため、1と0の両方をほぼ同じ期間表示しようとしました。驚いたことに、40 以上のパスが同じエラーで赤くなりました。

v_clockプロセスをコメントアウトすると、問題が解決します。

MSB のスラック タイムが他のビットよりもはるかに長いのはなぜですか? この問題を解決するにはどうすればよいですか?

これが私のコードです:

library ieee;
use ieee.std_logic_1164.all;

library Famikon;
use Famikon.Types.all;
use Famikon.VgaNames.all;


entity VgaDriver is
    port (
        -- inputs
        clock_50: in STD_LOGIC; -- 50 MHz
        reset: in bit; -- '1' resets
        r, g, b: in screen_pixel; -- bit_vector subtype

        -- outputs
        vga_x, vga_y: out hw_coord; -- integer subtype
        vga_drawing: out bit;
        hw_r, hw_g, hw_b: out hw_pixel; -- bit_vector subtype
        vga_hsync, vga_vsync: out bit;
        vga_blank, vga_clock: out bit
    );
end entity;


architecture Arch of VgaDriver is
    signal clock_h, clock_v: std_logic;
    signal h_counter, v_counter: vga_counter; -- integer subtype
    signal h_coord, v_coord: hw_coord; -- integer subtype
    signal h_active, v_active: bit;
begin

    -- some irrelevant code --

    h_active <= '1' when (h_counter >= H_BLANK) else '0';
    v_active <= '1' when (v_counter >= V_BLANK) else '0';


    divider_h: process (clock_50) begin
        if (rising_edge(clock_50)) then
            clock_h <= not clock_h;
        end if;
    end process;


    divider_v: process (h_counter) begin
        if (h_counter /= H_FRONT + H_SYNC - 1) then
            clock_v <= '0';
        else
            clock_v <= '1';
        end if;
    end process;


    h_clock: process (clock_h, reset) begin
        if (rising_edge(clock_h)) then
            if (reset = '1') then
                h_counter <= 0;
            elsif (h_counter = H_TOTAL - 1) then
                h_counter <= 0;
            else
                h_counter <= h_counter + 1;
            end if;
        end if;
    end process;


    v_clock: process (clock_v, reset) begin
        if (rising_edge(clock_v)) then
            if (reset = '1') then
                v_counter <= 0;
            elsif (v_counter = V_TOTAL - 1) then
                v_counter <= 0;
            else
                v_counter <= v_counter + 1;
            end if;
        end if;
    end process;


end architecture;

失敗したパスの詳細:

  • から:v_counter[9]
  • に:v_counter[9]
  • クロックから:clock
  • クロックするには:clock
  • 必要なホールド関係: 0.000 ns
  • 必要な最短 P2P 時間: 0.618 ns
  • 実際のショート P2P 時間: 0.568 ns
  • 最小スラック: -0.050 ns

v_counterですbit_vector(9 downto 0)このパスでLocate in Designを使用すると、Quartus はv_clockプロセスの最初の行 ( のある行) を指しrising_edge(clock_v)ます。

また、すべてのh_counterビットに言及するリップル クロックに関する警告clock_hと、3 つのゲート クロック: Equal0Equal0~1およびEqual0~0.

4

2 に答える 2

2

Famikon ライブラリ パッケージが含まれていないため、誰かがVGAタイミングを調べる必要があります。(あなたのコード サンプルは、最小限、完全、検証可能な例ではありません)。

デザインを分析するために何かを作成するには、以下を追加する必要がありました。

package Types is
    subtype screen_pixel is bit_vector (3 downto 0);
    subtype hw_coord     is natural range 0 to 1023;
    subtype hw_pixel     is bit_vector (3 downto 0);
    subtype vga_counter  is natural range 0 to 1023;
end package;
package VgaNames is
    constant H_FRONT:   natural range 0 to 1023 := 16;
    constant H_SYNC:    natural range 0 to 1023 := 96;
    constant H_BACK:    natural range 0 to 1023 := 48;
    constant H_BLANK:   natural range 0 to 1023 := H_FRONT + H_SYNC + H_BACK;
    constant H_VISIBLE: natural range 0 to 1023 := 640;
    constant H_TOTAL:   natural range 0 to 1023 := H_BLANK + H_VISIBLE;

    constant V_FRONT:   natural range 0 to 1023 := 10;
    constant V_SYNC:    natural range 0 to 1023 := 2;
    constant V_BACK:    natural range 0 to 1023 := 33;
    constant V_BLANK:   natural range 0 to 1023 := V_FRONT + V_SYNC + V_BACK;
    constant V_VISIBLE: natural range 0 to 1023 := 480;
    constant V_TOTAL:   natural range 0 to 1023 := V_BLANK + V_VISIBLE;
end package;

また、ブランキング間隔を最初にリストすると、次のことがわかります。

h_active <= '1' when (h_counter >= H_BLANK) else '0';
v_active <= '1' when (v_counter >= V_BLANK) else '0';

vga_x と vga_y のオフセット演算を行うか、別のカウンターを使用します。これは、h_counter と v_counter の両方について、ディスプレイの非ブランク部分を 0 から開始することで解決できます。

ただし、これは vcount[9] セットアップ時間の問題の原因ではありません。

他にも問題があります。

divider_v: process (h_counter) begin
    if (h_counter /= H_FRONT + H_SYNC - 1) then
        clock_v <= '0';
    else
        clock_v <= '1';
    end if;
end process;

これがリップル クロックの原因のようです。組み合わせロジックによって clock_v を生成しようとしています。いくつかの正当な理由により、これを行うべきではありません。h_counter ビットとゲートが比較を認識するために使用する間に非対称の遅延が発生する可能性があり、LUT を使用しても複数レベルの組み合わせロジックが存在し、ルーティング遅延が一致しない可能性があります。あなたの clock_v が機能するかどうかは、レイアウトの気まぐれ次第であり、(おそらく clock_h で) 登録する必要があります。

ターゲット デバイスのベンダーと実際の警告およびエラー メッセージを知ることは、回答者にとって非常に役立ちます。clock_v を修正するだけで十分だと思うかもしれませんが、そうではないかもしれません。その場合、Kevin は、デザインを適切に制約していないことを示していると思います。

最近スタック Exchange の質問に出てきた古いスタイルの VHDL VGA タイミング ジェネレーターがあります ( VHDL VGA 同期回路を参照)。これは、Pong P. Chu の著書「FPGA PROTOTYPING BY VHDL EXAMPLES, XILINX SPARTAN-3 Version」の第 12 章からのもので、ファイル名は list_ch12_01_vga_sync.vhd で、著者のコンパニオン Web サイトで入手可能なコード リスト zip ダウンロードにあります。ブライアン・ドラモンドが指摘しているように、エディター検索や印刷出力を使用したくない人にとっては、3 つのプロセス ステートメントに横方向と縦方向のカウンターを広げて読むのが難しいと指摘しています (元の設計仕様のビューは、好みによってはフラットすぎて、プロセスが多すぎるように見えます)。 )。

ブライアンには、プロセスを組み合わせた例を提供する追加の回答があり、水平カウンターでの垂直カウンターカウンターのネストを示しています。また、「0000000000」(0) から始まる非空白の水平および垂直間隔も示します。Brian は、h_active および v_active と同等のシグナルが未登録のままであることについてもコメントしていることに気付くでしょう。

于 2014-11-23T20:16:35.050 に答える
2

失敗したパスの始点と終点を提供していただけると助かります。主な問題は、異なるクロックを生成していて、ドメイン間のタイミングの問題や、異なるドメイン間の関係を確立する不完全な制約があることです。おそらくドメインresetからのclock_50ものであり、他の 2 つのドメインで直接使用するべきではありません。clock_vより堅牢なソリューションでは、同期イネーブルを持つ単一のクロックを使用して、および と同じ効果を得ますclock_h

生成されたクロックが必要な場合、FPGA ファブリックでそれらを構築しようとするのではなく、オンボード PLL/DLL を使用してそれらを管理する必要があります。そのようにすると、ドメイン間のスキューがより適切に制御され、タイミング アナライザーが状況をより適切に処理できるようになります。すべてのドメインには、独自のクロックに同期された独自のリセット信号が必要です。

v_active登録しh_activeて、比較ロジックをフィード先から分離することもお勧めです。さらに、同期リセットを使用しているため、感度リストに含める必要はありません。

于 2014-11-23T00:05:40.920 に答える