三、10【Verilog HDL】过程连续赋值、改写参数、条件编译执行、时间尺度、系统任务

前言

参考书籍:《Verilog HDL 数字设计与综合》第二版,本文档为第9章的学习笔记。

本章将探讨Verilog语言的另外一些增强特性

学习目标

  • 掌握连续赋值语句其他形式:assign/deassign/force/release
  • 掌握怎样的模块调用时用defparam语句重新定义参数值
  • 解释条件编译和Verilog描述部件的执行
  • 认识和理解系统任务

9.1 过程连续赋值

过程赋值将值赋给寄存器,值一直在寄存器中保存,知道另一个赋值语句存放该寄存器。

过程连续赋值允许有限时间段内将表达式的值连续地加(驱动)到寄存器或线网。

9.1.1 assign和deassign

第一类过程连续赋值语句,在过程连续赋值语句的左边只能是一个寄存器一个拼接的寄存器组,不可以是线网类型变量的部分 位选择、位选择或寄存器组。

过程连续赋值语句可以改写(覆盖)常用的过程赋值的结果。且一般只用于受控的一端时间内。

建议不要使用该种赋值语句。

assign q=1'b0; //代码运行过程中会一直给寄存器型变量q赋值。

deassign q; //取消给q一直赋值

9.1.2 force和release

第二类过程连续赋值语句,既可以改写(覆盖)寄存器上的赋值也可以改写(覆盖)线网上的赋值。多用于交互式调试过程,建议不要在设计模块的内部使用force和release语句,它们应只出现在激励中,或仅作为调试语句。

force q = 1'b1;

release q;

9.2 改写(覆盖)参数

参数可以在模块定义内定义。但是,在Verilog模块编译过程中,参数值可以针对每个模块调用单独改变。

两种改变方式:通过defparam语句、通过模块调用参数赋值。

9.2.1 defparam语句

在设计中,可以通过关键字defparam在任意模块中改变参数,且可以通过层次名称引用来改变。 

//实例
module hello_world;
    parameter id_num = 0;
    initial 
        $display("hello_world id number = %d", id_num);
endmodule
module top;
    hello_world w1();
    hello_world w2();
    defparam w1.id_num = 1;
    defparam w1.id_num = 2;
endmodule

 ANSI C风格的参数声明

module hello_world
    #(parameter id_num = 0)();
endmodule
module top
    #(.id_num(5))();
endmodule

9.2.1 defparam语句

module bus;
    parameter delay1 = 2;
    parameter delay2 = 3;
    parameter delay3 = 7;
    ...
endmodule
module top;
    bus #(4,5,6) b1();  //b1:delay1=4,delay2=5,delay3=6
    bus #(9,4)   b2();  //b2:delay1=9,delay2=4,delay3=7(默认)

    bus #(.delay1(4),delay2(7)) b3();  //b2:delay1=4,delay2=4,delay3=7(默认)
endmodule

9.3 条件编译和执行

可以在不同环境下编译不同的代码

9.3.1 条件编译

`ifdef:满足条件时编译

`ifndef:没有定义时进行编译

`elsif:其他满足条件编译

`else:其他情况进行编译,与`ifdef搭配使用

`endif:用来结束条件编译

9.3.2 条件执行 

所有语句都可以被编译,但是有条件控制其执行。且仅仅能用于行为语句

关键字$test$plusargs用于条件执行,只有设置了标志DISPLAY_VAR才执行变量

if($test$plusargs("DISPLAY_VAR"))
    $display("hello_world");
else
    $display("END");

系统任务关键字$value$plusargs来进一步控制条件执行。该系统任务用于测试调用选项的参数值。如果没有找到匹配的调用选项,那么$value$plusargs返回0。如果找到了调用选项,那么返回非0值。

9.4 时间尺度

用法:`timescale<reference_time_unit> / <time_precision>

`timescale  10us / 1ns ;   //参考时间单位:10us;时间精度:1ns。

