2012年11月1日 星期四

有限狀態機FSM coding style整理 (SOC) (Verilog)


源自於
http://www.cnblogs.com/oomusou/archive/2011/06/05/fsm_coding_style.html

有限狀態機FSM coding style整理 (SOC) (Verilog)

Abstract
FSM在數位電路中非常重要,藉由FSM,可以讓數位電路也能循序地執行起演算法。本文將詳細討論各種FSM coding style的優缺點,並歸納出推薦的coding style。
Introduction
使用環境:Debussy 5.4 v9 + ModelSim SE 6.3e + Quartus II 8.1
本文將討論以下主題:
1.Moore FSM的架構
2.Moore FSM各種coding style比較
3.Mealy FSM架構
4.Mealy FSM各種coding style比較
5.實務上推薦的coding style
6.Conclusion
若要讓數位電路也能循序地執行演算法,最簡單的方式可以使用D-FF產生counter,根據counter的值去決定要執行不同的程式碼,如此也能達到使數位電路循序執行演算法的目的,不過這種方式僅適用於很簡單的演算法,在一般規模的演算法若使用counter方式,程式碼將不容易維護,所以實務上會使用FSM方式來實現演算法。
其實FSM方式也是利用counter來實現,所謂的counter,並不是只有counter = counter + 1才算是counter,FSM的state register就是廣義的counter,只是這種counter不是一直加1而已,而是有自己的遞增規則。FSM只是提供了一種較為高階與較容易維護的方式來實現演算法。
Moore FSM架構
 fsm00
一般在寫FSM時,會以Moore FSM為主,所以先討論Moore。由上圖可知,Moore FSM內部由3個block所構成:Next state logic,State register與Output logic。
Next state logic:純粹的組合邏輯,以整個module的input與目前的state為輸入,目的在產生下一個state值存入state register。
State register:由D-FF所構成,將Next state logic所產生的state存入register。
Output logic:純粹的組合邏輯,根據目前的state產生整個module的output。
所以可以發現,整個Moore FSM事實上是由2塊的組合邏輯與1塊D-FF所構成,我們常聽到所謂的一段式、二段式與三段式FSM,事實上就是由這3個block排列組合而成。
Moore FSM各種coding style比較
fsm02
為了要實際比較各種coding style,在此舉一個簡單的例子,若input w_i為連續2個clk為high,則output會在下1個clk產生周期為1 T的high pulse,timing diagram如上圖所示。
fsm01
因此設計了Moore FSM,state diagram如上圖所示,接下來要做的就是用各種coding style來實現這個Moore FSM。
1.使用3個always (三段式)
fsm04
simple_fsm_moore_3_always_best.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_moore_3_always_best.v 5 Synthesizer : Quartus II 8.1 6 Description : 3 always block for moore fsm (BEST) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 parameter S1   = 2'b10;
25 
26 reg [1:0] curr_state;27 reg [1:0] next_state;28 reg z_o;29 
30 // state reg
31 always@(posedge clk or negedge rst_n)32   if (~rst_n) curr_state <= IDLE;33   else        curr_state <= next_state;34     35 // next state logic    
36 always@(*)37   case (curr_state)38     IDLE    : if (w_i) next_state = S0;39               else     next_state = IDLE;40     S0      : if (w_i) next_state = S1;41               else     next_state = IDLE;42     S1      : if (w_i) next_state = S1;43               else     next_state = IDLE;44     default :          next_state = IDLE;45   endcase    46 
47 // output logic
48 always@(*)49   case (curr_state)50     IDLE    : z_o = 1'b0;
51     S0      : z_o = 1'b0;
52     S1      : z_o = 1'b1;
53     default : z_o = 1'b0;
54   endcase
55   56 endmodule
复制代码
35行
复制代码
// next state logic    
always@(*)
  case (curr_state)
    IDLE    : if (w_i) next_state = S0;
              else     next_state = IDLE;
    S0      : if (w_i) next_state = S1;
              else     next_state = IDLE;
    S1      : if (w_i) next_state = S1;
              else     next_state = IDLE;
    default :          next_state = IDLE;
  endcase   
复制代码
使用1個always描述next state logic,因為是純粹組合邏輯,所以使用blocking。
根據Moore FSM架構圖所示,next state logic的結果與input與目前state有關,所以先用case對目前state做一次大分類,然後每個state再根據input做if判斷。
30行
// state reg
always@(posedge clk or negedge rst_n)
  if (~rst_n) curr_state <= IDLE;
  else        curr_state <= next_state;
使用1個always描述state register,因為是D-FF且含clk,所以使用nonblocking。
由於state register區塊並不包含任何邏輯,所以不會因為不同FSM而有不同寫法,不同FSM只會改變next state logic與output logic的寫法。
47行
复制代码
// output logic
always@(*)
  case (curr_state)
    IDLE    : z_o = 1'b0;
    S0      : z_o = 1'b0;
    S1      : z_o = 1'b1;
    default : z_o = 1'b0;
  endcase
复制代码
使用1個always描述output logic,因為是純粹組合邏輯,所以使用blocking。
根據Moore FSM架構圖所示,output logic的結果只與目前state有關,所以只需用case對state做一次分類即可。
使用3個always寫法有幾個優點:
1.可忠實地反映出原本的Moore FSM硬體架構2.可輕易地將state diagram改用Verilog表示3.將Next state logic與output logic分開,可降低code的複雜度,便於日後維護
3個always是一個推薦的寫法。
Testbench
simple_fsm_tb.v / Verilog
复制代码
1 /* 2 (C) OOMusou 2011 http://oomusou.cnblogs.com
3 
4 Filename : simple_fsm_tb.v5 Simulator : ModelSim SE 6.3e + Debussy 5.4 v96 Description : testbench for FSM7 Release : Jun.05,2011 1.08  */
9 
10  module simple_fsm_tb;11 
12  reg clk = 1'b1;
13  reg rst_n = 1'b1;
14  reg w_i = 1'b0;
15  wire z_o;16 
17  // clk
18  always #10 clk = ~clk;19 
20  event after_rst;21 
22  // rst_n
23  initial begin
24   #6; // 6ns
25   rst_n = 1'b0;
26   #30; // 36ns
27   rst_n = 1'b1;
28   ->after_rst; 29  end
30 
31  // w_i
32  initial begin
33   @(after_rst);34   repeat(2)@(posedge clk); // 60ns
35   w_i <= 1'b1;
36   @(posedge clk); // 80 ns
37   w_i <= 1'b0;
38   @(posedge clk); // 100 ns
39   w_i <= 1'b1;
40   repeat(2)@(posedge clk); // 140 ns
41   w_i <= 1'b0;
42   @(posedge clk); // 160 ns
43   w_i <= 1'b1;
44   repeat(3)@(posedge clk); // 220 ns
45   w_i <= 1'b0;
46 end
47 
48 initial begin
49   $fsdbDumpfile("simple_fsm.fsdb");50   $fsdbDumpvars(0, simple_fsm_tb);51 end
52 
53 simple_fsm u_simple_fsm (54   .clk (clk),55   .rst_n (rst_n),56   .w_i (w_i),57   .z_o (z_o)58 );59 
60 endmodule
复制代码
執行結果
 fsm05
