Verilog HDL 语法整理 (四)

目录

前言

一、时间相关语法

1、时间单位及精度

2、延时等待

2.1 有限等待

2.2 无限等待

2.3 变换等待

2.4 边沿等待

2.5 条件等待

2.6 赋值等待

二、时钟激励语法

1、占空比50%的时钟生成

2、时钟相位调整

3、差分时钟生成

三、仿真循环语法

1、while循环

2、forever循环

3、repeat循环

4、跳出循环

四、字符显示语法

五、系统数据导入

六、系统文件操作函数

1、文件打开、关闭、状态

1.1 文件打开

1.2 文件关闭

1.3 文件状态

2、读文件

2.1 $fgets

2.2 $fgetc

2.3 $fscanf

3、写文件

3.1 $display

3.2 $fwrite

3.3 $fstrobe

3.4 $fmonitor

七、系统屏幕操作函数

八、系统随机生成函数

九、系统仿真时间函数

1、仿真时间获取

1.1 $time

1.2 $stime

1.3 $realtime

2、时间格式设定函数

十、系统仿真进度控制任务

1、$stop

2、$finish

参考说明




前言

        本文承接前文:Verilog HDL 语法整理 (三)。主要介绍与 仿真相关 的语法内容。



一、时间相关语法

1、时间单位及精度

        在仿真 的test bench 文件最开始的地方,需要注明仿真所用的 时间单位以及 时间精度。

`timescale 1ns/1ps  //时间单位:1ns,精度:1ps

2、延时等待

2.1 有限等待

语法: #<延迟时间> ;

2.2 无限等待

用循环间接实现 无限等待。语句:

forever
    begin
        # <延迟时间> ;
    end

2.3 变换等待

语法:@(<信号名称>) ;

含义:某信号改变时,才会执行其后面的代码,否则一直等待其变化。

2.4 边沿等待

语法:@(negedge <信号名称>);// 信号下降沿 等待

           @(posedge <信号名称>);// 信号上升沿 等待

2.5 条件等待

语法:wait(<信号名称> == <数值>) ; //当程序执行到此语句时,开始等待,直到 <信号名称> == <数值> 条件为真时,停止等待,执行后续语句。

2.6 赋值等待

1、连续赋值等待语句

语法:assign  #<延迟时间>   <信号A>  =   <信号B> ;// 表示 信号B 延迟设定时间后 赋值给 信号A

此用法可以用来模拟FPGA内部 由于布线造成的信号延迟。

2、阻塞赋值等待语句

句法一:  #<延迟时间>   <信号名称> = <数值> ;//程序执行到 此语句时 开始等待所设定的时间后 将数值赋值给信号,之后再执行后面的语句。

句法二:<信号名称> = #<延迟时间>  <数值> ;//功能同上

3、非阻塞赋值等待语句

句法一:  #<延迟时间>   <信号名称>   <=   <数值> ;//程序执行到 此语句时 开始等待所设定的时间后 将数值赋值给信号,之后再执行后面的语句。

句法二:<信号名称>    <=    #<延迟时间>  <数值> ;//程序执行到 此语句时,没有延时继续执行后面的语句 ,等待所设定的时间后 将数值赋值给信号。

二、时钟激励语法

1、占空比50%的时钟生成

//产生 50MHz 50% 占空比的时钟 I_CLK
`define PERIOD 20
//法一:
reg I_CLK ;
initial 
    begin
        I_CLK = 0;
        #(PERIOD/2);
        forever
            begin
                #(PERIOD/2)  I_CLK = ~I_CLK ;
            end
    end

//法二:
reg I_CLK ;
always
    begin
        I_CLK = 1'b0 ;
        #(PERIOD/2);
        I_CLK = 1'b1 ;
        #(PERIOD/2);
    end
//法三:
reg I_CLK = 1'b0 ;
always
    begin
      #(PERIOD/2) ;
      I_CLK = ~I_CLK ;
    end

2、时钟相位调整

举例说明:

//产生 50MHz 50% 占空比的时钟 I_CLK
`define PERIOD 20
//原始时钟
reg I_CLK ;
always
    begin
        I_CLK = 1'b0 ;
        #(PERIOD/2);
        I_CLK = 1'b1 ;
        #(PERIOD/2);
    end
//右移5ns
//法一:
always
    begin
        I_CLK = 1'b1 ;
        #5 ;
        I_CLK = 1'b0 ;
        #(PERIOD/2);
        I_CLK = 1'b1 ;
        #(PERIOD/2-5);
    end
//法二:
always
    begin
        I_CLK <= #5 1'b0 ;
        #(PERIOD/2);
        I_CLK <= #5 1'b1 ;
        #(PERIOD/2);
    end
//法三:
always
    begin
        I_CLK_1 = 1'b0 ;
        #(PERIOD/2);
        I_CLK_1 = 1'b1 ;
        #(PERIOD/2);
    end
assign #5 I_CLK = I_CLK_1;

3、差分时钟生成

差分时钟的两个电平 时钟相反,抓住这一点即可,先构造单端时钟,然后取反。示例:

//产生 50MHz 50% 占空比的差分时钟 I_CLK_P、I_CLK_N
`define PERIOD 20
//法一:
reg I_CLK ;
initial 
    begin
        I_CLK_P = 1;
        I_CLK_N = 0;
        #(PERIOD/2);
        forever
            begin
                #(PERIOD/2)  {I_CLK_P,I_CLK_N} = ~{I_CLK_P,I_CLK_N} ;
            end
    end

