看思维导图:一文带你学Verilog HDL语言

2023-05-16

关注、星标嵌入式客栈,精彩及时送达

[导读] 基于FPGA的SOC在嵌入式系统应用越来越广了,往往一个复杂系统使用一个单芯片基于FPGA的SOC就搞定了。比较流行的方案主要有Altera/xilinx两家的方案。要用这样的方案,首要需要掌握的是硬件描述语言。最为流行的硬件描述语言有两种Verilog HDL/VHDL,均为IEEE标准。Verilog HDL具有C语言基础就很容易上手,而VHDL语言则需要Ada编程基础。另外Verilog HDL语言具有大量成熟的模块,从某种角度说Verilog HDL更具生命力。

本文整理了一下Verilog HDL语言技术要点,并分享给大家。如发现有错误,欢迎留言指正。

Verilog HDL能干啥?

Verilog HDL的特点:

  • 可描述顺序执行或并行执行的程序结构

  • 用延迟表达式或事件表达式来明确地控制过程的启动时间

  • 通过命令的事件来触发其他过程的激活行为或停止行为

  • 提供了条件/循环等逻辑控制结构

  • 提供了可带参数且非零延续时间的任务程序机构

  • 提供了用于建立表达式的算术运算符、逻辑运算符和位运算符

  • 实现了完整的表示组合逻辑基本元件的原语

  • 提供了双向通路和电阻器的描述

  • 可建立MOS器件的电荷分享和衰减模型

  • 可通过结构性语句精确地建立信号模型

在学习Verilog HDL之前,先明确一下FPGA的设计抽象层次:

 

基本程序结构

module module_name(port_list)
    //声明各种变量、信号
    reg  //寄存器
    wire //线网
    parameter //参数
    input  //输入信号
    output //输出信号
    inout  //输入输出信号
    function //函数
    task     //任务
    ....
        
    //程序代码
    initial assignment
    always assignment
    module assignment
    gate   assignment
    UDP    assignment
    continous assignment
endmodule

启示:描述的是模块,其本质是数字电路:

  • 组合逻辑电路模块:组合逻辑电路的特点是输入的变化直接反映了输出的变化,其输出的状态仅取决于输入的当前的状态,与输入、输出的原始状态无关。

  • 时序逻辑电路模块:时序电路具有记忆功能。时序电路的特点是:输出不仅取决于当时的输入值,而且还与电路过去的状态有关。时序逻辑电路又称时序电路,主要由存储电路和组合逻辑电路两部分组成。

数据类型及运算符

变量名

变量名类似C语言,以一组字母、数字、下划线和$符号的组合,且首字符须为字母或者下划线。如

input ctrl_1;

数据类型

将四种基本数据类型整理成一张导图:

其中须注意的是,对于memory型存储单元进行读写,须指定地址,如:

reg[15:0] addr; //定义addr为16位位宽的存储器变量
addr = 1;       //ok

reg addr[15:0]; //定义addr为1位位宽的16个存储器变量
addr    = 1;    //错误
addr[0] = 1;    //正确

//又如:
reg[15:0] addr[3:1]; //定义3个位宽为16位存储器
addr[1] = 16'h0      //16'指定位宽,h 表示16进制,0
addr[2] = 16'b011    //b表示二进制

对于parameter变量的实用价值可读性比较好理解,那么可维护性怎么体现呢?

熟悉C语言编程的,联想一下宏,如果宏变了,有宏的地方全替换,这里parameter变量作用类似,如:

module Decode(A,F); 
parameter  Width=1, Polarity=1; 
…………… 
endmodule 
module  Top; 
wire[3:0] A4; 
wire[4:0] A5; 
wire[15:0] F16; 
wire[31:0] F32; 
Decode  #(4,0)  D1(A4,F16); 
Decode  #(5)    D2(A5,F32); 
Endmodule 

常量

parameter定义常量,那么对于常数,整型常量即整常数有以下四种进制表示形式:

  1. 二进制整数(b或B)

  2. 十进制整数(d或D)

  3. 十六进制整数(h或H)

  4. 八进制整数(o或O)

数字表达方式有以下三种:

  1. <位宽><进制><数字>这是一种全面的描述方式。

  2. <进制><数字>在这种描述方式中,数字的位宽采用缺省位宽(这由具体的机器系统决定,但至少32位)。

  3. <数字>在这种描述方式中,采用缺省进制十进制。

