2013年11月17日 星期日

[ Verilog Tutorial ] 行為模型的敘述: always, if/else, case 與 for loop

Preface: 
在這個階層中,我們只需考慮電路模組的功能,而不需考慮其硬體的詳細內容. Verilog 的時序控制為以事件為基礎的時序控制: 
* 接線或暫存器的值被改變。
* 模組的輸入埠接收到新的值
* 正規事件控制:正緣、負緣、訊號值改變
* 多事件或訊號控制

always 敘述: 
always 敘述的觀念有如監督程式一般,隨時監看著輸出入埠訊號的變化,然後告知模組內部 進行相關的處理. 語法如下: 
  1. // Style1  
  2. always  
  3.     statement  
  4. // Style2  
  5. always@(event_expression)  
  6.     statement  
  7. // Style3  
  8. always  
  9.     begin  
  10.         statements  
  11.     end  
  12. // Style4  
  13. always@(event_expression)  
  14.     begin  
  15.         statements   
  16.     end  
always@ 敘述 
always@(…) 括弧內的運算式稱之為事件運算式 (event expression),其可以是: 
* 單一訊號: 屬於準位觸發 (level trigger)。
* 多個訊號: 利用 or 關鍵字連接不同訊號, 也屬於屬於準位觸發.
* 邊緣觸發: 正緣觸發/posedge 或 負緣觸發/negedge

接著來看 單一訊號範例: 
  1. module test(in, out);  
  2.     input in;  
  3.     output out;  
  4.     reg out;  
  5.     always@(in)  
  6.         out = ~ in;  
  7. endmodule  
實事上上面的模組就是一個 Not gate: 
 

接著來看 多個訊號的範例: 
  1. module test(a, b, out);  
  2.     input a, b;  
  3.     output out;  
  4.     reg out;  
  5.     always@(a or b)  
  6.     begin  
  7.         out = a | b;  
  8.     end  
  9. endmodule  
上面是一個 OR gate: 
 

