Verilog读书笔记---数据类型、系统任务、`define、parameter、localparam三者的区别

本文目的

主要梳理之前学习Verilog的疏漏内容,系统了解Verilog语法。

Verilog的数据类型:

Verilog有两组主要的数据类型:网络数据类型(Net Data Type)和寄存器数据类型(Register Data Type)。其他的数据类型有:事件(Event)、参数(Parameter)和范围(Specparam)以及其他数据类型。

Verilog还是用强度值来解决数字电路中不同强度的驱动源之间的赋值冲突
在这里插入图片描述
如果两个具有不同强度的信号驱动同一个线网,则竞争结果值为高强度信号的值。

如果两个强度相同的信号之间发生竞争,则结果为不确定值。

整数、实数和时间寄存器类型

整数

是一种通用的寄存器数据类型,用于对数量进行操作,使用integer进行声明。

integer counter;       //一般用途的变量用作计数器

initial

     counter = -1;    //把-1存储到寄存器中

实数:

实常量和实数寄存器数据类型使用关键字real来声明,可以用十进制或科学计数法
来表示。实数声明不能带有范围,其默认值为0.如果将一个实数赋予一个整数,
那么实数将会被取为最接近的整数。

real delta;         //定义一个名为delta的实型变量

时间寄存器

仿真是按照仿真时间进行的,verilog使用一个特殊的时间寄存器数据类型来保存仿真时间。
时间变量通过使用关键字time来声明,其宽度与具体实现无关,最小为64位。通过调用系统
函数$time可以取得当前的仿真时间。

数组

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.

nets型

wire型数据常用来表示用于以assign关键字指定的组合逻辑信号。

Verilog程序模块中输入输出信号类型默认为wire型。

wire型信号可以用做方程式的输入,也可以用做”assign”语句或者实例元件的输出
在这里插入图片描述

reg型

reg是寄存器数据类型的关键字。

寄存器是数据存储单元的抽象,通过赋值语句可以改变寄存器存储的值,其作用相当于改变触发器存储器的值。

reg型数据常用来表示always模块内的指定信号,代表触发器。

通常在设计中要由always模块通过使用行为描述语句来表达逻辑关系。在always块内被赋值的每一个信号都必须定义为reg型,即赋值操作符的右端变量必须是reg型

reg型号数据的格式:

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位寄存器

Reg mema [ 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位)

wire a;      //标量线网变量,默认

wire [7:0] bus;          //8位的总线

reg clock  ;                 //标量寄存器,默认

reg   [0:40]        virtual_addr;    //向量寄存器,41位宽的虚拟地址

向量通过[high#:low#]进行说明,方括号中左边的数总是代表向量的最高有效位。

可变向量域选择

在这里插入图片描述

Verilog的系统任务

系统任务也属于行为级建模,系统任务的调用要出现在initial与always结构中。所有的任务都已$开头。

1、 d i s p l a y , display, display,write用于信息的显示和输出。

%b或%B 二进制
%o或%O 八进制
%d或%D 十进制
%h或%H 十六进制
%e或%E 实数
%c或%C 字符
%s或%S 字符串
%v或%V 信号强度
%t或%T 时间
%m或%M 层次实例
===
\n 换行
\t 制表符
\ 反斜杠\
" 引号”
%% 百分号%
调用方式:eg:$display("%b+%b=%b",a,b,sum);

                         $write("%b+%b=%b",a,b,sum);

注:如果没有在指定变量的显示格式,不会输出数值。如果没有指定变量显示的位置,变量值会在字符串部分之后直接显示出来,变量之间是没有间隔的,只是一次简单的显示。

显示任务 d i s p l a y 默 认 显 示 的 格 式 是 十 进 制 的 , 还 有 display默认显示的格式是十进制的,还有 displaydisplayb, d i s p l a y o , displayo, displayo,displaybh的显示格式分别是二进制,八进制,十六进制。同理有 w r i t e , write, writewriteo, w r i t e b , writeb, writebwriteh。

d i s p l a y 与 display与 displaywrite的区别是: d i s p l a y 会 在 每 次 显 示 信 息 后 自 动 换 行 , display会在每次显示信息后自动换行, displaywrite不会换行.

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命令会在当前时间部结束时完成;而 strobedisplay是只要仿真器看到就会立即执行。

3、$monitor监测任务

监测任务用于持续监测指定变量,只要这些变量发生了变化,就会立即显示对应的输出语句,并且在仿真中只能进行一次调用,后面的调用会覆盖前面的。

eg:

initial begin

$monitor("x=%b,y=%b,cin=%b",x,y,cin);

end

同理,有 m o n i t o r , monitor, monitor,monitorb m o n i t o r o monitoro monitoromonitorh。
可用$monitoroff,monitoeron关闭监事和打开监视。

4、 s t o p , stop, stop,finish仿真控制任务
区别: s t o p 暂 停 当 前 方 针 , stop暂停当前方针, stopfinish终止值当前方针。

`define:作用 -> 常用于定义常量可以跨模块、跨文件;

                        范围 -> 整个工程;

parameter:     作用 -> 常用于模块间参数传递;

                       范围 -> 本module内有效的定义;

localparam       作用 -> 常用于状态机的参数定义;

                       范围 -> 本module内有效的定义,不可用于参数传递;

                                  localparam cannot be used within the module port parameter list.

2、应用举例

`define、parameter、localparam三者的区别及举例

`define

概念:可以跨模块的定义,写在模块名称上面,在整个设计工程都有效。
           一旦`define指令被编译,其在整个编译过程中都有效。例如,通
           过另一个文件中的`define指令,定义的常量可以被其他文件调用,
           直到遇到 `undef;
    举例:定义 `define UART_CNT 10'd1024
               使用 `UART_CNT

parameter

概念:本module内有效的定义,可用于参数传递;
           如果在模块内部定义时无法进行参数传递,
           若在模块名后照下面这样写则可以进行传递

举例:定义

module video_in
           #(
          parameter MEM_DATA_BITS = 64,
          parameter INTERLACE     = 1      // 0
          )
          (
           input     clk,
           input     rst_n,
          
           output    burst_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内有效的定义,不可用于参数传递;
           localparamcannot be used within the module port parameter list.
           一般情况下,状态机的参数都是用localparam的。

举例:

 
          localparam BURST_LEN               = 10'd64;     /*一次写操作数据长度 */
          
          localparam BURST_IDLE              = 3'd0;       /*状态机状态:空闲 */
          localparam BURST_ONE_LINE_START    = 3'd1;       /*状态机状态:视频数据一行写开始 */
          localparam BURSTING                = 3'd2;       /*状态机状态:正在处理一次ddr2写操作 */
          localparam BURST_END               = 3'd3;       /*状态机状态:一次ddr2写操作完成*/
          localparam BURST_ONE_LINE_END      = 3'd4;       /*状态机状态:视频数据一行写完成*/
          
          reg[2:0]  burst_state              = 3'd0;       /*状态机状态:当前状态 */
          reg[2:0]  burst_state_next         = 3'd0;       /*状态机状态:下一个状态*/

猜你喜欢

转载自blog.csdn.net/weixin_41445387/article/details/104615443