ZYNQ学习记录FPGA(二)Verilog语言

news2025/6/10 12:24:46

一、Verilog简介

1.1 HDL(Hardware Description language)

        在解释HDL之前,先来了解一下数字系统设计的流程:逻辑设计 -> 电路实现  -> 系统验证。

逻辑设计又称前端,在这个过程中就需要用到HDL,正文名硬件描述语言,本文所要介绍的Verilog就时HDL中的一种,需要注意的是,一般我们说的编程语言如C,C++,Python等其实是在描述软件,而HDL是在描述硬件,这是HDL与其他编程语言的重要区别。

        HDL 是描述数字电路的结构和功能的语言,用HDL描述的电路的结构和功能可以通过综合工具(EDA工具)将其转换成门级电路网表(数字电路最基本的单元就是门,门机电路网表可以组合成几乎所有的高级数字电路),有了门级电路网表,再结合特定的工艺(不同厂商有不同的工艺,如FPGA和ASIC),将工艺中的元件和网表一一对应起来,再通过布局布线形成电路结构,就能完成电路的实现,又称后端。

        HDL中除了Verilog语言外还有VHDL,这两个HDL中,Verilog在中国和美国应用更加广泛,而VHDL在欧洲应用更广一点。

1.2 Verilog简介

        Verilog语育最初是于1983 年由Gateway Design Automation 公司为其模拟器产品开发的硬件建模语言。
        Verilog 语言于1995 年成为IEEE 标准,称为IEEE Std 1364-1995,也就是通常所说的Verilog-95。Verilog-2001是对Verilog-95的一个重大改进版本。

1.3 Verilog 和 C语言的区别

        Verilog 是硬件描述语言,在编译下载到FPGA之后,会生成电路,所以Verilog 是并行运行的;
C语言是软件编程语言,编译下载到单片机之后,是存储器中的一组指令而单片机处理软件指令需要取指、译码、执行,这个过程是串行执行的。

        Verilog和C的区别也是FPGA和 单片机/CPU的区别。FPGA由于全并行处理,处理速度非常快,这个是 FPGA 的最大优势,这一点是 单片机/CPU 替代不了的。

二、Verilog语法

2.1 逻辑值

        逻辑0表示低电平,对应电路中的GND;

        逻辑1表示高电平,对应电路中的VCC;

        逻辑X表示未知电平,可能是高也可能是低;

        逻辑Z表示高阻态,外部没有激励,处于悬空状态;

        注意逻辑Z和逻辑X的区分,逻辑X是可高可低的而逻辑Z是不能判断电平高低的是悬空的。

2.2 数字进制格式

        Verilog包括二进制(b)、八进制(o)、十进制(d)和十六进制(h),verilog中定义常量需要说明位数和进制,如4‘b1101,4’o15,4d'13,4h'd都表示同一个数值但是不同进制

2.3 标识符(identifier)

        标识符类似于C语言中的变量名,它是用来定义模块名、端口名、信号名等的。

        定义标识符时应该注意一下三点:

        1)标识符可以是任意一组字母、数字、$符号和(下划线)符号的组合;

        2)标识符的第一个字符必须是字母或者下划线; 

        3)标识符是区分大小写的;

        一般定义标识符可以遵循以下规则:

        1)大小写不混合使用;2)普通内部信号小写表示;3)信号名应该体现信号的含义且应该简洁清晰。

        一些标识符举例:sum、cpu_addr、clk_10、clk_4、clk_cpu等

2.4 数据类型

        在 Verilog 语言中,主要有三大类数据类型:寄存器数据类型、线网数据类型和参数数据类型。前两者是要映射到实际电路中去的,是真正对电路进行描述的数据类型

2.4.1寄存器数据类型

        定义寄存器数据的关键字为 reg ,举例如下:

        

        这里定义了两个寄存器变量,也可以叫reg变量,分别为delay_cnt和key_reg,其中delay_cnt还指定了该寄存器变量的位宽为32位(0-31),值得注意的是每一个寄存器变量定义结束时都要有分号,位宽的定义为从大到小且定义reg变量时是禁止给予初始值的。

        reg类型的数据只能在 always 语和initial 语句中被赋值。

        如果该过程语句描述的是时序逻辑,即always语句带有时钟信号,则该寄存器变量对应的物理意义为触发器
        如果该过程语句描述的是组合逻辑,即always语句不带有时钟信号,则该寄存器变量对应的物理意义为硬件连线