x和z值

在数字电路中,x代表不定值,z代表高阻值。不确定是啥?高阻又是啥?记住verilog描述的数字电路,那么对于一个模块的I/O就有可能是高阻,或者状态不确定。

负数:

一个数字可以被定义为负数,只需在位宽表达式前加一个减号,减号必须写在数字定义表达式的最前面。注意减号不可以放在位宽和进制之间也不可以放在进制和具体的数之间。

-8'd7  //-号直接放在最前面
8'd-7  //这样则不正确

实数

实数可用十进制方式表述或者科学计数法描述,如:

//十进制表示
1.0
20.234
//科学计数法表示
6e-4

模块端口

  • input:模块从外界读取数据的接口,在模块内可读不可写

  • output:模块向外部输出数据的接口,模块内部可写不可读

  • inout:可读写数据,数据双向流动。

学习硬件描述语言,一定要时刻记住,这是描述的是电路,风格类C,但不是C!

表达式及运算符

和C语言类似,运算符也有三种:

  • 单目运算符(unary operator):可以带一个操作数,操作数放在运算符的右边。

  • 二目运算符(binary operator):可以带二个操作数,操作数放在运算符的两边。

  • 三目运算符(ternary operator):可以带三个操作,这三个操作数用三目运算符分隔开。

对于运算符,整理了一张导图:

大部分与C语言类似,除了等式运算符、位拼接运算符、缩减运算符,这里放点例子方便理解:

//缩减运算符
reg [3:0] B; 
reg C; 
C = &B; 
//相当于: 
C =( (B[0]&B[1]) & B[2] ) & B[3]; 
//位拼接运算符
{a,b[3:0],w,3’b101}
//相当于: 
{a,b[3],b[2],b[1],b[0],w,1’b1,1’b0,1’b1} 

运算符优先级

赋值语句

  • 非阻塞(Non_Blocking)赋值方式, 如 b <= a; 加粗是非阻塞的含义

    • 块结束后才完成赋值操作。

    • b的值并不是立刻就改变的。

    • 这是一种比较常用的赋值方法。

  • 阻塞(Blocking)赋值方式,如 b = a;

    • 赋值语句执行完后,块才结束。

    • b的值在赋值语句执行完后立刻就改变的。

    • 可能会产生意想不到的结果。

块语句

块语句有两种,一种是begin_end语句,通常用来标识顺序执行的语句,用它来标识的块称为顺序块。一种是 fork_join语句,通常用来标识并行执行的语句,用它来标识的块称为并行块。

顺序块

  • 块内的语句是按顺序执行的,即只有上面一条语句执行完后下面的语句才能执行。

  • 每条语句的延迟时间是相对于前一条语句的仿真时间而言的。

  • 直到最后一条语句执行完,程序流程控制才跳出该语句块。

begin 
    语句1; 
    语句2; 
    ...... 
    语句n; 
end 

并行块

  • 块内语句是同时执行的,即程序流程控制一进入到该并行块,块内语句则开始同时并行地执行。

  • 块内每条语句的延迟时间是相对于程序流程控制进入到块内时的仿真时间的。

  • 延迟时间是用来给赋值语句提供执行时序的。

  • 当按时间时序排序在最后的语句执行完后或一个disable语句执行时,程序流程控制跳出该程序块。

fork 
    语句1; 
    语句2; 
    ....... 
    语句n; 
join 

流控语句

流控语句风格与C语言类似,仅仅需要注意的有下面几点:

  • if 语句别忘了考虑else的情况,如忘了处置则最终硬件会最终产生意想不到的后果

  • 多条语句在条件内部需要用begin/end对包起来。

  • case语句与C语言也有default分支,实际使用注意处置default分支

结构说明语句

Verilog语言中的任何过程模块都从属于以下四种结构的说明语句:

  • initial说明语句:只执行一次

  • always说明语句 :是不断地重复执行

  • task说明语句

  • function说明语句

