使用DOT來描述你的狀態機

在數位設計中,最常用到技巧之一便是所謂的有限狀態機(Finite State Machine, FSM)。但是,撰寫FSM的Verilog時,您都怎麼來註解Verilog以表示這是一個FSM呢?也許大家都有自己的技巧吧。可是,我相信最佳描述FSM的技巧就是使用狀態圖。問題是,Verilog是純文字檔,你不能像在Word或是Visio裡面一樣畫圖。只能使用ASCII來做。用ASCII來畫圖?的確是可以,但是好像怪怪的。

我要介紹另外一個工具。這個免費的工具叫做Graphviz 。它是專門用來畫各種有向圖與無向圖。而且不是像Visio那樣使用圖形介面來畫,而是使用一種叫做dot的language來畫。OK,有人聽到要再學一個language,可能已經開始準備關掉這個網頁了!等一下,別急!完整的dot學起來,當然很花時間,不過如果我們只要用到畫FSM的部份,就很簡單,很直覺了。

大家都知道FSM其實就是某種有向圖。有向圖主要由兩個東西組成,一個是node,另外一個是有向的edge。而且,有向圖的node與edge都各自有自己的label。

先讓我們考慮一個非常簡單的FSM。

case (state)  
`S0:  
begin  
 state <= (x == 1'b0 ? `S0 : `S1);   
 z <= 1'b0;   
end  
`S1:  
begin  
 state <= (x == 1'b1 ? `S0 : `S1);   
 z <= 1'b1;   
end  
endcase 這是一個非常簡單的Moore FSM。現在我們就看看如何用dot來描述它。在 dot中,註解的寫法與Verilog或是C/C++是一樣的。而且它規定一個有向圖一定是digraph NAME { .... }這樣的形式。請看下面:  

digraph G {  
// Graph attributes  
graph [rankdir="LR"];  

// State trasition.  
"start" -> "S0/0" [label="reset"];  
"S0/0" -> "S1/1" [label="1"];  
"S1/1" -> "S0/0" [label="0"];  

// self loop.  
"S0/0" -> "S0/0" [label="0"];  
"S1/1" -> "S1/1" [label="1"];  
}  

非常好理解吧?要表示node A到另一個node B,寫法就像是

"A" -> "B" [label="edge label"];

對於dot來說,只要名字不一樣,就會視為不同的node。而node與node之間的關係,dot會幫你處理的好好的。也就是說,上面這個dot language的順序是沒有關係的。我之所以把self loop的部份特別擺在下面,單純是為了讓自己好懂而已,你要擺上面一點,或是怎麼樣的穿插都無所謂,只要node名字別不小心打錯,dot都會幫你處理的很好的。

此外,那個rankdir指的是要求node的擺法是由左到右,如果將那行拿掉,dot預設會由上到下的擺放node。不過這樣似乎與我們在教科書常見的擺法不同。

現在只要把Graphviz的工具安裝一下。接著,可以透過下面的命令來產生出圖形。

dot.exe -o fsm.png -T png fsm.dot

首先,你要開一個名為fsm.dot的文字檔,將前面的dot程式碼複製到檔案中,然後透過上面這個命令,就可以產生一個名為fsm.png的檔案。我想應該沒有人不知道怎麼看png檔吧?

因為,前面的dot程式碼是放在你的Verilog中。如果想看的時候,還要copy到一個檔案中,然後再下命令,其實有點煩。您可以建立一個batch檔案。其內容如下:

dot.exe -o fsm.png -T png < con

fsm.png

您只要執行這個batch檔案,就會被要求輸入資料。接著把從Verilog註解中剪下的dot程式碼貼上,然後按下"ctrl+z"。就會看到與教科書一模一樣的狀態圖出現在你眼前囉!舉上面的例子來說,所產生出的圖形如下:

[![][5]][6]

能夠產生出這樣的圖形,我想不會有人對您的Verilog註解有所挑剔了吧?至少在FSM這個部份是這樣啦!而且,dot程式碼本身就已經非常直覺了。就算沒有轉成圖形,放在註解中也非常容易讓人明暸你想描述的狀態機。

前面的dot範例程式有個不好的地方,就是self loop的部份被分開來了。若想直接透過dot看出狀態圖時,比較沒有那麼直覺。不過,沒關係,我們可以改良一下。

digraph G {

// Graph attributes

graph [rankdir="LR"];

// Initial trasition.  
"start" -> "S0/0" [label="reset"];  

// State S0 trasition.  
"S0/0" -> "S0/0" [label="0"];  
"S0/0" -> "S1/1" [label="1"];  

// State S1 trasition.  
"S1/1" -> "S1/1" [label="1"];  
"S1/1" -> "S0/0" [label="0"];  
}  

這樣有沒有比較清楚一點?也就是將同一個state的描述寫在一起。如此可能連產生圖形都不用,就能直接瞭解一些簡單的FSM了!

我們軟體人員開發C/C++程式時,有時候會使用如Doxygen這種工具,它可以把程式裡的註解弄成文件。如果你註解裡有 dot 程式碼,它還會自動幫你變成圖形,嵌入在產生出來的文件中。真是一個非常好用的工具,不清楚Verilog裡面有沒有這樣的工具了。或者,也許哪天Doxygen可以支援Verilog,那就非常perfect了!!

comments powered by Disqus