2014-11-22 61 views
-1

我正在嘗試在VHDL中創建一個VGA驅動程序。如何修復此代碼中的時鐘保持?

我打算用640x480 @ 60 Hz,所以我需要25 MHz和31.5 KHz的時鐘。過程由50 MHz時鐘驅動,併產生25 MHz時鐘。在25 MHz時鐘的每個節拍上,h_counter通過過程h_sync遞增,當它達到某個值(H_FRONT + H_SYNC - 1)時,divider_v過程被觸發並在短時間內將clock_v設置爲1。

Quartus II的時序分析失敗,並出現一個警告:不能實現最小設置並保持沿着1條路徑的要求時鐘編制報告中的時鐘保持部分指出v_counter的MSB是罪魁禍首,最小松弛時間爲-0.050ns。第二低的鬆弛時間是0.218ns,這很好。

我試圖使用長狀態1爲clock_v與簡短的0狀態和最小松弛時間增加到-0.019納秒,這仍然是不可接受的。

據我所知,保持時鐘問題意味着輸入在被正確處理之前被改變,所以我試圖讓1和0出現大致相同的時間段。令我驚訝的是,超過40條路徑變成了紅色,同樣的錯誤。

註釋掉v_clock流程解決了這個問題。

爲什麼MSB的鬆弛時間比其他位高很多?我能做些什麼來解決這個問題?

這裏是我的代碼:

  • 來源::v_counter[9]
  • 爲:v_counter[9]
  • 從時鐘:clock
  • 時鐘出現故障路徑的

    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; 
    

    詳細:clock

  • 要求的保持關係:0.000納秒
  • 所需最短時間P2P:0.618納秒
  • 實際Shortes P2P時間:0.568納秒
  • 最小時差:-0.050納秒

v_counterbit_vector(9 downto 0)。當我使用定位於此路徑上的設計時,Quartus指向v_clock過程的第一行(其中一個與rising_edge(clock_v)一致)。

還有一個關於波紋時鐘警告,其中提到的所有h_counter位,clock_h和三個門控時鐘:Equal0Equal0~1Equal0~0

+0

與您的問題並不完全相關,但實際上,您需要'640x480 @ 60Hz'的25.175 MHz時鐘[來源](http://tinyvga.com/vga-timing/[email protected])。我建議你使用內部的PLL來產生這個時鐘(如果你有任何可用的話)。 – HeyYO 2014-11-23 00:05:32

+0

VGA的時間容限是根據顯示器的水平和垂直速率定義的。我在一個月前檢查了幾個關於另一個VGA問題的規格,25 MHz似乎讓您在我檢查的顯示器的容差範圍內。 – user1155120 2014-11-23 02:24:56

回答

3

如果您提供了失敗路徑的起點和終點,它將有所幫助。看起來主要問題是您生成不同的時鐘,並且跨域時序問題或不完整的約束建立不同域之間的關係。據推測reset來自clock_50域,它不應該直接在其他兩個域使用。更強大的解決方案將使用同步啓用的單個時鐘來獲得與clock_vclock_h相同的效果。

當生成時鐘是必要的時,您不應該嘗試在FPGA架構中構建它們,而是使用板載PLL/DLL來管理它們。域之間的偏差可以更好地控制,定時分析器可以更好地處理這種情況。每個域都需要有自己的復位信號,它與自己的時鐘同步。

註冊v_activeh_active也可能是一個好主意,以便將比較邏輯從它們輸入的內容中分離出來。另外,您正在使用同步重置,因此無需將它們放入敏感列表中。

+0

這是從'v_counter [9]'到'v_counter [9]'的路徑,我在這個問題中增加了更多細節。 'reset'連接到硬件開關。我最初嘗試在'h_clock'過程中增加'v_counter',但是引入了鎖存器('v_counter'如果它沒有增加,它必須保存它的值)。 「register v_active and h_active」是什麼意思? – gronostaj 2014-11-23 11:36:19

+0

您沒有正確設計您的設計。代碼中沒有名爲'clock'的時鐘。您只是使用默認名稱。按照我的建議切換到單個時鐘,並生成同步控制信號,以所需速率脈衝模擬'clock_v'和'clock_h'。將這些控制檯關閉。您也不應該將外部世界的異步信號引入同步邏輯,而不同步它們。這適用於重置以及任何其他信號。通過一對FF發送重置。 – 2014-11-23 17:23:49

+0

使用>和<布爾比較生成進行鏈比相等比較慢。 '* _active'信號由組合邏輯驅動,它會將延遲添加到任何連接它們的地方。儘可能通過插入寄存器來隔離這些延遲通常是一個好主意。在現代設備上,在50MHz頻率上這不是必要條件,但這是最佳實踐,並且在更高速度下變得更重要。 – 2014-11-23 17:30:46

2

因爲你不包括你的Famikon庫包,有人不得不查找VGA時間。 (您的代碼示例不是Minimal, Complete, and Verifiable example)。

詹寧斯一些東西讓你的設計,分析了添加這些:

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表示它缺乏適當地限制你的設計。

有一種老式VHDL VGA時序發生器,最近出現在堆棧Exchange問​​題上(請參閱VHDL VGA sync circuit)。它來自作者的companion website上可用的代碼清單壓縮下載中Pong P. Chu的書「FPGA原型化VHDL實例,XILINX SPARTAN-3版本」的第12章,文件名list_ch12_01_vga_sync.vhd。 正如Brian Drummond指出,對於那些不願意使用編輯器搜索或打印輸出的人來說,閱讀起來很難,因此將橫向和縱向計數器分佈在三個過程語句中(原始設計規範的視圖對於某些口味而言過於單調,並且似乎過多流程)。

Brian還有一個附加答案,它提供了一個組合過程的例子,並顯示了垂直計數器在水平計數器中的嵌套。它還顯示從「0000000000」(0)開始的非消隱水平和垂直間隔。您可能會注意到,Brian還對與h_active和v_active保持未註冊的等效信號進行了評論。