2.4.2 线网数据类型

        定义线网数据的关键字为 wire 或 tri,两者用法是一致的,但一般用wire,举例如下:

        

        线网数据类型表示结构实体(例如门)之间的物理连线

        线网类型的变量不能储存值,它的值是由驱动它的元件所决定的。那能够驱动线网类型变量的元件有门、连续赋值语句、assign等,如果没有驱动元件连接到线网类型的变量上,则该变量就是高阻的,即其值为z。 

        需要注意的是在举例中没有指定wire变量的位宽,则默认是1位的位宽,当然位宽的定义和reg变量的定义格式相同。

2.4.3 参数数据类型

         定义参数数据的关键字为 parameter,实际就是定义常量,举例如下:

                

       参数型数据常用于定义状态机的状态、数据位宽和延迟大小等采用标识符来代表一个常量可以提高程序的可读性和可维护性在模块调用时,可通过参数传递来改变被调用模块中已定义的参数。

2.5 运算符

        Verilog的运算符主要有算术运算符、关系运算符、逻辑运算符、条件运算符、位运算符、移位运算符、拼接运算符。

2.5.1 算术运算符

        

需要注意的是除法运算只能整除,%为取余的操作。

2.5.2 关系运算符

2.5.3 逻辑运算符

从上到下分别为非、与、或运算

2.5.4 条件操作符

        条件操作符(条件运算符)是Verilog特有的运算符:

        用法举例如下:

result=(a >= b)? a:b;

        表示如果a>=b成立则将a的值赋给result否则将b的值赋给result,即取a和b中的最大值。

2.5.5 位运算符

位运算符就是对数据进行按位进行计算并将每一位之间的计算结果合并后返回,当然位运算符只针对二进制数据有效。

        需要注意的是当a和b的位宽不一致时,位运算会自动对位宽较小的数据的前面进行补零,补零到位宽一致再进行运算。对于异或操作,可以借助之前的条件操作符来理解:异或就可以写成result=(a!=b)?1:0

2.5.6 移位运算符

        需要注意的是两种移位运算都用0来填补移出的空位。当左移时,位宽增加。当右移时,位宽不变。

举例如下:

4'b1001<<2=6'b100100

4'b1001>>1=4 b0100

2.5.7 位拼接运算符

        

        举例如下:

c = {a[7:0],b[1:0]} 

        这样计算出来的c就应该是一个位宽为9的数据c[8:0]。

2.5.8 运算符优先级

        最后将前面介绍的运算符进行优先级排列:

 三、Verilog程序框架

3.1 注释

        Verilog有两种注释方式:注释单行内容“//”;注释范围内容起点用“/*”,结尾用“*/”。

3.2 关键字

        除了前面介绍的变量定义所用的关键字外,Verilog中还有许多关键字,定义标识符应该避免与这些关键字重名:

3.3 框架结构

3.3.1 模块结构(module)

        模块是Verilog中的基本设计单元,可以对照C语言中的函数来理解模块的含义。

        模块一般分为两部分,一部分描述模块的接口,一部分描述模块的逻辑功能。这两部分也同样可以参照C语言中的函数输入变量和函数内容来理解。这两部分可以细分为端口定义,IO说明,内部信号声明,功能定义四个部分,前两部分属于接口的描述,后面两个部分用于描述逻辑功能。

举例如下:

        这里描述模块功能时使用了assign关键字,这是给线网变量赋值的一种方法。只是这里没有声明内部信号,只利用了接口的信号就实现了功能。 

        需要注意的是每一个模块都必须以module关键字开头,以endmodule关键字结尾;input和output定义的变量默认时wire类型的变量;内容中的每一行结束都应该有分号结尾。

3.3.2 功能定义

        功能定义的方法有三种:assign关键字、always关键字、例化实例元件。其中assign只能用于描述组合逻辑功能,always可以描述组合和时序逻辑功能。需要注意的是这三种方式所定义的功能总是并行运行的,不论其在代码中的位置如何,这一点和C语言、python等软件描述语言的串行执行代码是完全不同的。

3.3.2.1 always关键字

下面对always关键字进行详细说明:

         其语法如下:

always @(信号) begin
    // 语句块
