本文目的
主要梳理之前学习Verilog的疏漏内容,系统了解Verilog语法。
Verilog的数据类型:
Verilog有两组主要的数据类型:网络数据类型(Net Data Type)和寄存器数据类型(Register Data Type)。其他的数据类型有:事件(Event)、参数(Parameter)和范围(Specparam)以及其他数据类型。
Verilog还是用强度值来解决数字电路中不同强度的驱动源之间的赋值冲突
如果两个具有不同强度的信号驱动同一个线网,则竞争结果值为高强度信号的值。
如果两个强度相同的信号之间发生竞争,则结果为不确定值。
整数、实数和时间寄存器类型
整数
是一种通用的寄存器数据类型,用于对数量进行操作,使用integer进行声明。
integercounter; //一般用途的变量用作计数器initialcounter=-1; //把-1存储到寄存器中
实数:
实常量和实数寄存器数据类型使用关键字real来声明,可以用十进制或科学计数法来表示。实数声明不能带有范围,其默认值为0.如果将一个实数赋予一个整数,那么实数将会被取为最接近的整数。realdelta; //定义一个名为delta的实型变量
时间寄存器
仿真是按照仿真时间进行的,verilog使用一个特殊的时间寄存器数据类型来保存仿真时间。时间变量通过使用关键字time来声明,其宽度与具体实现无关,最小为64位。通过调用系统函数$time可以取得当前的仿真时间。
数组
Verilog中允许声明reg、integer、time、real、realtime及其向量类型的数组,对数组的维数没有限制,即可声明任意维数的数组。线网数组也可用于连接实例的端口,数组中的每个元素都可以作为一个标量或者向量,以同样的方式来使用,形如<数组名>[<下标>]。
Integercount[0:7]; //由八位计数变量组成的数组regbool [31:0]; //由32个1位的布尔寄存器变量组成的数组wire [7:0] w_array2 [5:0]; //声明8位向量的数组
注意:不要把数组和线网或寄存器向量混淆起来。向量是一个单独的元件,它的位宽是n,数组由多个元件组成,其中每个元件的位宽为n或1.
nets型
wire型数据常用来表示用于以assign关键字指定的组合逻辑信号。
Verilog程序模块中输入输出信号类型默认为wire型。
wire型信号可以用做方程式的输入,也可以用做”assign”语句或者实例元件的输出
reg型
reg是寄存器数据类型的关键字。
寄存器是数据存储单元的抽象,通过赋值语句可以改变寄存器存储的值,其作用相当于改变触发器存储器的值。
reg型数据常用来表示always模块内的指定信号,代表触发器。
通常在设计中要由always模块通过使用行为描述语句来表达逻辑关系。在always块内被值的每一个信号都必须定义为reg型,即赋值操作符的右端变量必须是reg型
rg型号数据的格式:
reg[n-1:0]数据名1,数据名2,…,数据N;
//定义了N个寄存器变量,每个数据位宽为n
reg型数据的默认值是不定的。reg型数据可以为正值或负值。当一个reg型数据是一个表达式中的操作数时,它的值被当做无符号值,即正值(如果一个4位的reg型数据被写入-1,在表达式中运算时,其值被认为是+15)
reg型和wire型的区别:reg型保持最后一次的赋值,而wire型需要持续驱动。
Memory型
尽管memory型数据和reg型数据的定义格式很相似,但是要注意不同之处。Memory描绘的是深度,reg描绘的是宽度。
Reg [ n-1:0 ] rega; //一个n位寄存器Regmema [ n-1 ] //一个由n个一位寄存器组成的存储器组一个n位的寄存器可以在一条赋值语句里进行赋值。而一个完整的存储器不行Rega=0;//合法的赋值语句Mema=0;//非法的赋值语句Mema[3]=0;//合法,给memory中的第三个单元赋值为0
数组
Verilog中允许声明reg、integer、time、real、realtime及其向量类型的数组,对数组的维数没有限制,即可声明任意维数的数组。线网数组也可用于连接实例的端口,数组中的每个元素都可以作为一个标量或者向量,以同样的方式来使用,形如<数组名>[<下标>]。
Integer count[0:7]; //由八位计数变量组成的数组
reg bool [31:0]; //由32个1位的布尔寄存器变量组成的数组
wire [7:0] w_array2 [5:0]; //声明8位向量的数组
=注意:不要把数组和线网或寄存器向量混淆起来。向量是一个单独的元件,它的位宽是n,数组由多个元件组成,其中每个元件的位宽为n或1.==
向量
线网和寄存器类型的数据均可声明为向量(位宽大于1)。如果在声明中没有指定位宽,则默认为标量(1位)
wirea; //标量线网变量,默认wire [7:0] bus; //8位的总线regclock ; //标量寄存器,默认reg [0:40] virtual_addr; //向量寄存器,41位宽的虚拟地址
向量通过[high#:low#]进行说明,方括号中左边的数总是代表向量的最高有效位。
可变向量域选择
Verilog的系统任务
系统任务也属于行为级建模,系统任务的调用要出现在initial与always结构中。所有的任务都已$开头。
1、d i s p l a y , display,display,write用于信息的显示和输出。
调用方式:eg:$display("%b+%b=%b",a,b,sum); $write("%b+%b=%b",a,b,sum);
注:如果没有在指定变量的显示格式,不会输出数值。如果没有指定变量显示的位置,变量值会在字符串部分之后直接显示出来,变量之间是没有间隔的,只是一次简单的显示。
显示任务d i s p l a y 默 认 显 示 的 格 式 是 十 进 制 的 , 还 有 display默认显示的格式是十进制的,还有display默认显示的格式是十进制的,还有displayb,d i s p l a y o , displayo,displayo,displaybh的显示格式分别是二进制,八进制,十六进制。同理有w r i t e , write,write,writeo,w r i t e b , writeb,writeb,writeh。
display与write的区别是:d i s p l a y 会 在 每 次 显 示 信 息 后 自 动 换 行 , display会在每次显示信息后自动换行,display会在每次显示信息后自动换行,write不会换行.
2、$strobe探测任务
探测任务的语法和显示任务完全相同,也是把信息显示出来。也有s t r o b e , strobe,strobe,strobeb,s t r o b e o , strobeo,strobeo,strobeh四种。
两者的区别在于:s t r o b e 命 令 会 在 当 前 时 间 部 结 束 时 完 成 ; 而 strobe命令会在当前时间部结束时完成;而strobe命令会在当前时间部结束时完成;而display是只要仿真器看到就会立即执行。
3、$monitor监测任务
监测任务用于持续监测指定变量,只要这些变量发生了变化,就会立即显示对应的输出语句,并且在仿真中只能进行一次调用,后面的调用会覆盖前面的。
eg:initialbegin$monitor("x=%b,y=%b,cin=%b",x,y,cin); end
同理,有m o n i t o r , monitor,monitor,monitorbm o n i t o r o monitoromonitoromonitorh。
可用$monitoroff,monitoeron关闭监事和打开监视。
4、s t o p , stop,stop,finish仿真控制任务
区别:s t o p 暂 停 当 前 方 针 , stop暂停当前方针,stop暂停当前方针,finish终止值当前方针。
`define:作用 -> 常用于定义常量可以跨模块、跨文件;
范围->整个工程; parameter:作用->常用于模块间参数传递; 范围->本module内有效的定义; localparam作用->常用于状态机的参数定义; 范围->本module内有效的定义,不可用于参数传递; localparamcannotbeusedwithinthemoduleportparameterlist.
2、应用举例
`define、parameter、localparam三者的区别及举例
`define
概念:可以跨模块的定义,写在模块名称上面,在整个设计工程都有效。一旦`define指令被编译,其在整个编译过程中都有效。例如,通过另一个文件中的`define指令,定义的常量可以被其他文件调用, 直到遇到 `undef;
举例:定义 `defineUART_CNT10'd1024使用 `UART_CNT
parameter
概念:本module内有效的定义,可用于参数传递; 如果在模块内部定义时无法进行参数传递, 若在模块名后照下面这样写则可以进行传递
举例:定义
modulevideo_in#(parameterMEM_DATA_BITS=64, parameterINTERLACE=1//0) ( inputclk, inputrst_n, outputburst_finsh );
使用 -> 调用此模块的时候可以像端口信号传递一样进行参数传递
video_in#( .MEM_DATA_BITS ( 64 ), .INTERLACE ( 1 ) )u_video_in ( .clk (clk_50m), .rst_n (rst_n), .burst_finsh (burst_finsh) );
localparam:
概念:本module内有效的定义,不可用于参数传递;localparamcannotbeusedwithinthemoduleportparameterlist. 一般情况下,状态机的参数都是用localparam的。
举例:
localparamBURST_LEN=10'd64; /*一次写操作数据长度 */localparamBURST_IDLE=3'd0; /*状态机状态:空闲 */localparamBURST_ONE_LINE_START=3'd1; /*状态机状态:视频数据一行写开始 */localparamBURSTING=3'd2; /*状态机状态:正在处理一次ddr2写操作 */localparamBURST_END=3'd3; /*状态机状态:一次ddr2写操作完成*/localparamBURST_ONE_LINE_END=3'd4; /*状态机状态:视频数据一行写完成*/reg[2:0] burst_state=3'd0; /*状态机状态:当前状态 */reg[2:0] burst_state_next=3'd0; /*状态机状态:下一个状态*/