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

前言

在 Verilog 中,关键字(Keywords)和基数(Radix)是语言的重要组成部分,它们有助于描述和定义硬件设计。上期分享了 Verilog 的基本使用,以及数据类型、逻辑值和算数运算符的简单应用,掌握这些技能基础,我们可以高效地设计和验证 FPGA 电路,从而实现所需的数字系统功能。上期介绍了 Verilog 中的数据类型、逻辑值以及算术运算符,具体,请看上篇,

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

这里我们继续分享关于 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.mzph.cn/pingmian/53247.shtml

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

相关文章

快手电商上线 “金秋赶蟹季” 活动,特别推出“蟹无忧”服务

金秋九月&#xff0c;正是品蟹好时节。为引入更多源头好蟹&#xff0c;快手电商发起了「金秋赶蟹季」溯源活动。为了让全国老铁提前品尝肥美的盘锦河蟹&#xff0c;9月3日&#xff0c;快手电商携手盘山县人民政府举行盘锦河蟹开捕仪式&#xff0c;并在快手小店 直播间进行全程直…

SprinBoot+Vue校园活动报名微信小程序的设计与实现

目录 1 项目介绍2 项目截图3 核心代码3.1 Controller3.2 Service3.3 Dao3.4 application.yml3.5 SpringbootApplication3.5 Vue3.6 uniapp代码 4 数据库表设计5 文档参考6 计算机毕设选题推荐7 源码获取 1 项目介绍 博主个人介绍&#xff1a;CSDN认证博客专家&#xff0c;CSDN平…

性能测试经典案例解析——政务查询系统

各位好&#xff0c;我是 道普云 一站式云测试SaaS平台。一个在软件测试道路上不断折腾十余年的萌新。 欢迎关注我的主页 道普云 文章内容具有一定门槛&#xff0c;建议先赞再收藏慢慢学习&#xff0c;有不懂的问题欢迎私聊我。 希望这篇文章对想提高软件测试水平的你有所帮…

docker拉取redis5.0.5并建立redis集群

1.配置文件 mkdir -p redis-cluster/7001/ mkdir -p redis-cluster/7002/ mkdir -p redis-cluster/7003/ mkdir -p redis-cluster/7004/ mkdir -p redis-cluster/7005/ mkdir -p redis-cluster/7006/cd redis-clustervim 7001/redis.confbind 0.0.0.0port 7001cluster-enabled…

IJCAI-信也科技杯全球AI大赛-华东师范大学亚军队伍分享

作者&#xff1a;彭欣怡(找不到工作版) 华东师范大学; 马千里(搬砖版) 虾皮; 指导&#xff1a;闫怡搏(科研版) 华东师范大学 比赛链接&#xff1a;https://ai.ppdai.com/mirror/goToMirrorDetailSix?mirrorId34 前言 这是我们首次参加语音领域的比赛&#xff0c;最初只是抱着…

C语言程序设计 笔记代码梳理 重制版

前言 第1章 C语言的流程 1.C程序经历的六个阶段 编辑(Edit)预处理(Preprocess)编译(Compile)汇编(Assemble)链接(Link)执行(Execute) 2.C语言编写代码到运行 都是先编译&#xff0c;后链接&#xff0c;最后运行。&#xff08;.c ---> .obj --->.exe&#xff09;这个过…

开发适合el-dialog的拉伸拖拽自定义指令和适配自定义的图片查看组件

目录 一、应用场景 二、开发流程 1.自定义指令 2.功能原理 3.难点 三、详细开发 四、总结 一、应用场景 我之前有开发过一个图片查看的组件&#xff0c;这个组件可在单页面打开&#xff0c;也可以在弹窗里打开&#xff0c;但是弹窗因为是比较固定&#xff0c;所以有一些…

常见限流算法-固定窗口、滑动窗口、漏桶、令牌桶

为什么需要限流 限流可以认为服务降级的一种,限流就是限制系统的输入和输出流量已达到保护系统的目的。一般来说系统的吞吐量是可以被测算的,为了保证系统的稳定运行,一旦达到的需要限制的阈值,就需要限制流量并采取一些措施以完成限制流量的目的。比如:延迟处理,拒绝处理…

OpenCV颜色空间转换(1)颜色空间转换函数cvtColor()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将图像从一个颜色空间转换到另一个颜色空间。 此函数将输入图像从一个颜色空间转换到另一个颜色空间。在进行 RGB 颜色空间之间的转换时&#x…