2.使用2個always (二段式)
由於要使用2個always去描述3個block,根據排列組合原理,C3取2,共有3種可能,我們一個一個討論。
2.1 state register與next state logic合一
fsm06 
simple_fsm_moore_2_always_0_cs_ns_good.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_moore_2_always_0_cs_ns_good.v 5 Synthesizer : Quartus II 8.1 6 Description : 2 always block for moore fsm (GOOD) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 parameter S1   = 2'b10;
25 
26 reg [1:0] curr_state;27 reg z_o;28 
29 // state reg + next state logic
30 always@(posedge clk or negedge rst_n)31   if (~rst_n) curr_state <= IDLE;32   else
33     case (curr_state)34       IDLE    : if (w_i) curr_state <= S0;35                 else     curr_state <= IDLE;36       S0      : if (w_i) curr_state <= S1;37                 else     curr_state <= IDLE;38       S1      : if (w_i) curr_state <= S1;39                 else     curr_state <= IDLE;40       default :          curr_state <= IDLE;41     endcase
42     43 // output logic
44 always@(*)45   case (curr_state)46     IDLE    : z_o = 1'b0;
47     S0      : z_o = 1'b0;
48     S1      : z_o = 1'b1;
49     default : z_o = 1'b0;
50   endcase
51   52 endmodule
复制代码
29行
复制代码
// state reg + next state logic
always@(posedge clk or negedge rst_n)
  if (~rst_n) curr_state <= IDLE;
  else
    case (curr_state)
      IDLE    : if (w_i) curr_state <= S0;
                else     curr_state <= IDLE;
      S0      : if (w_i) curr_state <= S1;
                else     curr_state <= IDLE;
      S1      : if (w_i) curr_state <= S1;
                else     curr_state <= IDLE;
      default :          curr_state <= IDLE;
    endcase
复制代码
將state register與next state logic合起來用1個always去描述,雖然next state logic是純粹的組合邏輯,為了遷就於帶clk的state register,且要用一個always描述,就必須改用nonblocking。
由於state register與next state logic合一,所以可以少宣告next_state reg,不過這並不會影響合成結果,只是可以少打幾個字而已。
因為next state logic由input與state所構成,所以先用case對state做一次大分類,然後每個state再根據input做if判斷。
43行
复制代码
// output logic
always@(*)
  case (curr_state)
    IDLE    : z_o = 1'b0;
    S0      : z_o = 1'b0;
    S1      : z_o = 1'b1;
    default : z_o = 1'b0;
  endcase
