FPGA之道(41)HDL的三种描述方式

举报
李锐博恩 发表于 2021/07/15 00:57:16 2021/07/15
【摘要】 文章目录 前言三种描述方式结构化描述方式数据流描述方式行为级描述方式 前言 常编写Verilog代码的就会知道,我们对于某一功能的描述,可以通过门电路来描述,也可以直接描述其功能等,这就牵扯到HDL的描述方式,本文节选自《FPGA之道》,一起看下HDL语言的三种描述方式。 三种描述方式 当我们使用HDL代码在描述硬件功能的时候,主要有三种基本描述...

前言

常编写Verilog代码的就会知道,我们对于某一功能的描述,可以通过门电路来描述,也可以直接描述其功能等,这就牵扯到HDL的描述方式,本文节选自《FPGA之道》,一起看下HDL语言的三种描述方式。

三种描述方式

当我们使用HDL代码在描述硬件功能的时候,主要有三种基本描述方式,即结构化描述方式、数据流描述方式以及行为级描述方式。在平时的编程中,可以根据实际情况以及自己的喜好选择其中的一种或几种混合在一起进行自己的HDL代码编写。下面对这三种描述方式分别进行介绍。

结构化描述方式

结构化描述方式是最原始的描述方式,是抽象级别最低的描述方式,但同时也是最接近于实际的硬件结构的描述方式。因为采用结构化的描述方式来编写HDL代码,其思路就跟在面包板上搭建数字电路是一样一样的,唯一的不同点就是我们是通过HDL的形式来描述数字电路都需要哪些“元器件”以及它们之间的连接关系是怎么样的罢了。所以,随着FPGA芯片的集成度越来越高,项目的复杂性越来越大,要想纯粹使用这种描述方法完成FPGA设计,已经不是人类所能做得到的。因此,目前来说,我们一般不采用结构化的描述方式来直接描述电路的逻辑功能,取而代之的是接下来将要介绍的数据流描述方式和行为级描述方式。原因有二:首先,使用结构化的方式不易描述功能稍微复杂的电路,因为我们的大脑除了要抽象出电路的逻辑功能关系,还要抽象出具体的实现形式,这就好比人家都用C语言编代码,而你却还在用汇编一样;其次,不同FPGA厂商提供的软件集成开发环境中的原语名称是不同的,因此使用结构化描述方式编写的代码是非常不通用的。
不过,结构化描述方式有它独有的优势,这也使得我们在平时的HDL代码编写中几乎无法离开它。这是因为层次化的模块划分是FPGA设计思想的主流,尤其对于复杂一些的设计这种思想甚至是必须的,那么,父模块调用子模块的过程只能通过结构化的描述方式来实现。当然,必须要用到结构化描述方式的地方也不仅仅局限于此,例如IP核的调用等等也需要用到。
通过上面对结构化描述方式的介绍,我想大家应该能判断出具有什么样特征的HDL代码叫做结构化描述了吧?没错,那就是实例化语句。只要HDL代码中有实例化语句出现,那么它就采用了结构化的描述方式,如果一个模块中除了实例化语句外不再有其他功能语句,那么它就是一个纯结构化的HDL代码,一般来说,较高层级的父模块都应该采用这种纯粹的结构化描述方式。
下面通过一个例题来具体的看一下什么叫结构化的描述方式。如果我们要描述的是这样一个功能:这是一个四输入、一输出的逻辑,输入信号分别为1bit的a、b、c、d,输出为1bit的o,当且仅当a和b不相等且c和d不相等时,o为逻辑1,否则o为逻辑0。如果要用结构化的描述方式编写HDL代码的话,必须先要抽象出数字电路结构来才行。针对本例,抽象出的数字电路结构图如下(答案不唯一):
在这里插入图片描述
可以看出,为了实现题目要求的功能,我们使用了两个异或门和一个与门,假设我们使用的是Xilinx公司的ISE集成开发环境,由于ISE原语库中的两输入异或门和与门的名称分别为XOR2和AND2,因此最后的结构化描述代码如下:

-- VHDL example 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

