写在前面:本章将对 Verilog 进行简要介绍,并对其基本特性进行讲解说明。之后,我们将按步骤演示如何使用 Vivado 创建简单项目。手动实践部分将根据我们提供的 .v 和 .tb 代码,跟着步骤跑出 Simulation 结果即可。
Ⅰ. Verilog 基础速览
0x00 什么是 Verilog
HDL(Hardware Description Language),硬件描述语言。
Verilog 是一种用于描述电子系统的硬件描述语言(HDL)。它可以用来描述数字系统的结构和行为,并可以用于系统设计、模拟和综合。Verilog 最初是在 1984 年开发的,现在是电子设计自动化行业中使用最广泛的 HDL 之一。
Verilog 作为一种语言,它可以用于多种用途,包括电路设计、验证和实现。它具有类似于 C 语言的语法,因此用户可以轻松访问它。if 和 while 等控制结构相同,输出例程和运算符也相同差不多一样。与 C 语言这些语言不同,硬件描述语言的语法和含义描述了时间和并发性。还有就是的开头和结尾没有花括号,而是用 Begin 和 End 来区分。
0x01 Verilog 模块
module 模块名(端口列表) ;
port 声明
reg 声明
wire 声明
parameter 声明
子模块实例
初识Gate
always、initial
assign
function, task 定义
function, task 调用
endmodule
📚 Verilog 分为三个主要部分:头部、声明、主体。
- 头部以关键字 module 开头,后面跟模块名与端口列表,并以分号结尾。和大多数编程预压那一页,Verilog 也是不能用关键字命名的。
- 声明部分包含方向、位宽和reg 和 wire 声明、参数声明等模块,即声明需要的东西。
- 主体部分表示电路的功能、操作、结构等。它由各种 Verilog 语句组成。
0x02 Verilog 数据类型
Input:输入信号
Output:输出信号
寄存器:抽象存储设备
- reg :通过程序赋值语句(always,initial)接收值的个体。
- integer:整型变量
- time, realtime:时间类型的变量(在需要时序检查的情况下处理仿真时间)
- real:实数型变量
Net : 设备的物理连接
wire :指示变量在模块中的连接方式。
tri:用于将导线相互连接。与 wire 不同,tri 用于 tri-state net。
0x03 Verilog HDL 的常数声明
当声明一个限制位数的 reg 值时:
(位数)'(输入格式)(输入值)
未指定大小的值(未指定大小也可以声明):
214; [整数 214]
‘h32; [16进制的 32]
‘o324; [8进制的 324]
指定大小的值(在开头声明位数):
4’b1111; [4bit的 2进制 1111]
4’hf; [4bit的 16进制 f(=4’b1111)]
4’d15; [4bit的 10进制 15(4’b1111)]
有符号数的处理(负值作为二进制补码处理):
-8'd6; [8bit的 -6]
0x04 Verilog 操作符
普通操作符:
符号 | 功能 | 符号 | 功能 |
{} , {{}} | 结合,循环 | ^ | 异或 |
+, - , * , / , ** | 算数 | ^~ 或 ~^ | bit位等价 |
% | 取余 | & | and |
>, >=, <, <= | 关系 | ~& | nand |
! | 论理否定 | | | or |
// X=4'b1010, Y=4'b1101,Z=4'b10x1
~X // Negation, Result is 4'b0101
X&Y // Bitwise AND, Result is 4'b1000
X | Y // Bitwise OR, Result is 4'b1111
X^Y // Bitwise XOR, Result is 4'b0111
X^~Y // Bitwise XNOR, Result is 4'b1000
X&Z // Bitwise AND, Result is 4'b10x0
移位操作符:
符号 | 功能 | 符号 | 功能 |
<< | 左移 | >> | 右移 |
// X=4'b1101
Y=X>>1 // Y is 0110 (0 is filled in MSB position)
Y=X<<2 // Y is 0100 (0 is filled in LSB position)
条件运算符:
conditional_expression = exp1 ? exp2 : exp3
连接运算符(Concatenation Operators): { }
// A = 1’b1 , B=2’b00 , C=2’b10
Y = {B,C} // Results Y is 4’b0010
X = {A, B, 3’b110} // Result X is 6’b100110
Z = {A, B[0], C[1]} // Result Z is 3’b101
复制运算符(Replication Operators): {{ }}
//A = 1’b1 , B = 2’b01 , C = 2’b00
Y = {4{A}} // Result Y is 4’b1111
X = {4{A},2{B}} // Result X is 11110101
Z = {4{A}, {2{B}, C} // Result Z is 1111010100
0x05 Timescale
'timescale <时间单位> / <精密度>
<时间单位>:如果声明了该值,则文件中的所有时间单位都更改为声明的值。
(举个例子,如果声明“1ns”,文件中的所有时间单位都变为 1ns)
<精度> :表示给定时间单位内的最小可构成延迟,与 <时间单位> 关联使用,表示可使用的小数点的范围。
'timescale 10ns/1ns
#1.55a=b;
// 所有时间单位都是10ns,1.55*10ns = 15.5ns。
// 此处精度值向上舍入为1ns,结果为16ns。
'timescale 1ns/1ps
#1.0055a=b;
// 所有时间单位都是1ns,所以1.0055*1ns = 1.0055。
// 此处精度值向上舍入到1ps,得到1.006ns。 (1ps=0.001ns)
0x06 assign 语句
assign
当输入操作数的值中发生变化(event)时,assign 语句都会计算右侧的表达式。
因此该值具有围绕赋值语句驱动(drive)net 的硬件特性。
简单来说,就是用来给 net 变量赋值一个特定的逻辑值。
deassign
deassign 语句用于消除 assign 语句对变量的影响。
assign wire1 = reg1; // 简单的连接线
assign wire2 = (pin1) ? reg2[0] : reg2[1];
assign wire2 = {reg1,reg2[0]}; // 将两个不同的信号放入一个总线
0x07 alway 语句
always 语句在仿真运行时重复执行,因此它对于与时序控制相关的表达式很有用。@(sensitivity_list) 控制 always 语句的执行,并响应灵敏度列表中列出的一个或多个信号。当事件(event)发生时,总是执行里面的 begin-end 块。
always @(sensitivity_list) begin
// Blocking or nonBlocking statements;
end
0x08 initial 语句
与在模拟过程中无限重复的 always 语句不同,initial 语句仅在模拟运行时执行一次。
initial 语句的开始-结束块由过程语句组成,这些过程语句按列出的顺序执行。
initial begin
// Blocking or nonBlocking statements;
end
0x09 赋值语句
这些语句按照它们列出的顺序执行,并且具有更新赋值语句左侧变量值的软件特性。
always 语法,在 initial 语句中使用。
阻塞语句(Blocking statement):
- blocking 符号: =
- Begin ~ end 位置 Line by Line 的顺序计算并完成保存
- 当任务都执行完毕后执行下面语句 -> 即,语句在执行完成之前 blocking
- #t 变量 = 计算; -> t事件后,计算并分配给变量。
变量 C = A & B; //读取A和B的值进行 & 运算并赋值给C. 然后执行下一条语句
变量 D = A | B; // 读取A和B的值进行 | 运算并复制给D,此时它们的执行过程没有延迟
非阻塞语句(Non blocking statement):
- non Blocking 符号:<=
- 在执行完从 Begin ~ End 的所有计算后,立即执行保存操作。
- 多个非阻塞语句同时求值后分配。
- 变量 <= #t 计算; -> 计算t 后,保留变量赋值。
(* 用于在共同事件发生后同时传输多个数据)
变量 C <= A & B; // 读取A和B的值,并进行&操作
变量 D <= A | B; // 同时读取A和B的值, |操作, 然后将它们同时分配给 C 和 D。
💬 Verilog Blocking 语法举例:
Ⅱ. 动手操作
🔍 我的是 xc7a75tfgg484:
继续点 Finish:
在创建项目,等一会:
保存项目:
我们来写点代码试试:
💬 inv.v
`timescale 1ns / 1ps
module inv(
input a,
output y
);
assign y = ~a;
endmodule
再创建一个 csdn.tb 的 Sources:
💬 csdn.tb
`timescale 1ns / 1ps
module inv_tb;
reg aa;
wire y;
inv u_inv (
.a (aa ),
.y (y ) );
initial aa = 1'b0;
always aa = #100 ~aa;
initial begin
#1000
$finish;
end
endmodule
仿真:
等待
🚩 仿真结果如下:
📌 [ 笔者 ] 王亦优
📃 [ 更新 ] 2022.9.20
❌ [ 勘误 ] /* 暂无 */
📜 [ 声明 ] 由于作者水平有限,本文有错误和不准确之处在所难免,
本人也很想知道这些错误,恳望读者批评指正!
📜 参考资料 Introduction to Logic and Computer Design, Alan Marcovitz, McGrawHill, 2008 Microsoft. MSDN(Microsoft Developer Network)[EB/OL]. []. . 百度百科[EB/OL]. []. https://baike.baidu.com/. |