接著來看 邊緣觸發之 "posedge" (在 clock cycle 的正緣觸發
  1. module test(a, ck, out);  
  2.     input a, ck;  
  3.     output out;  
  4.     reg out;  
  5.     always@(posedge ck)  
  6.     begin  
  7.         out = ~ a;  
  8.     end  
  9. endmodule  
上面的 NOT gate 只在 clock 正緣觸發: 
 

如果是負緣觸發, 則使用 always@(negedge ck), 輸出結果: 
 

if 敘述: 
可用來進行訊號值的判斷,後根據判斷結果執行相關處理. if 敘述能處理正準位與負準位觸發兩種訊號, 語法如下: 
  1. // Style1  
  2. if (expression)  
  3.     statement  
  4.   
  5. // Style2  
  6. if (expression)  
  7. begin  
  8.     statements  
  9. end  
接著來看 準位觸發 範例: 
  1. module test(reset, in, out);  
  2.     input reset, in;  
  3.     output out;  
  4.     reg out;  
  5.     always  
  6.     begin  
  7.         if (reset == 1’b1) // 正  
  8.             out = 0;  
  9.         if (reset == 1’b0) // 負  
  10.             out = in;  
  11.     end  
  12. endmodule  
當 reset 為 1, 則設置 out 為 0; 當 reset 為 0, 則 out 等於 in
 

if-else 敘述: 
語法如下: 
  1. // Style1  
  2. if (expression)  
  3.     statement  
  4. else statement  
  5.   
  6. // Style2  
  7. if (expression)  
  8. begin  
  9.     statements  
  10. end  
  11. else  
  12. begin  
  13.     statements  
  14. end  
接著來看一個範例: 優先權編碼器 (priority encoder) 部分代碼 
  1. always@(X, Y, Z)  
  2. begin  
  3.     if (Z) // highest  
  4.         out = result4;  
  5.     else if (Y)  
  6.         out = result3;  
  7.     else if (X)  
  8.         out = result2;  
  9.     else out = result1; // lowest  
  10. end  
case 敘述: 
case 敘述為一多路分支選擇的敘述, 如果電路中所有可能的分支判別條件都被指定了,則稱為 full case. 語法如下: 
  1. case (expression)  
  2.     alter_1, alter_2: stm_1;  
  3.     alter_3: stm_2;  
  4.     …  
  5.     default: default_stm;  
  6. endcase  
接著來看一個範例: 2X1 Multiplexor 
  1. module mux21(in1, in2, sl, out);  
  2.     input in1, in2, sl;  
  3.     output out;  
  4.     reg out;  
  5.     always@(in1 or in2 or sl)  
  6.     begin  
  7.         case (sl)  
  8.             1’b0: out = in1;  
  9.             1’b1: out = in2;  
  10.         endcase  
  11.     end  
  12. endmodule  
上面是一個 2x1 多工器, 輸出結果: 
 

接著來考慮一個優先編碼模組: 
  1. module priencoder(X, Y, Z, out);  
  2. input [1:0] X, Y, Z;  
  3. output [2:0] out;  
  4. reg [2:0] out;  
  5. always@(X or Y or Z)  
  6. begin  
  7.   case (2'b11)  
  8.     X: out = 3'b001;  
  9.     Y: out = 3'b010;  
  10.     Z: out = 3'b100;  
  11.     default: out = 3'b000;  
  12.   endcase  
  13. end  
  14. endmodule  
而它的一個 testbench 代碼如下: 
  1. `timescale 1ns / 1ns  
  2.   
  3. module priencoder_tb;  
  4.   reg  [1:0] X,Y,Z;  
  5.   wire [2:0] out;  
  6.   priencoder ENCODER(X,Y,Z,out);  
  7.     
  8.   initial  
  9.     begin  
  10.       X <= 2'b00;  
  11.       Y <= 2'b00;  
  12.       Z <= 2'b00;  
  13.       #1 $display("out=%b", out);  
  14.       X <= 2'b11;  
  15.       Y <= 2'b00;  
  16.       Z <= 2'b00;  
  17.       #5 $display("out=%b", out);  
  18.       X <= 2'b00;  
  19.       Y <= 2'b11;  
  20.       Z <= 2'b00;  
  21.       #5 $display("out=%b", out);  
  22.       X <= 2'b00;  
  23.       Y <= 2'b00;  
  24.       Z <= 2'b11;  
  25.       #5 $display("out=%b", out);  
  26.       X <= 2'b11;  
  27.       Y <= 2'b11;  
  28.       Z <= 2'b11;  
  29.       #5 $display("out=%b", out);  
  30.     end  
  31. endmodule  
執行結果為: 
# out=000 # 此時 X,Y,Z 沒一個是 2'b11, 故輸出 output 為 default
# out=001 # 此時 X 為 2'b11, 故輸出 001
# out=010 # 此時 Y 為 2'b11, 故輸出 010
# out=100 # 此時 Y 為 2'b11, 故輸出 100
# out=001 # 此時雖然 X,Y,Z 皆為 2'b11, 但是因為 case 順序 X 是第一個, 故輸出 001

Verilog 中還有 casex 與 casez 兩種 case 敘述, 更多可以參考 Case Statement

迴圈敘述 for: 
Verilog 提供有 for、while、repeat 和 forever 等迴圈敘述, 語法如下: 
  1. for (statement; expression; statement)  
  2. begin  
  3.     statements;  
  4. end  
Ps. 所有迴圈敘述僅能在 always 敘述中執行。 

接著來看一個範例: 
  1. module forloop(a, b, out);    
  2.   parameter size=2;  
  3.   input  [size-1:0] a, b;    
  4.   output [size-1:0] out;    
  5.   reg    [size-1:0] out;    
  6.   integer i;    
  7.   always @(a or b)    
  8.   begin    
  9.     for (i = 0;i < size; i = i + 1)    
  10.       out[i] = a[i] & b[i];    
  11.   end    
  12. endmodule   
這是一個 AND gate 的範例, 透過 for loop 對 a兩個 array 進行 AND 運算後輸出到 out. 底下是一個 testbench: 
  1. `timescale 1ns / 1ns  
  2.   
  3. module forloop_tb;  
  4.   reg  [1:0] a, b;  
  5.   wire [1:0] out;  
  6.   forloop FL(a, b, out);  
  7.     
  8.   initial  
  9.     begin  
  10.       a <= 2'b00;  
  11.       b <= 2'b00;  
  12.       #1 $display("a=%b; b=%b; out=%b", a, b, out);  
  13.       a <= 2'b01;  
  14.       b <= 2'b00;  
  15.       #1 $display("a=%b; b=%b; out=%b", a, b, out);  
  16.       a <= 2'b01;  
  17.       b <= 2'b01;  
  18.       #1 $display("a=%b; b=%b; out=%b", a, b, out);  
  19.       a <= 2'b10;  
  20.       b <= 2'b01;  
  21.       #1 $display("a=%b; b=%b; out=%b", a, b, out);  
  22.       a <= 2'b10;  
  23.       b <= 2'b10;  
  24.       #1 $display("a=%b; b=%b; out=%b", a, b, out);  
  25.       a <= 2'b11;  
  26.       b <= 2'b10;  
  27.       #1 $display("a=%b; b=%b; out=%b", a, b, out);  
  28.       a <= 2'b11;  
  29.       b <= 2'b11;  
  30.       #1 $display("a=%b; b=%b; out=%b", a, b, out);  
  31.     end  
  32. endmodule  
執行結果: 
 

Supplement: 
Verilog online help > Loop Statements 
Bioelectromagnetics Lab > Verilog tutorial

沒有留言:

張貼留言

[Git 文章收集] Differences between git merge and git rebase

Source From  Here Preface Merging and rebasing are the two most popular way to applying changes from one branch into another one. They bot...