复制代码
使用1個always描述output logic,因為是純粹組合邏輯,所以使用blocking。
根據Moore FSM架構圖所示,output logic的結果只與目前state有關,所以只需用case對state做一次分類即可。
使用2個always (state register與next state logic合一)寫法有幾個優點:
1.程式碼較3個always寫法精簡2.可輕易地將state diagram改用Verilog表示3.因為state register原本程式碼就不多,將next state logic與state register合一後,next state logic仍與output logic分開,因此不會增加code的複雜度,便於日後維護
2個always (state register與next state logic合一)也是一個推薦的寫法。
接下來要討論的都是不推薦的寫法,主要目的是了解為什麼不推薦的原因。
2.2 state register與output logic合一
fsm07
simple_fsm_moore_2_always_1_cs_ol_ng.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_moore_2_always_1_cs_ol_ng.v 5 Synthesizer : Quartus II 8.1 6 Description : 2 always block for moore fsm (NO GOOD) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 parameter S1   = 2'b10;
25 
26 reg [1:0] curr_state;27 reg [1:0] next_state;28 reg z_o;29 
30 // state reg + output logic
31 always@(posedge clk or negedge rst_n)32   if (~rst_n) {curr_state, z_o} <= {IDLE, 1'b0};
33   else begin
34     curr_state <= next_state;35     36     case (next_state)37       IDLE    : z_o <= 1'b0;
38       S0      : z_o <= 1'b0;
39       S1      : z_o <= 1'b1;
40       default : z_o <= 1'b0;
41     endcase
42   end
43 
44 // next state logic    
45 always@(*)46   case (curr_state)47     IDLE    : if (w_i) next_state = S0;48               else     next_state = IDLE;49     S0      : if (w_i) next_state = S1;50               else     next_state = IDLE;51     S1      : if (w_i) next_state = S1;52               else     next_state = IDLE;53     default :          next_state = IDLE;54   endcase    55 
56 endmodule
复制代码
30行
复制代码
// state reg + output logic
always@(posedge clk or negedge rst_n)
  if (~rst_n) {curr_state, z_o} <= {IDLE, 1'b0};
  else begin
    curr_state <= next_state;
    
    case (next_state)
      IDLE    : z_o <= 1'b0;
      S0      : z_o <= 1'b0;
      S1      : z_o <= 1'b1;
      default : z_o <= 1'b0;
    endcase
复制代码
將state register與output logic合起來用1個always去描述,雖然output logic是純粹的組合邏輯,為了遷就於帶clk的state register,且要用一個always描述,就必須改用nonblocking。
因為output logic只與state有關,所以只用case對state做一次分類即可。
這種寫法最大的問題是:output logic必須用next_state去判斷!!
依照Moore FSM的架構圖得知,output logic只與目前state有關,之前的幾種FSM寫法,output logic也是由目前state去判斷,為什麼這種寫法要靠next_state去判斷呢?
主要原因是根據Moore FSM的定義,output logic只與目前state有關,且是個純粹的組合邏輯,但目前強迫將state register與output logic放在同一個always,迫使output logic必須使用nonblocking的方式呈現,也就是若output logic仍然使用目前state去做判斷,則output logic會多delay 1個clk,為了讓output logic結果正常,只好提前1個clk做判斷,也就是提前到next_state去做判斷。
所以當我們從state diagram換成Verilog表示時,若使用2個always,且是state register與output logic合一時,必須很小心要使用next_state去做output logic判斷,因為這個地方很不直覺,很容易出錯,所以不推薦這種寫法。
44行
复制代码
// next state logic    
always@(*)
  case (curr_state)
    IDLE    : if (w_i) next_state = S0;
              else     next_state = IDLE;
    S0      : if (w_i) next_state = S1;
              else     next_state = IDLE;
    S1      : if (w_i) next_state = S1;
              else     next_state = IDLE;
    default :          next_state = IDLE;
  endcase    
复制代码
使用1個always描述next state logic,因為是純粹組合邏輯,所以使用blocking。
根據Moore FSM架構圖所示,next state logic的結果與input與目前state有關,所以先用case對目前state做一次大分類,然後每個state再根據input做if判斷。
使用2個always (state register與output logic合一)寫法的缺點:
當使用1個always去描述state register與output logic時,output logic必須使用next_state做判斷,而非用目前state判斷,由於寫法不直覺,一不小心很容易弄錯
不推薦2個always (state register與output logic合一)寫法。
或許你會說,在實務上卻常看到state register與output logic合一的寫法,為什麼不會出問題?那是因為儘管是用Moore FSM,我們為了timing更好,常會在output時多敲一個D-FF,讓Output Logic的組合邏輯不要與其他module的input的組合邏輯合併,避免造成critical path,假如是這種需求,state register與output logic合一後,可以直接判斷curr_state,不用提早一個clk判斷next_state。
2.3 next state logic與output logic合一
fsm08
simple_fsm_moore_2_always_2_ns_ol_ng.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_moore_2_always_2_ns_ol_ng.v 5 Synthesizer : Quartus II 8.1 6 Description : 2 always block for moore fsm (NO GOOD) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 parameter S1   = 2'b10;
25 
26 reg [1:0] curr_state;27 reg [1:0] next_state;28 reg z_o;29 
30 // state reg
31 always@(posedge clk or negedge rst_n)32   if (~rst_n) curr_state <= IDLE;33   else        curr_state <= next_state;34     35 // next state logic + output logic 
36 always@(*)37   case (curr_state)38     IDLE    : if (w_i)   {next_state, z_o} = {S0  , 1'b0};
39               else       {next_state, z_o} = {IDLE, 1'b0};
40     S0      : if (w_i)   {next_state, z_o} = {S1  , 1'b0};
41               else       {next_state, z_o} = {IDLE, 1'b0};
42     S1      : if (w_i)   {next_state, z_o} = {S1  , 1'b1}; // always output 1'b143               else       {next_state, z_o} = {IDLE, 1'b1}; // always output 1'b144     default :            {next_state, z_o} = {IDLE, 1'b0};
45   endcase
46 
47 endmodule
复制代码
30行
// state reg
always@(posedge clk or negedge rst_n)
  if (~rst_n) curr_state <= IDLE;
  else        curr_state <= next_state;
使用1個always描述state register,因為是D-FF且含clk,所以使用nonblocking。
由於state register區塊並不包含任何邏輯,所以不會因為不同FSM而有不同寫法,不同FSM只會改變next state logic與output logic的寫法。
35行
复制代码
// next state logic + output logic 
always@(*)
  case (curr_state)
    IDLE    : if (w_i)   {next_state, z_o} = {S0  , 1'b0};
              else       {next_state, z_o} = {IDLE, 1'b0};
    S0      : if (w_i)   {next_state, z_o} = {S1  , 1'b0};
              else       {next_state, z_o} = {IDLE, 1'b0};
    S1      : if (w_i)   {next_state, z_o} = {S1  , 1'b1}; // always output 1'b1
              else       {next_state, z_o} = {IDLE, 1'b1}; // always output 1'b1
    default :            {next_state, z_o} = {IDLE, 1'b0};
  endcase
复制代码
將next state logic與output logic使用同一個always去描述,由於next state logic與output logic都是純粹的組合邏輯,所以使用blocking描述沒有問題。
由於next state logic與input與目前state有關,但output logic卻只與目前state有關,因為都是先用目前state做case判斷,然後再對input做if判斷,所以會出現output兩次都出現1的情形,起因於output logic只與目前state有關,與input無關,固任何input都會出現1。
使用2個always (next state logic與output logic合一)寫法的缺點:
1.將next state logic與output logic合一只會增加code的複雜度,日後維護會更加困難2.很類似Mealy FSM寫法,容易讓人誤以為是Mealy FSM
不推薦2個always (next state logic與output logic合一)寫法。
3.使用1個always (一段式)
fsm03 
simple_fsm_moore_1_always_ng.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_moore_1_always_ng.v 5 Synthesizer : Quartus II 8.1 6 Description : 1 always block for moore fsm (NO GOOD) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE  = 2'b00;
23 parameter S0    = 2'b01;
24 parameter S1    = 2'b10;
25 
26 reg [1:0] curr_state;27 reg z_o;28 
29 always@(posedge clk or negedge rst_n)30   if (~rst_n) {curr_state, z_o} <= {IDLE, 1'b0};
31   else
32     case (curr_state)33       IDLE    : if (w_i) {curr_state, z_o} <= {S0,   1'b0};
34                 else     {curr_state, z_o} <= {IDLE, 1'b0};
35       S0      : if (w_i) {curr_state, z_o} <= {S1,   1'b1}; //?
36                 else     {curr_state, z_o} <= {IDLE, 1'b0};
37       S1      : if (w_i) {curr_state, z_o} <= {S1,   1'b1};
38                 else     {curr_state, z_o} <= {IDLE, 1'b0}; //?
39       default :          {curr_state, z_o} <= {IDLE, 1'b0};
40     endcase
41 
42 endmodule
复制代码
29行
复制代码
always@(posedge clk or negedge rst_n)
  if (~rst_n) {curr_state, z_o} <= {IDLE, 1'b0};
  else
    case (curr_state)
      IDLE    : if (w_i) {curr_state, z_o} <= {S0,   1'b0};
                else     {curr_state, z_o} <= {IDLE, 1'b0};
      S0      : if (w_i) {curr_state, z_o} <= {S1,   1'b1}; //?
                else     {curr_state, z_o} <= {IDLE, 1'b0};
      S1      : if (w_i) {curr_state, z_o} <= {S1,   1'b1};
                else     {curr_state, z_o} <= {IDLE, 1'b0}; //?
      default :          {curr_state, z_o} <= {IDLE, 1'b0};
    endcase
复制代码
使用1個always同時描述next state logic、state register與output logic,雖然next state logic與output logic是純粹的組合邏輯,但為了遷就於帶clk的state register,所以必須使用nonblocking。
根據之前的經驗,由於Moore FSM的output logic只與目前state state有關,且是純粹的組合邏輯,若硬要與state register用同一個always去描述,判斷上會出現一些問題,需提早1個clk用next state判斷(在state register與output logic合一時曾經遇過)。
在1個always內,連next_state也省了,所以在35行
S0 : if (w_i) {curr_state, z_o} <= {S1, 1'b1};
當目前state為S0且輸入為1'b1時,output必須提前為1,因為這是在nonblocking內!!
37行
S1 : if (w_i) {curr_state, z_o} <= {S1, 1'b1};
同理,在目前state為S1且輸入為1'b1時,output也必須提前為1,也因為這是在nonblocking內!!
使用1個always寫法的缺點:
1.因為使用nonblocking去描述output logic,所以要提早1個clk判斷,要特別小心處理,一不小心很容易弄錯2.1個always內同時包含next state logic與output logic,會增加code的複雜度,日後維護更加困難
不推薦1個always寫法。
Mealy FSM架構
fsm09
談完了Moore FSM,接下來談Mealy FSM,與Moore FSM的差別只在於Moore FSM的output logic只由目前state決定,但是Mealy FSM可由目前state與input共同決定。
Mealy FSM各種coding style比較
fsm11
將之前的例子用Mealy FSM重新改寫,原本在Moore FSM下,若input w_i為連續2個clk為high,則output會在下1個clk產生週期為1 T的high pulse,若改用Mealy FSM,則output會提早1個clk出現,如上圖所示。
fsm10
原本Moore FSM需要3個state,若改用Mealy FSM後,會只剩下2個state,接下來要用各種coding style來實現Mealy FSM。
1.使用3個always (三段式)
fsm12
simple_fsm_mealy_3_always_best.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_mealy_3_always_best.v 5 Synthesizer : Quartus II 8.1 6 Description : 3 always block for mealy fsm (BEST) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 
25 reg [1:0] curr_state;26 reg [1:0] next_state;27 reg z;28 reg z_o;29 
30 // state reg
31 always@(posedge clk or negedge rst_n)32   if (~rst_n) curr_state <= IDLE;33   else        curr_state <= next_state;34     35 // next state logic    
36 always@(*)37   case (curr_state)38     IDLE    : if (w_i) next_state = S0;39               else     next_state = IDLE;40     S0      : if (w_i) next_state = S0;41               else     next_state = IDLE;42     default :          next_state = IDLE;43   endcase    44 
45 // output logic
46 always@(*)47   case (curr_state)48     IDLE    : if (w_i) z = 1'b0;
49               else     z = 1'b0;      
50     S0      : if (w_i) z = 1'b1;
51               else     z = 1'b0;
52     default :          z = 1'b0;
53   endcase
54 
55 // mealy output to delay 1 clk for moore  
56 always@(posedge clk or negedge rst_n)57   if (~rst_n) z_o <= 1'b0;
58   else        z_o <= z;59     60 endmodule
复制代码
30行
// state reg
always@(posedge clk or negedge rst_n)
  if (~rst_n) curr_state <= IDLE;
  else        curr_state <= next_state;
使用1個always描述state register。
35行
复制代码
// next state logic    
always@(*)
  case (curr_state)
    IDLE    : if (w_i) next_state = S0;
              else     next_state = IDLE;
    S0      : if (w_i) next_state = S0;
              else     next_state = IDLE;
    default :          next_state = IDLE;
  endcase  
复制代码
使用1個always描述next state logic。
45行
复制代码
// output logic
always@(*)
  case (curr_state)
    IDLE    : if (w_i) z = 1'b0;
              else     z = 1'b0;      
    S0      : if (w_i) z = 1'b1;
              else     z = 1'b0;
    default :          z = 1'b0;
  endcase
复制代码
使用1個always描述output logic。
以上3個always寫法與Moore FSM的3個always並無差異,基本上只要state diagram畫的出來,就能等效地用Verilog描述出來。
55行
// mealy output to delay 1 clk for moore  
always@(posedge clk or negedge rst_n)
  if (~rst_n) z_o <= 1'b0;
  else        z_o <= z;
之前提到使用Mealy FSM會少Moore FSM 1個state,且output會早Moore FSM 1個clk,所以最後特別將output在敲一級delay 1個clk,這樣Mealy FSM就會完全與Moore FSM一樣。
使用3個always寫法有幾個優點:
1.可忠實地反映出原本的Mealy FSM硬體架構2.可輕易地將state diagram改用Verilog表示3.將Next state logic與output logic分開,可降低code的複雜度,便於日後維護
3個always是一個推薦的寫法。
2.使用2個always (兩段式)
由於要使用2個always去描述3個block,根據排列組合原理,C3取2,共有3種可能,我們一個一個討論。
2.1 state register與next state logic合一
fsm13
simple_fsm_mealy_2_always_0_cs_ns_good.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_mealy_2_always_0_cs_ns_good.v 5 Synthesizer : Quartus II 8.1 6 Description : 2 always block for mealy fsm (GOOD) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 
25 reg [1:0] curr_state;26 reg z;27 reg z_o;28 
29 // state reg + next state logic
30 always@(posedge clk or negedge rst_n)31   if (~rst_n) curr_state <= IDLE;32   else
33     case (curr_state)34       IDLE    : if (w_i) curr_state <= S0;35                 else     curr_state <= IDLE;36       S0      : if (w_i) curr_state <= S0;37                 else     curr_state <= IDLE;38       default :          curr_state <= IDLE;39     endcase
40     41 // output logic
42 always@(*)43   case (curr_state)44     IDLE    : if (w_i) z = 1'b0;
45               else     z = 1'b0;
46     S0      : if (w_i) z = 1'b1;
47               else     z = 1'b0;
48     default :          z = 1'b0;
49   endcase
50 
51 // mealy output to delay 1 clk for moore  
52 always@(posedge clk or negedge rst_n)53   if (~rst_n) z_o <= 1'b0;
54   else        z_o <= z;55 
56 endmodule
复制代码
29行
复制代码
// state reg + next state logic
always@(posedge clk or negedge rst_n)
  if (~rst_n) curr_state <= IDLE;
  else
    case (curr_state)
      IDLE    : if (w_i) curr_state <= S0;
                else     curr_state <= IDLE;
      S0      : if (w_i) curr_state <= S0;
                else     curr_state <= IDLE;
      default :          curr_state <= IDLE;
    endcase
复制代码
使用1個always同時描述state register與next state logic。
41行
复制代码
// output logic
always@(*)
  case (curr_state)
    IDLE    : if (w_i) z = 1'b0;
              else     z = 1'b0;
    S0      : if (w_i) z = 1'b1;
              else     z = 1'b0;
    default :          z = 1'b0;
  endcase
复制代码
使用1個always描述output logic。
以上2個always寫法(state register與next state logic合一)與Moore FSM的2個always寫法(state register與next state logic合一)並無差異,基本上只要state diagram畫的出來,就能等效地用Verilog描述出來。
51行
// mealy output to delay 1 clk for moore  
always@(posedge clk or negedge rst_n)
  if (~rst_n) z_o <= 1'b0;
  else        z_o <= z;
之前提到使用Mealy FSM會少Moore FSM 1個state,且output會早Moore FSM 1個clk,所以最後特別將output在敲一級delay 1個clk,這樣Mealy FSM就會完全與Moore FSM一樣。
使用2個always (state register與next state logic合一)寫法有幾個優點:
1.程式碼較3個always寫法精簡2.可輕易地將state diagram改用Verilog表示3.因為state register原本程式碼就不多,將next state logic與state register合一後,next state logic仍與output logic分開,因此不會增加code的複雜度,便於日後維護
2個always (state register與next state logic合一)也是一個推薦的寫法。
接下來要討論的都是不推薦的寫法,主要目的是了解為什麼不推薦的原因。
2.2 state register與output logic合一
fsm14
雖然理論上可以用1個always同時描述state register與output logic,但實際上做不到,因為Mealy FSM的output logic是目前state與input的純粹組合邏輯,與state register合一後,就必須使用nonblocking描述,之前Moore FSM還可以提前一個state去做判斷,但Mealy FSM還有input,該如何提前1個clk去判斷input呢?
2個always (state register與output logic合一)無法描述Mealy FSM。
2.3 next state logic與output logic合一
fsm15
simple_fsm_mealy_2_always_2_ns_ol_ng.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_mealy_2_always_2_ns_ol_ng.v 5 Synthesizer : Quartus II 8.1 6 Description : 2 always block for mealy fsm (NO GOOD) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 
25 reg [1:0] curr_state;26 reg [1:0] next_state;27 reg z;28 reg z_o;29 
30 // state reg
31 always@(posedge clk or negedge rst_n)32   if (~rst_n) curr_state <= IDLE;33   else        curr_state <= next_state;34     35 // next state logic + output logic   
36 always@(*)37   case (curr_state)38     IDLE    : if (w_i)   {next_state, z} = {S0  , 1'b0};
39               else       {next_state, z} = {IDLE, 1'b0};
40     S0      : if (w_i)   {next_state, z} = {S0  , 1'b1};
41               else       {next_state, z} = {IDLE, 1'b0};
42     default :            {next_state, z} = {IDLE, 1'b0};
43   endcase
44 
45 // mealy output to delay 1 clk for moore  
46 always@(posedge clk or negedge rst_n)47   if (~rst_n) z_o <= 1'b0;
48   else        z_o <= z;49 
50 endmodule
复制代码
30行
// state reg
always@(posedge clk or negedge rst_n)
  if (~rst_n) curr_state <= IDLE;
  else        curr_state <= next_state;
使用1個always描述state register。
35行
复制代码
// next state logic + output logic   
always@(*)
  case (curr_state)
    IDLE    : if (w_i)   {next_state, z} = {S0  , 1'b0};
              else       {next_state, z} = {IDLE, 1'b0};
    S0      : if (w_i)   {next_state, z} = {S0  , 1'b1};
              else       {next_state, z} = {IDLE, 1'b0};
    default :            {next_state, z} = {IDLE, 1'b0};
  endcase
复制代码
使用1個always同時描述next state logic與output logic,因為兩者都是純粹的組合邏輯,所以使用blocking。
45行
// mealy output to delay 1 clk for moore  
always@(posedge clk or negedge rst_n)
  if (~rst_n) z_o <= 1'b0;
  else        z_o <= z;
之前提到使用Mealy FSM會少Moore FSM 1個state,且output會早Moore FSM 1個clk,所以最後特別將output在敲一級delay 1個clk,這樣Mealy FSM就會完全與Moore FSM一樣。
使用2個always (next state logic與output logic合一)寫法的缺點:
將next state logic與output logic合一只會增加code的複雜度,日後維護會更加困難
不推薦2個always (next state logic與output logic合一)寫法。
3.使用1個always (一段式)
fsm16
理論上存在使用1個always同時描述next state logic、state register與output logic,但實際上做不到,理由與2個always (state register與output logic合一)的理由一樣,1個always必須使用nonblocking描述,而Mealy FSM的output logic是目前state與input的組合邏輯,我們無法提前1個clk去判斷input,所以無法使用1個always去描述。
1個always 無法描述Mealy FSM。
只要output logic使用nonblocking去描述,就無法實現Mealy FSM output。
實務上推薦的coding style
如之前所述,實務上為了timing更好,常在Moore FSM的output logic再多敲一級,以下為推薦的coding style:
fsm_n_00
1.使用2個always (兩段式)
fsm_n_01
simple_fsm_moore_2_always_0_cs_ns_good_pratical.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_moore_2_always_0_cs_ns_good.v 5 Synthesizer : Quartus II 8.1 6 Description : 2 always block for moore fsm (GOOD) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 parameter S1   = 2'b10;
25 
26 reg [1:0] curr_state;27 reg z_o;28 
29 // state reg + next state logic
30 always@(posedge clk or negedge rst_n)31   if (~rst_n) curr_state <= IDLE;32   else
33     case (curr_state)34       IDLE    : if (w_i) curr_state <= S0;35                 else     curr_state <= IDLE;36       S0      : if (w_i) curr_state <= S1;37                 else     curr_state <= IDLE;38       S1      : if (w_i) curr_state <= S1;39                 else     curr_state <= IDLE;40       default :          curr_state <= IDLE;41     endcase
42     43 // output logic
44 always@(posedge clk or negedge rst_n)45   if (~rst_n)46     z_o <= 1'b0;
47   else
48     case (curr_state)49       IDLE    : z_o <= 1'b0;
50       S0      : z_o <= 1'b0;
51       S1      : z_o <= 1'b1;
52       default : z_o <= 1'b0;
53     endcase
54   55 endmodule
复制代码
29行
复制代码
// state reg + next state logic
always@(posedge clk or negedge rst_n)
  if (~rst_n) curr_state <= IDLE;
  else
    case (curr_state)
      IDLE    : if (w_i) curr_state <= S0;
                else     curr_state <= IDLE;
      S0      : if (w_i) curr_state <= S1;
                else     curr_state <= IDLE;
      S1      : if (w_i) curr_state <= S1;
                else     curr_state <= IDLE;
      default :          curr_state <= IDLE;
    endcase
复制代码
使用2個always,且state register與next state logic合一,只要判斷curr_state即可,不用擔心是否要提早1個clk判斷。
43行
复制代码
// output logic
always@(posedge clk or negedge rst_n)
  if (~rst_n)
    z_o <= 1'b0;
  else
    case (curr_state)
      IDLE    : z_o <= 1'b0;
      S0      : z_o <= 1'b0;
      S1      : z_o <= 1'b1;
      default : z_o <= 1'b0;
    endcase
复制代码
output logic也敲clk,只要判斷curr_state即可,不用擔心是否要提早1個clk判斷。
2.使用3個always (三段式)
fsm_n_02
simple_fsm_moore_3_always_practical.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_moore_3_always_practical.v 5 Synthesizer : Quartus II 8.1 6 Description : 3 always block for moore fsm (BEST) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 parameter S1   = 2'b10;
25 
26 reg [1:0] curr_state;27 reg [1:0] next_state;28 reg z_o;29 
30 // state reg
31 always@(posedge clk or negedge rst_n)32   if (~rst_n) curr_state <= IDLE;33   else        curr_state <= next_state;34     35 // next state logic    
36 always@(*)37   case (curr_state)38     IDLE    : if (w_i) next_state = S0;39               else     next_state = IDLE;40     S0      : if (w_i) next_state = S1;41               else     next_state = IDLE;42     S1      : if (w_i) next_state = S1;43               else     next_state = IDLE;44     default :          next_state = IDLE;45   endcase    46 
47 // output logic
48 always@(posedge clk or negedge rst_n)49   if (~rst_n) z_o <= 1'b0;
50   else 51     case (curr_state)52       IDLE    : z_o <= 1'b0;
53       S0      : z_o <= 1'b0;
54       S1      : z_o <= 1'b1;
55       default : z_o <= 1'b0;
56     endcase
57   58 endmodule
复制代码
30行
// state reg
always@(posedge clk or negedge rst_n)
  if (~rst_n) curr_state <= IDLE;
  else        curr_state <= next_state;
使用1個always描述state register。
35行
复制代码
// next state logic    
always@(*)
  case (curr_state)
    IDLE    : if (w_i) next_state = S0;
              else     next_state = IDLE;
    S0      : if (w_i) next_state = S1;
              else     next_state = IDLE;
    S1      : if (w_i) next_state = S1;
              else     next_state = IDLE;
    default :          next_state = IDLE;
  endcase  
复制代码
使用1個always描述next state logic,為純粹組合邏輯,所以使用blocking。
47行
复制代码
// output logic
always@(posedge clk or negedge rst_n)
  if (~rst_n) z_o <= 1'b0;
  else 
    case (curr_state)
      IDLE    : z_o <= 1'b0;
      S0      : z_o <= 1'b0;
      S1      : z_o <= 1'b1;
      default : z_o <= 1'b0;
    endcase
复制代码
使用1個always描述output logic,因為output logic也敲clk,只要判斷curr_state即可,不用擔心是否要提早1個clk判斷。
看到這裡,或許你會問:『為了timing好,多敲一級會多delay一個clk,若我output logic提前1個clk用next_state判斷,不就既可有較好的timing,也不會多delay一個clk?』
fsm_n_03
1.使用3個always (三段式)
fsm_n_05
simple_fsm_moore_3_always_practical2.v / Verilog
复制代码
 1 /*  2 (C) OOMusou 2011 http://oomusou.cnblogs.com
 3 
 4 Filename    : simple_fsm_moore_3_always_practical2.v 5 Synthesizer : Quartus II 8.1 6 Description : 3 always block for moore fsm (BEST) 7 Release     : Jun.05,2011 1.0 8 */
 9 
10 module simple_fsm (11   clk,12   rst_n,13   w_i,14   z_o15 );16 
17 input  clk;18 input  rst_n;19 input  w_i;20 output z_o;21 
22 parameter IDLE = 2'b00;
23 parameter S0   = 2'b01;
24 parameter S1   = 2'b10;
25 
26 reg [1:0] curr_state;27 reg [1:0] next_state;28 reg z_o;29 
30 // state reg
31 always@(posedge clk or negedge rst_n)32   if (~rst_n) curr_state <= IDLE;33   else        curr_state <= next_state;34     35 // next state logic    
36 always@(*)37   case (curr_state)38     IDLE    : if (w_i) next_state = S0;39               else     next_state = IDLE;40     S0      : if (w_i) next_state = S1;41               else     next_state = IDLE;42     S1      : if (w_i) next_state = S1;43               else     next_state = IDLE;44     default :          next_state = IDLE;45   endcase    46 
47 // output logic
48 always@(posedge clk or negedge rst_n)49   if (~rst_n) z_o <= 1'b0;
50   else 51     case (next_state)52       IDLE    : z_o <= 1'b0;
53       S0      : z_o <= 1'b0;
54       S1      : z_o <= 1'b1;
55       default : z_o <= 1'b0;
56     endcase
57   58 endmodule
复制代码
47行
复制代码
// output logic
always@(posedge clk or negedge rst_n)
  if (~rst_n) z_o <= 1'b0;
  else 
    case (next_state)
      IDLE    : z_o <= 1'b0;
      S0      : z_o <= 1'b0;
      S1      : z_o <= 1'b1;
      default : z_o <= 1'b0;
    endcase
复制代码
使用1個always去描述output logic,重點是,使用next_state去判斷,因此可以提早一個clk,這樣無論是在Simulator或者經過Synthesizer合成後的結果都會一樣,而且既可在output敲過D flip-flop,也不會多delay一個clk。
不過這種寫法也不是沒有缺點,由於next_state本身是一個純粹的組合邏輯,拿來當output logic的判斷,timing會稍微差一點,很可能critical path就出現在這裡,前一個例子的output logic用的是curr_state,是一個D flip-flop,沒有組合邏輯,所以timing比較好。
另外一個缺點是output logic必須判斷next_state,很容易出錯,觀念必須非常清楚。
完整程式碼下載simple_fsm_moore_3_always_best.7z (Moore FSM 3 always)
simple_fsm_moore_2_always_0_cs_ns_good.7z (Moore FSM 2 always [state register + next state logic合一])
simple_fsm_moore_2_always_1_cs_ol_ng.7z (Moore FSM 2 always [state register + output logic合一])
simple_fsm_moore_2_always_2_ns_ol_ng.7z (Moore FSM 2 always [next state + output logic合一])
simple_fsm_moore_1_always_ng.7z (Moore FSM 1 always)
simple_fsm_mealy_3_always_best.7z (Mealy FSM 3 always)
simple_fsm_mealy_2_always_0_cs_ns_good.7z (Mealy FSM 2 always [state register + next state logic合一])
simple_fsm_mealy_2_always_2_ns_ol_ng.7z (Mealy FSM 2 always [next state logic + output logic合一])
simple_fsm_moore_2_always_0_cs_ns_good_practical.7z (Moore FSM 2 always [state register + next state logic合一] with better timing)
simple_fsm_moore_3_always_practical.7z (Moore FSM 3 always with better timing)
simple_fsm_moore_3_always_practical2.7z (Moore FSM 3 always with better timing and no delay 1 clk)
Conclusion1.3個always與2個always (state register與next state logic合一)是兩種推薦的寫法,而且這兩種寫法無論要描述Moore FSM或者Mealy FSM都沒問題,其他寫法都不推薦,個人是比較喜歡2個always寫法(state register + next state logic),因為這種寫法最精簡,各種需求都可描述,也不用擔心是否要提前一個clk判斷,最為直覺不易錯。
2.實務上不會特別拘泥使用Moore或者Mealy,只要符合需求即可,一般會以Moore FSM為正宗。
3.實務上為了timing更好,會在Moore FSM的output logic多敲一級。
4.Mealy會比Moore少1個state,且output會比Moore早1個clk。
5.Moore與Mealy之間可以互換,只要在Mealy的output多敲一級即可。
Reference[1] Douglas J. Smith, HDL Chip Design, A practical guide for designing, synthesizing and simulating ASICs and FPGAs using VHDL or Verilog
[2] Stephen Brown 2005, Zvonko Vranesic, Fundamentals of Digital Logic with VHDL Design, McGraw-Hill
全文完。

使用者定義的原始值 User Defined Primitive (UDP)

源自於http://soc.eecs.yuntech.edu.tw/Course/Digital%20Logic%20Design/Verilog-Chap3.pdf


           使用者定義的原始值 

• 使用關鍵字 primitive 作宣告 
• 只可以有一個輸出且此輸出必須列在埠名 
   單的第一個還有必須用關鍵字output來宣告 。 
• 輸入數目不限制 ,至於它們在input宣告中的 
   順序則必須與它們在下面表中所給值的順 
   序相同 。

• 真值表必須在關鍵字table及endtable之間 。 
• 輸入值依順序列出 ,用冒號( :)代表結束 , 
   輸出通常是每一列的最後一個記錄 ,後面 
   跟著是一個分號( ;) 。 
• 最後用關鍵字endprimitive作結束 。 
   (利用一個真值表來定義UDP) 


//=========================
//Instantiate primitive 
module declare_crctp; 
     reg  x,y,z; 
     wire w; 
     crctp (w,x,y,z); 
endmodule 
//=========================

//User defined primitive(UDP) 
primitive  crctp (x,A,B,C); 
    output  x; 
    input A,B,C; 
//Truth table for x(A,B,C) = Minterms (0,2,4,6,7) 

    table 
//     A    B    C  :  x  (Note that this is only a comment) 
         0   0   0  :  1; 
         0   0   1  :  0; 
         0   1   0  :  1; 
         0   1   1  :  0; 
         1   0   0  :  1; 
         1   0   1  :  0; 
         1   1   0  :  1; 
         1   1   1  :  1; 
   endtable 
endprimitive 




User Defined Primitives Part-I




../images/main/bullet_green_ball.gifIntroduction

Verilog has built-in primitives like gates, transmission gates, and switches. This is a rather small number of primitives; if we need more complex primitives, then Verilog provides UDP, or simply User Defined Primitives. Using UDP we can model
space.gif
  • Combinational Logic
  • Sequential Logic
space.gif
We can include timing information along with these UDP to model complete ASIC library models.
space.gif
../images/main/bulllet_4dots_orange.gifSyntax
UDP begins with reserve word primitive and ends withendprimitive. Ports/terminals of primitive should follow. This is similar to what we do for module definition. UDPs should be defined outside module and endmodule
space.gif

  1 //This code shows how input/output ports
  2 // and primitve is declared
  3 primitive udp_syntax (
  4 a, // Port a
  5 b, // Port b
  6 c, // Port c
  7 d  // Port d
  8 );
  9 output a;
 10 input b,c,d;
 11 
 12 // UDP function code here
 13 
 14 endprimitive
You could download file udp_syntax.v here
space.gif
In the above code, udp_syntax is the primitive name, it contains ports a, b,c,d.
space.gif
The formal syntax of the UDP definition is as follows:
space.gif
<UDP>
   ::= primitive <name_of_UDP> ( <output_terminal_name>,
      <input_terminal_name> <,<input_terminal_name>>* ) ;
   <UDP_declaration>+
   <UDP_initial_statement>?
   <table_definition>
   endprimitive

<name_of_UDP>
   ::= <IDENTIFIER>

<UDP_declaration>
   ::= <UDP_output_declaration>
   ||= <reg_declaration>
   ||= <UDP_input_declaration>

<UDP_output_declaration>
   ::= output <output_terminal _name>;
<reg_declaration>
   ::=   reg <output_terminal_name> ;

<UDP_input_declaration>
   ::= input <input_terminal_name> <,<input_terminal_name>>* ;

<UDP_initial_statement>
   ::= initial <output_terminal_name> = <init_val> ;

<init_val>
   ::= 1'b0
   ||= 1'b1
   ||= 1'bx
   ||= 1
   ||= 0

<table_definition>
   ::= table
         <table_entries>
      endtable

<table_entries>
   ::= <combinational_entry>+
   ||= <sequential_entry>+

<combinational_entry>
   ::= <level_input_list> : <OUTPUT_SYMBOL> ;

<sequential_entry>
   ::= <input_list> : <state> : <next_state> ;

<input_list>
   ::= <level_input_list>
   ||= <edge_input_list>

<level_input_list>
   ::= <LEVEL_SYMBOL>+

<edge_input_list>
   ::= <LEVEL_SYMBOL>* <edge> <LEVEL_SYMBOL>*

<edge>
   ::= ( <LEVEL_SYMBOL> <LEVEL_SYMBOL> )
   ||= <EDGE_SYMBOL>

<state>
   ::= <LEVEL_SYMBOL>

<next_state>
   ::= <OUTPUT_SYMBOL>
   ||= -    
space.gif
../images/main/bulllet_4dots_orange.gifUDP ports rules
space.gif
  • An UDP can contain only one output and up to 10 inputs.
  • Output port should be the first port followed by one or more input ports.
  • All UDP ports are scalar, i.e. Vector ports are not allowed.
  • UDPs can not have bidirectional ports.
  • The output terminal of a sequential UDP requires an additional declaration as type reg.
  • It is illegal to declare a reg for the output terminal of a combinational UDP
space.gif
space.gif
../images/main/bulllet_4dots_orange.gifBody
Functionality of primitive (both combinational and sequential) is described inside a table, and it ends with reserved word 'endtable' as shown in the code below. For sequential UDP, we can use initial to assign an initial value to output.
space.gif

  1 // This code shows how UDP body looks like
  2 primitive udp_body (
  3 a, // Port a
  4 b, // Port b
  5 c  // Port c
  6 );
  7 output a;
  8 input b,c;
  9 
 10 // UDP function code here
 11 // A = B | C;
 12 table
 13  // B  C    : A
 14     ?  1    : 1;
 15     1  ?    : 1;
 16     0  0    : 0;
 17 endtable
 18 
 19 endprimitive
You could download file udp_body.v here
space.gif
Note: An UDP cannot use 'z' in the input table
space.gif
TestBench to check the above UDP

  1 `include "udp_body.v"
  2 module udp_body_tb();
  3 
  4 reg b,c;
  5 wire a;
  6 
  7 udp_body udp (a,b,c);
  8 
  9 initial begin
 10   $monitor(" B = %b C = %b  A = %b",b,c,a);
 11   b = 0;
 12   c = 0;
 13    #1  b = 1;
 14    #1  b = 0;
 15    #1  c = 1;
 16    #1  b = 1'bx;
 17    #1  c = 0;
 18    #1  b = 1;
 19    #1  c = 1'bx;
 20    #1  b = 0;
 21    #1  $finish;
 22 end  
 23 
 24 endmodule
You could download file udp_body_tb.v here
space.gif
Simulator Output
space.gif
  B = 0 C = 0  A = 0
  B = 1 C = 0  A = 1
  B = 0 C = 0  A = 0
  B = 0 C = 1  A = 1
  B = x C = 1  A = 1
  B = x C = 0  A = x
  B = 1 C = 0  A = 1
  B = 1 C = x  A = 1
  B = 0 C = x  A = x
space.gif
../images/main/bullet_star_pink.gifTable
Table is used for describing the function of UDP. Verilog reserved word table marks the start of table and reserved word endtablemarks the end of table.
space.gif
Each line inside a table is one condition; when an input changes, the input condition is matched and the output is evaluated to reflect the new change in input.
space.gif
../images/main/bullet_star_pink.gifInitial
Initial statement is used for initialization of sequential UDPs. This statement begins with the keyword 'initial'. The statement that follows must be an assignment statement that assigns a single bit literal value to the output terminal reg.
space.gif

  1 primitive udp_initial (a,b,c);
  2 output a;
  3 input b,c;
  4 reg a;
  5 // a has value of 1 at start of sim
  6 initial a = 1'b1;               
  7 
  8 table
  9 // udp_initial behaviour
 10 endtable
 11 
 12 endprimitive
You could download file udp_initial.v here
space.gif
../images/main/bulllet_4dots_orange.gifSymbols
UDP uses special symbols to describe functions like rising edge, don't care and so on. The table below shows the symbols that are used in UDPs:
space.gif
Symbol
Interpretation
Explanation
?
0 or 1 or X
? means the variable can be 0 or 1 or x
b
0 or 1
Same as ?, but x is not included
f
(10)
Falling edge on an input
r
(01)
Rising edge on an input
p
(01) or (0x) or (x1) or (1z) or (z1)
Rising edge including x and z
n
(10) or (1x) or (x0) or (0z) or (z0)
Falling edge including x and z
*
(??)
All transitions
-
no change
No Change

P7-20 以任務呼叫函數及任務完成16bit Comparator 適用於DE2-70

P7-20 以任務呼叫函數及任務完成16bit Comparator
適用於DE2-70 


//------------------------------------------------
// 16-bit Comparator using 4-bit-comparator task & 
// 4-bit-comparator function
// filename: compare16.v
//------------------------------------------------
module comp_16_t_tf(SW, LEDR, LEDG , CLOCK_27 ,KEY ,HEX0 ,HEX1 ,HEX2,HEX3 ,HEX4 );

input  [17:0] SW; // toggle switches
input  [3:0] KEY;     // Push bottom
input  CLOCK_27; //Clock 27MHz , 50Mhz

output [17:0] LEDR; // red  LEDS   
  output [7:0] LEDG; // green LEDs
    
    output [6:0] HEX0,HEX1,HEX2,HEX3,HEX4; //7-segment display
    
// set original program input , output 

// ( A, B, Yout );
// input [15:0] A ; //16-bit input A and B
// input [15:0] B ;
// output [2:0] Yout;
// Yout[2]=1'b1 -->Great than,
// Yout[1]=1'b1 --> Equal, and 
    //Yout[0]=1'b1 -->Less than

reg [15:0] A,B ; //16-bit input A and B
//set SW17=1 then A input , SW=0 Then B input , Enable is KEY[0] 


reg [7:0] A8bit; // 4-bit data in input A
reg [7:0] B8bit; // 4-bit data in input B
reg [2:0] Yout ;
  
reg [6:0] HEX0,HEX1,HEX2,HEX3,HEX4;


assign LEDR=SW;
assign LEDG[3]=KEY[3];


always @( negedge KEY[3] )  //Setting A or B value
begin 
                       
if (SW[17]) 
A<=SW[15:0];   //SW17=1 then Setting A value
else
B<=SW[15:0];   //SW17=0 then Setting B value
     end


always @( A or B )
begin
A8bit = A[15:8] ; 
B8bit = B[15:8] ;
compare8( A8bit , B8bit , Yout );
if( Yout == 3'b010 ) // A[15:12] == B[15:12]
begin
   A8bit = A[7:0] ;
       B8bit = B[7:0] ;
       compare8( A8bit , B8bit , Yout ) ;
     
         end
end
//=================================
always @( Yout )
    begin
case (Yout)
3'b010 : 

 begin 
   
HEX4=7'b0000110;  //e
HEX3=7'b0011000;  //q
HEX2=7'b1100011;  //u
HEX1=7'b0000110;  //e
HEX0=7'b1000111;  //l
end


3'b100 : 
 
 begin 
HEX4=7'b0000010;  //g
HEX3=7'b0001101;  //r
HEX2=7'b0000110;  //e
HEX1=7'b0001000;  //a
HEX0=7'b0000111;  //t
 end

3'b001 :  
 begin 
HEX4=7'b1111111;  //
HEX3=7'b1000111;  //L
HEX2=7'b0000110;  //e
HEX1=7'b0010010;  //s
HEX0=7'b0010010;  //s
 end



  default : 
   begin 
HEX4=7'b1111111;  //
HEX3=7'b1111111;  //
HEX2=7'b1111111;  //
HEX1=7'b1111111;  //
HEX0=7'b1111111;  //

       end
       
  endcase

end

//=================================
// Task for a 8-bit comprator
task compare8 ;
 input [7:0] I_A ;  //4-bit input I_A and I_B
 input [7:0] I_B ;
 output [2:0] S ;  //S[2]=1'b1 -->Great than, S[1]=1'b1 --> Equal, and 
                   //S[0]=1'b1 -->Less than

 reg [3:0] A4bit;
 reg [3:0] B4bit;
  

 begin
A4bit=I_A[7:4];
B4bit=I_B[7:4];
compare4_T(A4bit,B4bit,S);   //Call Task

if(  S == 3'b010) // Equal )

begin 

A4bit=I_A[3:0];
B4bit=I_B[3:0];
S=compare4_F(A4bit,B4bit); //Call Function

end
 

 end
endtask
//

//===================================
// Task for a 4-bit comprator
//===================================

task compare4_T ;

 input [3:0] I_A ;  //4-bit input I_A and I_B
 input [3:0] I_B ;
 output [2:0] S ;  //S[2]=1'b1 -->Great than, S[1]=1'b1 --> Equal, and 
                   //S[0]=1'b1 -->Less than
 begin
if( I_A > I_B )
S = 3'b100 ; // Great than
else if( I_A == I_B )
      S = 3'b010 ; // Equal
else
 S = 3'b001 ; // Less than  

 end
endtask

//===================================
// Function for a 4-bit comprator
//===================================

function [2:0] compare4_F;

 input [3:0] I_A ;  //4-bit input I_A and I_B
 input [3:0] I_B ;
 // output [2:0] S ;  //S[2]=1'b1 -->Great than, S[1]=1'b1 --> Equal, and 
                     //S[0]=1'b1 -->Less than
 begin
if( I_A > I_B )
compare4_F = 3'b100 ; // Great than
else if( I_A == I_B )
compare4_F = 3'b010 ; // Equal
else
compare4_F = 3'b001 ; // Less than  

 end
endfunction
//

endmodule

P7-18 以function 呼叫function 完成16bit Even Parity checker 適用於DE2-70

P7-18 以function 呼叫function 完成16bit Even Parity checker
適用於DE2-70 

Even 時HEX3..HEX0 Display EVEN (相近於)
Odd  時HEX3..HEX0 Display Odd    (相近於)




//--------------------------------------------------------------------------------
// 16-bit even-parity generator modified from ex.7-2 using function call 
// Filename : even_parity_16.v
//--------------------------------------------------------------------------------
module enev_16f_funcall_fun(SW, LEDR, LEDG , CLOCK_27 ,KEY ,HEX0 ,HEX1 ,HEX2,HEX3 );

input  [17:0] SW; // toggle switches
input  [3:0] KEY;     // Push bottom
input  CLOCK_27; //Clock 27MHz , 50Mhz

output [17:0] LEDR; // red  LEDS   
  output [8:0] LEDG; // green LEDs
    
    output [6:0] HEX0,HEX1,HEX2,HEX3; //7-segment display
    
  
//set original program input , output 
  
//even_parity_16(Din, Pout);
//input [15:0] Din;
//output Pout;

wire [15:0] Din;
reg [6:0] HEX0,HEX1,HEX2,HEX3;
reg [7:0] High_byte;  // Hight byte of input data
reg [7:0] Low_byte;  // Low byte of input data
reg High, Low;      // Parities of high and low byte
reg Pout;        // Parity output

assign LWDR=SW;
assign Din=SW[15:0];  


always @(Din)
     begin
      High_byte = Din[15:8];
     Low_byte = Din[7:0];
 High = even8(High_byte); //Call function even8
 Low = even8(Low_byte);
 Pout = High ^ Low;   //Bitwise xor
     end

always @(Pout)
begin
  case (Pout)
1'b0 : 

 begin 
   
HEX3=7'b0000110;  //e
HEX2=7'b1100011;  //v
HEX1=7'b0000110;  //e
HEX0=7'b0101011;  //n
end


1'b1 : 
 
 begin 
   
HEX3=7'b1111111;  //
HEX2=7'b1000000;  //o
HEX1=7'b0100001;  //d
HEX0=7'b0100001;  //d
end


  default : 
   begin 
HEX3=7'b1111111;  //
HEX2=7'b1111111;  //
HEX1=7'b1111111;  //
HEX0=7'b1111111;  //

       end
       
  endcase

   end



//==========================================
function even8;
  input [7:0] I8;
  begin 
   even8 = even4(I8[7:4]) ^ even4(I8[3:0]);  // xor operation
  end
endfunction


//==========================================
function even4;
  input [3:0] I4;
  begin 
   even4 = ^ I4;  // reduction xor operation
  end
endfunction

endmodule

P7-15 以4-bit Comparator 完成16 bits Comparator 適用於DE2-70

P7-15 以4-bit Comparator 完成16 bits  Comparator 適用於DE2-70 
16bit Data input 因為DE2-70 只有16 SW[15:0] 所以分成2次輸入 SW[17]=1 或SW[17]=0 分別輸入A SW[15:0] 及B SW[15:0];

KEY[3] = Enable Input  比較結果在HEX0 --> H , L,  = 



//------------------------------------------------
// 16-bit Comparator using 4-bit-comparator task
// filename: compare16.v
//------------------------------------------------
module comparator_16(SW, LEDR, LEDG , CLOCK_27 ,KEY ,HEX0 ,HEX1 ,HEX2,HEX3 );

input  [17:0] SW; // toggle switches
input  [3:0] KEY;     // Push bottom
input  CLOCK_27; //Clock 27MHz , 50Mhz
output [17:0] LEDR; // red  LEDS   
  output [7:0] LEDG; // green LEDs
    
    output [6:0] HEX0,HEX1,HEX2,HEX3; //7-segment display
    
// set original program input , output 

// ( A, B, Yout );
// input [15:0] A ; //16-bit input A and B
// input [15:0] B ;
// output [2:0] Yout;
// Yout[2]=1'b1 -->Great than,
// Yout[1]=1'b1 --> Equal, and 
    //Yout[0]=1'b1 -->Less than

reg [15:0] A,B ; //16-bit input A and B
//set SW17=1 then A input , SW=0 Then B input , Enable is KEY[0] 

reg [3:0] A4bit; // 4-bit data in input A
reg [3:0] B4bit; // 4-bit data in input B
reg [2:0] Yout ;
  
reg [6:0] HEX0;
assign LEDR=SW;
assign LEDG[3]=KEY[3];

always @( negedge KEY[3] )
begin 
                       
if (SW[17]) 
A<=SW[15:0];   //SW17=1 then Setting A value
else
B<=SW[15:0];   //SW17=0 then Setting B value
     end

always @( A or B )
begin
A4bit = A[15:12] ; 
B4bit = B[15:12];
compare4( A4bit , B4bit , Yout );
if( Yout == 3'b010 ) // A[15:12] == B[15:12]
begin
  A4bit = A[11:8] ;
       B4bit = B[11:8] ;
       compare4( A4bit , B4bit , Yout ) ;
       if( Yout == 3'b010 ) // A[15:8] == B[15:8]
    begin
 A4bit = A[7:4] ;
           B4bit = B[7:4] ;
           compare4( A4bit , B4bit , Yout ) ;
           if( Yout == 3'b010 ) // A[15:4] == B[15:4]
        begin
 A4bit = A[3:0] ;
                B4bit = B[3:0] ;
                compare4( A4bit , B4bit , Yout ) ;
                 end
             end
          end
end
//=================================
always @( Yout )
    begin

 case (Yout)
 3'b010 : HEX0=7'b0110111;  //Equal pattern 
 3'b100 : HEX0=7'b0001001;  //Great than pattern 
 3'b001 : HEX0=7'b1000111;  //Less than pattern 
 default : HEX0=7'b1111111;  //default pattern 
 endcase
end
//=================================
// Task for a 4-bit comprator
task compare4 ;
 input [3:0] I_A ;  //4-bit input I_A and I_B
 input [3:0] I_B ;
 output [2:0] S ;  //S[2]=1'b1 -->Great than, S[1]=1'b1 --> Equal, and 
                   //S[0]=1'b1 -->Less than
 begin
if( I_A > I_B )
S = 3'b100 ; // Great than
else if( I_A == I_B )
      S = 3'b010 ; // Equal
else
 S = 3'b001 ; // Less than  

 end
endtask
//

endmodule


  清除項目編譯快取 執行 flutter clean 重新取得套件依賴 執行 flutter pub get 完整重新編譯並執行 flutter run 1. 新增專案套件 (pubspec.yaml) 在 Flutter 專案根目錄下的 pubspec.yaml 中,新增 ...