assign做爲一個組合邏輯經常使用的語句,可認爲是將電線鏈接起來,固然它能作的不單單是將一個輸入直接輸出,它能把輸入信號進行邏輯運算後再輸出。當assign左右兩邊位寬不相等時,將自動進行零擴展或截斷以匹配左邊的位寬。less
eg:異步
module top_module ( input a, input b, input c, input d, output out, output out_n ); wire w1, w2; // Declare two wires (named w1 and w2) assign w1 = a&b; // First AND gate assign w2 = c&d; // Second AND gate assign out = w1|w2; // OR gate: Feeds both 'out' and the NOT gate assign out_n = ~out; // NOT gate endmodule
type [upper:lower] vector_name;
type
指定向量的數據類型,一般是wire
或reg
。若是要聲明輸入或輸出端口,則該類型還能夠另外包括端口類型(例如,input
或output
)函數
wire [7:0] w; // 8-bit wire reg [4:1] x; // 4-bit reg output reg [0:0] y; // 1-bit reg that is also an output port (this is still a vector) input wire [3:-2] z; // 6-bit wire input (negative ranges are allowed) output [3:0] a; // 4-bit output wire. Type is 'wire' unless specified otherwise. wire [0:7] b; // 8-bit wire where b[0] is the most-significant bit.
使用向量名稱訪問整個向量,可是當assign左右兩邊位寬不相等時,將自動進行零擴展或截斷以匹配左邊的位寬。oop
使用vector_name[up:low]
的形式獲取部分向量,注意方向應與定義的一致,如定義了一個a[3:0]
,那麼不能反向獲取a[0:3]
。this
符號 | 功能 |
---|---|
~ |
按位取反 |
& |
按位與 |
| |
按位或 |
^ |
按位異或 |
^~ |
按位同或 |
注意:除了~
外均爲雙目運算符;若進行雙目運算時左右兩個操做數位數不同,位數少的將在相應的高位用0擴展。編碼
邏輯運算會將整個向量視爲布爾值(真=非零,假=零),而且產生1位輸出,若有input [2:0] a
和input [2:0] b
那麼他們的邏輯或運算即爲assign out = a || b;
,a和b均視爲一個布爾值。.net
對一個向量的每一位進行位操做,若有a[2:0]
,那麼b=&a
至關於b=(a[0]&a[1])&a[2]
code
串聯運算符{a,b,c}
用來將小向量串聯起來建立一個更大的向量。串聯中不容許使用不定尺寸的常量。如{1,2,3}
是非法的,由於Verilog不知道他們的位寬。blog
還能夠用{n{vec}}
的形式來複制向量,如{6{a}}
和{a,a,a,a,a,a}
是同樣的,同時注意兩組大括號都是必須的,即{1'b1,6{1'b0}}
是非法的,由於其中的6{1'b0}
少了一組大括號,正確的寫法是{1'b1,{6{1'b0}}}
。這其實比較好理解,串聯運算符{a,b,c}
中的abc均爲一個向量,{n{vec}}
也表明了一個向量,所以{a,b,{n{c}}}
也是一個向量ci
mod_name instance_name (signal_name1,signal_name2,signal_name3);//by position
mod_name instance_name (.port_name1(signal_name1),.port_name2(signal_name2),.port_name3(signal_name3));//by name
能夠理解爲一個函數,注意括號內的是外部鏈接到模塊的信號。
使用always @(*)
能夠相似於assign
的效果,當右方有變量發生改變時,左邊輸出隨之當即改變。assign out1 = a & b | c ^ d;
和always @(*) out2 = a & b | c ^ d;
是同樣的
//同步復位 always @(posedge clk) begin if(reset == 1) begin //reset end end //異步復位 always @(posedge clk,posedge areset) begin if(areset == 1) begin //reset end end
通常來講,咱們在組合邏輯的always塊中使用阻塞賦值(x = y;
);在時序邏輯的always塊中使用非阻塞賦值(x <= y;
)
always @(*) begin //這是一個組合邏輯 case (in) 1'b1: begin out = 1'b1; end 1'b0: out = 1'b0; default: out = 1'bx; endcase //必定記得寫endcase end
注意必定要寫endcase。
另外還有case的好兄弟casez,他能夠匹配形如4'bzzz1
的向量,z表示無關位。
eg:優先編碼器
module top_module ( input [7:0] in, output reg [2:0] pos ); always @(*) begin casez (in) 8'bzzzzzzz1 : pos = 0; 8'bzzzzzz1z : pos = 1; 8'bzzzzz1zz : pos = 2; 8'bzzzz1zzz : pos = 3; 8'bzzz1zzzz : pos = 4; 8'bzz1zzzzz : pos = 5; 8'bz1zzzzzz : pos = 6; 8'b1zzzzzzz : pos = 7; default: pos =0; endcase end endmodule
與C語言的用法相似。
eg:人口計數器
module top_module ( input [254:0] in, output reg [7:0] out ); always @(*) begin //組合邏輯always塊 out = 0; //必定要初始化爲0 for (int i=0;i<255;i++) out = out + in[i]; end endmodule
當對矢量中多個位進行重複操做時,或進行多個模塊的實例化引用的重複操做時,可以使用生成塊簡化程序。寫法以下
genvar i;//只能用genvar做爲循環變量 generate for (i=1;i<99;i=i+1) begin: add_loop//這個名字是必須的 mod_name instance_name(......);//括號裏寫由i推出的信號 end endgenerate
eg:Bcdadd100
module top_module( input [399:0] a, b, input cin, output cout, output [399:0] sum ); genvar i; wire [99:0]cout1; bcd_fadd mod1(a[3:0],b[3:0],cin,cout1[0],sum[3:0]); generate for (i=1;i<99;i=i+1) begin: addloop bcd_fadd mod2(a[(4*i+3):(4*i)],b[(4*i+3):(4*i)],cout1[i-1],cout1[i],sum[(4*i+3):(4*i)]); end endgenerate bcd_fadd mod3(a[399:396],b[399:396],cout1[98],cout,sum[399:396]); endmodule
三段式寫法:使用一個state用於存當前狀態,使用一個next_state用於存下一狀態。第一段用於寫狀態轉換邏輯,第二段用於狀態轉移,第三段用於輸出。
reg state, next_state; //第一段: always @(*) begin //一個組合邏輯always塊,用於寫狀態轉換邏輯,當in改變時,next_state將當即改變。 case(state) A: next_state = f(in)//關於in的函數 B: next_state = f(in) ... endcase end //第二段(異步): always @(posedge clk, posedge areset) begin if(areset == 1) begin state <= 0;//reset end else state <= next_state; end //第二段(同步): always @(posedge clk) begin if(reset == 1) begin state <= 0;//reset end else state <= next_state; end //第三段(assign法) assign out = (state == ...);//判斷state //第三段(組合邏輯always塊法) always@(*) begin case (state) A: {out3,out2,out1} = 3'b111; B: {out3,out2,out1} = 3'b110;//對每一種狀態輸出 ... endcase end
僅僅第三段發生了改變,可以使用{state,in}
來作輸出判斷。
//第三段(assign法) assign out = f(state,in);//關於state和in的函數 //第三段(組合邏輯always塊法) always@(*) begin case ({state,in}) 4'b0000: {out3,out2,out1} = 3'b111; 4'b0001: {out3,out2,out1} = 3'b110;//對每一種state與in作輸出 ... end
(但願明天P1能過嗚嗚嗚