Verilog入门教程与实例分享


前言

本文记录了Verilog语言的入门基础知识,并通过一些代码实例帮助大家上手,主要基于Xilinx Vivado完成,以下个人学习经验仅供参考。


一、Verilog入门教程

1.基础语法

(1)关键字必须小写,如reginput

(2)标识符区分大小写,开头必须是字母或下划线,如CLK、clk(两者不同)

(3)每行必须以;结束

(4)单行注释用//xxx,跨行注释用/* xxx */

2.数值表示

(1)基本数值种类:0(0 或 假)、1(1 或 真)、x/X(未知)、z/Z(高阻)

(2)整数基数格式:二进制('b 或 'B),八进制('o 或 'O),十进制('d 或 'D),十六进制('h 或 'H)

(3)整数表示方法:4’b1001(指明位宽,4位二进制“1001”)或100(不指明位宽,默认十进制“100”)

(4)负数表示方法:-4’b1001(指明位宽时)或-100(不指明位宽时)

(5)实数表示方法:十进制(0.001)或科学记数法(1.2e4)

(6)字符串表示方法:需要定义相应大小的存储单元,比如字符串"www.csdn.net"需要12*8bit的存储单元,代码如下:

reg [12*8-1:0] str;
assign str = "www.csdn.net";

3.数据类型

(1)线网:wire,表示硬件单元之间的物理连线,由其连接的器件输出端连续驱动

(2)寄存器:reg,表示存储单元,它会保持数据原有的值直到被改写

(3)向量:当位宽大于 1 时线网或寄存器即可表示向量,举例如下:

wire [8-1:0] addr;
reg [8-1:0] addr_temp;
addr_temp[7:6] = addr[1:0] + 1'b1 ;

(4)整数:用integer声明,注意变量为有符号数

(5)实数:用 real 声明,十进制或科学计数法表示

(6)时间:用time声明, 通过调用系统函数 $time 获取当前时间

(7)数组:数组中的每个元素都可视为一个标量或者向量,形如<数组名字>[<位数>],举例如下:

integer flag [7:0] ; //8个整数组成的数组flag
reg [3:0] counter [3:0] ; //4个4位reg型变量组成的数组counter
wire [7:0] addr [3:0] ; //4个8位wire型变量组成的数组addr
flag [1] = 32'd0 ; //将flag中第2个元素赋值为32位的0值
counter [3] = 4'hF ;  //将counter中第4个元素赋值为4位的十六进制数F
assign addr [0] = 8'b0 ; //将addr中第1个元素赋值为0

(8)参数:用parameterlocalparam声明,表示常量

4.表达式

(1)表达式:由操作符和操作数构成,目的是根据操作符的意义得到一个计算结果

(2)操作数:可以是任意数据类型,如常数、整数、实数、线网、寄存器、时间、函数等

(3)操作符:包括算术、关系、等价、逻辑、按位、归约、移位、拼接、条件操作符等,圆括号内表达式优先执行,同类型操作符之间除条件操作符从右往左关联,其余操作符都是自左向右关联

(4)算术操作符:包括单目操作符(“+”、“-”,表示操作数正负,优先级最高)和双目操作符(加“+”、减“-”、乘“*”、除“/”、求幂(两个星号)、取模“%”)

(5)关系操作符:大于“>”、小于“<”、大于等于“> =”、小于等于“< =”,结果为真“1”或假“0”

(6)等价操作符:逻辑相等“= =”、逻辑不等“! =”、全等”= = =“、非全等“! = =”,结果为真“1”或假“0”

(7)逻辑操作符:逻辑与“& &”、逻辑或“| |”、逻辑非“!”

(8)按位操作符:取反“~ ”、与“&”、或“|”、异或“^”、同或“~ ^”

(9)归约操作符:归约与“&”、归约与非“~ &”、归约或“|”、归约或非“~ |”、归约异或“^”、归约同或“~ ^”

(10)移位操作符:左移“<<”、右移“>>”、算术左移“<<<”、算术右移“>>>”

(11)拼接操作符:用大括号 {,} 表示,用于将多个操作数拼接成新的操作数,每个操作数必须指定位宽

(12)条件操作符:判断条件condition是否满足,满足执行true对应语句,不满足执行false对应语句,可嵌套执行多次判断,格式如下:

condition ? true : false

5.编译指令

(1)宏定义编译指令(与C一致)

`define

`undef

(2)条件编译指令(与C一致)

`ifdef

`ifndef

`else

`elsif

`endif

(3)`include:用于将全局或公用头文件包含在设计文件里,使用相对或绝对路径皆可

(4)`timescale:定义时间单位和时间精度,两者都是由数字和单位(s、ms、us、ns、ps、fs)组成,时间精度大小小于等于时间单位大小,举例如下:

`timescale 1ns/100ps     //合法
//`timescale 100ps/1ns   //不合法

(5)`resetall:将所有编译指令重设为缺省值

(6)单元模块定义(cell)

`celldefine

`endcelldefine

举例如下:

`celldefine
module (
    input      clk,
    input      rst,
    output   A,
    output   B );
endmodule
`endcelldefine

6.过程结构

(1)initial语句:
initial语句从0时刻开始执行,单次执行,多个语句之间并行执行,单个语句内顺序执行;
块内包含多个语句时需要使用关键字beginend,只有一条语句时可不用

(2)always语句:
always语句从0时刻开始执行,重复执行,多个语句之间并行执行,单个语句内顺序执行;
块内包含多个语句时需要使用关键字beginend,只有一条语句时可不用

7.过程赋值

(1)阻塞赋值“=”:语句顺序执行,即下一条语句执行前当前语句一定会执行完毕

(2)非阻塞赋值“<=”:语句并行执行,即其他语句的执行和当前语句的执行同时进行

8.语句块

(1)顺序块:块中语句顺序执行,但非阻塞赋值仍按并行执行,用begin & end表示

(2)并行块:块中语句并行执行,包括阻塞赋值,用fork & join表示

(3)嵌套块:顺序块+并行块

(4)命名块:给块语句结构命名,块中可以声明局部变量,通过层次名引用的方法对变量进行访问,格式如下:

module test;
	initial begin: A //块命名为A,disable后禁用命名块
		integer B; //变量B可通过text.A.B被其他模块调用
	end
endmodule

9.连续赋值语句

连续赋值语句“assign”用于对wire型变量进行赋值,格式如下:

wire      z, x, y;
assign  z = x & y;  //只要x、y改变z就会相应改变,注意z必须是wire型变量,x、y可以是wire型或reg型变量

10.延时语句

(连续赋值)延时语句“assign #time”用于控制任意操作数发生变化到语句左端赋予新值之间的延时时间,格式如下:

wire z, x, y;
assign #10 z = x & y; //延时10个时间单位后赋值,若信号脉冲宽度小于延时则对输出无影响,称为惯性延时

11.时序控制

(1)延时控制:包括常规延时控制与内嵌延时控制

常规延时格式为:(先延时再赋值,无惯性延时问题)

#10;
y = x; //或直接合并为#10 y = x;

内嵌延时格式为:(先赋值再延时,有惯性延时问题)

y = #10 x;

(2)事件控制:包括边沿触发事件控制与电平敏感事件控制

边沿触发事件格式为:

always @(posedge clk or negedge rst_n) //用@表示边沿触发条件,只有当信号发生特定变化时才能继续执行语句A
	begin
		A;
	end

posedge指信号边沿正向跳变时触发,negedge指信号边沿负向跳变时触发,未指明时正负边沿跳变都会触发;
用关键字or连接多个变量,当变量很多时可简写为@(*),表示对所有输入变量的边沿跳变都会触发;
命名事件控制是一种特殊的事件控制,用关键字event声明并触发该变量来识别该事件是否发生,格式如下:

event A;
always @(posedge clk) begin //clk上升沿作为A触发
	-> A; //->表示触发
	end
always @(A) begin //A触发时执行B
	B;
	end

电平敏感事件格式为:

wait (x); //x为电平敏感条件,只有当电平敏感条件为真时才能继续执行语句A
	begin
		A;
	end

12.条件语句

条件语句“if”用于根据条件判断是否执行相应语句,格式如下:

if (x) A; //如果满足条件x则执行A语句(若语句不只一行则应用“ begin A end; ”格式)
else if (y) B; //如果满足条件y则执行B语句(else if可有多级或者没有)
else C; //否则执行C语句

13.多路分支语句

多路分支语句"case"用于解决if语句中条件选项过多时使用不方便的问题,格式如下:

case (variable)
	x : A; //variable = x时执行A语句(若语句不只一行则应用“ begin A end; ”格式)
	y : B; //variable = y时执行B语句(除x、y还可以有多级case)
	default : Z; //default语句可没有

14.循环语句

(1)while循环语句(所有循环语句只能在“always”或“initial”块中使用)

while  (x) 
	begin
		A; //满足x条件时执行A语句,A只有一行时begin & end可省略
	end

(2)for循环语句

for (x; y; z) //x为初始条件,y为终止条件,z为控制变量的过程赋值语句,注意增加或减少变量计数不能写成 i++或i--
	begin
		A;
	end

(3)repeat循环语句

repeat (n) //执行固定次数n个循环
	begin
		A;
	end

(4)forever循环语句

forever //相当于while(1),表示永久循环,通过系统函数$finish退出
	begin
		A;
	end

15.过程连续赋值

(1)assign(过程赋值) & deassign(取消过程赋值):
赋值对象只能是wire型变量而不能是reg型变量,赋值过程中对寄存器连续赋值,寄存器中的值被保留直到被重新赋值

(2)force(强制赋值) & release(取消强制赋值):
赋值对象可以是reg型或wire型变量;
force作用在寄存器上时,寄存器当前值被覆盖,release时该寄存器值将继续保留强制赋值时的值;
force作用在线网上时,线网当前值被覆盖,但release时该线网值马上变为原有的驱动值

16.数值转换

(1)十进制有符号数转二进制补码:
正数的补码为原码;
负数的补码有两种计算方式:
a、将有符号数最高位符号位改写为1,剩余数值部分取反加1
比如4位数字-7的数值部分为4’b0111,高位改写后为4’b1111,剩余数值部分取反加1后为4’b1001
b、将有符号数直接与其代表的最大数值范围相加
比如4位数字-7与16(2的4次幂)的和为9, 即对应4’b1001

(2)二进制补码转十进制有符号数:
补码最高位为0时其数值大小即为表示的十进制正数;
补码最高位为1时有两种计算方式:
a、将补码取反加1,并增加符号位
比如4位数字-7的补码为4’b1001,取反加1后为4’b0111,增加符号位后为-7
b、将补码对应的无符号数与其代表的最大数值范围相减
比如4位数字-7的补码为4’b1001,无符号数为9,9-16=-7

(3)求二进制补码的绝对值:
将补码取反加1,比如4位数字-7的补码为4’b1001,取反加1后为4’b0111,即7

(4)符号位扩展:
将代表符号位的最高位填充至扩展的高位数据位中,比如4’b1011(-7)扩展到8位为8’b11111011(-7)

二、Verilog实例分享

1.计算数据位数

代码如下:

function integer log2(input integer n);
	integer i;     
	for( i=0; 2**i<=n; i=i+1) 
		log2 = i + 1;
endfunction

假设n=15(0000 1111),那么log2=4,也就是4位;
假设n=16(0001 0000),那么log2=5,也就是5位。

2.多次判断

代码如下:

reg x;
x <= ((x == 4'd0)	?	A	:	((x == 4'd1)	?	B	:	((x == 4'd2)	?	C	:	D)));

变量x为4’d0执行A语句,为4’d1执行B语句,为4’d2执行C语句,否则执行D语句。

3.循环计数

代码如下:

(*mark_debug = "true"*)reg	[5:0] CNT;
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		CNT	<=	1'b0;
	else
		CNT	<=	(CNT==最大计数-1) ? 1'd0 : CNT + 1'd1;
end

“最大计数”位置应给定一个值,CNT将在0~最大计数区间内循环+1。注意第一句(mark_debug = “true”)表示监视该变量。

4.捕捉上升&下降沿

代码如下:

reg triger, triger_dly1, triger_dly2;
always @ (posedge CLK or negedge RST)
begin
	if(!RST)
		begin
			triger_dly1 <= 1'b0;
			triger_dly2 <= 1'b0;
		end
	else
		begin
			triger_dly1 <= triger;
			triger_dly2 <= triger_dly1;
		end
end
wire posedge_triger = triger_dly1 && (~triger_dly2);
wire negedge_triger = (~triger_dly1) && triger_dly2;

对triger延时1拍和2拍产生triger_dly1和triger_dly2变量,triger_dly1为上升沿时通过posedge_triger捕捉,triger_dly2为下降沿时通过negedge_triger捕捉。


总结

如果文章中有错误或疏漏之处烦请指正,希望大家多交流共同进步!

  • 335
    点赞
  • 2752
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
目 录 译者序 前言 第1章 简介 1 1.1 什么是Verilog HDL? 1 1.2 历史 1 1.3 主要能力 1 第2章 HDL指南 4 2.1 模块 4 2.2 时延 5 2.3 数据流描述方式 5 2.4 行为描述方式 6 2.5 结构化描述形式 8 2.6 混合设计描述方式 9 2.7 设计模拟 10 第3章 Verilog语言要素 14 3.1 标识符 14 3.2 注释 14 3.3 格式 14 3.4 系统任务和函数 15 3.5 编译指令 15 3.5.1 `define和`undef 15 3.5.2 `ifdef、`else 和`endif 16 3.5.3 `default_nettype 16 3.5.4 `include 16 3.5.5 `resetall 16 3.5.6 `timescale 16 3.5.7 `unconnected_drive和 `nounconnected_drive 18 3.5.8 `celldefine 和 `endcelldefine 18 3.6 值集合 18 3.6.1 整型数 18 3.6.2 实数 19 3.6.3 字符串 20 3.7 数据类型 20 3.7.1 线网类型 20 3.7.2 未说明的线网 23 3.7.3 向量和标量线网 23 3.7.4 寄存器类型 23 3.8 参数 26 第4章 表达式 28 4.1 操作数 28 4.1.1 常数 28 4.1.2 参数 29 4.1.3 线网 29 4.1.4 寄存器 29 4.1.5 位选择 29 4.1.6 部分选择 29 4.1.7 存储器单元 30 4.1.8 函数调用 30 4.2 操作符 30 4.2.1 算术操作符 31 4.2.2 关系操作符 33 4.2.3 相等关系操作符 33 4.2.4 逻辑操作符 34 4.2.5 按位操作符 35 4.2.6 归约操作符 36 4.2.7 移位操作符 36 4.2.8 条件操作符 37 4.2.9 连接和复制操作 37 4.3 表达式种类 38 第5章 门电平模型化 39 5.1 内置基本门 39 5.2 多输入门 39 5.3 多输出门 41 5.4 三态门 41 5.5 上拉、下拉电阻 42 5.6 MOS开关 42 5.7 双向开关 44 5.8 门时延 44 5.9 实例数组 45 5.10 隐式线网 45 5.11 简单示例 46 5.12 2-4解码器举例 46 5.13 主从触发器举例 47 5.14 奇偶电路 47 第6章 用户定义的原语 49 6.1 UDP的定义 49 6.2 组合电路UDP 49 6.3 时序电路UDP 50 6.3.1 初始化状态寄存器 50 6.3.2 电平触发的时序电路UDP 50 6.3.3 边沿触发的时序电路UDP 51 6.3.4 边沿触发和电平触发的混合行为 51 6.4 另一实例 52 6.5 表项汇总 52 第7章 数据流模型化 54 7.1 连续赋值语句 54 7.2 举例 55 7.3 线网说明赋值 55 7.4 时延 55 7.5 线网时延 57 7.6 举例 57 7.6.1 主从触发器 57 7.6.2 数值比较器 58 第8章 行为建模 59 8.1 过程结构 59 8.1.1 initial 语句 59 8.1.2 always语句 61 8.1.3 两类语句在模块中的使用 62 8.2 时序控制 63 8.2.1 时延控制 63 8.2.2 事件控制 64 8.3 语句块 65 8.3.1 顺序语句块 66 8.3.2 并行语句块 67 8.4 过程性赋值 68 8.4.1 语句内部时延 69 8.4.2 阻塞性过程赋值 70 8.4.3 非阻塞性过程赋值 71 8.4.4 连续赋值与过程赋值的比较 72 8.5 if 语句 73 8.6 case语句 74 8.7 循环语句 76 8.7.1 forever 循环语句 76 8.7.2 repeat 循环语句 76 8.7.3 while 循环语句 77 8.7.4 for 循环语句 77 8.8 过程性连续赋值 78 8.8.1 赋值—重新赋值 78 8.8.2 force与release 79 8.9 握手协议实例 80 第9章 结构建模 83 9.1 模块 83 9.2 端口 83 9.3 模块实例语句 83 9.3.1 悬空端口 84 9.3.2 不同的端口长度 85 9.3.3 模块参数值 85 9.4 外部端口 87 9.5 举例 89 第10章 其他论题 91 10.1 任务 91 10.1.1 任务定义 91 10.1.2 任务调用 92 10.2 函数 93 10.2.1 函数说明部分 93 10.2.2 函数调用 94 10.3 系统任务和系统函数 95 10.3.1 显示任务 95 10.3.2 文件输入/输出任务 97 10.3.3 时间标度任务 99 10.3.4 模拟控制任务 99 10.3.5 定时校验任务 100 10.3.6 模拟时间函数 101 10.3.7 变换函数 102 10.3.8 概率分布函数 102 10.4 禁止语句 103 10.5 命名事件 104 10.6 结构描述方式和行为描述方式的 混合使用 106 10.7 层次路径名 107 10.8 共享任务和函数 108 10.9 值变转储文件 110 10.9.1 举例 111 10.9.2 VCD文件格式 112 10.10 指定程序块 113 10.11 强度 114 10.11.1 驱动强度 114 10.11.2 电荷强度 115 10.12 竞争状态 116 第11章 验证 118 11.1 编写测试验证程序 118 11.2 波形产生 118 11.2.1 值序列 118 11.2.2 重复模式 119 11.3 测试验证程序实例 123 11.3.1 解码器 123 11.3.2 触发器 124 11.4 从文本文件中读取向量 126 11.5 向文本文件中写入向量 127 11.6 其他实例 128 11.6.1 时钟分频器 128 11.6.2 阶乘设计 130 11.6.3 时序检测器 132 第12章 建模实例 136 12.1 简单元件建模 136 12.2 建模的不同方式 138 12.3 时延建模 139 12.4 条件操作建模 141 12.5 同步时序逻辑建模 142 12.6 通用移位寄存器 145 12.7 状态机建模 145 12.8 交互状态机 147 12.9 Moore有限状态机建模 150 12.10 Mealy型有限状态机建模 151 12.11 简化的21点程序 153 附录 语法参考 157 参考文献 172
Verilog 是一种硬件描述语言(HDL),用于设计和模拟数字电路。以下是一个简单的 Verilog 入门教程: 1. Verilog 基本语法 Verilog 代码由模块(module)、端口(port)、输入(input)、输出(output)、寄存器(reg)和线(wire)等组成。 模块定义格式如下: ``` module module_name (input port1, input port2, ..., output port3, output port4, ...); // Verilog 代码 endmodule ``` 其中,module_name 是模块名称,port1、port2、port3、port4 等是端口名称,它们可以是输入或输出。 2. Verilog 数据类型 Verilog 支持多种数据类型,包括: - bit:1 位二进制数 - reg:与 bit 相同,但可以存储多个 bit - integer:整数类型 - real:实数类型 - wire:表示信号线,可以连接不同模块的端口 - parameter:常量定义 3. Verilog 运算符 Verilog 支持各种运算符,例如: - 算术运算符:+、-、*、/、%(取模) - 比较运算符:==、!=、<、<=、>、>= - 逻辑运算符:&&、||、!、&、|、^ - 位运算符:&、|、^、~、<<、>> 4. Verilog 控制语句 Verilog 支持多种控制语句,例如: - if 语句: ``` if (condition) begin // Verilog 代码 end ``` - for 语句: ``` for (initialization; condition; increment) begin // Verilog 代码 end ``` - while 语句: ``` while (condition) begin // Verilog 代码 end ``` 5. Verilog 模块实例化 在 Verilog 中,一个模块可以实例化另一个模块,例如: ``` module module1 (input port1, output port2); endmodule module module2 (input port3, output port4); module1 m1 (port1, port2); endmodule ``` 其中,module2 实例化了 module1,m1 是 module1 的实例名称,port1 和 port2 是 module1 的输入和输出端口。 以上是一个简单的 Verilog 入门教程,希望对你有帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 21
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值