Verilog数字系统设计教程——基础>读书笔记

一、模块

端口定义

模块的端口声明了模块的输入输出口,在引用模块时其端口可以用两种方法连接:

  • 在引用时,严格按照模块定义的端口顺序来连接,不用标明原模块定义时规定的端口名
  • 在引用时用”.“符号,标明原模块是定义时规定的端口名
模块内容
I/O口
内部信号

在模块内部用到的和端口有关的 wirereg 类型变量的声明

功能定义

模块中最重要的部分是逻辑功能定义部分。有3种方法可在模块中产生逻辑:

  • assign声明语句
  • 用实例元件
  • always

这三种逻辑功能时并行执行的,顺序并不会影响实现的功能

要点
  • always块中的语句成为”顺序语句”,因为它们是顺序执行的
  • 两个或更多的always块都是同时执行,块内部的语句是顺序执行
  • Verilog模块中所有的过程块(如:initial块、always块)、连续赋值语句、实例引用都是并行的
  • 它们表示的是一种通过变量名相互连接的关系
  • 在同一模块中这三者出现的先后次序没有关系
  • 只有连续赋值语句assign和实例引用语句可以独立于过程块而存在于模块的功能定义部分

二、数据类型及其常量和变量

4个基本的数据类型: reg型、wire型、integer型和 parameter

常量
数字

1)整数
2) xz值:代表不定值,代表高阻值
3)负数:位宽表达式前加一个减号
4)下划线:分隔开数的表达以提高程序可读性,只能用在具体数字之间

参数(parameter)型

参数型常数经常用于定义延迟时间和变量宽度。在模块或实例引用时,可通过参数传递改变在被引用模块或实例中已定义的参数
在一个模块中改变另一个模块中的参数时,需要使用defparam命令

变量
wire

wire型数据常用来表示以assign关键字指定的组合逻辑信号。Verilog程序模块中输入、输出类型信号默认自动定义为wire型。wire型信号可以用作任何方程式的输入,也可以用作assign语句或实例元件的输出。

reg

reg类型数据的默认初始值为不定值x
reg型数据常用来表示always模块内指定信号,常代表触发器,在always块内被赋值的每一个信号都必须定义为reg
reg型只表示被定义的信号将用在always模块内

memory

定义一个名为mema的储存器,该储存器有256个8位的存储器。该存储器的地址范围是 0 到 255。
reg[7:0] mema[255:0];

三、运算符及表达式

按功能分:

  • 算术运算符+, -, *, /, %
  • 赋值运算符=, <=
  • 关系运算符>, <, >=, <=
  • 逻辑运算符&&, ||, !
  • 条件运算符? :
  • 位运算符~, |, ^, &, ^~
  • 移位运算符<<, >>
  • 拼接运算符{ }
  • 其它

按所带操作数个数分类:

  • 单目运算符
  • 双目运算符
  • 三目运算符
等式运算符

== 等于
!= 不等于
=== 等于
!== 不等于

=====的区别:

===01xz==01xz
01000010xx
10100101xx
x0010xxxxx
z0001zxxxx
缩减运算符

缩减运算符是对单个操作数进行或、与、非递推运算,最后的运算结果是1位的二进制数

四、赋值语句和块语句

赋值语句
非阻塞赋值方式b <= a;
  • 在语句块中,上面语句所赋的变量值不能立即就为下面的语句所用;
  • 块语句结束后才能完成这次赋值操作,而所赋的变量值是上一次赋值得到的;
  • 在编写可综合的时序逻辑块时,这是最常用的赋值操作。
阻塞赋值方式b = a;
  • 赋值语句执行完后,块才结束
  • b的值在赋值语句执行完后立刻就改变的
  • 在时序逻辑中使用,可能会产生意想不到的后果
块语句
顺序块begin end
并行块fork join
块名

可以给每一个块取一个名字,只需要加在关键词beginfork后面即可

  • 可以在块内定义局部变量,即只在块内使用的变量。
  • 可以允许块被其它语句调用,如disable语句。
  • 所有的变量都是静态的,即所有的变量都只有一个唯一的存储地址,因此进入或跳出块并不影响存储在变量内的值

所以,块名就提供了一个在任何仿真时刻确认变量值的方法。

起始时间和结束时间

在并行块和顺序快中都有一个起始时间和结束时间的概念,当一个块嵌入另一个块时,块的起始时间和结束时间就很重要

五、条件语句、循环语句、块语句与生成语句

条件语句

else总与它上面的最近的if配对,可以用begin_end块语句来确定配对关系
if_else语句一定要有else或者elseif选项,否则会产生不必要的锁存器

case语句

case语句所有表达式的值的位宽必须相等
casez语句来处理不考虑高阻值z的比较过程
casex语句则将高阻值z和不定值都视为不必关心的情况
使用case语句时一定不要忘记default项,否则有可能产生不必要的锁存器

循环语句
forever语句

forever循环语句常用于产生周期性的波形,用来作为方针测试信号。它与always语句不同之处在于不能独立写在程序中,而必须写在initial块中

repeat语句
while语句
for语句
生成块
循环生成语句
条件生成语句
case生成语句

六、结构语句、系统任务、函数语句和显示系统任务

结构说明语句
initial语句

