Verilog小總結

Verilog小總結

基礎

assign

assign做爲一個組合邏輯經常使用的語句,可認爲是將電線鏈接起來,固然它能作的不單單是將一個輸入直接輸出,它能把輸入信號進行邏輯運算後再輸出。當assign左右兩邊位寬不相等時,將自動進行零擴展或截斷以匹配左邊的位寬。less

eg:Wiredecl2.png異步

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

Vectors

聲明向量

type [upper:lower] vector_name;
type指定向量的數據類型,一般是wirereg。若是要聲明輸入或輸出端口,則該類型還能夠另外包括端口類型(例如,inputoutput函數

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] ainput [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塊

組合邏輯

使用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;

case

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

for

組合for循環

與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

生成for循環

當對矢量中多個位進行重複操做時,或進行多個模塊的實例化引用的重複操做時,可以使用生成塊簡化程序。寫法以下

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

狀態機寫法

Moore型

三段式寫法:使用一個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

Mealy型

僅僅第三段發生了改變,可以使用{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能過嗚嗚嗚

相關文章
相關標籤/搜索