library UNISIM;
use UNISIM.VComponents.all;

entity Example is
port ( a, b, c, d : in  std_logic; o : out std_logic
);
end Example;

architecture Behavioral of Example is
	--由于使用了ise中的unisim库,因此这里不需要使用component语句
	signal tmp0, tmp1 : std_logic;

begin

	m0 : XOR2 PORT MAP(O => tmp0, I0 => a, I1 => b);
	m1 : XOR2 PORT MAP(O => tmp1, I0 => c, I1 => d);

	m2 : AND2 PORT MAP(O => o, I0 => tmp0, I1 => tmp1);

end Behavioral;

// Verilog example
module Example(
input a, b, c, d,
output o
);

	wire tmp0, tmp1;

	XOR2 m0(.O(tmp0), .I0(a), .I1(b));
	XOR2 m1(.O(tmp1), .I0(c), .I1(d));

	AND2 m2(.O(o), .I0(tmp0), .I1(tmp1));

endmodule

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

数据流描述方式

数据流描述方式要比结构化描述方式的抽象级别高一些,因为它不再需要清晰的刻画出具体的数字电路架构,而是可以比较直观的表达底层逻辑的行为。基于数据流的描述方式,形象点来说,每个模块就好比一个容器,大量外部信息从模块的输入端口“流入”,相应的,大量的处理后信息也会从模块的输出端口“流出”,因此,基于这种思路编写的HDL代码被称之为数据流描述方式。数据流描述方式又可称为RTL级描述方式,即寄存器传输级描述,因为它主要从数据的变换和传送的角度来描述设计模块,并且使用的语句多为和硬件行为一致的并行语句,因此它的抽象级别远没有后续要介绍的行为级描述方式高,所以纯数据流的描述方式也只适用于小规模的电路设计。不过也正因为数据流描述方式这种折中的抽象级别,使得它既显式地表达了模块的行为,又隐式地刻画了模块的电路结构。因此对于功能较简单的模块,我们可以轻松的使用数据流的描述方式来实现,这样对设计者和编译器都方便;而对于复杂些的模块,一般都是行为级描述为主,数据流描述方式为辅;更一般的,我们可能会在一个模块中同时使用这三种描述方式,来实现对数字电路更灵活的描述。
为了增强对比,加深印象,我们仍沿用【结构化描述方式】小节的题目。经过一些简单思考,抽象出一些数据流经过的关键节点(答案不唯一),那么上例写成基于数据流的描述方式,代码如下:

-- VHDL example 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Example is
port ( a, b, c, d : in  std_logic; o : out std_logic
);
end Example;

architecture Behavioral of Example is

	signal tmp0, tmp1 : std_logic;

begin tmp0 <= a xor b;
	tmp1 <= c xor d; o <= tmp0 and tmp1;

end Behavioral;

// Verilog example
module Example(
input a, b, c, d,
output o
);

	wire tmp0, tmp1;

	assign tmp0 = a ^ b;
	assign tmp1 = c ^ d;

	assign o = tmp0 & tmp1;

endmodule

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40

对比【结构化描述方式】小节的HDL描述,我们可以看出数据流描述方式清晰的阐明了数据从输入端口至输出端口的传递情况,并且从代码中我们也很容易能看出数字电路的基本脉络,但是对于tmp0、tmp1和输出o却并没有显式的规定一定要用什么具体电路去实现。以tmp0为例,数据流的描述只说明了tmp0可以由a、b两个信号进行异或操作得到,但并没有写明使用什么门电路来具体实现异或操作。是直接使用一个异或门?还是使用独立的与、或、非门搭出一个异或功能复合电路?异或是使用多路选择器或者查找表等来实现?我们都不得而知。其实这部分的工作实际上是交给了编译器,这也是为什么结构化描述写起来更费劲的原因,因为我们帮编译器做了本该由它去做的工作。当然,有时候我们担心编译器优化的不够好,或者是我们有自己特殊的目的,那么结构化描述就必不可少了。

行为级描述方式

