FPGA-verilog

数据类型

常量

  • 整数:整数可以用二进制 b 或 B,八进制 o 或 O,十进制 d 或 D,十六进制 h 或 H 表示。例如:
    8’b00001111 表示 8 位位宽的二进制整数,4’ha 表示 4 位位宽的十六进制整数。
  • x 和 z:x 代表不定值,z 代表高阻值。例如:
    5’b00x11,第三位不定值,3’b00z 表示最低位
    为高阻值。
  • 下划线:在位数过长时可以用来分割位数,提高程序可读性,如 8’b0000_1111
  • 参数 parameter:parameter 可以用标识符定义常量,运用时只使用标识符即可,提高可读性及维护性,如定义 parameter width = 8 ; 定义寄存器 reg [width-1:0] a; 即定义了 8 位宽度的寄存器。
    Parameter 可以用于模块间的参数传递,而 localparam 仅用于本模块内使用,不能用于参数传递。localparam 多用于状态机状态的定义。

变量

  • wire型
    wire 类型变量,也叫网络类型变量,用于结构实体之间的物理连接,如门与门之间,不能储存值,用连续赋值语句 assign 赋值,定义为 wire [n-1:0] a ; 其中 n 代表位宽,如定义 wire a ; assign a = b ; 是将 b 的结点连接到连线 a 上。
  • reg型
    reg 类型变量,也称为寄存器变量,可用来储存值,必须在 always 语句里使用。其定义为 reg [n-1:0] a ; 表示 n 位位宽的寄存器,如 reg [7:0] a; 表示定义 8 位位宽的寄存器 a。
  • memory型
    可以用 memory 类型来定义 RAM,ROM 等存储器,其结构为 reg [n-1:0] 存储器名[m-1:0],意义为 m 个 n 位宽度的寄存器。例如,reg [7:0] ram [255:0]表示定义了 256 个 8 位寄存器,256 也即是存储器的深度,8 为数据宽度。

运算符

其他运算符与C语言大多相似,重点是赋值运算符。

  • **=**:阻塞赋值
    阻塞赋值为执行完一条赋值语句,再执行下一条,可理解为
    顺序执行,而且赋值是立即执行。
    如 b <= a;b的值并不是立刻就改变的,块结束后才完成赋值操作。
  • **<=**:非阻塞赋值
    非阻塞赋值可理解为并行执行,不考虑顺序,在 always 块语句执行完成后,才进行赋值。
    如 b = a;b的值在赋值语句执行完后立刻就改变。赋值语句执行完后,块才结束。

非阻塞:

1
2
3
4
5
always @(posedge clk)
begin
b <= a;
c <= b;
end

上面的 always 块中使用了非阻塞赋值方式,定义了两个 reg 型信号 b 和 c,clk 信号的上升沿到来时,b 就等于 a,c 就等于 b,这里应该用到了两个触发器。

请注意:赋值是在 always 块结束后执行的,c 应为原来 b 的值。这个”always”块实际描述的电路功能如下图所示:
非阻塞

阻塞:

1
2
3
4
5
always @(posedge clk)
begin
b = a;
c = b;
end

而该例中用了阻塞赋值方式。clk信号的上升沿到来时,将发生如下的变化:b 马上取 a 的值,c 马上取 b 的值(即等于 a),生成的电路图如下所示只用了一个触发器来寄存器 a 的值,又输出给 b 和 c。
非阻塞

块语句

块语句通常用来将两条或多条语句组合在一起,使其在格式上看更象一条语句。
块语句有两种,一种是 begin_end 语句,通常用来标识顺序执行的语句,用它来标识的块称为顺序块。一种是 fork_join 语句,通常用来标识并行执行的语句,用它来标识的块称为并行块。

顺序块

顺序块特点:

  1. 块内的语句是按顺序执行的,即只有上面一条语句执行完后下面的语句才能执行。
  2. 每条语句的延迟时间是相对于前一条语句的仿真时间而言的。
  3. 直到最后一条语句执行完,程序流程控制才跳出该语句块。
    1
    2
    3
    4
    5
    6
    begin
    语句1;
    语句2;
    ···
    语句n;
    end

并行块

并行块特点:

  1. 块内语句是同时执行的,即程序流程控制一进入到该并行块,块内语句则开始同时并行地执行。
  2. 块内每条语句的延迟时间是相对于程序流程控制进入到块内时的仿真时间的。
  3. 延迟时间是用来给赋值语句提供执行时序的。
  4. 当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块。
    1
    2
    3
    4
    5
    6
    fork
    语句1;
    语句2;
    ···
    语句n;
    join

if_else

1
2
3
4
5
6
7
8
9
10
11
12
if(判断)
begin
语句1;
语句2;
···
end
else
begin
语句1;
语句2;
···
end

case

1
2
3
4
5
6
7
case()
1: 语句1;
2: 语句2;
3: 语句3;
4: 语句4;
default: 语句;
endcase

使用条件语句不当生成锁存器

Verilog HDL设计中容易犯的一个通病是由于不正确使用语言,生成了并不想要的锁存器。下面是一个在“always”块中不正确使用if语句,造成这种错误的例子。
例
左边的 always 块,if语句保证了只有当 al=1 时,q 才取 d 的值。这段程序没有写出 al = 0 时的结果, 如果在给定的条件下变量没有赋值,这个变量将保持原值,也就是说会生成一个锁存器。