0%

Verilog语法

Verilog语法

连续赋值语句, 阻塞赋值语句, 非阻塞赋值语句

数据流的描述是采用连续赋值语句(assign )语句来实现的。语法如下:

assign net_type = 表达式;

连续赋值语句用于组合逻辑的建模
等式左边是wire 类型的变量
等式右边可以是常量. 由运算符如逻辑运算符. 算术运算符参与的表达。

如下几个实例:

1
2
3
4
5
6
7
8
wire [3:0] Z, Preset, Clear; //线网说明
assign Z = Preset & Clear; //连续赋值语句

wire Cout, C i n ;
wire [3:0] Sum, A, B;
. . .
assign {Cout, Sum} = A + B + Cin;
assign Mux = (S = = 3)? D : 'bz;
  1. 连续赋值语句的执行是:
    只要右边表达式任一个变量有变化,表达式立即被计算,
    计算的结果立即赋给左边信号。
  2. 连续赋值语句之间是并行语句,因此与位置顺序无关
    (“=”用于阻塞的赋值, 凡是在组合逻辑(如在assign 语句中)赋值请用阻塞赋值)

行为建模方式

一般是指用过程赋值语句
(initial 语句和always 语句)

  1. 顺序语句块(begin . . . end):
    语句块中的语句按给定次序顺序执行;
1
2
3
4
5
6
7
8
begin
#2 Stream = 1;
#5 Stream = 0;
#3 Stream = 1;
#4 Stream = 0;
#2 Stream = 1;
#5 Stream = 0;
end
  1. 两种过程赋值语句 initial 和 always 语句:
    这两种语句之间的执行是并行的,即语句的执行与位置顺序无关
    这两种语句通常与语句块(begin ….end)相结合,则语句块中的执行是按顺序执行
    initial 语句只执行一次;
    always 语句与initial 语句相反, 是被重复执行, 执行机制是通过对一个称为敏感变量表的事件驱动来实现的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
initial
Clk = 0 ;
always
#5 Clk = ~Clk; // 周期为10 的方波。

always @ ( posedge Clk or posedge Rst )
begin
if Rst
Q <= ‘ b 0;
else
Q <= D; // D 触发器

always @( sel ,a ,b)
C = sel ? a :b;
// sel ,a,b 同样称为敏感变量,当三者之一有变化时,always 被执行

对于always:

  • 对组合逻辑器件的赋值采用阻塞赋值 “=”
  • 时序逻辑器件的赋值语句采用非阻塞赋值 “<=”,如上的 Q 〈= D;)

结构建模

实例化语句:

1
module_name instance_name(port_associations);

信号端口可以通过位置或名称关联;但是关联方式不能够混合使用
端口关联形式如下:

1
2
port_expr //通过位置。
.PortName (port_expr) //通过名称。

port_expr 可以是以下的任何类型:

  1. 标识符(reg 或net )如: .C(T3),T3为wire型标识符
  2. 位选择 ,如 .C(D[0]),C端口接到D信号的第0bit 位
  3. 部分选择 ,如 .Bus (Din[5:4])
  4. 上述类型的合并,如 .Addr({ A1,A2[1:0]})
  5. 表达式(只适用于输入端口),如 .A (wire Zire = 0 )
  6. 对输入管脚悬空的,则该管脚输入为高阻 Z,输出管脚被悬空的,该输出管脚废弃不用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
module and (C,A,B);
input A,B;
output C;
...
and A1 (T3, A, B ); //实例化时采用位置关联,T3对应输出端口C,A对应A,B对应B。
and A2(
//实例化时采用名字关联,.C是and 器件的端口,其与信号T3相连
.C(T3),
.A(A),
.B(B)
);

DFF d1 (
.Q(QS),
.Qbar ( ),
.Data (D ) ,
.Preset ( ),
// 该管脚悬空
.Clock (CK)
); //名称对应方式

书写建议

  1. 条件表达式需用括号括起来
  2. 若为if - if 语句,请使用块语句 begin —- end:
1
2
3
4
5
6
7
if (Clk)
begin
if(R e s e t)
Q = 0;
else
Q = D;
end

以上两点建议是为了使代码更加清晰,防止出错。

  1. 对if 语句,除非在时序逻辑中,if 语句需要有else 语句
    若没有缺省语句, 设计将产生一个锁存器, 锁存器在ASIC设计中有诸多的弊端(可看同步设计技术所介绍)。
    如下一例:
1
2
3
4
5
6
if (T)
Q = D;
// 没有else 语句,
// 当T为1(真)时,D 被赋值给Q,
// 当T为0(假)时,因为没有else 语句,电路保持 Q 以前的值,
// 这就形成一个锁存器。

注意语法

算术表达式结果的长度由最长的操作数决定

1
2
assign Dbus [7:4] = {Dbus [0], Dbus [1], Dbus[2], Dbus[3] } ;
// 以反转的顺序将低端4 位赋给高端4 位。

reg 是最常用的寄存器类型, 寄存器类型通常用于对存储单元的描述
如在always 语句中进行描述的必须用reg 类型的变量

  1. reg 类型定义语法如下:
    reg [msb: lsb] reg1, reg2, . . . reg N;
    msb 和lsb 定义了范围,并且均为常数值表达式。
  2. 寄存器类型的值可取负数,但若该变量用于表达式的运算中,则按无符号类型处理
  3. 对数组类型,请按降序方式,如[7:0];