《电子技术应用》
您所在的位置:首页 > 可编程逻辑 > 业界动态 > 零基础教你学FPGA之Verilog语法基础(下)

零基础教你学FPGA之Verilog语法基础(下)

2015-02-09
关键词: FPGA Verilog 基础

9、关于任务和函数的小结,挑几点重要的说一下吧

  (1)任务具有多个输入、输入/输出和输出变量,在任务重可以使用延迟、事件和时序控制结构,在任务重可以调用其它任务和函数。与任务不同,函 数具有返回值,而且至少要有一个输入变量,而且在函数中不能使用延迟、事件和时序控制结构,函数可以条用函数,但是不能调用任务。

  (2)在声明函数时,系统会自动的生成一个寄存器变量,函数的返回值通过这个寄存器返回到调用处。

  (3)函数和任务都包含在设计层次中,可以通过层次名对他们实行调用。这句话什么意思啊?

  10、系统任务

  (1)$diplay和$write任务

  $display任务相当于C语言里的printf,用于输出信息,他的基本格式$display (p0,p1,p2);意思就是把p1、p2以p1的格式输出,至于具体格式,C语言里面讲的很清楚,下面用一张图帮大家回忆一下

  

360桌面截图20140311213804.jpg

 

  

360桌面截图20140311213848.jpg

 

  此外,在display中,输出列表中的数据的现实宽度总是按照自动输出格式进行调整的。因此,我们通常在%和表示进制的符号之间加一个0来确保总是用最少的位数来表示表达式的当前值。

  例如

  begin

  r1=10;

  $display("size=%d=%h",r1,r1);

  $display("size=%0d=%0h",r1,r1);

  输出结果分别为 10,00a和10,a

  所以在以后写程序时,为了养成良好习惯,应该注意加上0来保证代码的可读性。

  如果输出的列表中含有不定值或者高阻态时,要遵循下列情况

  (1)如果按10进制输出

  如果输出列表全部为不定值,则输出为小写x;

  如果输出列表部分为不定值,则输出为大写X;

  如果输出列表全部为高阻态,则输出为小写的z;

  如果输出列表部分为高阻态,则输出为大写的Z;

  (2)如果按十六进制或者8进制输出

  那么十六进制对应的四位或者8进制对应的3位中,如果部分是高阻态或者是不定值,那么输出结果为大写的Z或者X否则就输出小写的z或者x;

  例如

  

360桌面截图20140324223251.jpg

 

  (2)$monitor

  系统任务$monitor提供了监控和输出参数列表中的表达式或变量值的功能,其参数列表中输出控制格式字符串和输出列表的规则 和$display一样,当启动一个带有一个或者多个的$monitor任务时,仿真器则创立一个仿真机制,使得每当参数列表中的表达式或值发生变化时, 整个参数列表中的变量或者表达式的值都将输出显示,如果在同一时刻,两个或者多个参数的值发生变化,则在这时刻只输出显示一次,但在$monitor任务 中,参数可以是$time系统函数,这样参数列表中变量或者表达式的值同时发生变化的时刻可以通过标明同一时刻的多行输出来显示。

  例如

  

360桌面截图20140325161107.jpg

 

  $monitoron和$monitoroff的功能就是通过打开或者关闭监控标志来控制监控任务$monitor的启动和停止。这样可以使得程序员很容易的控制$monitor什么时候执行了。

  (3)时间度量系统函数$time

  在verilog hdl语法中有两种时间度量系统函数,分别是$time和$realtime,用这两个系统函数可以得到当前的仿真时刻。$time可以返回一个64位的值来记录当前的仿真时刻。

  (4)$finish

  系统任务$finish的作用是退出仿真器,返回主操作系统,也就是结束仿真过程。格式是

  $finish或者$finish(1);如果不带参数,则默认参数为1,下面是具体参数下系统输出的特征信息。

  0 不输出任何信息

  1 输出当前仿真时刻和位置

  2 输出当前仿真时刻、位置和在仿真过程中所用memory及CPU时间的统计。