end

        这里的信号表示只有该信号触发时就执行语句块的内容(串行执行),信号可以是边沿触发,也可以是电平触发。边沿触发需要用到posedge(上升沿)和negedge(下降沿)关键字后面加信号名的方式来表示边沿触发的类型。电平触发只需信号名来表示,信号为高电平时触发always,低电平时就不触发always,举例如下:  

        如图中代码所示 ,always语句的功能内容由begin关键字标志开始,end关键字标志结束,begin和end之间的内容是串行进行的,即逐行运行。对于电平触发有一种简单的书写方式:

        用“*”代表所有的输入变量信号,这里“*”表示“a or b or c or d or e or f or g or h or p or m”
3.3.2.2 模块调用(模块例化)

        例化的语法如下:

被例化模块本来的名字 #(
    .常量参数名 (要赋给该常量参数的值)
)例化名(
    .被例化模块的接口变量名 (传入的与该接口相对应的变量名),
);

        可以把例化模块对比软件描述语言中的函数的调用,不外乎就是调用函数名、传入参数,只不过这里“调用函数名”还要给“函数”一个新的名字,称为例化名,传入参数时要传入模块的接口变量和模块中定义的常量的值,这样例化后就可以实现模块之间信号的传递了。下面举一个实列来帮助理解:

 

        左图是顶层模块对模块的例化,右图是被例化模块的定义。需要注意的是在例化时,被例化模块的输入接口可以连接reg和wire类型的变量,但是输出接口只能连接wire类型的变量,如在例化time_out模块时,在连接该模块的flag信号时就专门定义了一个wire类型的add_flag变量来连接。

四、进阶Verilog知识点

4.1 结构语句

        结构语句有initial和always两种语句分别由initial和always关键字来开始,区别在于initial语句在程序中只执行一次,而always语句是重复运行的。initial常用于测试文件的编写,用来产生仿真测试信号激励信号),或者用于对存储器变量赋初值。always则用来描述模块功能。举例如下:

         图中的#20这样的#+数字的组合表示延时,延时时间的单位由仿真文件的开头,如`timescale 1ns / 1ps决定,这里是ns为单位,#20就表示延时20ns。

4.2 赋值语句

        Verilog中的赋值包含阻塞赋值和非阻塞赋值两种模式,形式如下:

阻塞赋值b = a
非阻塞赋值b <= a

        我们把a叫做RHS(Right Hand Side),b叫做LHS(Left Hand Side)。那么对于阻塞赋值它实际上做的操作是计算RHS再更新LHS,当在always的语句块中执行时,由于执行过程是串行的,所以必须等阻塞赋值结束后,即更新完LHS后,才会进行下一段代码,这里可以看出阻塞赋值是将计算RHS和更新LHS作为一个整体,一段一段的运行的,颇有阻塞的感觉。对于非阻塞赋值,它把计算RHS和更新LHS两个部分拆开了,并且在计算非阻塞赋值的RHS以及更新LHS期间,允许其他的非阻塞赋值语句同时计算RHS和更新LHS,这样就做到了相较于阻塞赋值的非阻塞赋值。

        对于阻塞赋值和非阻塞赋值怎么选?什么时候用?这两个问题可以参照下面的规定:

                1)在描述组合逻辑的 always 块中用阻塞赋值“=”,综合成组合逻辑的电路结构;

        这种电路结构只与输入电平的变化有关系。
                2)在描述时序逻辑的 always 块中用非阻塞赋值<,综合成时序逻辑的电路结构;

        这种电路结构往往与触发沿有关系,只有在触发沿时才可能发生赋值的变化。
        注意:在同一个always块中不要既用非阻塞赋值又用阻塞赋值;不允许在多个always块中对同       一个变量进行赋值!

4.3 条件语句        

条件语句有if-else和case两种 ,if语句语法如下:

if(表达式1)
    语句1;
else if(表达式2)
    语句2;
else if(表达式3)
    语句3;
else
    语句4;
if(a) begin
    语句1;
    语句2;
end
else begin
    语句3;
    if(!b)
        语句4;
    else
        语句5;
end

         需要注意的是,在if进行值的判断时,0(低电平)、x(未知)、z(高阻态)均表示假。用begin,end的组合可以使得一个if或else包含多个语句。

        对于case语句,举例如下:

        case的内容中包含分支表达式和控制表达式,分支表达式表示需要被满足的条件,控制表达式则表示满足条件后执行的内容。需要注意的是在写分支表达式时,位宽必须和输入num的位宽一致且不能省略。default表示所有分支表达式都不满足时就执行default的内容。

        case在Verilog中还有两种写法casez和casex

        casez表示比较时不考虑高阻值,casex表示比较时不考虑高阻值和未知值。

