如何编写一个基本的 Verilog Module(模块)
1、概述
这篇文章主要介绍了 Verilog 在 FPGA 设计中的概念和使用方法。首先讨论使用模块(module)关键字构造 Verilog 设计的方式,以及这与所描述的硬件的关系。这包括对参数、端口(port)和例化(instantiaton)的讨论及一个完整示例。
虽然不需要为了使用它而讨论Verilog的整个发展历史,但是却必须考虑另一个重点——所使用的Verilog语言版本。Verilog 的主要标准发布于1995年(Verilog-1995)和2001年(Verilog-2001)。除此之外,2005年(Verilog-2005)还发布了另一个小更新。
原则上,我们应该为创建的任何新 FPGA 设计使用 Verilog-2001 或 Verilog-2005 标准。然而,我们可能仍然会遇到基于 Verilog-1995 标准的遗留设计。因此,我们将在这些文章中看到 Verilog-1995 标准和 Verilog-2001 年标准之间的重要区别。
2、构建 Verilog 代码
当我们设计 FPGA 时,需要记住一个基本的原则——我们是在设计硬件,而不是在编写软件程序。因此,我们必须描述许多不同电子组件(electronic component)的行为,然后将它们连接在一起。这反映在 Verilog 文件的结构方式中。
对于每个电子组件,我们需要知道组件的外部接口。此信息使我们能够将其连接到我们系统中的其他组件。我们还需要知道组件的行为方式,以便我们可以在我们的系统中使用它。
在 Verilog 中,我们使用称为模块(module)的构造来定义此信息。Verilog中的module相当于VHDL中的 entity architecture pair。
下面的代码片段显示了在 Verilog 中声明模块的一般语法。
module ( //module开始//定义参数parameter <parameter_name> = <default_value>
)
<module_name> (//IO定义<direction> <data_type> <size> <port_name>
);//完整的RTL代码endmodule //module结束
在此构造中,<module_name> 是正在设计的模块的名称。虽然我们可以在一个文件中声明多个模块,但最好让一个文件对应一个模块(好的开发习惯)。保持文件名和模块名相同也是一种很好的做法。这会让管理包含许多层级的大型设计变得更加简单。
在 Verilog 中,我们使用 // 字符来表示我们正在编写注释。我们使用注释来包含有关我们代码的重要信息,这些信息可能会帮助到其他人理解代码。Verilog 编译器会忽略我们在注释中写的任何内容。
在上面的 Verilog 代码片段中,我们可以看到这一点,因为这些注释仅用于描述代码的功能。
2.1、Verilog-1995 模块(Modules)
Verilog 模块声明语法作为 verilog-2001 标准的一部分进行了更新。这意味着用于在 Verilog 中声明模块的方法会略有不同。
使用 Verilog-1995 代码时,我们仅在初始模块声明中定义端口名称。然后我们在模块主体中定义每个端口的方向、数据类型和大小。除此之外,我们还在模块中定义了模块参数。
下面的代码片段显示了如何使用 Verilog-1995语法来声明模块。
module <module_name> (// All IO names are defined here<port_name>
);//在这里声明参数,可选项parameter <parameter_name> = <default_value>;//IO定义<direction> <data_type> <size> <port_name>;//完整的RTL代码endmodule
2.2、Verilog 模块中的参数(Parameters)
参数(parameter)是常量(constant)的局部形式,我们可以使用它来配置 Verilog 中的模块。当我们在设计的另一部分实例化我们的模块时,可以为参数分配一个值来配置模块的行为。
由于参数的作用域有限,所以我们可以多次调用同一个模块,每次都为参数赋不同的值。因此,参数允许我们随时修改模块的行为。
参数是 Verilog 模块声明的可选部分,在大多数情况下我们并不需要使用它们。然而,参数允许我们编写更通用的模块接口,这些接口更容易在其他 Verilog 设计中被复用。
在模块中声明了一个参数之后,我们就可以像使用普通变量一样使用它。但是,必须记住--参数是一个常量值,所以只能读取它。因此,我们只能在参数声明时为其赋值。
2.3、功能代码
我们使用模块 IO 声明下方的空间来定义模块的功能。我们最常为此使用RTL(Register Transfer Level),但也可以编写结构代码或描述性原语。
我们使用关键字 module 开始一个模块的设计,从关键字 module 到关键字 endmodule 内的所有内容构成了一个完整的模块。
当我们完成描述模块行为的代码时,使用 endmodule 关键字来作为结束。在此关键字之后编写的任何代码都不会包含该模块中。
2.4、Verilog 模块端口(Ports)
我们在模块声明中使用端口来定义 Verilog 模块的输入和输出。可以近似地认为这些端口相当于传统电子元件中的管脚。
下面的代码片段显示了我们用来声明端口的一般语法。
<direction> <data_type> <size> <port_name>
<direction> :我们可以在 Verilog 模块中将端口定义为in(输入)、out(输出)或 inout(双向端口)。上述构造中的可用于执行此操作。
<port_name> :字段用于为端口指定一个唯一的名称。
<data_type> :声明端口的数据类型,最常见的类型是reg 和 wire 。
<size> :用来表述端口多位向量的位数。当我们定义向量类型输入的大小时,我们必须指出向量中的最高有效位(most significant bit,MSB)和最低有效位(least significant bit,LSB)。因此,我们在声明端口大小时使用 [MSB:LSB]。
下面的示例显示了名为 example_in 的 8 位输入的声明。
input wire [7:0] example_in;
在此示例中,[7:0] 表示第 7 位是最高有效位。这称为小字节序或低字节序(little endian),是 FPGA 设计中最常用的表示方法。
如果我们将声明改为 [0:7],也可以将 MSB 定义为位置 0。这种称为大字节序或高字节序(big endian)的表示方法在设计 FPGA 时不像小字节序那样常用。
2.5、Verilog 中的 Reg 和 Wire 类型
Verilog中的数据类型有很多,但是最常用的只有两种--reg 和 wire。
wire 类型被用来来声明信号,这些信号在我们的 Verilog 代码中是简单的点对点连接(电线)。因此,电线不能驱动数据,也不能存储数值。顾名思义,它们大致相当于传统电路中的一根导线。
reg 类型被用来声明一个信号,该信号在我们的 Verilog 代码中主动驱动数据。顾名思义,它们大致相当于传统数字电路中的触发器(flip flop)。
由于wire类型是基本的点对点连接,所以我们可以在声明 Verilog 模块时将wire用作in或者out类型。相反,reg 类型只能用于 Verilog 模块中的输出。
wire类型主要被用来构建组合逻辑电路,当我们使用 assign 关键字在 Verilog 中对组合逻辑建模时,我们只能将其与wire类型一起使用。
reg 类型主要被用来构建时序逻辑电路,我们必须使用always块(always block)来为时序逻辑电路建模。我们只能在 always 块中使用 reg 类型。
在声明模块端口时,其默认数据类型是wire。因此,当我们使用wire端口时,可以省略掉wire这个关键字,但是reg关键字则不能被省略。
3、Verilog 模块例化(Instantiation)
我们可以调用已经在设计的另一部分编写的 Verilog 模块。在 Verilog 中调用模块的过程称为实例化(实例化,instantiation)。
每次例化一个模块时,都会创建一个唯一的对象(Object),它有自己的名称、参数和端口。
在 Verilog 设计中,我们将每个例化模块称为模块的实例(instance)。我们使用例化来创建许多不同的实例,并用它们来构建更复杂的设计。
我们可以认为Verilog中的模块例化相当于在传统电子电路中放置了一个电子元件。一旦我们创建了设计中需要的所有实例,就必须将它们互连以创建一个完整的系统。这与在传统电子系统中将组件接线在一起完全相同。
Verilog 为我们提供了两种可用于模块实例化的方法——命名例化(named instatiation)和位置例化(positional instatiation)。
Verilog-2001 标准编支持以上两种例化方式,而Verilog-1995标准只支持位置例化方法。
3.1、位置例化方法
在 Verilog 中使用位置例化方法时,需要使用有序列表来连接模块端口。被例化的模块实例的端口顺序必须与我们模块中声明端口的顺序一样。
例如,如果我们依次声明时钟clock,复位rst,那么我们在例化时就必须先将时钟信号连接到模块端口。
下面的 Verilog 代码片段显示了位置模块例化方法的一般语法。
<module_name> # (//例化的参数列表<parameter_value>
)
<instance_name> (//例化的端口,需要按照被例化模块的顺序排列出来<signal_name>, //第一个端口<signal_name> //第二个端口
);
<module_name> :必须与在声明模块时给它的名称相匹配。
<instance_name>:设计中的例化模块的唯一名称。
这种方法可能难以维护,因为我们的端口顺序可能会随着我们设计的发展而改变。
下面看一个简单的例子来展示如何使用位置例化方法。对于这个例子,我们将创建一个如下所示的简单电路的实例。

