Press "Enter" to skip to content

Verilog小总结

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

Verilog小总结

 

基础

 

assign

 

assign作为一个组合逻辑常用的语句,可认为是将电线连接起来,当然它能做的不仅仅是将一个输入直接输出,它能把输入信号进行逻辑运算后再输出。 当assign左右两边位宽不相等时,将自动进行零扩展或截断以匹配左边的位宽。

 

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

 

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左右两边位宽不相等时,将自动进行零扩展或截断以匹配左边的位宽。

 

使用 vector_name[up:low] 的形式获取部分向量,注意方向应与定义的一致,如定义了一个 a[3:0] ,那幺不能反向获取 a[0:3]

 

矢量运算

位运算

符号 功能
~ 按位取反
& 按位与
| 按位或
^ 按位异或
^~ 按位同或

 

注意:除了 ~ 外均为双目运算符;若进行双目运算时左右两个操作数位数不一样,位数少的将在相应的高位用0扩展。

逻辑运算

逻辑运算会将整个向量视为布尔值(真=非零,假=零),并且产生1位输出,如有 input [2:0] ainput [2:0] b 那幺他们的逻辑或运算即为 assign out = a || b; ,a和b均视为一个布尔值。

缩减运算

对一个向量的每一位进行位操作,如有 a[2:0] ,那幺 b=&a 相当于 b=(a[0]&a[1])&a[2]

 

矢量串联

 

串联运算符 {a,b,c} 用来将小向量串联起来创建一个更大的向量。 串联中不允许使用不定尺寸的常量。 如 {1,2,3} 是非法的,因为Verilog不知道他们的位宽。

 

还可以用 {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}}} 也是一个向量

 

模块

 

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块法)
    [email protected](*) 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块法)
    [email protected](*) begin
        case ({state,in})
            4'b0000: {out3,out2,out1} = 3'b111;
            4'b0001: {out3,out2,out1} = 3'b110;//对每一种state与in做输出
            ...
    end

 

(希望明天P1能过呜呜呜

Be First to Comment

发表评论

电子邮件地址不会被公开。 必填项已用*标注