FPGA第 9 篇,Verilog 中的关键字和基数

news/2024/9/17 3:06:15/ 标签: fpga开发

前言

在 Verilog 中,关键字(Keywords)和基数(Radix)是语言的重要组成部分,它们有助于描述和定义硬件设计。上期分享了 Verilog 的基本使用,以及数据类型、逻辑值和算数运算符的简单应用,具体,请看,

Verilog中的数据类型、逻辑值以及算术运算符icon-default.png?t=O83Ahttps://blog.csdn.net/weixin_65793170/article/details/141629702?spm=1001.2014.3001.5501

掌握这些技能基础,我们可以高效地设计和验证 FPGA 电路,从而实现所需的数字系统功能。这里我们继续分享关于 Verilog 的关键字和基数的应用,记录一下


一. Verilog 关键字

        关键字:在 Verilog 中,关键字是 Verilog 语言的特殊词汇,它们用于定义硬件描述和控制程序的结构。关键字在 Verilog 中具有特定的语法和语义,帮助描述硬件的行为和结构,不能用作标识符(如变量名、信号名等)。

1. 模块定义与实例化

(1)模块的开始和结束 

module:模块开始

endmodule:模块结束

代码示例:

module simple_example (    // 模块开始,模块名称为simple_example // 端口列表// ......);    // 模块内部的内容endmodule    // 结束模块定义

这里使用 module 定义了一个名为 simple_example模块,包含端口列表和模块内部逻辑,使用endmodule结束模块定义。

  • module:定义一个模块的开始(定义模块名),后面跟模块名称,一般与文件名相同。simple_example 开始了一个名为 simple_example 的模块定义,simple_example 是模块的名字。
  • endmodule:定义一个模块的结束,表示模块定义的结束。

(2)模块的输入和输出

input:输入信号

output:输出信号

inuot:输入和输出

代码示例:

module simple_example (input wire sys_clk,      // 输入时钟信号input wire sys_rst_n,    // 输入复位信号(低电平有效) inout wire sda,          // 双向数据线output wire po_flag      // 输出标志信号
);
endmodule代码解析:
sys_clk (input wire):
这是一个输入端口,类型为 wire。
sys_clk 通常代表系统时钟信号,用于同步电路的操作。
时钟信号通常是一个周期性的方波信号。sys_rst_n (input wire):
这也是一个输入端口,类型为 wire。
sys_rst_n 代表系统复位信号,带下划线 _n 表明这是一个“非”信号,即低电平有效(active low)。
当 sys_rst_n 为低电平时,表示复位有效;高电平时,系统正常工作。sda (inout wire):
这是一个双向端口,类型为 wire。
sda 通常用于串行数据传输,例如在I²C(Inter-Integrated Circuit)总线中作为数据线使用。
双向端口意味着这个信号线既可以被模块用作输入也可以用作输出。po_flag (output wire):
这是一个输出端口,类型为 wire。
po_flag 代表一个输出标志信号,可能是模块内部某些条件满足后产生的标志。

这个模块包含两个输入端口(时钟和复位)、一个双向端口(数据线)和一个输出端口(标志信号)。这种端口定义方式是Verilog中常见的描述电路的方式。

  • inputinput 关键字用于声明一个端口为输入端口,用于接收来自外部模块或其他实例的数据。输入端口可以是 wirereg 或其他类型的变量。
  • inoutinout 关键字用于声明一个端口为双向端口,双向端口既可以用作输入端口,也可以用作输出端口。它们通常用于需要双向通信的场合,例如 I²C 总线中的 SDA 信号线。双向端口通常是 wire 类型。
  • outputoutput 关键字用于声明一个端口为输出端口,输出端口用于将模块内部的数据发送给外部模块或其他实例。输出端口通常是 wire 类型,但也可以是 reg 类型。只有输入信号是不能生成输出信号的,所以要用到一些变量和参数,对输入信号进行处理。

2. 数据类型与信号

wire:线网型变量

reg:寄存器变量

parameter:全局常量

localparam:局部常量

代码示例:

module simple_example();parameter WIDTH = 4;  // 定义参数 WIDTHlocalparam MAX_VALUE = 15;  // 定义本地参数 MAX_VALUEreg [WIDTH-1:0] count;  // 定义寄存器 countwire [WIDTH-1:0] out;  // 定义线网 outassign out = count;  // 将寄存器的值连接到线网endmodule代码解析:
parameter WIDTH = 4;
定义位宽为 4 的参数 WIDTH。在顶层文件,通过实例化,可以对参数进行修改。localparam MAX_VALUE = 15;
定义一个不可更改的本地参数 MAX_VALUE,其值为 15,只能在模块内部使用。reg [WIDTH-1:0] count;
定义一个位宽为 WIDTH(4位)的寄存器 count,用于存储值。wire [WIDTH-1:0] out;
定义一个与寄存器 count 同样位宽的线网 out。assign out = count;
定义一个持续赋值的逻辑,它将右侧表达式的值赋给左侧的网线(wire)或信号。
这种赋值是连续的,并且会在任何相关信号变化时自动更新。
这里使用 assign 将寄存器 count 的值赋给线网 out。

这个模块定义了一些参数和变量,并建立了一个简单的连接。这种模块结构可以作为更复杂电路的基础,通过实例化和连接多个这样的模块来构建更大的电路系统。当然这段代码并不涉及任何行为逻辑。

  • wire:一种用于模拟硬件中的连线的数据类型,用于表示组合逻辑中的连线或信号。
  • reg:一种用于存储状态的数据类型,通常用于描述触发器(存储元件)的行为,用于表示时序逻辑中的寄存器。
  • parameter:parameter 用于定义全局常量,这些常量在整个模块中都是可见的,并且可以在模块实例化时通过实例化语句传递不同的值。
  • localparam:localparam 用于定义局部常量,这些常量仅在定义它的模块内部可见。

其中 simple_example 这是模块的名称,没有输入或输出端口时,括号可以省略,可以写成以下

这样,请看

module simple_example;parameter WIDTH = 4;  // 定义参数 WIDTHlocalparam MAX_VALUE = 15;  // 定义本地参数 MAX_VALUEreg [WIDTH-1:0] count;  // 定义寄存器 countwire [WIDTH-1:0] out;  // 定义线网 outassign out = count;  // 将寄存器的值连接到线网endmodule

注意这里的 simple_example 后没带括号,直接可以省略。


3. 赋值与操作

assign:持续赋值

initial:初始化信号

always:始终块(用于逻辑)

代码示例:

module simple_example();reg [7:0] data;     // 定义8位寄存器wire [7:0] result;  // 定义8位线网// 持续赋值,将寄存器值赋给线网assign result = data;// 初始化块,仿真开始时设置寄存器的初值initial begindata = 8'hFF;  // 将寄存器 data 初始化为 255 (十六进制 FF)end// 始终块,根据时钟上升沿修改寄存器的值always @(posedge clk) begindata <= data + 1;  // 每个时钟周期递增寄存器的值endendmodule代码解析:
module simple_example;
这一行定义了一个新的Verilog模块simple_example。reg [7:0] data;     // 定义8位寄存器wire [7:0] result;  // 定义8位线网
这两行定义了两个变量,一个是8位宽的寄存器data,另一个是8位宽的线网result。
寄存器用来存储数据,而线网则用于传递数据。assign result = data;
这行是一个连续赋值语句(continuous assignment),它把寄存器data的值赋给了线网result。
这意味着任何时候data的值发生变化,result也会立即反映出这个变化。initial begindata = 8'hFF;  // 将寄存器 data 初始化为 255 (十六进制 FF)end
这是一个初始化块(initial block)。当模块被加载到仿真环境中时,这段代码会被执行一次。
在这里,data被初始化为255(十六进制FF)。always @(posedge clk) begindata <= data + 1;  // 每个时钟周期递增寄存器的值end
这部分是一个敏感于时钟信号上升沿的always块。
每当检测到clk信号的上升沿时,寄存器data的值就会增加1。
这里使用的是阻塞赋值(<=),这是因为在时序逻辑中,
我们关心的是在一个时钟周期内完成赋值,而不是立即完成。endmodule
这一行标志着模块simple_example的结束。

这段代码定义了一个简单的模块simple_example,它包含了一个8位的寄存器data和一个8位的线网result。这个模块的目的是演示如何在Verilog中定义寄存器和线网,并展示如何使用initialalways块来初始化和更新寄存器的值。

  • assign: 用于持续赋值,将一个表达式的值分配给一个 wire 类型的信号,常用于组合逻辑。

  • initial: 定义初始块,在仿真开始时执行一次,用于初始化信号的值。

  • always: 定义始终块,用于描述时序逻辑或组合逻辑,根据触发条件执行块中的代码。


4. 以上关键字整合

module:模块开始

endmodule:模块结束

input:输入信号

output:输出信号

inuot:输入和输出

wire:线网型变量

reg:寄存器变量

parameter:全局常量

localparam:局部常量

assign: 持续赋值

initial: 初始化信号

always: 始终块(用于逻辑)

等等


5. 关键字与数据类型

  1. Verilog HDL 中的关键字和数据类型不是同一个概念,并且它们之间存在一定的差异,尽管有时会有重叠的地方。
  2. 有一些标识符既是关键字也是数据类型,比如 wirereg。在有些情况下,它们作为关键字时用于声明信号或变量,并且它们本身也指示了一种特定的数据类型。然而,像 if, else, case, begin, end 这样的关键字则不是数据类型。
  3. 关键字和数据类型虽然有交集,但它们并不是同一个概念。关键字主要用于定义Verilog程序的语法结构,而数据类型则是用于定义变量的属性。在编写Verilog代码时,正确区分和使用这两者是非常重要的。


二. Verilog 基数

1. 基数介绍

        基数:在 Verilog 中,基数用于表示数值的进制方式,有助于更清晰地表达数字的意义。常见的基数包括二进制、八进制、十进制和十六进制,它们在代码中的表示语法各不相同。这种灵活性使得我们能够直观且方便地表达数值,从而提高代码的可读性和可维护性。


2. 基数分类

(1)二进制表示符 (b)

作用:用于表示二进制数。
语法:<位宽>'b<二进制数>
例如:8'b10101010
解释:这里,8 表示位宽为 8 位,b 表示这是二进制数,10101010 是二进制值。

(2)八进制表示符 (o)

作用:用于表示八进制数。
语法:<位宽>'o<八进制数>
例如:8'o52

解释:这里,8 表示位宽为 8 位,o 表示这是八进制数,52 是八进制数值。

(3)十进制表示符 (d)

作用:用于表示十进制数。
语法:<位宽>'d<十进制数>
例如:8'd85

解释:这里,8 表示位宽为 8 位,d 表示这是十进制数,85 是十进制值。

(4)十六进制表示符 (h)

作用:用于表示十六进制数。
语法:<位宽>'h<十六进制数>
例如:8'hAA

解释:这里,8 表示位宽为 8 位,h 表示这是十六进制数,AA 是十六进制值(即二进制为 10101010)。

(5)基数小结

  • b: 二进制
  • o: 八进制
  • d: 十进制
  • h: 十六进制

3. 基数使用

(1)示例代码

module simple_example;reg [7:0] binary_value;  // 二进制值reg [7:0] octal_value;   // 八进制值reg [7:0] decimal_value; // 十进制值reg [7:0] hex_value;     // 十六进制值initial beginbinary_value  = 8'b10101010;  // 二进制表示,8'b 表示 8 位二进制octal_value   = 8'o52;        // 八进制表示,8'o 表示 8 位八进制decimal_value = 8'd85;        // 十进制表示,8'd 表示 8 位十进制hex_value     = 8'hAA;        // 十六进制表示,8'h 表示 8 位十六进制endendmodule

这段代码定义了一个名为 simple_example 的模块,其中包含了四个8位宽的寄存器,分别用于存储二进制、八进制、十进制和十六进制的值。模块中还包含了一个初始化块,用于设置这些寄存器的初始值。

(2)详细解析

module simple_example;
同样定义了一个新的Verilog模块 simple_example。reg [7:0] binary_value;  // 二进制值reg [7:0] octal_value;   // 八进制值reg [7:0] decimal_value; // 十进制值reg [7:0] hex_value;     // 十六进制值
这四行定义了四个8位宽的寄存器:
binary_value 用于存储一个8位的二进制值。
octal_value 用于存储一个8位的八进制值。
decimal_value 用于存储一个8位的十进制值。
hex_value 用于存储一个8位的十六进制值。
尽管这些名称暗示了它们存储的数值类型,但实际上它们都是8位的二进制数。
不同的表示方式只是在初始化时使用的数值前缀不同。initial beginbinary_value  = 8'b10101010;  // 二进制表示,8'b 表示 8 位二进制octal_value   = 8'o52;        // 八进制表示,8'o 表示 8 位八进制decimal_value = 8'd85;        // 十进制表示,8'd 表示 8 位十进制hex_value     = 8'hAA;        // 十六进制表示,8'h 表示 8 位十六进制end
这是一个初始化块(initial),它会在模块加载到仿真环境中时执行一次。
在这段代码中,设置了四个寄存器的初始值:
binary_value 被初始化为 8'b10101010,即二进制表示的 10101010,对应的十进制值为 170。
octal_value 被初始化为 8'o52,即八进制表示的 52,对应的十进制值为 42。
decimal_value 被初始化为 8'd85,即十进制表示的 85,对应的十进制值为 85。
hex_value 被初始化为 8'hAA,即十六进制表示的 AA,对应的十进制值为 170。
这些不同的表示方式只是在初始化时使用的数值前缀不同,
最终存储在寄存器中的仍然是8位的二进制数。endmodule
同样这一行标志着模块 simple_example 的结束。

创作不易,感觉有用,就一键三连,感谢(●'◡'●)


http://www.ppmy.cn/news/1523337.html

相关文章

Obsidian git sync error / Obsidian git 同步失敗

Issue: commit due to empty commit message Solution 添加commit資訊&#xff0c;確保不留空白 我的設置&#xff1a;auto-backup: {{hostname}}/{{date}}/

AWS EC2安全组配置:轻松开放端口访问

在AWS EC2实例上开放特定端口是配置服务器安全性和可访问性的重要步骤。本文中九河云将介绍如何通过AWS控制台配置EC2安全组来实现端口开放。 1. 登录AWS控制台 首先,登录到AWS管理控制台,并导航到EC2服务页面。 2. 找到目标EC2实例 在EC2控制面板中,找到需要开放端口的实例…

投放Facebook广告开户全流程解析:从开户到广告投放的实用指南

Facebook作为全球最大的社交平台之一&#xff0c;广告业务覆盖范围广泛&#xff0c;已成为各类企业推广产品和服务的重要渠道。要在Facebook上成功投放广告&#xff0c;首先需要完成广告账户的开户流程。本文将详细介绍投放Facebook广告开户的步骤和条件&#xff0c;并解释如何…

随身 WiFi 大探秘:芯片竟有二手货?快来避雷!随身wifi芯片哪个好?随身wifi芯片排行榜!

你的随身wifi芯片可能是二手的...是的&#xff0c;你没听错&#xff01; 随身wifi的好坏主要取决于芯片&#xff0c;他决定了网速&#xff0c;散热性等关键性能。目前市场上常见的随身 WiFi 芯片有多种&#xff0c;我们该如何挑选高性能芯片&#xff0c;避免买到二手芯片设备呢…

python之异步任务

在 Python 中&#xff0c;异步任务通常通过使用库如 Celery 来实现。Celery 是一个简单、灵活且可靠的分布式系统&#xff0c;用于处理大量消息&#xff0c;同时提供操作控制。 在 Celery 中&#xff0c;delay 和 apply_async 是两种常用的方法来调度异步任务。 delay 方法 …

Harmony arkTs组件开发:ListItem控件中不能使用多个组件

如下代码&#xff1a; List(){ForEach(this.indexList, (item: number) >{ListItem(){Text("测试")Row(){Image(this.images[item]).width(20).height(20).margin({left:15})Text(this.arr[item])//.width(80%).fontSize(sizes.oneFontSize).fontColor(colors.Tit…

Web 原生组件化方案:Web Components

你好&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏、评论和关注。 Web 组件化是一种将Web应用的UI部分拆分成可复用的独立组件的架构方法。这种方法有助于提高代码的可维护性、可重用性和可测试性。 而Web Components 标准则提供了一套原生的API&#xff0c;允许开发者创建…

【阿雄不会写代码】全国职业院校技能大赛GZ036第十套

也不说那么多了&#xff0c;要用到这篇博客&#xff0c;肯定也知道他是干嘛的&#xff0c;给博主点点关注点点赞&#xff01;&#xff01;&#xff01;这样博主才能更新更多免费的教程&#xff0c;不然就直接丢付费专栏里了&#xff0c;需要相关文件请私聊

Java进阶13讲__第12讲_2/2

线程安全问题 线程同步方案 线程池 线程通信 理论补充 1. 线程安全问题 1.1 举例说明 1.2 代码实现 package com.itheima.a_线程安全;/* 线程安全:多个线程同时修改同一个资源取钱案例小明和小红是一对夫妻&#xff0c;他们有一个共同的账户&#xff0c;余额是10万元如…

《React Native 应用开发最佳实践》

⭐️React Native 应用开发最佳实践⭐️ 近年来&#xff0c;React Native 应用开发因其能够使用 JavaScript 构建原生移动应用的能力而大受欢迎。它提供了跨平台兼容性、更快的开发时间以及更易于维护的特性&#xff0c;成为了许多开发者的首选。然而&#xff0c;要确保 React…

免费的 Mac 应用清理工具Pearcleaner v3.8.6

免费的 Mac 应用清理工具。这是一款免费开源的 Mac 应用清理工具&#xff0c;能够彻底卸载应用并清理残留文件。它采用 SwiftUI 开发&#xff0c;提供了简单易用的界面&#xff0c;支持右键卸载、迷你模式和 Homebrew 清理等功能。 下载链接&#xff1a;https://pan.quark.cn/s…

计算机网络(三) —— 简单Udp网络程序

目录 一&#xff0c;初始化服务器 1.0 辅助文件 1.1 socket函数 1.2 填充sockaddr结构体 1.3 bind绑定函数 1.4 字符串IP和整数IP的转换 二&#xff0c;运行服务器 2.1 接收 2.2 处理 2.3 返回 三&#xff0c;客户端实现 3.1 UdpClient.cc 实现 3.2 Main.cc 实现 …

前端面试热点题目——typescript篇

在TypeScript面试中&#xff0c;面试官通常会考察你对TypeScript特性的理解、类型系统的掌握、以及在实际项目中的应用能力。以下是一些热点题目及其相应的代码示例&#xff0c;旨在帮助你准备TypeScript相关的面试。 1. 类型别名与接口的区别及使用场景 问题&#xff1a;请解…

react js 笔记 3

起因&#xff0c; 目的: 专注。 学习 react js 的时候&#xff0c; 就专注这一方面 &#xff0c;其他都不要碰。 比如&#xff0c; python, C语言&#xff0c; R, 都不看。 只看 js.专注&#xff0c;减少来回切换。 重复。 自己写的笔记&#xff0c;需要反复多看几遍&#xff…

java开发后端

1.BeanUtils.toBean 方法 它是一个常见的 Java 工具方法&#xff0c;用于将一个 JavaBean 对象转换为另一个 JavaBean 对象 FlowOrderDO flowOrder BeanUtils.toBean(createReqVO, FlowOrderDO.class); 这行代码使用了 BeanUtils.toBean 方法&#xff0c;它是一个常见的 Ja…

MySQL笔记2(DQL查询语言【条件、分组、排序、限制、子查询、左右连接、内连接、联合查询】)

DQL数据查询语言与项目高级查询实战 先安装数据库并创建一个库 并创建以下数据 /*创建部门表*/CREATE TABLE dept( deptnu INT PRIMARY KEY comment 部门编号, dname VARCHAR(50) comment 部门名称, addr VARCHAR(50) comment 部门地址 );/*某个公司的员工表*/ CREATE TABLE…

html备忘录

备忘录 网站收藏数据&#xff1a; 网站收藏.js const webLinks [{ title: "智能翻译", src: "https://fanyi.baidu.com" },{ title: "哔哩哔哩", src: "https://www.bilibili.com" },{ title: "百度一下&#xff0c;你就知道&…

漫谈设计模式 [9]:外观模式

引导性开场 菜鸟&#xff1a;老鸟&#xff0c;我最近在做一个项目&#xff0c;感觉代码越来越复杂&#xff0c;我都快看不懂了。尤其是有好几个子系统&#xff0c;它们之间的调用关系让我头疼。 老鸟&#xff1a;复杂的代码确实让人头疼。你有没有考虑过使用设计模式来简化你…

微信支付开发避坑指南

1 微信支付的坑 1.1 不能用前端传递过来的金额 订单的商品金额要从数据库获取&#xff0c;前端只传商品 id。 1.2 交易类型trade type字段不要传错 v2版API&#xff0c;不同交易类型&#xff0c;要调用的支付方式也不同。 1.3 二次签名 下单时&#xff0c;在拿到预支付交…

记录深度学习量化操作

0. 简介 深度学习中做量化提升运行速度是最常用的方法&#xff0c;尤其是大模型这类非常吃GPU显存的方法。一般是高精度浮点数表示的网络权值以及激活值用低精度&#xff08;例如8比特定点&#xff09;来近似表示达到模型轻量化&#xff0c;加速深度学习模型推理&#xff0c;目…