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语句执行了一遍后有的变量根本没有更新动作,更新之后值和原来一样的情况不算)。常用做法有:
- 必须在所有分支上给输出信号赋值,比如记得在else或者default中赋值
- 给定初始值
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_both和out_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

浙公网安备 33010602011771号