Verilog 最常用的 2 种数据类型就是线网(wire)与寄存器(reg),其余类型可以理解为这两种数据类型的扩展或辅助。
线网(wire)
wire 类型表示硬件单元之间的物理连线,由其连接的器件输出端连续驱动。如果没有驱动元件连接到 wire 型变量,缺省值一般为 "Z"。举例如下
wire interrupt ; wire flag1, flag2 ; wire gnd = 1'b0 ;
线网型还有其他数据类型,包括 wand,wor,wri,triand,trior,trireg 等。
寄存器(reg)
寄存器(reg)用来表示存储单元,它会保持数据原有的值,直到被改写。其中1位的话可以存储2个数,0和1;2位的话,就是2的2次方,4个数:0,1,2,3;以此类推,n位寄存器可以存储2^n个数
声明举例如下:
reg clk_temp; reg flag1, flag2 ; reg [1:0] cnt;
例如在 always 块中,寄存器可能被综合成边沿触发器,在组合逻辑中可能被综合成 wire 型变量。寄存器不需要驱动源,也不一定需要时钟信号。在仿真时,寄存器的值可在任意时刻通过赋值操作进行改写。例如:
reg rstn ; initial begin rstn = 1'b0 ; #100 ; rstn = 1'b1 ; end
关于wire和reg寄存器的理解
图1 变量类型
由图 1 可以看出,wire 型变量在物理结构上只是一根线,在 Verilog HDL 描述时,对线型变量赋值用 assign 即可,相对比较简单。由图 1 可以看出 reg 型变量左端有一个输入端口 D,右端有一个输出端口 Q, 并且 reg 型存储数据赋值需要在 clk(时钟)沿的控制下完成,它是由晶振产生,是我们描述数字电路时最基本的时间单元,它的周期固定,占空比一般为 50%(即高电平占整个周期的比例)。clk 的低电平用数字 0 表示,高电平用 1 表示,从低电平转变到高电平的过程叫做上升沿,从高电平转变到低电平的过程叫做下降沿,如图 2 所示。
图2 时钟周期
reg 在物理结构上相对比较麻烦,在 Verilog HDL 描述时也相对麻烦。在对reg 型变量进行赋值时,必须在 always 块内完成,可以选择用时钟上升沿,也可以选择时钟下降沿,具体用上升沿还是用下降沿可以根据需要所定。我们可以试着将第一章中的 po_c 改为 reg 型变量,完成 pi_a 和 pi_b 想与之后的结果传输给 寄存器变量 po_c,RTL 电路图如图 3 所示。
图3 RTL电路
向量
当位宽大于 1 时,wire 或 reg 即可声明为向量的形式。例如:
reg [3:0] counter ; //声明4bit位宽的寄存器counter wire [32-1:0] gpio_data; //声明32bit位宽的线型变量gpio_data wire [8:2] addr ; //声明7bit位宽的线型变量addr,位宽范围为8:2 reg [0:31] data ; //声明32bit位宽的寄存器变量data, 最高有效位为0
对于上面的向量,我们可以指定某一位或若干相邻位,作为其他逻辑使用。例如:
wire [9:0] data_low = data[0:9] ; addr_temp[3:2] = addr[8:7] + 1'b1 ;
关于Always语句的使用,先写了这些
在Verilog中always@(*)语句的意思是always模块中的任何一个输入信号或电平发生变化时,该语句下方的模块将被执行。
1、always语句有两种触发方式。第一种是电平触发,例如always @(a or b or c),a、b、c均为变量,当其中一个发生变化时,下方的语句将被执行。
2、第二种是沿触发,例如always @(posedge clk or negedge rstn),即当时钟处在上升沿或下降沿时,语句被执行。
3、而对于always@(*),意思是以上两种触发方式都包含在内,任意一种发生变化都会触发该语句。