当我们使用位置例化方法时,模块声明中端口的顺序很重要。下面的代码片段显示了如何为这个电路声明一个模块。
and_or (input a,input b,input c,output logic_out
);
下面的 Verilog 代码片段显示了如何使用位置例化方法来创建此模块的实例。
and_or example_and_or (in_a,in_b,in_c,and_or_out
);
3.2、命名例化方法
在 Verilog 中使用命名例化方法时,我们需要明确定义将信号连接到的端口的名称。与位置例化方法不同的是--声明端口的顺序并不重要。
这种方法通常优于位置例化方法,因为它生成的代码更易于阅读和理解。它也更容易维护,因为我们可以修改端口而不必担心我们声明它们的顺序。
下面的 Verilog 代码片段显示了命名模块实例化的一般语法。
<module_name> # (//被例化的参数与例化的参数.<parameter_name> (<parameter_value>)
)
<instance_name> (//被例化的端口与例化的端口.<port_name> (<signal_name>),.<port_name> (signal_name>)
);
<module_name>、<parameter_name> 和 <port_name> 必须与在定义模块时使用的名称相匹配。
<instance_name> 对位置例化和命名例化具有相同的功能。
使用上一节用到的电路作为简单案例来展示如何使用命名例化方法。

下面的 Verilog 代码片段显示了我们如何使用命名例化创建此模块的实例。
and_or example_and_or (.a (in_a),.b (in_b),.c (in_c),.logic_out (and_or_out)
);
4、完整的Verilog module示例
为了完全理解我们在这篇文章中讨论的所有概念,让我们看一个基本示例。
在这个例子中,我们将创建一个使用参数的同步计数器电路,然后实例化它的两个实例。
这些实例之一将在输出中具有 12 位,而另一个将只有 8 位。
我们将在这里排除这些模块的 RTL,因为我们还没有学会如何编写它。相反,我们将简单地定义模块的 IO 以及它们之间的互连。
计数器模块将有两个输入——时钟和复位——和一个输出——计数器值。
除此之外,我们还需要一个参数来定义输出中的位数。
下面的代码片段显示了使用 verilog 2001 和 verilog 1995 兼容代码的计数器模块的声明。
// Verilog-2001
module counter #(parameter WIDTH = 8
)
(input clock,input reset,output reg [WIDTH-1:0] count
);// Verilog-1995
module counter (clock,reset,count
);paramater WIDTH = 8;input clock;
input reset;
output reg [WIDTH-1:0] count;endmodule
我们现在需要一个模块--用它来例化这个计数器的两个实例。该模块将有两个输入--时钟和复位以及两个来自例化计数器的输出。
在计数器模块中,我们定义了默认的计数器输出为 8 位。这意味着我们可以在不改变参数值的情况下实例化 8 位计数器。但是,当例化 12 位计数器时,则必须将 WIDTH 参数的值设置为 12。
下面的代码片段显示了使用命名例化方法连接到端口时此模块的代码。
module top_level (input clock,input reset,output reg [7:0] count_8,output reg [11:0] count_12
);//例化一个8bit的计数器
counter 8bit_count (.clock (clock),.reset (reset),.count (count_8)
);//例化一个12bit的计数器
counter #(.WIDTH (12)) 12_bit_count (.clock (clock),.reset (reset),.count (count_12)
);endmodule
📣您有任何问题,都可以在评论区和我交流📃!
📣本文由 孤独的单刀 原创,首发于CSDN平台🐵,博客主页:wuzhikai.blog.csdn.net
📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐!
相关文章:

