FPGA的设计艺术(19)触发器以及线网的建模工具之Verilog中的两类数据类型
前言
说到底,Verilog中的数据类型其实可以分为两种:
- 网络类型
- 变量类型
我们平时最常用的wire以及reg就是这两种的代表,我们可以仅仅使用这两种数据类型来完成几乎全部设计。
我们在verilog中使用wire类型来声明信号,这是我们设计中非常基本的点对点连接。顾名思义,它们大致等效于传统电路中的电线。
在电路中,我们将使用reg类型对触发器输出进行建模,因为它可以有效地存储单个数据位。
尽管如此wire和reg应用很广泛,我们还是需要对其他数据类型进行了解,要不然就过于狭隘了。
本文将介绍Verilog中最常用的数据类型。其中包括对数据表示形式,net类型,变量类型,向量类型和数组的讨论。
尽管Verilog被认为是一种松散类型的语言(相较于VHDL,更加的“宽松”),但我们仍必须在Verilog设计中为每个端口或信号声明一种数据类型。
我们指定的类型用于定义数据的特征。
例如,我们可以使用将数据纯粹解释为逻辑值的类型。我们还可以使用将数据解释为数值的类型。
当我们在Verilog中将数据分配给信号时,在大多数情况下,数据会隐式转换为正确的类型。结果,通常不需要在Verilog中显式执行类型转换。
在Verilog中表示数据
编写Verilog时,我们经常需要在代码中表示数字数据值。我们可以将此数据表示为二进制,十六进制或八进制值。
与其他编程语言不同,我们还需要定义数据表示形式中的位数。
这是因为我们在使用Verilog时从根本上描述了硬件电路。因此,我们可以创建包含所选择位数的数据总线。
下面的代码段显示了在Verilog中表示数字数据的一般语法。
<bits>'<representation><value>
我们使用bits字段来表示我们所代表的数据中的位数。
我们使用representation字段指示如何表示我们的数据。此字段可以设置为b(对于二进制),h(对于十六进制),o(对于八进制)或d(对于十进制)。
最后,我们使用value字段设置数据的实际值。
下面的代码片段显示了我们如何使用每个不同的有效表示形式来表示十进制值8。
// Binary value of 8
4'b1000;
// Hex value of 8
4'h8;
// Octal value of 8
4'o10;
// Decimal value of 8
4'd8
Verilog中的基本数据类型
概括地说,verilog中的基本数据类型可以分为两个主要组-网络类型和变量类型。
我们使用这两个不同的组来对我们的数字电路的不同元素进行建模。
我们使用网络类型对数字电路中的连接进行建模。它们无法自行存储值,必须由数据驱动。
我们在设计中主要使用变量类型为寄存器或触发器建模。这些类型可以存储数据,这意味着它们的行为类似于其他编程语言(例如C)中的变量。
上述网络类型以及变量类型的代表,或者说最常用的是:
- wire
- reg
无论我们使用的是哪种类型,都可以为数据中的各个位分配四种有效值。下面显示了这四个不同的值。
- 0 二进制0值
- 1 二进制1值
- z 高阻抗值
- x 未知值
我们使用相同的语法在verilog中声明变量,而不管其确切类型如何。下面的代码段显示了这种常规语法。
// General syntax to declare a variable in verilog
<type_name> <size> <variable_name> = <value>;
在上面的示例中,我们使用type_name字段声明我们拥有的变量的类型。我们只需将字段替换为类型名称即可。
例如,下面的verilog代码声明一个整数类型变量,并将其赋值为100。
integer example = 100;
或者如下定义一个reg类型变量,赋初值为200
reg [7:0] example0 = 8'd100;
Verilog中的网络类型
我们在verilog中使用net数据类型来描述设计中不同组件之间的物理连接。因此,不能单独使用网络类型来存储数据值或驱动数据。
为了更好地演示何时使用网络类型,请考虑以下电路图。
在此电路中,我们将使用网络类型将多路复用器的输出连接到触发器的输入。
电路图显示了两个输入多路复用器和一个D型触发器。 多路复用器的输出是触发器的输入。
我们通常使用连续分配将数据驱动到wire类型上。为此,我们必须使用assign关键字,如下面的代码片段所示。例如对上述电路进行描述:
wire din;
assign din = addr ? A:B;
always@(posedge clock) begin
q <= din;
end
其中din就是多路选择器的输出。
我们不能在过程代码块中使用net类型,例如always块。
Verilog中的wire类型
Verilog中最常用的网络类型是我们在上一篇文章中讨论过的wire类型。
我们在verilog中使用wire类型来声明信号,这是我们设计中非常基本的点对点连接。顾名思义,它们大致等效于传统电路中的电线。
下面的Verilog代码显示了我们如何将wire类型与assign关键字一起使用。
// Declaration of a single wire
wire a;
// Driving data onto the wires using assign
assign a = c;
assign b = d;
wand与wor类型
尽管线类型是网络数据类型中最常用的类型,但在Verilog设计中也可以使用其他几种类型的网络。
wand和wor net类型用于将基本逻辑门嵌入我们的电路。我们使用wand类型嵌入与门,而wor类型创建或门。
当使用wand和wor类型时,我们必须多次分配信号。我们这样做是因为每个分配代表一个到底层逻辑门的输入。
下面的Verilog代码显示了如何将wand和wor类型与assign关键字一起使用。
// Declaration of our wand and wor types
wor a;
wand b;
// Wires which connect to our gates
wire c, d, e, f;
// Create an or gate with the function c or d
assign a = c;
assign a = d;
// create an and gate with the function e and f
assign b = e;
assign b = f;
上述描述等价于:
wire a,b;
wire c,d,e,f;
assign a = c | d;
assign b = e & f;
正如我们将在以后的文章中看到的那样,我们可以轻松地使用线类型在verilog中对组合逻辑进行建模。因此,不建议使用wor和wand类型。
tri,triand和trior类型
除了wire,wand和wor状态之外,我们还可以使用等效的tri,triand或trior类型。
我们使用这些类型的方式与wire,wand和wor的类型完全相同。实际上,这些类型的功能是完全相同的。但是,我们可以使用它们来更清楚地表明我们的设计意图。
下面的代码段显示了一个基本示例,其中,将Tri型驱动为高阻抗。
// Declaration of our tri type
tri a;
// Drive the tri type to high impedance
assign tri = 1'bz;
但是,由于wire类型也可以采用三态值,因此我们很少在实践中使用三态。trior和triand类型也是如此,在我们的verilog设计中,也可以使用wire型轻松代替它们。
supply0和supply1类型
我们可以在Verilog设计中使用的最后的网络类型是supply0和supply1类型。
我们可以使用这些类型将信号绑定到二进制1或0的常数值。由于这具有创建连接到地或Vcc的网的效果,因此我们无需为该类型分配任何数据。
下面的代码片段显示了我们如何使用这些类型来创建高电平或低电平的信号。
// Create a net which is tied to 0b
supply0 a;
// Create a net which is tired to 1b
supply1 b;
但是,我们很少需要在设计中将信号限制为高电平或低电平,并且当我们这样做时,使用wire类型很容易完成。因此,实际上很少使用supply0和supply1类型。
Verilog中的变量类型
与网络类型不同,我们在verilog中使用变量数据类型来存储值。当我们给变量类型赋值时,它会一直保持该值,直到再次赋值为止。
与网络类型相比,变量类型通常比网络类型更直观易懂,因为它们的行为方式类似于诸如C之类的语言中的变量。
为了更好地演示何时使用变量类型,请考虑以下电路图。
在此电路中,我们将使用变量类型对触发器输出进行建模,因为它可以有效地存储单个数据位。
电路图显示了两个输入多路复用器和ad型触发器。 多路复用器的输出是触发器的输入。
我们必须在过程代码块(例如always块)中使用变量类型,如下面的代码段所示,该代码段为D型触发器建模。
always @(posedge clock)
q <= d;
end
Verilog中的reg类型
Verilog中最常用的变量类型是reg类型。每当我们需要在设计中存储值时,都可以使用此类型。
我们最常使用reg类型对触发器的行为进行建模。
但是,在某些情况下,reg类型也可以用于在Verilog中对组合逻辑进行建模。
这将放在下一篇进行介绍,使用组合always块对组合逻辑进行建模。
下面的Verilog代码片段显示了我们如何使用reg类型对基本触发器进行建模。
// Declaration of our reg types
reg q;
// Code for a basic flip flop
always @(posedge clock)
q <= d;
end
数值变量类型
到目前为止,我们所研究的类型都与单个数据位一起使用。但是,我们也可以在Verilog设计中以数字表示数据。
在verilog中,有两种常用的数字类型-整数类型和实数类型。让我们仔细看看这两种类型。
Verilog integer类型
Verilog中最常用的数字数据类型是integer类型。但是,我们通常将其用于模块中的内部信号,而不是端口。
我们可以用integer来表示verilog设计中的任何整数。
当我们使用整数类型时,我们将数字而不是二进制值分配给变量。
由于我们还可以将数字值分配给reg类型,因此通常在verilog中将整数用作常量或循环变量。
我们的综合工具将自动修剪我们整数类型中所有未使用的位。例如,如果我们声明一个值为255的整数常量,那么我们的综合工具会将其缩减为8位。
下面的代码段显示了我们如何在verilog中声明和分配整数类型。
// Example of an integer
integer a = 255;
还例如我们使用整数类型与for循环一起使用:
reg [7:0] a [255:0];
integer i;
always@(posedge clk) begin
for(i = 0; i < 256; i = i + 1) begin
a[i] <= 8'd0;
end
end
Verilog real类型
除了整数类型,我们还可以在verilog中使用实数类型。我们使用这种类型来存储非整数数字,即也有小数部分的数字。
实型通常在Verilog中实现为64位浮点数。因此,它不能直接合成,我们通常只在verilog测试平台中使用实数类型。
我们可以使用十进制或科学计数法将值分配给实型。
下面的代码段显示了我们如何声明实型并为其分配数据。
// Declaration of a real type
real a;
// Assign of data using decimal notation
a = 2.5;
// Assignment of data using engineering notation
a = 1e-3;
Verilog中的向量类型
除了数值类型,到目前为止,我们所研究的所有类型都由一个位组成。
但是,我们经常使用数据总线在数字电路中传输数据。
在verilog中,我们可以使用向量类型来创建数据总线。这使我们可以声明一个多于一个的信号。
下面的代码段显示了用于在Verilog中声明向量类型的常规语法。
// General syntax to declare a vector type
<type> <size> <variable_name>;
当我们定义向量的大小时,我们必须指定最高有效位和最低有效位(MSB和LSB)。因此,size字段采用[MSB:LSB]的形式。
例如,要声明一个4位的小端类型矢量,我们将使用结构[3:0]。
我们可以使用二进制,十六进制,八进制或十进制格式表示数据。当我们将数据分配给向量时,我们可以使用任何这些表示形式。
下面的verilog代码显示了如何声明4位宽的reg类型。我们还将看到如何使用不同的数据表示形式将1010b的值分配给变量。
// Declare our reg type vector
reg [3:0] a;
// Assign binary data
reg [3:0] a = 4'b1010;
// Assign hex data
reg [3:0] a = 4'ha;
// Assign decimal data
reg [3:0] a = 4'd10;
// Assign octal data
reg [3:0] a = 4'o12;
Verilog中的无符号和有符号数据
在verilog 2001标准发布之前,所有变量和网络类型只能用于存储无符号的数据类型。
同样,整数类型始终被解释为带符号的值。
但是,有符号和无符号关键字是作为verilog 2001标准的一部分引入的。这使我们能够更改变量解释数据的方式。
当我们声明一个类型为Verilog签名时,它将被解释为2的补码。这意味着我们可以为这些信号分配负数。
默认情况下,整数类型是有符号的,而reg和wire类型都是无符号的。仅当我们希望修改此默认行为时,才需要使用这些关键字。
下面的Verilog代码显示了如何使用reg,wire和integer类型声明有符号和无符号数据。在这种情况下,我们声明的所有变量均为32位宽。
// Declarations for signed and unsigned reg type
reg [31:0] a;
reg signed [31:0] b;
// Declaration for signed and unsigned wire type
wire [31:0] a;
wire signed [31:0] b;
// Declaration for signed and unsigned wire type
integer unsigned a;
integer b;
更多阅读
- 分享
- 举报
-
浏览量:11462次2021-05-23 01:13:25
-
浏览量:10812次2021-03-20 13:22:58
-
浏览量:5938次2021-03-22 01:26:53
-
浏览量:6308次2021-03-22 00:49:53
-
浏览量:8909次2021-03-21 22:58:26
-
浏览量:5269次2021-03-14 01:12:39
-
浏览量:5020次2021-03-14 01:58:15
-
浏览量:6968次2021-02-21 01:20:21
-
浏览量:4766次2021-03-18 22:57:24
-
浏览量:4994次2021-05-23 23:50:14
-
浏览量:5234次2021-03-20 00:58:29
-
浏览量:18928次2020-12-06 18:59:36
-
浏览量:7609次2021-02-07 00:59:28
-
浏览量:5750次2021-02-14 01:58:16
-
浏览量:5623次2021-04-27 00:06:35
-
浏览量:6860次2021-01-31 01:07:50
-
浏览量:5351次2021-03-17 23:24:53
-
浏览量:4122次2021-03-12 23:39:20
-
浏览量:4884次2021-05-15 23:39:10
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
李锐博恩
感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明