Verilog 备忘(更新中)

Verilog 备忘

语法速查

示例代码

module 模块名 (
    input 端口名,
    output 端口名
);

    wire w1, w2;
    assign w1 = w2;
    // 条件表达式不一定像Java那样写成一个 xxx == 1'b1,可以用C风格的判断
    assign w = xxx ? w1 : w2;

    wire [100:0] v1;
    reg [0:10] v2;
    assign v1 = {10{w1}, 1'b1, 2'd2, 10'f8, w2};
    assign all_and = & v1;

    //------------------"+:"--------------
    data[begin +: width]
    data[(begin + width -1): begin]//这里是上式的等价表达式
    //------------------"-:"--------------
    data[end   -: width]
    data[end :(end-width+1)]       //这里是上式的等价表达式

    reg r1, r2;
    always @(*) begin
        r1 = 1'b1;
        // 0, x, z为假,否则为真
        if (xxx) begin
            r1 = xxx;
        end

        if (xxx) begin
            xxx
        end
        else if (xxx) begin
            xxx
        end
        else begin
            xxx
        end

        case (in)
            1'b1: begin
                      xxx
                  end
            1'b0: xxx
            default: xxx
        endcase

        casez (in[3:0])
            4'bzzz1: out = 0;
            4'bzz1z: out = 1;
            4'bz1zz: out = 2;
            4'b1zzz: out = 3;
            default: out = 0;
        endcase

        // $bits() is a system function that returns the width of a signal.
        for (int i=0;i<$bits(out);i++)
            // $bits(out) is 100 because out is 100 bits wide.	
			out[i] = in[$bits(out)-i-1];
    end

    mod m(wa, wb, wc);
    mod m(.out(wc), .a(wa), .b(wb));


endmodule

operator

bitwise和logical运算符:

  • bitwise是按位运算,n输入就是n输出
  • logical是逻辑运算,n输入1输出
  • bitwise用来进行位运算,logical用来进行逻辑判断
operator type not and or xor
bitwise ~ & | ^
logical ! && ||

防踩坑指南

module

一对module-endmodule中不能再嵌套module-endmodule。module的使用方法叫实例化,而不是调用

两种端口连接方法:

// 已知有如下module声明
module mod ( input a, input b, output out );

// 方法一
mod m(wa, wb, wc); // 其中wa, wb, wc对应mod中的a, b, out,顺序必须和形参顺序一样

// 方法二
mod m(.out(wc), .a(wa), .b(wb)); // wa, wb, wc的顺序无所谓

其中,如果端口是vector,则连接时实参如果宽度不匹配,会进行零扩展或截断

procedures(包括always, if, case)

assign的左边必须是net类型(比如wire),always语句块中左边必须是variable类型(比如reg

不要在procedure块里面写assign,不要在procedure块外面写if-else

Combinational: always @(*)

本语句用来生成组合逻辑。使用combinational always block与使用assign等价,但是不要在always里写assign。不要在()中写变量名。只需把always @(*)当成模板用就可以了

在combinational always中必须只使用blocking assignment =

reg a;
always @(*) begin
    a = 1'b1; // 正确
    a <= 1'b2; // 不要这么写
end

Clocked: always @(posedge clk)

此语句块用来生成时序逻辑。在clocked always中必须只使用non-blocking assignment <=

reg a;
always @(posedge clk) begin
    a <= 1'b2;
end

In Verilog-1995 the signals are separated by the keyword or. In Verilog-2001 the signals may be separated by a comma. This new comma-separated sensitivity list does not add new functionality.

case, casez 语句

不用写break,case item可以重复,以第一个匹配的项为准

casez的匹配按从上往下顺序,以第一个匹配到的准,z也可以写成x, ?

避免生成锁存器

只要避免有的信号没有被赋值就可以,总的来说就是不能让电路“记住”上一个时刻的的值(即always语句执行了一遍后有的变量根本没有更新动作,更新之后值和原来一样的情况不算)。常用做法有:

  1. 必须在所有分支上给输出信号赋值,比如记得在else或者default中赋值
  2. 给定初始值
always @(*) begin
    // 所有分支都给信号一个值
    if (cpu_overheated)
        shut_off_computer = 1;
    else
        shut_off_computer = 0;

    // 给定初值
    left = 1'b0; down = 1'b0; right = 1'b0; up = 1'b0;
    case (scancode)
        16'he06b: left = 1'b1;
        16'he072: down = 1'b1;
        16'he074: right = 1'b1;
        16'he075: up = 1'b1;
    endcase
end

wire, reg

wire在verilog中是有方向的,赋值时使用assign,所有的assign都是并行完成的。assign时如果左右长度不匹配,则右方会进行零扩展或被截断

不能给wire进行初始化,但是可以给reg初始化

implicit net

wire是一种net类型。对于net类型,当出现以下两种情况:一、在assign时没有被声明;二、是把一个没声明的net-type连到module端口上。此时net类型被隐式创建,且默认为1-bit宽

wire a;
assign b = a; // 凭空出现了wire b,默认为1-bit
my_module (d, e); // 凭空出现了d e,默认为1-bit

在源文件开头加上 `default_nettype 可以阻止 implicit net 生成

vector

vector的维度在名字之前,可以用下标访问

wire [99:0] vec, out; // 两个vector
assign out[2:0] = vec[3:1];

可选格式

output/input wire/reg [upper:lower] vec_name;
  • 中括号中的range可以为负,reg [1:-1] vec 是三个 reg 构成的 vector ,下标访问时也可以为负,比如z[-1:-2]表示z的最低二字节
  • 小端存储:wire [3:0] v;大端存储:wire [0:3] v

下标访问的上下界顺序必须和声明时一致,即不能声明为小端vector却用大端方式访问,以下代码为错误代码

wire [2:0] w1;
assign xxx = w1[0:2]; // 错误:声明时为上界在前,下界在后,则访问时必须为上界在前,下界在后

Unpacked arrays vs. Packed arrays

reg [7:0] mem [255:0]; // 256个unpacked元素,每个元素都是一个8-bit reg(packed vector)
reg mem [28:0];  // 29个unpacked元素,每个元素都是1-bit的reg

vector 连接符与replication operator

连接符可以出现在assign的左边或右边,如果左右宽度不一致,则超出去的宽度不会被赋值

大括号内出现的常量必须指定宽度,{1'b1, 4'hf, 2'd2}正确,{1, 2, 3} 错误

{3'b111, 4'ha} // 表示 7'b1111010

replication 的外面必须有一层大括号

{5{1'b1}} // 表示 5'b11111
{2{a, b}} // 表示 {a b a b}

其他特性

三目运算符

格式和C一样,用来生成多路选择器。写在procedure里面或外面都可以

((sel[1:0] == 2'h0) ? a :     // A 3-to-1 mux
 (sel[1:0] == 2'h1) ? b :
                      c )

reduction operators

常用于把一个 vector 的所有位都异或起来

& a[3:0]     // AND: a[3]&a[2]&a[1]&a[0]. Equivalent to (a[3:0] == 4'hf)
| b[3:0]     // OR:  b[3]|b[2]|b[1]|b[0]. Equivalent to (b[3:0] != 4'h0)
^ c[2:0]     // XOR: c[2]^c[1]^c[0]

常见代码手法

根据真值表写电路

利用最小项之积即可,例:

module top_module( 
    input x3,
    input x2,
    input x1,  // three inputs
    output f   // one output
);
    assign f = ~x3 & x2 & ~x1 | ~x3 & x2 & x1 | x3 & ~x2 & x1 | x3 & x2 & x1;
endmodule

判断两vector相等

module top_module ( input [1:0] A, input [1:0] B, output z ); 
    // 直接写A == B也行,不用专门写一个三目运算符
	assign z = (A[1:0] == B[1:0]);
endmodule

错位比较

原题:https://hdlbits.01xz.net/wiki/Gatesv

解析:out_bothout_any可以各从in中拿出正好差了一个下标位置的3位来,进行位运算即可得结果。out_different是手动做了一个in循环右移一位的临时vector,然后和原vector按位异或

module top_module (
	input [3:0] in,
	output [2:0] out_both,
	output [3:1] out_any,
	output [3:0] out_different
);

	// Use bitwise operators and part-select to do the entire calculation in one line of code
	// in[3:1] is this vector:   					 in[3]  in[2]  in[1]
	// in[2:0] is this vector:   					 in[2]  in[1]  in[0]
	// Bitwise-OR produces a 3 bit vector.			   |      |      |
	// Assign this 3-bit result to out_any[3:1]:	o_a[3] o_a[2] o_a[1]

	// Thus, each output bit is the OR of the input bit and its neighbour to the right:
	// e.g., out_any[1] = in[1] | in[0];	
	// Notice how this works even for long vectors.
	assign out_any = in[3:1] | in[2:0];

	assign out_both = in[2:0] & in[3:1];
	
	// XOR 'in' with a vector that is 'in' rotated to the right by 1 position: {in[0], in[3:1]}
	// The rotation is accomplished by using part selects[] and the concatenation operator{}.
	assign out_different = in ^ {in[0], in[3:1]};
	
endmodule

a 4-bit wide, 256-to-1 multiplexer

The 256 4-bit inputs are all packed into a single 1024-bit input vector. sel=0 should select bits in[3:0], sel=1 selects bits in[7:4], sel=2 selects bits in[11:8], etc

module top_module( 
    input [1023:0] in,
    input [7:0] sel,
    output [3:0] out );
    assign out = in[sel*4 +: 4];
endmodule

Synchronous & Asynchronous Reset

见:https://vlsi.pro/synchronous-asynchronous-reset/

同步复位:

module top_module (
    input clk,
    input reset,            // Synchronous reset
    input [7:0] d,
    output [7:0] q
);
    always @(posedge clk) begin
        if (reset) q <= 8'b0;
        else q <= d;
    end
endmodule

异步复位:

module top_module (
    input clk,
    input areset,   // active high asynchronous reset
    input [7:0] d,
    output [7:0] q
);
    always @(posedge clk, posedge areset) begin
        if (areset) q <= 8'b0;
        else q <= d;
    end

endmodule
posted @ 2022-01-26 20:06  nahso4  阅读(204)  评论(0)    收藏  举报