//法二:
reg I_CLK ;
always
    begin
        I_CLK_P = 1;
        I_CLK_N = 0;
        #(PERIOD/2);
        I_CLK_P = 0;
        I_CLK_N = 1;
        #(PERIOD/2);
    end

三、仿真循环语法

1、while循环

语法:

while (<循环条件>)//当循环条件为真时,一直执行,否则跳出
    begin
        <代码段>;
    end

2、forever循环

语法:

forever 
    begin
        <代码段> ;//一直重复执行
    end

3、repeat循环

语法:

repeat (<数值>)//持续执行 代码段 所设定的次数后 退出
    begin
        <代码段> ;
    end

4、跳出循环

语法:

disable  <循环标识符> ;

举例:

initial
    forever 
        begin : clock_gen
            #10 clk=1;
            #10 clk=0;
        end
always @(posedge quit)
    begin 
        disable clock_gen;//quit 信号上升沿到来,退出循环 :clock_gen
    end

四、字符显示语法

波形图显示 有意义的 ASCII 字符。(实际仿真用的少)

示例:

reg [(8*8)-1 : 0] state_string = "power on";//8个字符

always
    begin
        #10 state_string = "idle";//4个字符
        #50 state_string = "work";//4个字符
    end

【注意】:

1、一个ASCII 字符占 8 位。需要为 ASCII 字符串留足够的空间;

2、查看波形时,将基数设置为 ASCII 

五、系统数据导入

语法:

//首先 定义寄存器数组用来存放读出数据
reg [<数据位宽>]  <数组名称>  [<数据深度>] ;

initial 
    begin 
    //二进制数据读入
    $readmemb ("文件路径", <数组名称> ,<起始地址> ,<结束地址>) ;

    //十六进制数据读入
    $readmemh ("文件路径", <数组名称> ,<起始地址> ,<结束地址>) ;

【注意】:

1、文件中只能包含数据、空白、注释、标号,编号的语法:@<地址>;

2、数组中载入的第0个数据,是与起始地址相对应的数据。

六、系统文件操作函数

1、文件打开、关闭、状态

1.1 文件打开

语法:

integer  <文件地址> ;//定义一个 地址变量
<文件地址> = $fopen ("<文件路径>" , "<打开方式>") ;// 文件地址赋值

//可选的打开方式
"r"  : 以文本形式读取
"r+" : 以文本形式读、写
"w"  : 以文本形式打开文件,进行写入(会覆盖 该文件以前所有的内容)
"wb" : 以二进制形式打开文件,进行写入(会覆盖 该文件以前所有的内容)
"a"  : 以文本形式打开文件,进行写入(写入的内容会加在原文件的末尾)
"ab" : 以二进制形式打开文件,进行写入(写入的内容会加在原文件的末尾)

1.2 文件关闭

语法:

$fclose  (<文件地址>) ;//一般在 打开一个文件操作完成后,关闭文件时,用此函数

1.3 文件状态

文件末尾判断:

$feof  (<文件地址>)  ; //到达文件末尾 返回 1,否则返回 0

2、读文件

2.1 $fgets

语法:

integer <整型变量> ;

reg [8*<字符个数>-1 :0]  <字符变量> ;
<整型变量> = $fgets(<字符变量> ,<文件地址>);

$fgets 一次读取文件中的一行数据,以 字符串 的形式保存到字符变量中,返回 字符个数。

2.2 $fgetc

语法:

reg [7:0] <变量名> ;
<变量名> = $fgetc(<文件地址>) ;

$fgetc 一次读取一个字符,返回-1时 表示读取到文件末尾了。

2.3 $fscanf

语法:

integer  <整型变量> ;
<整型变量>  = $fscanf (<文件地址> , "<形式>" , <目的寄存器变量名>) ;

//形式可包括:
%b : 二进制数据
%h : 十六进制数据
%d : 十进制数据
%o : 八进制数据
%t : 时间类型数据
%s : 字符串数据
%c : ASCII字符数据
%f : 实数数据
%e : 指数数据
%m : 模块层次名数据
%v : 驱动强度数据

//转义字符
%% : 百分号
\t : 制表符
\n : 回车
\\ : 反斜杠
\" : 双引号
\<octal> : ASCII 码字符