怎样查看电脑文件夹大小?文件夹数据丢失怎么找回

在日常使用电脑的过程中&#xff0c;‌我们经常需要查看文件夹的大小&#xff0c;‌以便更好地管理磁盘空间。‌然而&#xff0c;‌有时我们可能会遇到文件夹数据丢失的问题&#xff0c;‌这可能是由于误删除、‌系统错误或病毒感染等多种原因造成的。‌本文旨在介绍如何查看电…

【苍穹外卖】Day 7 地址簿、下单、定时处理

1 地址簿模块 地址簿实体对象&#xff1a; package com.sky.entity;import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor;import java.io.Serializable;/*** 地址簿*/ Data Builder NoArgsConstructor AllArgsCon…

001集——CAD—C#二次开发入门——开发环境基本设置

CAD C#二次开发首先需要搭建一个舒服的开发环境&#xff0c;软件安装后&#xff0c;需要修改相关设置。本文为保姆级入门搭建开发环境教程&#xff0c;默认已成功安装vs和cad 。 第一步&#xff1a;创建类库 第二步&#xff1a;进行相关设置&#xff0c;如图&#xff1a; 下一…

JavaEE:多线程进阶(CAS)

文章目录 CAS什么是 CASCAS 伪代码 CAS有哪些应用CAS的ABA问题什么是ABA问题ABA问题带来的BUG解决方案 CAS 什么是 CAS CAS: 全称Compare and swap&#xff0c;字面意思:”比较并交换“&#xff0c;一个 CAS 涉及到以下操作: 我们假设内存中的原数据V&#xff0c;旧的预期值A…

刷题记录(2)

1. HWOD机试 - 模拟消息队列(100) package com.yue.test;import org.junit.Test;import java.util.ArrayList; import java.util.Arrays; import java.util.LinkedList; import java.util.List;/*** Author: 夜雨* Date: 2021-12-08-10:31* Description:* Version 1.0*/ public…

【Android】ViewPager基本用法总结

文章目录 一、添加ViewPager控件二、构建适配器类三、在 MainActivity 中设置适配器示例一&#xff1a;图片切换适配器MainActivity 示例二&#xff1a;Fragment切换适配器FragmentMainActivity ViewPager 是 Android 中一个用于在同一屏幕上滑动不同页面&#xff08;通常是左右…

OBS怎么设置录制配置?3个电脑录屏小技巧妥妥教会你

OBS Studio是一款广受好评的开源录屏和直播软件&#xff0c;它以其强大的功能和用户友好的操作界面而闻名。对于初次接触OBS的用户来说&#xff0c;可能会对软件的众多按钮感到困惑。本文将为你提供一份简洁明了的OBS录屏指南&#xff0c;帮助你快速上手。 演示机型&#xff1a…

Hive数据库与表操作全指南

目录 Hive数据库操作详解 创建数据库 1&#xff09;语法 2&#xff09;案例 查询数据库 1&#xff09;展示所有数据库 &#xff08;1&#xff09;语法 &#xff08;2&#xff09;案例 2&#xff09;查看数据库信息 &#xff08;1&#xff09;语法 &#xff08;2&#…

Simulink:循环计数器 Counter Free-Running

原文&#xff1a;Matlab生成stm32代码_matlab stm32-CSDN博客 使用“Counter Free-Running”模块进行计数&#xff0c;参数配置如下 此配置的意思为每0.5秒计数一次&#xff0c;计数的最大值为2^Nbits – 1&#xff0c;其中Nbits为所填的2&#xff0c;所以这里最大值为3。 示波…

【多线程】死锁

&#x1f970;&#x1f970;&#x1f970;来都来了&#xff0c;不妨点个关注叭&#xff01; &#x1f449;博客主页&#xff1a;欢迎各位大佬!&#x1f448; 文章目录 1. 死锁的三种情况1.1 一个线程一把锁&#xff08;同一个线程给同一个对象加两次锁的情况&#xff09;1.2 两…

彻底解决 node/npm, Electron下载失败相关问题, 从底层源码详解node electron 加速配置

最近玩了一下electron项目, 总是会遇到electron的下载失败问题, 于是看了一下node源码, 做一个记录. node/npm 加速配置 这个配置通过设置node配置里面的registry 这个配置项来完成加速. 配置方法 npm config set registry https://registry.npmmirror.com上面的命令就是将当…