2013-01-10 70 views
4

我在VHDL中看到的很多FSM都是通過在FSM邏輯中設置一個變量「next_state」,然後將其單獨分配給進程之外的狀態變量。VHDL FSM中的狀態管理

如果簡單地寫入「state <= state_five」有任何問題,改爲設置下一個狀態? 我假設有一個原因,許多人使用單獨的下一個狀態變量,而不是直接分配到狀態,因爲我一直看到它,但據我所知,除了它之外沒有區別使代碼更長,更復雜。

我錯過了什麼嗎?還是僅僅是一個風格問題?如果是這樣,爲什麼這種風格更好,對我來說似乎沒有必要。

回答

6

「簡單地寫state <= state_five;有什麼不對嗎?」

什麼都沒有 - 提供狀態分配是在一個鐘控過程中完成的。

這導致了簡潔可靠的「單一進程狀態機」風格,而不是不可靠的(因爲它很容易讓敏感性列表錯誤),這是兩種過程風格,這種風格在許多教科書和在線教程中都有教導。

搜索「單一進程狀態機」,你應該能夠找到很好的示例材料和進一步的討論。

歷史註釋:上個世紀可能有一些綜合工具存在單進程風格問題;但現在沒有理由避免它。

2

甚至使用一個變量:

state := state_five 

使用變量來存儲狀態意味着它仍然完全本地的過程,不會污染整個architecture的命名空間。

這也意味着,如果你在用printf(對不起report)來跟蹤調試時,狀態機的進展(這有時是最好的波形觀衆)的習慣,你可以報告預期下一個狀態在狀態機進程結束時,這可以很方便。

補充: 正如評論指出的那樣,變量賦值發生「瞬間」(是明確的 - 這不會導致case聲明立即切換到下一個狀態,儘管!)

這個效果如果您需要提前輸出一個循環 - 通過根據過程結束時的下一個狀態分配所述信號,可以有利於(偶爾)。如果我最終需要這樣做,我傾向於有一個明確的next_state變量,除了case聲明和state := next_state;(這正好在鍾控過程結束時)之外,我使用該變量。它向代碼審查人員證明您打算這樣做!

+0

好主意也許:)我的理解是變量的賦值發生在他們寫的地方,而信號的變化發生在過程的結尾。我想在實踐中,除了在switch語句中,你不會看到狀態,所以它沒什麼區別。 – jcoder

+0

關於你的next_state變量技術;有趣的想法,但是你的代碼中的每個狀態都會在不同的地方發生。 (儘管在這種情況下,這兩個地方是在同一個進程中)。帶有下一個信號的雙進程狀態機的好處在於,你有一個case語句,其中每個狀態的所有賦值(同步和併發)都在一樣的地方。這可以更容易閱讀。 (並不是說我是這種風格的狂熱粉絲,只是試圖使討論更加平衡)。 – pc3e

+0

@ pc3 - 如果使用next_state變量,它與雙進程系統並沒有太大的不同。但它仍然具有單個進程的特性(例如,沒有鎖存器,所有輸出端都有一個DFF,所有內容都保持在一起,狀態在單個進程中是局部的,信號混亂少)。正如你在答案中所陳述的那樣,如果你絕對不得不減少等待時間,你仍然無法實現你可以採用雙進程方法。 –

3

有些人總是編寫雙進程狀態機(也就是說,一個同步進程和一個併發進程)的原因很可能主要是因爲他們在學校學會這樣做,就像其他人說的那樣。

但是,在某些情況下,這種編碼風格實際上可能比具有單個同步過程更好。簡而言之,它允許您在同一上下文中混合同步和併發分配。考慮下面的兩段代碼,都完成同樣的事情:

雙進程狀態機:

process (clk) 
begin 
    if rising_edge(clk) then 
    state <= state_next; 
    end if; 
end process; 

process (all) 
begin 
    state_next <= state; 
    case state is 
    when s_idle => 
     if req_i = '1' then 
     fifo_read <= '1'; -- Concurrent assignment 
     state_next <= s_check_data; -- "Synchronous" assignment 
     end if; 
    when s_check_data => 
     if fifo_out = x"1234" then 
     (...) 
     end if; 
    (...) 
    end case; 
end process; 

單進程狀態機:

process (clk) 
begin 
    if rising_edge(clk) then 
    case state is 
     when s_idle => 
     if req_i = '1' then 
      fifo_read <= '1'; 
      state <= s_wait_for_data; 
     end if; 
     when s_wait_for_data => 
     state <= s_check_data; 
     when s_check_data => 
     -- Data word from FIFO now available. 
     if fifo_out = x"1234" then 
      (...) 
     end if; 
     (...) 
    end case; 
    end if; 
end process; 

請注意,在額外的狀態第二個例子。因爲沒有辦法在VHDL的同步過程中進行併發賦值(我希望有!),寄存器將被添加到fifo_read信號,延遲一個週期。雖然這個例子很簡單,但總是堅持單進程狀態機有時會導致代碼變得非常混亂並且很難遵循這個原因。它還可能導致狀態機在硬件上花費更多資源,甚至使代碼變得更長。兩種風格都不是正確的選擇,但我通常更喜歡單一過程的變體。