每次从文件中读取一个符合 所给形式 的数据,存入目的寄存器变量。

3、写文件

3.1 $display

语法:

$fdisplay(<文件地址>,"<形式>",<变量名列表>);

$fdisplay 将 ”<形式>“ 中的内容写入目标文件中,且自动回车

"<形式>" 与 $fscanf 中的相同

<变量名列表> 中的元素多于一个 用英文 逗号隔开

3.2 $fwrite

语法:

$fwrite(<文件地址>,"<形式>",<变量名列表>);

用法与 $fdisplay 相同,只不过不会在写入一次数据后进行回车。

3.3 $fstrobe

语法:

$fstrobe(<文件地址>,"<形式>",<变量名列表>);

用法与 $fdisplay 相同,只不过需要等待队列中的仿真事件结束之后才开始写入数据。

3.4 $fmonitor

语法:

$fmonitor(<文件地址>,"<形式>",<变量名列表>);

当变量列表中 ,某个变量发生变化,将所对应的 ”<形式>“ 中的内容写入 文件中,并有回车

【注】:形式中 可以是有意义的字符串,引用的变量要和后面 变量名列表中的一一对应

如:

$fdisplay(message,"Error occurred on adress bus" , "at time %d , address = %h" , $time , address ) ;

$fdisplay(alu_chann , "acc= %h f= %h a= %h b= %h" , acc , f , a , b ) ;

七、系统屏幕操作函数

        用法与第六小节的相同,只不过没有 文件地址 这一项。常用的有:$display 、$write 、$strobe 、$monitor 。举例:

$display ("rval = %h hex %d decimal" , rval , rval) ;

$display ("rval = %o octal \n rval = %b bin" , rval , rval) ;

八、系统随机生成函数

语法:

<寄存器变量名> = $random(<seed>);// 用于产生最基本的伪随机序列
<寄存器变量名> = $dist_uniform(<seed>,<start>,<\end>);// 用于产生均匀分布在<start>,<\end>之间的随机序列
<寄存器变量名> = $dist_normal(<seed>,<mean>,<standard_deviation>);// 用于产生均值为<mean>,方差为<standard_deviation>的正态随机序列
<寄存器变量名> = $dist_exponential(<seed>,<mean>);// 用于产生均值为<mean>的指数分布随机序列
<寄存器变量名> = $dist_poisson(<seed>,<mean>);// 用于产生均值为<mean>的泊松分布随机序列
<寄存器变量名> = $dist_chi_square(<seed>,<自由度>);// 用于产生自由度为设定值的卡方分布随机序列
<寄存器变量名> = $dist_t(<seed>,<自由度>);// 用于产生自由度为设定值的t分布随机序列

【注】

1、关键字作为变量时 前面加 转义字符 ”\“ ,如 \end

2、种子 <seed> 不能直接以 整型常数的形式出现在 系统任务中。

例:

reg [15:0] RANDOM ;

RANDOM = $random %100 ; //产生 介于【-99 , 99】之间的随机数

RANDOM = {$random} %100 ; //产生 介于【0 , 99】之间的随机数

RANDOM = 5 + {$random} %(100 - 5 + 1) ; //产生 介于【5 , 100】之间的随机数

九、系统仿真时间函数

1、仿真时间获取

1.1 $time

        以64位整形数返回当前系统所处的仿真时间。

1.2 $stime

        以32位整形数返回当前系统所处的仿真时间。

1.3 $realtime

        以实数形式返回当前系统所处的仿真时刻。

2、时间格式设定函数

语法:

$timeformat(<单位>,<精度>,<单位字符串>,<时间区域的最小字符宽度>) ;

【说明】

1、<单位> 是整数,表示时间单位 ,如-9,表示10的-9次方,即纳秒;

2、<精度> 表示精度位数,在时间单位之后 有几位小数。

例:

initial

        begin

               $timeformat(-6,6,"us,13);

        end

十、系统仿真进度控制任务

1、$stop

        暂停当前仿真执行,可继续。

2、$finish

        直接退出当前仿真,不可继续,除非开启新一次的仿真。

参考说明

【1】夏宇闻. Verilog 数字系统设计教程 第二版.

【2】狄超. FPGA之道.

【3】IEEE Standard for Verilog Hardware Description Language 1364-2005.



文末推荐

掌握了基本的Verilog语法,不去实战练习的话很难有大的突破。牛客网可以为大家提供一个免费的刷题练习的平台。非常推荐大家使用。

 链接如下:牛客网-Verilog专项https://www.nowcoder.com/link/pc_csdncpt_zls_verilog这个里面有很多代码题目练习,对于新手来说可以快速掌握Verilog编程的基本语法,对于老手来说也可以巩固自己的编程能力。不用付费免费使用哦。基本是每个即将找工作的人必备的刷题网站。快行动起来吧!

  • 3
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

在路上-正出发

哈哈,多少是个心意

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值