例如用initial语句对存储器初始化,整个初始化过程不需要任何仿真时间,即在0ns时间内,便可以完成存储器的初始化工作
一个模块可以有多个initial块,他们都是并行运行的

always语句

如果一个always语句没有时序控制,则这个always语句将会使仿真器产生死锁
沿触发的 always块常常描述时序行为,如有限状态机。
电平触发的always块常常用来描述组合逻辑的行为
一个模块可以有多个always块,他们都是并行运行的,多个always块并没有前后之分

taskfunction说明语句

任务和函数有些不同,主要有4点:

  • 函数只能与主模块共用同一个仿真时间单位,而任务可以定义自己的仿真时间单位
  • 函数不能启动任务,而任务能启动其他任务和函数
  • 函数至少有一个输入变量,而任务可以没有或者有多个任意类型的变量
  • 函数返回一个值,而任务则不返回值
tast说明语句

例:描述红绿黄交通灯行为的Verilog模块,用到了任务。

module traffic_lights;
    reg  clkck,red,amber,green;
    parameter on = 1,off = 0, red_tics=350,amber_tics=30, green_tics=200;
    //交通灯初始化
    initial red=off;
    initial amber=off;
    initial green=off;
    //交通灯控制时序
    always
    begin
        reg = on;//开红灯
        light(red,red_tics);/调用等待任务/
        green=on;//开绿灯
        light(green,green_tics);//等待
        amber=on;//开黄灯
        light(amber,amber_tics);//等待
    end
    //定义交通灯开启时间的任务
    task light;
        output color;
        input[31:0] tics;
    begin
        repeat(tics)
            @(posedge clock);//等待tics个时钟的上升沿
        color = off;//关灯
    end
    endtask
    //产生时钟脉冲的always块
    always
        begin
        #100 clock = 0;
        #100 clock = 1;
        end
endmodule
function说明语句

函数的目的是返回一个用于表达式的值。
默认返回值为一位寄存器类型数据。
函数的使用规则:

  • 函数的定义不能包含任何的时间控制语句,即任何用#@、或wait来标识的语句。
  • 函数不能启动任务
  • 定义函数时要至少有一个输入参量
  • 在函数的定义中必须有一条赋值语句给函数中的一个内部变量赋以函数的结果值,该内部变量具有和函数名相同的名字
//定义一个模块,其中包含能够计算偶校验位的函数(calc_parity)
module parity;
reg[31:0] addr;
reg parity;
initial
begin
    addr = 32'h3456_789a;
    #10 addr = 32'hc4c6_78ff;
    #10 addr = 32'hff56_ff9a;
    #10 addr = 32'h3faa_aaaa;
end
//每当地址值发生变化时,计算新的偶校验位
always@(addr)
begin
    parity = calc_parity(addr);//第一次启动校验位计算函数
    $display("Parity calculated = %b",calc_parity(addr));//第二次启动校验位计算函数
end

//定义偶校验位计算函数
function calc_parity;
input[31:0] address;
begin
    //适当的设置输出值,使用隐含的内部寄存器calc_parity
    calc_parity = ^address;//返回所有地址位的异或值
end
endfunction
endmodule
//左/右移位寄存器
//定义一个包含移位函数的模块
module shifter;

//左/右移位寄存器
`define LEFT_SHIFT 1'b0
`define RIGHT_SHIFT 1'b1
reg[31:0] addr, left_addr, right_addr;
reg control;

//每当新地址出现时就计算右移位和左移位的值
always@(addr)
    begin
    //调用下面定义的具有左右移位功能的函数
    left_addr = shift(addr, `LEFT_SHIFT);
    right_addr = shift(addr, `RIGHT_SHIFT);
    end
//定义移位函数,其中输出是一个32位的值
function[31:0] shift;
input[31:0] address;
input control;
begin
    //根据控制信号适当的设置输出值
    shift = (cntrol == `LEFT_SHIFT) ? (address << 1) : (address >> 1);
end
endfunction
endmodule
自动递归函数
常量函数
带符号函数

常用系统任务

$display$write任务

七、调试用系统任务和常用编译预处理语句

系统任务$monitor

该任务提供了监视和输出参数列表中的表达式或变量值的功能

时间度量系统函数$time

$time可以返回一个64位的整数来表示当前仿真时刻值,该时刻是以模块的仿真时间尺度为基准的。而$realtime作用一样,只不过返回的时间数字是一个实型数

系统任务$finish

作用是退出仿真器,返回主操作系统,也就是结束仿真过程

系统任务$stop

作用是把EDA工具设置成暂停模式,在仿真环境下给出一个交互式的命令提示符,将控制权交给用户。

系统任务$readmemb$readmemh

用来从文件中读取数据到存储器中

系统任务$random

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

宏定义`define

用一个指定的标识符来代表一个字符串

“文件包含”处理`include

一个源文件可以将另外一个源文件的全部内容包含进来,即将另外的文件包含到本文件之中

时间尺度`timescale

timescale命令用来说明跟在该命令后的模块的时间单位和时间精度
`timescale<时间单位>/<时间精度>

条件执行

条件执行标志允许设计者在运行时控制语句执行的流程。所有语句都被编译,但是有条件的执行它们。条件执行标志仅用于行为语句,系统任务关键字$test``$plusargs用于条件执行

  • 8
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值