对于task/function的不同点,使用时需要注意:

  • 函数只能与主模块共用同一个仿真时间单位,而任务可以定义自己的仿真时间单位。函数的定义不能包含有任何的时间控制语句,即任何用#、@、或wait来标识的语句。

  • 函数不能启动任务,而任务能启动其它任务和函数。

  • 函数至少要有一个输入变量,而任务可以没有或有多个任何类型的变量。

  • 函数返回一个值,而任务则不返回值。

  • 函数的目的是通过返回一个值来响应输入信号的值。任务却能支持多种目的,能计算多个结果值,这些结果值只能通过被调用的任务的输出或总线端口送出

  • 在函数的定义中必须有一条赋值语句给函数中的一个内部变量赋以函数的结果值,该内部变量具有和函数名相同的名字。

系统函数和任务

在Verilog HDL语言中每个系统函数和任务前面都用一个标识符$来加以确认,有这些系统函数和任务。

rtoi, setup, skew, setuphold, strobe, time, timefoemat, width, write, $recovery,

按字面意思理解,需要用到时查询手册即可。

编译预处理

宏定义 `define

用法:

`define 标识符(宏名) 字符串(宏内容)

如:

//类似C宏替换
`define signal hello 

与C语言宏类似,除了关键字不一样,也支持嵌套。组成宏内容的字符串不能够被以下的语句记号分隔开的,下面几点需要注意:

  • 注释行

  • 数字

  • 字符串

  • 确认符

  • 关键词

  • 双目和三目字符运算符

“文件包含”处理`include

用法:`include “文件名”

四点说明:

  • 一个`include命令只能指定一个被包含的文件,如果要包含n个文件,要用n个`include命令。注意下面的写法是非法的`include"aaa.v""bbb.v"

  • `include命令可以出现在Verilog HDL源程序的任何地方,被包含文件名可以是相对路径名,也可以是绝对路径名。例如:'include"parts/count.v"

  • 可以将多个`include命令写在一行,在`include命令行,只可以出空格和注释行。

  • 如果文件1包含文件2,而文件2要用到文件3的内容,则可以在文件1用两个`include命令分别包含文件2和文件3,而且文件3应出现在文件2之前

时间尺度 `timescale

`timescale命令用来说明跟在该命令后的模块的时间单位和时间精度。使用`timescale命令可以在同一个设计里包含采用了不同的时间单位的模块。用法:

`timescale<时间单位>/<时间精度>

//模块中所有的时间值都表示是1ns的整数倍
//1ns/ps:1纳秒/脉冲 
`timescale  1ns/1ps 

注意:如果在同一个设计里,多个模块中用到的时间单位不同,需要用到以下的时间结构:

  • 用`timescale命令来声明本模块中所用到的时间单位和时间精度。

  • 用系统任务$printtimescale来输出显示一个模块的时间单位和时间精度。

  • 用系统函数和realtime及%t格式声明来输出显示EDA工具记录的时间信息。

条件编译命令

