Verilog HDL 简介与基本语法(1)

FPGA学习 阶段一:Verilog HDL 简介与基本语法(1)

FPGA硬件开发路线学习规划:

由于想学习FPGA的相关内容,同时给数字电路打点基础,于是借助着B站上西安电子科技大学的视频开始学习Verilog HDL这门硬件描述语言,在学完语言后,将按照**《FPGA设计技巧与案例开发详解》**这本书上的相关内容在一块核心为Altera Cyclone IV的开发板上完成基本例程,之后在网上寻找相关项目学习、开发

1. Verilog的基本概念

  • Verilog是一门类C语言,语法非常接近C,将电路设计转变为程序设计
  • Verilog的代码对应的是现实中的一个硬件,这个过程叫“综合”,类似于C语言的编译
  • Verilog的代码是并行执行的

2. Verilog HDL基础知识

2.1 Verilog HDL语言要素

2.1.1 空白符

空白符包括空格符\b、制表符\t、换行符\n、和换页符\f。在编译和综合时,空白符被忽略:

initial begin a = 3'b100; b = 3'b010; end

equals to:

initial
begin
    a = 3'b100;
    b = 3'b010;
end
2.1.2 注释符

注释与C语言相同,单行注释用//,多行注释用/* */

2.1.3 标识符

标识符命名规则与C语言基本相同,只允许出现字母、数字、$符号和_ 下划线,第一个字符必须是字母或 _下划线

2.1.4 数值
  • Verilog HDL有四种基本的逻辑数值状态:
状态含义
0低电平、逻辑0、“假”
1高电平、逻辑1、“真”
x或X不确定或未知的逻辑状态
z或Z高阻态

备注:高阻态High impedance表示电路中的某个节点具有相对电路中其他点相对更高的阻抗
电路分析时高阻态可做开路理解。可以把它看作输出(输入)电阻非常大。它的极限状态可以认为悬空(开路)。
当门电路的输出上拉管导通而下拉管截止时,输出为高电平;反之就是低电平;如上拉管和下拉管都截止时,输出端就相当于浮空(没有电流流动),其电平随外部电平高低而定,即该门电路放弃对输出端电路的控制 。

  • 整数及其表示