(4)系统任务$stop

  $stop任务作用是把EDA工具置成暂停模式,在仿真环境下给出一个交互式的命令操作符,将控制权交给用户。这个任务可以带有参数表达式,根据参数值(0、1、2)的不同,输出不同的信息,参数值越大,输出信息越多。

  (5)系统任务$random

  这个系统函数提供了一个产生随机数的手段,当函数被占用时返回一个32位的随机数,它是一个带符号的整形数。

  下面是一个产生随机数的例子

  reg[23:0] rand;

  rand=$random %60;

  上面的例子产生一个-59到59之间的随机数,所以$random的用法是产生一个(-b+1)到(b-1)之间的随机数。

  下面的例子通过并位产生一个值在0—59之间的随机数

  reg[23:0 rand];

  rand = {$random} %60;

  利用这个系统函数可以产生随机脉冲序列或宽度随机的脉冲序列,用于电路的测试。

  下面是个产生随机脉冲序列的例子

  

360桌面截图20140417132822.jpg

 

  

360桌面截图20140417133014.jpg

 

  (6)关于编译预处理

  编译预处理这部分和C语言差不多,主要用到的是`define、`include、和时间尺度`timescale

  `define 就是宏定义,在C语言了用的也比较多,在verilog中灵活的使用宏定义可以增加程序的可读性,又方便修改。例如在声明一个8位寄存器时用宏定义

  `define WINDOWS 8

  module

  reg [1:`WINDOWS] date;

  ……

  习惯上一般宏定义的内容用大写字母表示,这里的WINDOWS就代表数字8,在下面的程序中调用WINDOWS时加个 `,表示调用,这样宏定义的好处就是,在大的程序中如果想改变寄存器的大小,可以直接改数字8为16,这样,所有的WINDOWS都变成了16,这样改一 个就可以改变所有的,给程序员带来了方便。

  对于`include,C语言里用的比较多这里就不在多提,主要是模块化编程思想的应用,这个很重要,练好模块化编程,可以大大提高程序的可读性和可移植性,也使修改程序变得更加方便。

  对于`timescale,就是一个时间尺度,C语言里面没有,这里说一下。

  `timescale 包括两部分,一部分是时间单位,一部分是时间精度,下面举个例子

  

360桌面截图20140417142814.jpg

 

  在这个例子中,时间单位是10ns,时间精度是1ns,这里d=1.55,也就是说d等于1.55乘10纳秒,也就是15.5纳秒,再看时间精度是一纳秒,四舍五入就是16纳秒,所以在16纳秒时,set置零,32纳秒时set置一。

  小结

  (1)、在多模块调试的情况下,$monitor需配合$monitoron和$monitoroff来使用。

  (2)、$monitor和$diplay的区别在于$monitor是连续监视数据的变化,因而往往只要在测试模块的initial块中调用一次就可以监控被测模块中所有感兴趣的信号不需要,也不能在always块中调用$monitor.

  (3)、$time常在$monitor中作时间标记

  (4)、$stop 和 $finish 常用在测试模块的initial块中,配合时间延迟用来控制仿真的持续时间。

  (5)、$random在编写程序是非常有用的,可以用来产生边沿不稳定的波形和随机出现的脉冲。正确的使用它能有效的发现设计中出现的问题。

  (6)、$readman在编写测试程序时很有用,可以用来生成给定的复杂数据流。复杂数据可以用C语言产生,存在文件中。用$readman取出存入存储器,再按节拍输出这在验证算法逻辑电路中特别有用。

  (7)、在用`timescale时要注意当多个带不同`timescale定义的模块包含在一起时,只有最后一个才起作用,所以属于一个项目,但`timescale定义不同的多个模块最好分开编译,以免把时间单位搞混。

  (8)、宏定义字符串和include引用时,不要忘记用“`”这个标号。

本站内容除特别声明的原创文章之外,转载内容只为传递更多信息,并不代表本网站赞同其观点。转载的所有的文章、图片、音/视频文件等资料的版权归版权所有权人所有。本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如涉及作品内容、版权和其它问题,请及时通过电子邮件或电话通知我们,以便迅速采取适当措施,避免给双方造成不必要的经济损失。联系电话:010-82306118;邮箱:aet@chinaaet.com。