`ifdef、`else、`endif

这与C语言用法类似,这里就不赘述了。

总结一下

Verilog HDL的语法与C语言的语法类似,但是一定要意识到Verilog HDL描述的是电路,光有代码还不够,器件可能运行的结果并不是代码想要的效果。另外要注意理解并行的概念,这里的并行是硬件在时钟驱动真的同时按照所设计的逻辑运行。一些重要的概念:

  • 阻塞〔Blocking〕和非阻塞〔Non-Blocking〕赋值的不同

  • 顺序块和并行块的不同

  • 块与块之间的并行执行的概念;

  • task和function的概念。

那么最好的学习办法是什么呢?写代码、仿真、综合、优化布局布线,挖坑、踩坑、填坑,在错误中总结,渐进明晰、不断实践总结。

本文辛苦原创分享,如果觉得有价值也请帮忙点赞/转发支持,不胜感激!

参考资料:

《夏宇闻-Verilog经典教程》,如需要本电子书,关注后发送Verilog,可领取pdf。

END

往期精彩推荐,点击即可阅读

▲Linux内核中I2C总线及设备长啥样? 

手把手教系列之梳状滤波器设计实现

手把手教系列之IIR数字滤波器设计实现

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

看思维导图:一文带你学Verilog HDL语言 的相关文章

  • 从零开始编写一个上位机(串口助手)QT Creator + C++

    提示 xff1a 本博客作为学习笔记 xff0c 有错误的地方希望指正 xff0c 此文可能会比较长 xff0c 作为学习笔记的积累 xff0c 希望对来着有帮助 绪论 xff1a 笔者这里使用的是QTCreator和C 43 43 来实现
  • MPU6050对卡尔曼、一阶互补滤波、二阶互补滤波的比较

    这是总体的滤波效果 这是放大的版的 可以看出 xff0c 卡尔曼和二阶基本在重合在一起 xff0c 一阶也还好 xff0c 也没有差得太远 这里是从一放在桌子上一段时间后再进行测试的 xff0c 可以看出一阶的跟随性上面要比其他二个都要好
  • 基于UCOSIII+机智云的远程空调遥控器

    一年前 xff0c 我通过师兄的介绍知道了机智云这家创业公司 xff0c 后来 xff0c 他们的经理来我们学校开了一次宣讲会 xff0c 然后我就以个人开发者的名义申请了他们家的GoKit2代开发板 xff0c 开始对这家公司有一定的关注
  • VMware Workstation12安装Ubuntu和VMware Tools教程

    之前我通过百度经验上的过程来安装Ubuntu16 xff0c 但是每次安装的时候没有什么问题 xff0c 就是安装好了Tools xff0c 也设置好了共享文件夹 xff0c 但是在路径 xff1a mnt hgfs 下每次都找不到共享文件
  • IIC上拉电阻的选择

    上周项目评审的时候 xff0c 评审部门问了我一个问题 xff1a 为什么单片机内部有上拉电阻 xff0c 你们还要用外部的上拉电阻 xff1f 我的答复如下 xff1a 上拉电阻的选取要考虑上限值和下限值这两点 xff1a 上限值的最大限
  • 手写RTOS-创建工程

    今天开始我手写RTOS的第一步 xff0c 创建一个工程 这个工程要能够在MDK环境中能够进行编译和仿真 xff0c 不用借助任何的开发板和仿真器 xff0c 完全基于Cotex M3内核进行实验 现在我们开始创建这一个工程 xff0c 首
  • STM8S之TIM2_CH1输出不了PWM波解决办法

    最近由于项目需要 xff0c 用到STM8S103F3P6 xff0c 开发方式采用库函数方式开发 xff0c 编译环境为ST Visual Develop 43 Cosmic CxSTM8 32K 4 3 4 初始化PWM的程序如下 xf
  • 陀螺仪和加速度计互补滤波的一些推导

    1 首先 xff0c 简单介绍一下加速度计和陀螺仪的一些特性 加速度计 xff1a 静态稳定性好 xff0c 动态响应较慢 xff0c 在高频时信号不可用 xff0c 在运动时其数据相对不可靠 陀螺仪 xff1a 动态性能好 xff0c 响
  • 树莓派4B gpio readall 出现Oops - unable to determine board type... model: 17

    树莓派使用GPIO接口是基于wiringPi的 官网链接 xff1a http wiringpi com 1 xff1a 出现问题的界面 pi 64 raspberrypi gpio v gpio version 2 50 Copyrigh
  • 树莓派4B +远程SSH+远程桌面

    一 有线SSH连接树莓派 我的实验环境是笔记本电脑 43 树莓派4B 具体步骤为 xff1a 1 电脑连接上无线网络 xff0c 将电脑网线连接树莓派 2 打开如下界面 3 双击WLAN gt gt 点击属性 gt gt 再点击共享 选择以
  • 树莓派4B+wifi远程无线连接

    在树莓派无线连接前 xff0c 先设置一个静态IP 一来可以防范DHCP自动分配的ip来回变动 xff0c 导致远程SSH时常无法连接 xff1b 二来还可以提高树莓派的网络连接速率 1 一般先使用HDMI连接树莓派 xff0c 若没有额外
  • ESP32 FreeRTOS-流缓冲区(12)

    提示 xff1a 好记性不如烂笔头 本博客作为学习笔记 xff0c 有错误的地方希望指正 文章目录 前言 xff1a 一 xStreamBufferCreate xStreamBufferCreateWithCallback 二 xStre
  • windows10下安装docker,并运行ubuntu

    先上三个参考链接 xff1a 安装参考链接docker安装 xff1b docker镜像仓库 xff1a docker hub xff1b docker官方windows安装参考文档 xff1a install docker desktop
  • windows10下使用docker开启Ubuntu桌面

    先安装docker xff1a https blog csdn net Mr FengT article details 107007999 然后随便在仓库中选择一个带有桌面的Ubuntu 比如我下载的 xff1a docker pull
  • Linux下的tar压缩解压缩命令详解

    tar c 建立压缩档案 x xff1a 解压 t xff1a 查看内容 r xff1a 向压缩归档文件末尾追加文件 u xff1a 更新原压缩包中的文件 这五个是独立的命令 xff0c 压缩解压都要用到其中一个 xff0c 可以和别的命令
  • Apex安装

    直接 xff1a pip install apex 最后发现会出错 xff0c 用不了 所以使用以下方法来安装 xff1a git clone https github com NVIDIA apex cd apex python setu
  • ROS 主从通信机制要点记录

    本文主机是PC xff0c 从机是树莓派4B 1 主从机器都处于同一局域网下 xff0c 即连接同一wifi 2 分别在主从机上终端输入 ifconfig 查看当前ip 3 分别打开主从机器的 etc hosts 文件 xff0c 使用su
  • 怎么制作自己的数据集

    我们在做深度学习时 xff0c 一般都是跑别人公开的数据集 xff0c 如果想要跑自己的数据集怎么办 xff1f 今天就记录一下我自己用的一种方法 1 假设待分类一共有n类 2 新建一个文件夹 xff0c 在该文件夹下新建n子个文件夹和n个
  • python 将列表中的字符串转为数字

    python 将列表中的字符串转为数字 转自 xff1a https www jb51 net article 86561 htm 本文实例讲述了Python中列表元素转为数字的方法 分享给大家供大家参考 xff0c 具体如下 xff1a
  • AI编程软件会取代程序员吗?

    最近听到同事问了这样一个问题 xff0c 今天就来好好的唠一唠 xff0c 随着科学技术的发展 xff0c 现在生命上都已经开始出现AI编程软件了 不由得感叹 xff0c 一句现在时代发展还真快呀 xff01 然后我就和他一样产生了一种小小

随机推荐

  • python的requests快速上手、高级用法和身份认证

    https www cnblogs com linkenpark p 10221362 html 快速上手 迫不及待了吗 xff1f 本页内容为如何入门 Requests 提供了很好的指引 其假设你已经安装了 Requests 如果还没有
  • MongoDB

    MongoDB简介 MongoDB是一个基于分布式文件存储的数据库 由C 43 43 语言编写 旨在为WEB应用提供可扩展的高性能数据存储 解决方案 MongoDB是一个介于关系数据库和非关系数据库之间的产品 xff0c 是非关系数据库当中
  • 路由器的连接——图解

    导读 现如今路由器的使用越来越普遍 xff0c 路由器有很多网线口 xff0c 你知道这些网线口该如何连接吗 xff1f 路由器后面都有哪些口 下图为一张最常用的路由器接口示意图 我们可以看到 xff0c 除了电源接口外 xff0c 路由器
  • 【PX4自动驾驶用户指南】距离传感器

    距离传感器 xff08 测距仪 xff09 距离传感器提供距离测量 xff0c 可用于地形跟踪 地形保持 如摄影时精确悬停 改进着陆行为 距离辅助 高度限制警告 碰撞预防等 本节列出了PX4支持的距离传感器 链接到更详细的文档 xff0c
  • 【MATLAB UAV Toolbox】使用指南(一)

    开始使用UAV Toolbox 设计 xff0c 仿真和部署无人机应用程序 UAV Toolbox给设计 仿真 测试和部署无人机应用程序提供了工具和参考应用 你能够设计自动飞行算法 无人机任务和飞行控制器 飞行日志分析仪应用程序可以让您交互
  • 【MATLAB UAV Toolbox】使用指南(二)

    可视化和回放MAVLink飞行日志 这个例子将展示如何将包含MAVLink包的遥测日志 xff08 TLOG xff09 加载进MATLAB 提取的详细信息用来绘图 然后再次仿真飞行 xff0c 这些消息通过MAVLink通信接口重新发布
  • ROS小乌龟程序在服务器通信的应用

    上次我们已经利用launch 文件和话题通信成功实现了小乌龟的位置与姿态的消息发布 xff0c 这次我们将利用服务通信来实现这一功能 我们将以spawn 产卵 xff0c 生成新的小乌龟 为例进行实践 首先是对相关信息的获取 xff1a r
  • STM32实验:串口接受和发送消息

    在STM32里 xff0c USART负责进行串口通信 STM32可以通过串口和其他设备进行传输并行数据 xff0c 是全双工 异步时钟控制 xff0c 设备之间进行的是点对点的数据传输 对应的STM32引脚分别是RX xff08 接收端
  • 关于传感器标定(imu标定,camera标定,camera-imu联合标定)

    博主最近在帮同门做实验 关于传感器这些标定也是初次接触 xff0c 使用orb slam3代码包 其中涉及一些传感器标定 xff0c 这里就把我用的东西汇总一下 目录 1 imu标定 1 1 使用imu utlies标定 1 1 1安装步骤
  • nuxt服务器渲染,获取数据赋值给组件 - nuxtServerInit

    前言 xff1a vue 43 nuxt js 项目中 xff0c 根据IP定位赋值 xff0c 头部可切换城市 xff0c header在layouts下调用 xff0c 首页根据定位接口返回一些数据 async asyncData ct
  • Docker基础篇

    视频链接 xff1a https www bilibili com video BV1og4y1q7M4 xff08 大名鼎鼎的B站狂神说 xff09 1 概述 官网 xff1a https docs docker com 1 1 容器较为
  • Docker进阶篇

    视频链接 xff1a https www bilibili com video BV1og4y1q7M4 xff08 大名鼎鼎的B站狂神说 xff09 1 Docker镜像详解 1 1 UnionFS xff08 联合文件系统 xff09
  • sw模型转urdf,并在gazebo和rviz中显示

    sw模型转urdf xff0c 并在gazebo和rviz中显示 1 sw模型转urdf1 1建立机器人的三维模型1 2机器人三维模型预处理1 3装配1 4建立坐标系 2 显示2 1 在gazebo中显示2 2 在rviz中显示 3 让模型
  • JSON对象/数组与JSON字符串之间的相互转换

    文章目录 前言JSON介绍如何判断JS数据类型JSON数组转化为JSON字符串JSON对象转化为JSON字符串JSON字符串转化为JSON数组 对象注意点 前言 这里先介绍一个个人觉得很好用的谷歌浏览器的功能 xff1a snippet 就
  • js分片上传&断点续传

    一 基本介绍 1 xff0c 什么是 WebUploader xff1f WebUploader 是由百度公司团队开发的一个以 HTML5 为主 xff0c FLASH 为辅的现代文件上传组件 官网地址 xff1a http fex bai
  • JavaScript超大文件上传解决方案:分片断点上传(一)

    前段时间做视频上传业务 xff0c 通过网页上传视频到服务器 视频大小 小则几十M xff0c 大则 1G 43 xff0c 以一般的HTTP请求发送数据的方式的话 xff0c 会遇到的问题 xff1a 1 xff0c 文件过大 xff0c
  • 基于JS的大文件分片

    项目需要上传超大文件 xff0c 后台为DJANGO xff0c 不能直接用H5 的FILE API来POST xff0c 所以采用slice分片 在分片后为BLOB不能直接传 xff0c bolb转file有些浏览器又有支持问题 所以做一
  • 【网络安全】如何在 Apache 安装开源 WAF

    说明 xff1a 本文以 Windows 环境下的 Apache 安装 mod security 为例 xff0c 介绍开源 WAF 产品的安装使用 http www modsecurity cn https github com Spid
  • 手把手教系列之梳状滤波器设计实现

    导读 前面一篇文章关于IIR 移动平均滤波器设计的文章 本文来聊一聊陷波滤波器 该滤波器在混入谐波干扰时非常有用 算法简单 实现代价低 本文来一探其在机理 应用场景 注 尽量在每篇文章写写摘要 方便阅读 信息时代 大家时间都很宝贵 如此亦可
  • 看思维导图:一文带你学Verilog HDL语言

    关注 星标嵌入式客栈 xff0c 精彩及时送达 导读 基于FPGA的SOC在嵌入式系统应用越来越广了 xff0c 往往一个复杂系统使用一个单芯片基于FPGA的SOC就搞定了 比较流行的方案主要有Altera xilinx两家的方案 要用这样