+/-(size>'<base_format><number>

数制基数符号合法标识符
二进制b或B0、1、x、X、z、Z、?、_
八进制o或O0~7、x、X、z、Z、?、_
十进制d或D0~9、_
十六进制h或H09、af、A~F、x、X、z、Z、?、_
//正确的表示
8'b10001101 //位宽为8位的二进制数10001101
8'ha6       //位宽为8位的十六进制数a6
5'o35       //位宽为5位的八进制数35
4'd6        //位宽为4位的十进制数6
4'b1x_01    //位宽为4位的二进制数1x01

//错误的表示
4'd-4       //数值不能为负,有负号应放在最左边
3' b001     //'和基数b之间不能有空格
(4+4)'b11   //位宽不能是表达式
  • 实数及其表示
    和C语言相同:
    a.十进制表示法,小数点两边必须都有数字
    b.科学计数法
2.7                 //十进制计数法
5.2e8               //科学计数法
3.5E-6              //e和E意义相同
5_4582.2158_5896    //使用下划线可提高可读性
6.                  //非法表示
.3e5                //非法表示

2.2 物理数据类型

物理数据类型有连线型、寄存器型和储存器型

2.2.1 信号强度

信号强度表示数字电路中不同强度的驱动源,用来解决不同驱动强度存在下的赋值冲突

标记符名称类型强弱程度
supply电源级驱动驱动最强
strong强驱动驱动
pull上拉级驱动驱动较强
large大容性存储中强
weak弱驱动驱动
medium中性驱动存储较弱
small小容性存储
highz高容性高阻最弱
2.2.2 连线型
连线型数据类型功能说明
wire,tri标准连线(缺省视为该类型)
wor,trior多重驱动时,具有线或特性的连线型
wand,trand多重驱动时,具有线与特性的连线型
trireg具有电荷保持特性的连线型数据(特例)
tri1上拉电阻
tri0下拉电阻
supply1电源线,用于对电源建模,为高电平1
supply0电源线,用于对“地”建模,为低电平0
  • 单连线之间的逻辑wire和tri
wire/tri01xz
00xx0
1x1x1
xxxxx
z01xz
  • 含有线或时连线之间的逻辑
wor/trior01xz
001x0
11111
xx1xx
z01xz
2.2.3 连续型数据类型的声明

<net_declar><drive_strength><range><delay><list_of_variables>;

  • net_declar:包括wire、tri等等连线型中的任意一种
  • dirve_strength:用来表示连线变量的驱动强度
  • rang:用来指定数据位标量或矢量。若该项默认,表示数据类型为1位的标量,超过1位则为矢量
  • delay:指定仿真延迟时间
  • list_of_variables:变量名称,一次可定义多个名称,用逗号分开
2.2.4 寄存器型

reg型是数据储存单元的抽象类型,其对应的硬件电路原件具有状态保持作用,能够存储数据,如触发器、锁存器等
reg型变量常用于行为级描述,由过程赋值语句对其进行赋值

//reg型变量简单例子:
reg a;          //定义一个1位的名为'a'的reg变量
reg[3:0]b;      //定义一个4位的名为'b'的reg变量
reg[8:1]c,d,e;  定义三个名称分别为c、d、e的8位reg型变量

//reg型变量一般为无符号数,若将一个负数赋给reg型变量,则自动转换成二进制补码形式。例如:
reg signed[3:0]rega;
rega = -2;      //rega的值为1110(14),是2的补码
2.2.5 寄存器型数据类型的声明

reg<range><list_of_register_variables>;

  • range:可选项,它指定了reg型变量的位宽,缺省时为1位
  • list_of_register_variables:为变量名称列表,一次可以定义多个名称,之间用逗号分开
2.2.6 物理数据类型声明的例子
reg rega;           //定义一个1位寄存器型变量
reg[7:0] regb;      //定义一个8位的寄存器型变量
tri[7:0] tribus;    //定义一个8位的三态总线
tri0[15:0] busa;    //定义一个16位连线型,处于三态时为下拉电阻
tri1[31:0] busb;    //定义一个32位连线型,处于三态时为上拉电阻
reg scalared[1:4] b;//定义一个4位的标量型储存器矢量
wire(pull1,strong0) c = a + b;  //定义一个1和0的驱动强度不同的1位连线型变量c
trireg(large) storeline;        //定义一个具有大强度的电荷存储功能的存储线

/*在数字电路中,三态逻辑(英语:Three-state logic)允许输出端在0和1两种逻辑电平之外呈现高阻态,等效于将输出的影响从后级电路中移除。
这允许多个电路共同使用同一个输出线,例如总线结构
在总线连接的结构上。总线上挂有多个设备,设备与总线以高阻的形式连接。这样在设备不占用总线时自动释放总线,以方便其他设备获得总线的使用权.*/
2.2.7 存储器型

储存器型变量可以描述RAM型、ROM型储存器以及reg文件
储存器变量的一般声明格式为:
reg<range1><name_of_register><range2>

  • range1和range2都是可选项,缺省都为1
  • range1:表示存储器当中寄存器的位宽,格式为[msb:lsb]
  • range2:表示寄存器的个数,格式为[msb:lsb],即拥有msb-lsb+1个
  • name_of_registers:变量名称,一次可以定义多个名称,之间用逗号隔开
reg[7:0] mem1[255:0];           //定义了一个有256个8位寄存器的存储器mem1
                                //地址范围是0到255
reg[15:0] mem2[127:0],reg1,reg2;//定义了一个具有128个16位寄存器的储存器mem2和两个16位寄存器reg1和reg2
reg[n-1:0] a;                   //表示一个n位寄存器a
reg mem1[n-1:0]                 //表示一个由n个1位寄存器构成的存储器mem1

2.3 抽象数据类型

抽象数据类型主要包括整型integer、时间型time、实型real及参数型parameter

2.3.1 整型

integer<list—of—register—variables>;

integer index;          //简单的32位有符号整数
integer i[31:0];        //定义了整型数组,它有32个元素
2.3.2 时间型

时间型数据与整型数据相似,只是它是64位无符号数。时间型数据主要用于对模拟时间的储存与计算处理,常与系统函数$time一起使用。
声明格式:
time<list_of_register_variables>

time a,b;           //定义了两个64位的时间型变量
2.3.3 实数型

实数型数据在机器码表示法中是浮点型数值,可用于对延迟时间的计算
声明格式:
real<list_of_variables>

real stime;         //定义了一个实数型数据

####2.3.4 参数型
属于常量,在仿真开始之前就被赋值,在仿真过程中保持不变,以提高程序的可读性和维护性
声明格式:
parameter<name_of_parameter>=<value>

parameter length = 32,weight = 16;
parameter PI = 3.14,LOAD = 4'b1101;
parameter DELAY=(BYTE+BIT)/2;

2.3 运算符和表达式

运算符

2.3.1 算术运算符

算术运算符包含加法+;减法-;乘法*;除法/;取模%

  1. 算术操作结果的算术表达式的结果由最长的操作数决定。在赋值语句下,算术操作结果的长度由操作左端目标长度决定
reg[3:0] A,B,C;
reg[5:0] D;
A = B + C;      //4位
D = B + C;      //6位
  1. 有符号数和无符号数的使用
module arith_tb;
reg[3:0] a;
reg[2:0] b;
initial
    begin
        a = 4'b1111;        //15
        b = 3'b011;         //3
        $display("%b",a*b)  //乘法运算,结果等于4'b1101,高位被舍去
        $display("%b",a/b); //除法运算,结果为4'b0101
        $display("%b",a+b); //加法运算,结果为4'b0010
        $diaplay("%b",a-b); //减法运算,结果为4'b0010
        $diaplay("%b",a%b); //取模运算,结果为4'b0000
    end
endmodule
/*注意:二进制的减法先补全位数,使两个数同位,然后再取补码,
正二进制数的补码是它本身,
负二进制数的补码是它取反后加1*/
2.3.2 相等关系运算符
  1. 等于“”、不等于“!=”、全等“=”、非全等“!==”
  2. 比较的结果有三种,真“!”、假“0”、不定值“x”
  • “==”真值表
==01xz
010xx
101xx
xxxxx
zxxxx
  • “===”真值表
===01xz
01000
10100
x0010
z0001
2.3.3 条件运算符
  • 表达形式如下:
    <条件表达式>?><表达式1>:<表达式2>
    条件表达式的计算结果只有1,0x三种,结果为1时执行表达式1;结果为0时执行表达式2
module mux2(in1,in2,sel,out);
input [3:0] in1,in2;
input sel;
output [3:0] out;
reg [3:0] out;
assign out = (sel!)?in1:in2;
//sel为0时out等于in1,反之等于in2
endmodule
2.3.4 连接和复制运算符

连接运算符“{}”和复制运算符“{{}}”

  • 连接运算符
    {信号1的某几位,信号2的某几位,…,信号n的某几位}

  • 复制操作符
    将一个表达式放入双重花括号中,复制因子放在第一层括号中

module con_rep_tb;
reg [2:0] a;
reg [3:0] b;
reg [7:0] c;
reg [4:0] d;
reg [5:0] e;
initial
    begin
    a = 3'b101;
    b = 4'b1110;
    c = {a,b};
    d = {a[2:1],b[2:0]};//d取了a的第3位到2位与b的第3位到1位拼接
    e = {2{a}};
    $display("%b",c);   //8'b01011110
    $display("%b",d);   //5'b10110
    $display("%b",e);   //6'b101101
    end
endmodule

2.4 模块

2.4.1 模块的基本概念
  1. 模块(module)是Veril HDL语言的基本单元,它代表一个基本的功能块,用于描述某个设计的功能或结构以及与其他模块通信的外部接口
    在这里插入图片描述
  2. 一个模块主要包括:
  • 模块的开始与结束:以关键词module开始,以关键词endmodule结束的一段程序,其中模块开始语句必须要以分号结束
  • 端口定义:用来定义端口列表里的变量哪些是输入(input)、输出(output)和双向端口(inout)以及位宽的说明。
  • 数据类型说明:数据类型在语言上包括wire、reg、memory和parameter等类型,用来说明模块中所用到的内部信号、调用模块等的声明语句和功能定义语句
  • 逻辑功能描述:用来产生各种逻辑(主要是组合逻和时序逻辑)。主要包括以下部分:initial语句、always语句、其它子模块实例化语句、门实例化语句、用户自定义原句(UDP)实例化语句、连续赋值语句(assign)、函数(function)和任务(task)
    例:上升沿D触发器
module dff(din,clk,q);
    input din,clk;
    output q;
    reg q;
    always@(posedge clk)    //posedge指D触发器上升沿触发
        q <= din;
endmodule
2.4.2 端口

端口的定义:
模块的端口可以是输入口input、输出端口output或双向端口inout
模块的端口声明了模块的输入输出口。其格式如下:
module 模块名(口1,口2,…)
模块的端口表示的是模块的输入和输出口名,也就是说,它与别的模块联系端口的标识。
在模块被引用时,在引用的模块中,有些信号要输入到被引用的模块中,有的信号需要从被引用的模块中取出来。在引用模块时其端口可以用两种方法连接:

  1. 在引用时严格按照模块定义的端口顺序来连接,不用标明原模块定义时规定的端口名,例如:
    模块名(连接端口1信号名,连接端口2信号名,...)
  2. 在引用时用“.”符号,标明原模块是定义时规定的端口名,例如:
    模块名(.端口1名(连接信号1名),.端口2名(连接信号2名),...)
    这样的好处在于可以用端口名与被引用模块的端口相对应,而不必严格按端口顺序对应,提高了程序的可读性和可移植性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值