如何编写一个基本的 Verilog Module(模块)
1、概述这篇文章主要介绍了 Verilog 在 FPGA 设计中的概念和使用方法。首先讨论使用模块(module)关键字构造 Verilog 设计的方式,以及这与所描述的硬件的关系。这包括对参数、端口(port)和例化(instantiato…...

让乔布斯想要「发动核战争」的 Android,为何成了占有率最高的系统?
2008 年 9 月 23 日,Apple 的创始人和 CEO 史蒂夫乔布斯像往常一样走进了公司,此时距离初代 iPhone 的发布会才过了一年半,这款充满了争议的产品就像一块从山崖滚落的巨岩,一路电光石火的给手机市场的《小石潭记》来了场焚书坑儒。…...

FPGA开发软件(vivado + modelsim)环境搭建(附详细安装步骤+软件下载)
本文详细介绍了vivado软件和modelsim软件的安装,以及vivado中配置modelsim仿真设置,每一步都加文字说明和图片。一、软件安装包下载1、vivado vivado版本很多,目前最新的已更新到vivado2022.2,版本越高,安装包越大&…...
TypeScript 学习之类型
布尔类型 类型: boolean最简单的类型,值只有 true/false let isDone: boolean true;数字类型 类型:number数字都是浮点数,支持二进制、八进制、十进制、十六进制。 let decLiteral: number 16; // 十进制 let hexLiteral: number 0xf0…...

基于MATLAB计算MIMO信道容量(附完整代码与分析)
目录 一.介绍 二. 代码 三. 运行结果及分析 3.1 MIMO信道容量:固定发射天线数为4 3.2 MIMO信道容量:固定接收天线数为4 3.3 AWGN信道与瑞利信道容量 四. 总结 一.介绍 本文章将在MATLAB环境中分析MIMO信道容量,AWGN信道容量…...

CSDN城市开发者联盟、C友会期待你的加入
文章目录🌟 课前小差🌟 chatGPT🌟 CSDN中的持续学习🌟 23年原力计划🌟 C友会、CDC🌟 如何关联本地的开发者?🌟 写在最后🌟 课前小差 哈喽,大家好,…...
【新2023】华为OD机试 - 吃火锅(Python)
华为 OD 清单查看地址:blog.csdn.net/hihell/category_12199275.html 吃火锅 题目 入职后,导师会请你吃饭,你选择了火锅, 火锅里会在不同时间下很多菜, 不同食材要煮不同时间,才能变得刚好合适, 你希望吃到最多的刚好合适的菜, 但是你的手速不够快用m代替手速, 每次…...

类似LeetCode的登录页面(小程序版)
前言每一个项目都会有用户端的注册和登录页面,对于刚入门的小白来说,在UI设计方面不太擅长,就算大致的UI界面设计出来了,但是落实到代码上来实现的时候就很容易卡住。这篇博客主要介绍的就是仿作一个类似LeetCode登录的简约大方页…...

CUDA的统一内存
CUDA的统一内存 文章目录CUDA的统一内存N.1. Unified Memory IntroductionN.1.1. System RequirementsN.1.2. Simplifying GPU ProgrammingN.1.3. Data Migration and CoherencyN.1.4. GPU Memory OversubscriptionN.1.5. Multi-GPUN.1.6. System AllocatorN.1.7. Hardware Coh…...
MySQL-其他函数(补充)
格式化函数FORMAT(x, n) 例:将数字x进行格式化,以四舍五入的方式保留n位小数,结果以字符串的形式返回mysql> select format(12.3456,3),format(2.2,4),format(9.333,0); --------------------------------------------------- | format(12…...

MySQL Study Notes Design in 2023
文章目录1 概述1.1 MySQL相关概述1.2 数据模型1.3 SQL分类2 数据库设计-DDL2.1 约束2.2 字段3 数据库操作-DML3.1 增加(insert)1 概述 1.1 MySQL相关概述 数据库:英文为 DataBase,简称DB,它是存储和管理数据的仓库。 数据库管理系统…...

C++ 修改防火墙firewall设置(Windows)
文章目录1、简介1.1 防火墙概述1.2 入站,还是出站?1.3 防火墙规则优先级2、系统界面方式3、命令行方式3.1 防火墙基本状态设置3.2 入站出站规则设置3.3 其他设置3.4 telnet检测端口4、C方式4.1 注册表4.2 COM(Windows XP)4.3 COM&…...

Spring 入门教程详解
✅作者简介:2022年博客新星 第八。热爱国学的Java后端开发者,修心和技术同步精进。 🍎个人主页:Java Fans的博客 🍊个人信条:不迁怒,不贰过。小知识,大智慧。 💞当前专栏…...

day43【代码随想录】动态规划之一和零、完全背包理论基础
文章目录前言一、一和零(力扣474)二、完全背包前言 1、一和零 2、完全背包理论基础 一、一和零(力扣474) 求装满这个背包最多有多少个物品 给你一个二进制字符串数组 strs 和两个整数 m 和 n 。 请你找出并返回 strs 的最大子集…...

GEE学习笔记 七十八:干涸的洪泽湖
今天看了一篇报道直击60年一遇气象干旱:洪泽湖缩小近一半,鱼蟹受灾严重!_新华报业网(直击60年一遇气象干旱:洪泽湖缩小近一半,鱼蟹受灾严重!),既然玩GEE那就要玩出点花样…...

双指针【灵神基础精讲】
来源0x3f:https://space.bilibili.com/206214 文章目录同向双指针[209. 长度最小的子数组](https://leetcode.cn/problems/minimum-size-subarray-sum/)[713. 乘积小于 K 的子数组](https://leetcode.cn/problems/subarray-product-less-than-k/)[3. 无重复字符的最…...
tushare量化数据库模块怎么分析?
tushare量化数据其实包含的数据库有些是需要收费的,也有些会免费提供,不过tushare量化数据库整个库就很大很大,涉及的范围也广,挖掘这些数据还得从量化股票接口说起,就比如说在股票量化领域,tushare量化数据…...

模型转换 PyTorch转ONNX 入门
前言 本文主要介绍如何将PyTorch模型转换为ONNX模型,为后面的模型部署做准备。转换后的xxx.onnx模型,进行加载和测试。最后介绍使用Netron,可视化ONNX模型,看一下网络结构;查看使用了那些算子,以便开发部署…...

【深度学习】激活函数
上一章——认识神经网络 新课P54介绍了强人工智能概念,P55到P58解读了矩阵乘法在代码中的应用,P59,P60介绍了在Tensflow中实现神经网络的代码及细节,详细的内容可以自行观看2022吴恩达机器学习Deeplearning.ai课程,专…...
【新2023】华为OD机试 - 数字的排列(Python)
华为 OD 清单查看地址:blog.csdn.net/hihell/category_12199275.html 数字的排列 题目 小华是个很有对数字很敏感的小朋友, 他觉得数字的不同排列方式有特殊的美感。 某天,小华突发奇想,如果数字多行排列, 第一行1个数, 第二行2个, 第三行3个, 即第n行n个数字,并且…...

大数据学习栈记——Neo4j的安装与使用
本文介绍图数据库Neofj的安装与使用,操作系统:Ubuntu24.04,Neofj版本:2025.04.0。 Apt安装 Neofj可以进行官网安装:Neo4j Deployment Center - Graph Database & Analytics 我这里安装是添加软件源的方法 最新版…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序
一、开发准备 环境搭建: 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 项目创建: File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...