只有1、10、100才是合法的说明时间单位和时间精度的整数

9.5 常用的系统任务

在第3节基本概念的博客中有简单说明

9.5.1 文件输出

Verilog的结果通常输出到标准输出和文件verilog.log中。可以将Verilog的输出重新定向到选择的文件。

  • 打开文件

文件可以用系统任务$fopen打开

用法:$fopen("<name_of_file>");

用法:<file_handle> = $fopen("<name_of_file>");

任务$返回一个被称为多通道描述符的32位值,多通道描述符中只有1位被设置成1。标准输出有一个多通道描述符,其最低位(第0位)被设置成1,标准输出也成为通道0。标准输出一直是开放的,当每次调用$fopen则必有一位被设置成1,最多可以设置到第30位,第31位为保留位。通道号与设置的位号相对应。

  • 写文件

系统任务$fdisplay , $fmonitoe , $fwrite , $fstrobe都用于写文件。

用法:$fdisplay(<file_descripr or>, p1, p2, ... pn);其他三种类似               

  • 关闭文件

用法:$fclose(<filedescriptor>); 用来文件的关闭,文件关闭后不能再写入,多通道其相应的位也被置为0。下次开启文件$fopen时才会重启这一位。

//文件写入操作
//打开相应的文件名的文件,并设置多通道描述符
integer handle1, handle2;   //整形数为32位
    //标准输出是打开的;   descriptor = 32'h0000_0001(第0位置1)
initial begin
    handle1 = $fopen("file1.out");    //handle1 = 32'h0000_0002(第1位置1)
    handle2 = $fopen("file2.out");    //handle1 = 32'h0000_0004(第2位置1)
end
//写到文件中
integer des1, des2;                 //文件描述符
initial begin
    des1 = handle1 | 1;             //按位或,des1 = 32'h0000_0003
    $fdisplay(des1,"Diaplay 1");    //将Diaplay 1写道文件file1.out中
    des2 = handle1 | handle2;
    $fdisplay(des2,"Diaplay 2");    //将Diaplay 2写道文件file2.out中 
end
//关闭文件
$fclose(handle1);   

9.5.2 显示层次

在系统显示任务中$display , $write , $monitor , $strobe中使用%m选项,可以显示任何级别的层次。

//功能模块
module M;
...
...
initial  $display("display in %m");
endmodule
//调用功能模块
module top;
...
M m1();
endmodule

仿真结果为:display in top.m1

因此通过上面例子可以显示完整层次路径名,如模块、任务、函数和命名块。

9.5.3 选通显示

选通显示由关键字 $strobe来完成。该任务与$display类似,都用于显示。但是 $strobe是在同一时刻的其他赋值语句执行完才执行。如在同一上升沿既有赋值语句,又有显示语句。在该上升沿$display会调用赋值语句未执行的变量值,而$strobe会调用赋值语句执行结束的变量值。

9.5.4 随机数生成

用法:$random;                 //返回一个32位整数

          $random(<seed>);

<seed>可选项,确保每次运行生成同样的随机数序列。其值可以是reg、integer、time型变量。

$random % 60;            //返回一个 -59 : +59的随机数

{$random} % 60;         //返回一个 0 : +59的随机数

9.5.5 用数据文件对存储器进行初始化

用法:$readmemb("<file_name>", <memory_name>, <start_addr>, <finish_addr>);

          $redmemh语法与之相同

<file_name>、<memory_name>是必须的;<start_addr>, <finish_addr>是可选的。

<start_addr>:默认值是存储器数组的开始位置;<start_addr>:结束位置

reg  [7:0] memory [0:7];   //8个8位寄存器型变量

$readmemb("init.dat", memory);   //把数据文件init.dat读入memory中

9.5.6 值变转储文件

值变转储文件(VCD)是一个ASCII文件,包含仿真时间、范围与信号的定义以及仿真运行过程信号值的变化等信息。 

 这一部分并未深入学习,用到VCD时,会回来补充。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

追逐者-桥

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值