五、总结

        在本篇学习过程中,我们深入了解了Verilog语言的基本概念、语法和应用,重点提到了Verilog作为硬件描述语言(HDL)与传统编程语言如C语言的差异,我们还详细解析了Verilog的语法,包括逻辑值的表示、常用的数据类型(如寄存器类型reg与线网类型wire)以及多种运算符的使用。

        然后讲解了Verilog的模块,Verilog的程序结构由模块(module)构成,每个模块定义了电路的功能和接口。模块的功能可以通过assign语句、always语句或模块实例化来实现。尤其需要注意的是,Verilog中的设计是并行执行的,与传统软件编程语言的串行执行方式不同,这一点也是其在硬件实现中的巨大优势。最后学习了Verilog的三种进阶的语句。

       

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2406614.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java中HashMap底层原理深度解析:从数据结构到红黑树优化

一、HashMap概述与核心特性 HashMap作为Java集合框架中最常用的数据结构之一&#xff0c;是基于哈希表的Map接口非同步实现。它允许使用null键和null值&#xff08;但只能有一个null键&#xff09;&#xff0c;并且不保证映射顺序的恒久不变。与Hashtable相比&#xff0c;Hash…

【记录坑点问题】IDEA运行:maven-resources-production:XX: OOM: Java heap space

问题&#xff1a;IDEA出现maven-resources-production:operation-service: java.lang.OutOfMemoryError: Java heap space 解决方案&#xff1a;将编译的堆内存增加一点 位置&#xff1a;设置setting-》构建菜单build-》编译器Complier

【阅读笔记】MemOS: 大语言模型内存增强生成操作系统

核心速览 研究背景 ​​研究问题​​&#xff1a;这篇文章要解决的问题是当前大型语言模型&#xff08;LLMs&#xff09;在处理内存方面的局限性。LLMs虽然在语言感知和生成方面表现出色&#xff0c;但缺乏统一的、结构化的内存架构。现有的方法如检索增强生成&#xff08;RA…

【笔记】AI Agent 项目 SUNA 部署 之 Docker 构建记录

#工作记录 构建过程记录 Microsoft Windows [Version 10.0.27871.1000] (c) Microsoft Corporation. All rights reserved.(suna-py3.12) F:\PythonProjects\suna>python setup.py --admin███████╗██╗ ██╗███╗ ██╗ █████╗ ██╔════╝…

五、jmeter脚本参数化

目录 1、脚本参数化 1.1 用户定义的变量 1.1.1 添加及引用方式 1.1.2 测试得出用户定义变量的特点 1.2 用户参数 1.2.1 概念 1.2.2 位置不同效果不同 1.2.3、用户参数的勾选框 - 每次迭代更新一次 总结用户定义的变量、用户参数 1.3 csv数据文件参数化 1、脚本参数化 …

python基础语法Ⅰ

python基础语法Ⅰ 常量和表达式变量是什么变量的语法1.定义变量使用变量 变量的类型1.整数2.浮点数(小数)3.字符串4.布尔5.其他 动态类型特征注释注释是什么注释的语法1.行注释2.文档字符串 注释的规范 常量和表达式 我们可以把python当作一个计算器&#xff0c;来进行一些算术…

C++11 constexpr和字面类型:从入门到精通

文章目录 引言一、constexpr的基本概念与使用1.1 constexpr的定义与作用1.2 constexpr变量1.3 constexpr函数1.4 constexpr在类构造函数中的应用1.5 constexpr的优势 二、字面类型的基本概念与使用2.1 字面类型的定义与作用2.2 字面类型的应用场景2.2.1 常量定义2.2.2 模板参数…

EEG-fNIRS联合成像在跨频率耦合研究中的创新应用

摘要 神经影像技术对医学科学产生了深远的影响&#xff0c;推动了许多神经系统疾病研究的进展并改善了其诊断方法。在此背景下&#xff0c;基于神经血管耦合现象的多模态神经影像方法&#xff0c;通过融合各自优势来提供有关大脑皮层神经活动的互补信息。在这里&#xff0c;本研…

C++中vector类型的介绍和使用

文章目录 一、vector 类型的简介1.1 基本介绍1.2 常见用法示例1.3 常见成员函数简表 二、vector 数据的插入2.1 push_back() —— 在尾部插入一个元素2.2 emplace_back() —— 在尾部“就地”构造对象2.3 insert() —— 在任意位置插入一个或多个元素2.4 emplace() —— 在任意…

CVE-2023-25194源码分析与漏洞复现(Kafka JNDI注入)

