Verilog HDL 基本语法 STEP 2016/12/3
目录 Verilog HDL语言的特点 Verilog HDL语言的描述方式 模块与端口 注释 常量,变量与逻辑值 操作符 操作数 参数 编译指令 程序实例
Verilog HDL语言的特点 Verilog HDL是一种用于数字逻辑电路设计的硬件描述语 言,具有下列特点: 互连:互连是硬件系统中的一个基本概念,Verilog语言中的wire 变量可以很好地表达这样的功能;而软件语言并没有这样的描述。
Verilog HDL的描述方式 Verilog HDL采用三种描述方式来进行设计: 数据流描述:采用assign语句,连续赋值,数据实时变化,赋值 对象一般定义为wire型。 行为级描述:使用always或者initial语句,过程赋值,赋值对象一 般定义为reg型,不一定会形成寄存器。 结构化模型:通过实例化已有的功能模块来建模。 在一个设计中我们往往会混合使用这三种描述方式。 Verilog HDL是对大小写敏感的语言,同样的词汇,大写和小写是 不同的符号。 关键字都是小写的。
Verilog 的四种逻辑值 0、低、伪、逻辑低、地、VSS、负 1、高、真、逻辑高、电源、VDD、正 X、不确定:逻辑冲突无法确定其逻辑值 1 X Z buf bufif1 0、低、伪、逻辑低、地、VSS、负 1、高、真、逻辑高、电源、VDD、正 X、不确定:逻辑冲突无法确定其逻辑值 HiZ、高阻抗、三态、无驱动源
Verilog编程案例
Verilog编程结构 module 模块名称(端口列表); //端口定义声明; input, output, inout //内部变量及参数声明 wire, reg, functioion, task, parameter, define, etc //模块功能实现 数据流描述: assign 行为级描述:initial, always 结构化描述: module例化 其他用户原语 endmodule
Verilog编程结构介绍 模块是Verilog的基本描述单元,可大可小,大到一个复杂的系统, 小到一些基本的逻辑门单元,主要用来描述某个设计的功能或结 构及其与其他功能模块通信的外部端口。 对于模块而言,需要有一个模块名称来标示模块,在端口列表的 括号后面一定要以 “;”结束。 模块一般都有端口列表,端口与端口之间用 “,”隔开。但是仿 真语言没有端口列表,因为仿真是一个封闭的系统,端口已经实 例化在内部。 端口声明部分需要声明端口的方向和位宽。
Verilog编程结构介绍 尽管信号和内部变量定义声明只要出现在被调用的语句之前就行, 可是代码风格一般要求在执行语句之前就定义好,这样可以提高 代码的可读性。 在声明后,便是功能执行语句,功能执行语句包括always语句、 initial语句、assign语句、task、function、模块例化等等。可以 混合描述,没有先后顺序,但是要注意的是initial语句只能用于仿 真程序中,不能生成实际的电路。 任何一个模块都要以 “endmodule”结束。
模块和端口 例 端口声明 //Port Declaration input [4:0] a; // 信号名为a的5输入信号 例 端口声明 //Port Declaration input [4:0] a; // 信号名为a的5输入信号 inout b; // 双向信号b output [6:0] c; // 信号名为c的7输出总线信号
模块和端口 有些设计会把端口的声明部分和端口列表写在一起,在端口中可 以对每个信号进行注释。 module counter( input clk, //全局时钟信号 input reset_l, //全局复位信号 output [7:0] cnt //八位数据总线 );
常用数据类型 线网数据类型: wire型的线网是不具备数据存取 功能的 定义为wire型的线网是不能够在 always语句中被赋值的,只能被 连续赋值。
常用数据类型 寄存器数据类型: reg型的则可以存取最后一次赋 给它的值, 定义为reg型的线网只能在 always和initial语句中被赋值, 不能被连续赋值。
数据类型的选择 对于模块而言: 输入变量都是线网类型的 输出变量可以是线网类型的,也可以是寄存器类型的
线网型与寄存器型赋值区别 ①用assign声明语句 如:assign c = a&b; ②用always块 如:always@(posedge clk) c <= a&b; 例子描述了一个与门,但是只有在clk上升沿(posedge)时候a与b才 会进行与。
线网型与寄存器型赋值区别 clk a b assign c always c
常用数据类型 参数数据类型: reg型的则可以存取最后一次赋给它的值, 定义为reg型的线网只能在always和initial语句中被赋值,不能被连 续赋值。
常量表示 常量就是不变的数值,比如说4’d8,表示的是一个4位宽的十进 制整数8。 在Verilog中,有三种不同类型的常量:整数型、实数型以及字符 串型。 整数型常量可以直接使用十进制的数字表示。 基数表示法的格式如下: 长度’+数制简写+数字 当设定的位宽比实际数字的位宽少,则自动截去左边超出的位数, 反之则在左边不够的位置补足0。如果长度不显示,那么数字的位 宽则取决于本身的长度。 注意:这里说的长度或位宽表示数值在二进制形态下的位宽
与C语言相似 操作符 Verilog HDL语言和C语言相似,有丰富的各种操作符,总体分为8 类,如下: 算术运算符 关系运算符 逻辑运算符 条件运算符 位运算符 移位运算符 赋值运算符 拼接运算符 与C语言相似
算数运算符 cnt_main <= cnt_main + 1'b1;
关系运算符 if(cnt_main >= 4'd6) cnt_main <= 4'd5;
逻辑运算符 if(!rst_n_in) cnt_main <= 4'd0; 操作符 表达式 描述 && A&&B A,B是否都为真? || A || B A,B任意一个是否为真? ! ! B B是否为假 if(!rst_n_in) cnt_main <= 4'd0;
逻辑运算符实例 A = 3; //参数A B = 0; //参数B C = 2'b0x; //参数C D = 2'b10; //参数D C&&D = X
条件运算符 assign seg_dot_1 = (mode_flag==3'b100)? 1'b1:1'b0; assign data = (mode_flag==3'b100)? hour:((mode_flag==3'b010)? min:sec);
位运算符 if(cnt_200khz >= CNT_NUM-1) clk_200khz <= ~clk_200khz; 操作符 表达式 描述 ~ ~B 将B中的每一位取反 & A & B 将A中的每位与B中对应的位相与 | A | B 将A中的每位与B中对应的位相或 ^ A ^ B 将A中的每位与B中对应的位异或 ~^ A ~^B 将A中的每位与B中对应的位相异或非 ^~ A^~B if(cnt_200khz >= CNT_NUM-1) clk_200khz <= ~clk_200khz;
位运算符实例 A = 4’b1011 B = 4’b1101 C = 4’b10x1 ~A =4'b0100 A&B =4'b1001 A&C =4'b10x1
移位运算符 always sys_clk = #(CLK_PERIOD>>1) ~sys_clk;
归约运算符 操作符 表达式 描述 & &B 将B中的每一位相与得出一位的结果 ~& ~& B 将B中的每个比特相与非得出一比特的结果 | ~| ~| B 将B中的每个比特相或非得出一比特的结果 ~^ ~^B 将B中的每一位相异或非得出一比特的结果 ^~ ^~B ^ ^B 将B中的每一位相异或得出一比特的结果
归约运算符实例 B = 4’b1101 &B = 1&1&0&1 = 1'b0 |B = 1|1|0|1 = 1'b1
拼接运算符 if(sec_pulse)mode_flag <= {mode_flag[0],mode_flag[2:1]}; 操作符 表达式 描述 {} {A,B} 将A和B连接起来,产生更大的向量 {{}} {B{A}} 将A重复B次 if(sec_pulse)mode_flag <= {mode_flag[0],mode_flag[2:1]};
拼接运算符实例 A = 2'b00; //参数A B = 2'b10; //参数B {A,B} = 4'b0010
<, <=, >, >= 各种运算符优先级 操作符 级别 +,-, !,~(一元) 最高级 *,/,% 二元的加减 +,- <<, >> <, <=, >, >= ==, ===, !=, !== &, ~&, ^, ^~, ~^, |, ~| &&, || ?: 最低级 建议使用小括号运算符限制优先级
阻塞赋值 阻塞赋值方式 = 块内语句逐条进行赋值 建议在组合逻辑中使用
非阻塞赋值 非阻塞赋值方式 <= 块内赋值语句同时执行 建议在时序逻辑中使用 <=
Verilog常用关键字 注意关键字使用小写
编译指令 使用`define 编译引导能提供简单的文本替代功能 `define <宏名> <宏文本> 在编译时会用宏文本来替代源代码中的宏名。 合理地使用`define可以提高程序的可读性 举例说明: `define on 1’b1 `define off 1’b0 `define and_delay #3 在程序中可以用有含义的文字来表示没有意思的数码提高了程序 的可读性,在程序中可以用 `on, `off, `and_delay 分别表 示 1,0,和 #3 。
`include “parts/counter.v” `include “../../library/mux.v” 编译指令 使用`include 编译引导,在编译时能把其指定的整个文件包括进来一起处理 举例说明: `include “global.v” `include “parts/counter.v” `include “../../library/mux.v” 合理地使用`include 可以使程序简洁、清晰、条理清楚、易于查错。
编译指令 `timescale 用于说明程序中的时间单位和仿真精度 举例说明: `timescale 1ns/100ps module MUX2_1(out,a,b,sel); … … not #1 not1(nsel, sel); and #2 and1(a1, a, nsel); endmodule 尽可能地使精度与时间单位接近,只要满足设计的实际需要就行。
编译指令 条件编译指令的格式一般如下: `ifdef NORMAL parameter A = B; `else parameter A =C; `endif 如果宏NORMAL事先已经被定义好,则编译器会执行 parameter A = B;语句,否则执行parameter A =C;语 句。
典型的Verilog设计描述示意图
注释 Verilog 是一种格式很自由的语言。 空格在文本中起一个分离符的作用, 别的没有其他用处。 单行注释符用 //********* 单行注释符用 //********* 与C 语言一致 多行注释符用 /* ------------------------- */
谢谢!