和前面两种描述方式比起来,行为级描述方式的抽象级别最高,概括力也最强,因此规模稍大些的设计,往往都以行为级描述方式为主。在【本篇->编程语法】章节中,我们曾经介绍过,高级语言的执行思路都是串行的,例如C语言,因为顺序执行的语句更容易帮助我们来表达我们的设计思想,尤其是使描述时序逻辑变得容易。所以,虽然FPGA的设计思路都是并行的,但是HDL中还是支持大量的串行语句元素。由此可见,行为级描述方式的主要载体就是串行语句,同时辅以并行语句用于描述各个算法之间的连接关系。
在这里,我们仍沿用【结构级描述方式】小节中的题目。采用行为级的描述方式,几乎可以无思考的迅速提笔写出代码如下:

-- VHDL example 
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity Example is
port ( a, b, c, d : in  std_logic; o : out std_logic
);
end Example;

architecture Behavioral of Example is

	signal tmp0, tmp1 : std_logic;

begin process(a, b, c, d)
	begin
		if(a /= b and b /= c)then o <= '1';
		else o <= '0';
		end if;
	end process;

end Behavioral;

// Verilog example
module Example(
input a, b, c, d,
output reg o
);

wire tmp0, tmp1;

always@(a, b, c, d)
	if(a != b && c != d)
		o = 1'b1;
	else
		o = 1'b0;

endmodule

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

还记得我们的题目么?“当且仅当a和b不相等且c和d不相等时,o为逻辑1,否则o为逻辑0”,对比一下上述行为级描述代码,这简直就是对由自然语言所描述题目的赤裸裸HDL直译啊!所以在一开始我才说几乎可以无思考的写出代码。当然了,题目本身很简单也是原因之一,不过这也从侧面说明了使用行为级的描述方式会让HDL代码的开发过程更为的迅速、快捷。对于上例,由于行为级描述只需要描述清楚输出o为逻辑1或逻辑0时所应该对应的输入a、b、c、d情况,而不需要给出o应该怎样由a、b、c、d得到,更不需要给出具体的门级实现电路,所以行为级描述方式的抽象级别最高、概括力也最强。
由此可见,行为级描述方式使超大规模设计的短周期开发成为可能,这是行为级描述方式为FPGA设计带来的根本性变革,也是行为级描述方式最大的优点。不过佛语有云“空即是色,色即是空”,缺点可以转化为优点,优点也可以转化为缺点,关键看你从什么角度上去看。对于行为级描述方式来说,它最大的优点其实也是它最大的缺点!结构化描述方式直接给出底层电路结构,数据流描述方式间接给出底层电路结构,而行为级描述方式几乎压根就不给出底层电路结构!从题目描述到FPGA实现,无论采用何种描述方式,这中间的工作量是一定的,只不过不同的描述方式分配给人脑和电脑的工作量不同而已,那么在上例中,我们的代码之所以可以不假思索、提笔就来,肯定是行为级描述方式将工作量大部分分配给了电脑(也就是编译器)而已。电脑其实很笨的,之所以有人认为它聪明,是因为它的运算速度比人脑快太多太多了,不过它有个最大的缺点,就是不会创造,也就是对于你没有“教过”它的东西,它是绝对不会的,至少目前来说,电脑还不具有人脑的创造性。这也是为什么,FPGA的软件集成开发环境是人脑写的,而不是电脑自己创造出来的!由于行为级描述方式极大的减轻了人脑的负担,所以也就极大的增加了电脑的负担,并且越复杂的FPGA设计越是这样,因此使用行为级描述方式的代码在综合的时候效率较低,并且对最终电路的可控性也很差。所以,用行为级描述方式进行HDL代码编写的时候,态度要认真,思路要严谨,代码要规范,这样才能最大限度的保证我们想要的和编译器最终实现的具有一致性,也有助于编译器实现出更优秀、更精简的底层电路,切忌天马行空,随心所欲!

文章来源: reborn.blog.csdn.net,作者:李锐博恩,版权归原作者所有,如需转载,请联系作者。

原文链接:reborn.blog.csdn.net/article/details/104322281

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。