【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第1张图片

写在前面:本章将对 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 数据类型

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第2张图片  

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 语句对变量的影响。

14dcddbdc9d8424083eed445ecaf9141.png

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 语法举例:

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第3张图片

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第4张图片

Ⅱ. 动手操作

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第5张图片

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第6张图片

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第7张图片

 【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第8张图片

 【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第9张图片

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第10张图片

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第11张图片

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第12张图片

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第13张图片

我的是 xc7a75tfgg484:【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第14张图片

继续点 Finish:

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第15张图片

在创建项目,等一会:

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第16张图片

 【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第17张图片 

 保存项目:

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第18张图片

 我们来写点代码试试:

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第19张图片

  inv.v

`timescale 1ns / 1ps

  module inv(
  input a,
  output y
  );

assign y = ~a;
 

endmodule

再创建一个 csdn.tb 的 Sources:

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第20张图片

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

 仿真:

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第21张图片

等待

 【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第22张图片

仿真结果如下:

【FPGA】Verilog 基础速览 | 数据类型 | HDL常数声明 | Timescale | 操作符 | 阻塞语句 | 非阻塞语句_第23张图片

7a80245f0b5f4021a033b3789a9efdeb.png

 [ 笔者 ]   王亦优
 [ 更新 ]   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/.

你可能感兴趣的:(⚡《FPGA开发》,fpga开发,Verilog,数字电路)