漏洞概述 漏洞名称&#xff1a;Apache Kafka Connect JNDI注入导致的远程代码执行漏洞 CVE编号&#xff1a;CVE-2023-25194 CVSS评分&#xff1a;8.8 影响版本&#xff1a;Apache Kafka 2.3.0 - 3.3.2 修复版本&#xff1a;≥ 3.4.0 漏洞类型&#xff1a;反序列化导致的远程代…

Copilot for Xcode (iOS的 AI辅助编程)

Copilot for Xcode 简介Copilot下载与安装 体验环境要求下载最新的安装包安装登录系统权限设置 AI辅助编程生成注释代码补全简单需求代码生成辅助编程行间代码生成注释联想 代码生成 总结 简介 尝试使用了Copilot&#xff0c;它能根据上下文补全代码&#xff0c;快速生成常用…

Axure零基础跟我学:展开与收回

亲爱的小伙伴,如有帮助请订阅专栏!跟着老师每课一练,系统学习Axure交互设计课程! Axure产品经理精品视频课https://edu.csdn.net/course/detail/40420 课程主题:Axure菜单展开与收回 课程视频:

RabbitMQ 各类交换机

为什么要用交换机&#xff1f; 交换机用来路由消息。如果直发队列&#xff0c;这个消息就被处理消失了&#xff0c;那别的队列也需要这个消息怎么办&#xff1f;那就要用到交换机 交换机类型 1&#xff0c;fanout&#xff1a;广播 特点 广播所有消息​​&#xff1a;将消息…

高保真组件库:开关

一:制作关状态 拖入一个矩形作为关闭的底色:44 x 22,填充灰色CCCCCC,圆角23,边框宽度0,文本为”关“,右对齐,边距2,2,6,2,文本颜色白色FFFFFF。 拖拽一个椭圆,尺寸18 x 18,边框为0。3. 全选转为动态面板状态1命名为”关“。 二:制作开状态 复制关状态并命名为”开…

未授权访问事件频发,我们应当如何应对?

在当下&#xff0c;数据已成为企业和组织的核心资产&#xff0c;是推动业务发展、决策制定以及创新的关键驱动力。然而&#xff0c;未授权访问这一隐匿的安全威胁&#xff0c;正如同高悬的达摩克利斯之剑&#xff0c;时刻威胁着数据的安全&#xff0c;一旦触发&#xff0c;便可…

欢乐熊大话蓝牙知识17:多连接 BLE 怎么设计服务不会乱?分层思维来救场!

多连接 BLE 怎么设计服务不会乱&#xff1f;分层思维来救场&#xff01; 作者按&#xff1a; 你是不是也遇到过 BLE 多连接时&#xff0c;调试现场像网吧“掉线风暴”&#xff1f; 温度传感器连上了&#xff0c;心率带丢了&#xff1b;一边 OTA 更新&#xff0c;一边通知卡壳。…

Element-Plus:popconfirm与tooltip一起使用不生效?

你们好&#xff0c;我是金金金。 场景 我正在使用Element-plus组件库当中的el-popconfirm和el-tooltip&#xff0c;产品要求是两个需要结合一起使用&#xff0c;也就是鼠标悬浮上去有提示文字&#xff0c;并且点击之后需要出现气泡确认框 代码 <el-popconfirm title"是…

Selenium 查找页面元素的方式

Selenium 查找页面元素的方式 Selenium 提供了多种方法来查找网页中的元素&#xff0c;以下是主要的定位方式&#xff1a; 基本定位方式 通过ID定位 driver.find_element(By.ID, "element_id")通过Name定位 driver.find_element(By.NAME, "element_name"…

OPENCV图形计算面积、弧长API讲解(1)

一.OPENCV图形面积、弧长计算的API介绍 之前我们已经把图形轮廓的检测、画框等功能讲解了一遍。那今天我们主要结合轮廓检测的API去计算图形的面积&#xff0c;这些面积可以是矩形、圆形等等。图形面积计算和弧长计算常用于车辆识别、桥梁识别等重要功能&#xff0c;常用的API…

spring boot使用HttpServletResponse实现sse后端流式输出消息

1.以前只是看过SSE的相关文章&#xff0c;没有具体实践&#xff0c;这次接入AI大模型使用到了流式输出&#xff0c;涉及到给前端流式返回&#xff0c;所以记录一下。 2.resp要设置为text/event-stream resp.setContentType("text/event-stream"); resp.setCharacter…