文章目录

  • 前言
  • VHDL的并行语句
    • VHDL直接信号赋值语句
    • VHDL条件式信号设置语句
    • VHDL选择式信号设置语句
    • VHDL进程语句
      • 时钟事件表示方法
      • 纯组合process
      • 纯时序process
      • 具有同步复位的process
      • 具有异步复位的process
      • 具有混合复位的process
      • VHDL块语句
      • VHDL元件例化语句
      • VHDL生成语句
      • 条件生成
      • VHDL函数调用语句

前言

VHDL的并行语句类似于Verilog的always块,下面摘自《FPGA之道》的讲解,一起学习。

VHDL的并行语句

在VHDL的基本程序框架一节中,我们了解到,architecture语句部分里面的语句都是并行的。 那么到底VHDL里面有哪些并行语句可以供我们使用呢?请看如下描述:
architecture <arch_name> of <entity_name> is
begin
<VHDL直接信号赋值语句>;
<VHDL条件式信号设置语句>;
<VHDL选择式信号设置语句>;
<VHDL进程语句>;
<VHDL块语句>;
<VHDL元件例化语句>;
<VHDL生成语句>;
<VHDL函数调用语句>;
end <arch_name>;
以上这些并行语句,没有哪一类是不可或缺的,但是一个architecture中怎么着也得至少有一条,否则虽然从语法上来讲没什么问题,但是这个architecture就不具有任何功能了。一般来说,只要有元件例化、进程语句和信号赋值语句这三类语句就足够描述FPGA的功能了 ,下面详细介绍一下这些并行语句。

VHDL直接信号赋值语句

直接信号赋值语句语法如下:
<signal_name> <= ;
entity中的非输入端口以及architecture声明与定义部分中声明的signal,都可以在这个地方进行赋值。例如:

a <= (others => '0'); -- e.g. a is a signal, type std_logic_vector(3 downto 0);
b <= c or d; -- e.g. b, c, d are type std_logic;

VHDL条件式信号设置语句

条件式信号设置语句语法如下:
<signal_name> <= <expression 1> When <logic_expression1> Else<expression 2> When <logic_expression2> Else……<expressions n>;
举例如下:
equal <= '1' when data1 = data2 else '0';

VHDL选择式信号设置语句

除了条件式信号设置语句外,还有另一种语句可以实现类似的功能,那就是选择式信号设置语句。语法如下:

with <expression> select
<signal_name> <= <expression 1> When <constant_value 1> ,<expression 2> When <constant_value 2>,……    <expression n> When others;

举例如下:

 signal a, b : std_logic;signal c : std_logic_vector(1 downto 0);signal xorOfAB : std_logic;c <= a & b;With c Select
xorOfAB <= '1' when "01",'1' when "10",'0' when others;

那么,条件式赋值语句和选择式赋值语句到底有什么区别和联系呢?首先,将上例用条件赋值语句改写如下:

xorOfAB <= ’0’ when a = b else ‘1’;

对比这两种写法,从表面上来看,选择式赋值语句的语法要求更为严格点,且constant_value的值必须互不相同,而条件式赋值语句的logic_expression却没有这种严格的要求。从本质上来看,条件式赋值语句之所以对logic_expression没有严格的要求,是因为它是有优先级的,即写在前面的logic_expression优先级高于写在后面的。
在VHDL基本程序框架一小节,我们说过,architecture中的独立语句其实就相当于只有一条代码的纯组合逻辑process。那么如果把条件式赋值语句和选择式赋值语句都改写为进程语句来实现的话,那么,条件式赋值语句就相当于if-else语法,而选择式赋值语句就相当于case语法。

VHDL进程语句

进程语句是VHDL中非常重要的一种语句体,在VHDL的基本程序框架一节中,我们已经有过简单介绍。Process是一种并行语句结构,位于一个architecture下的若干个process是并发执行的,但是Process内的语句却是顺序执行的顺序语句,process的语法结构如下:

<lable> : process (<sensitive_signals_list>)variable <name>: <type> := <value>;<other variables>...
begin  <statements>;
end process;

其中,是可选的,它是进程的标号,主要起到提高代码可读性的作用。之前已经介绍过,按照<sensitive_signals_list>的形式来分,process共有三个“纯种”的基本类型:纯组合process、纯同步时序逻辑process、具有异步复位的同步时序逻辑process。 不过如果从process的结构入手,我们的可以将process的语法划分可以更细一些,即:纯组合process、纯时序process、具有同步复位的process、具有异步复位的process以及具有混合复位的process。 可见,基于结构的划分比基于<sensitive_signals_list>的划分更细致一些、面更广一些。基于结构的划分其实就是基于时钟描述结构的划分,因此,首先来介绍一下在process中表示时钟事件的方法。

时钟事件表示方法

'event属性
首先要介绍一下’event属性,这个属性是VHDL进程语句中常用的描述信号事件的手段(进程语句最开始的敏感量表也是描述信号事件的手段,只不过它们所处的位置不同)。一般来说,时序逻辑主要响应两种时钟事件,即时钟的上升沿和下降沿。在process中,要表示这两种事件,我们可以采用如下代码:

 signal clk : std_logic;if (clk'event and clk = '1') then – 表示时钟上升沿if (clk'event and clk = '0') then – 表示时钟下降沿rising_edge() & falling_edge()

除了’event属性之外,VHDL还提供了一种方法用来描述时钟事件,参考例子如下:

signal clk : std_logic;
if (rising_edge(clk)) then – 表示时钟上升沿
if (falling_edge(clk)) then – 表示时钟下降沿

切记!在一个process中,只能出现一个时钟信号的一种边沿事件,并且针对边沿事件的if(或elsif)条件分支,后续不得再有else或elsif分支存在。 这是由寄存器的结构决定的,因为一个寄存器只有一个时钟端口,并且只敏感这个端口的某一个边沿,因此凡是不尊重这个事实的代码都是不可综合的。并且,即便该寄存器存在异步复位信号,由于异步复位信号的优先级要高于时钟信号,而if语句是具有优先级的条件语句,故异步复位所处的条件分支也只能出现在时钟事件所处的分支之前(就像【具有异步复位的process】和【具有混合复位的process】中介绍的那样)。

下面根据时钟描述结构的不同,分别介绍五种基本process代码结构如下:

纯组合process

纯组合process语法如下:

process (<sensitive_signals_list>)
begin  <statements>;
end process;

参考例子如下:
– e.g. all signals are std_logic

process(a, b)
beginc <= a and b;d <= not c;
end process;

上述例子描述了一个与非门的结构,我们可以注意信号c并不在敏感量列表里面,因为c只是一个中间信号,而不是输入信号。

纯时序process

纯时序process的语法如下:

process (clk) -- only clk in the sensitive list
begin  if (clk'event and clk = '1') then -- or if (clk'event and clk = '0') then<statements>;end if;
end process;

参考例子如下:
– all signals are std_logic

process(clk)
beginif(clk’event and clk = '1') then    a <= b;end if;
end process;

具有同步复位的process

具有同步复位的process的语法如下:

process (clk) -- only clk in the sensitive list
begin  if (clk’event and clk = '1') then -- or if (clk’event and clk = '0') thenif (rst = '1') then -- or if (rst = '0') then<reset statements>;else<function statements>;end if;end if;
end process;

参考例子如下:

-- all signals are std_logic
process(clk)
begin
if(clk'event and clk = '1') then
if (rst = '1') thena <= '0';
else
a <= b and c;
end if;
end if;end process;

具有异步复位的process

具有异步复位的process语法如下:

process (clk, aRst) -- clk and asynchronous reset
begin  if (aRst = '1') then -- or if (aRst = '0') then <reset statements>;elsif (clk'event and clk = '1') then -- or elsif (clk'event and clk = '0') then<function statements>;end if;end if;
end process;

也可以写成如下形式:

process (clk, aRst) -- clk and asynchronous reset
begin  if (aRst = '1') then -- or if (aRst = '0') then <reset statements>;elsif (clk'event and clk = '1') then -- or elsif (clk'event and clk = '0') then<function statements>;end if;
end process;

参考例子如下:
– all signals are std_logic

process(clk, aRst)
begin
if (aRst = '1') thena <= '0';
else
if(clk'event and clk = '1') then
a <= b and c;
end if;
end if;end process;

具有混合复位的process

具有混合复位的process的语法如下:

process (clk, aRst) -- clk and asynchronous reset
begin  if (aRst = '1') then -- or if (aRst = '0') then <asynchronous reset statements>;elseif (clk'event and clk = '1') then -- or if (clk'event and clk = '0') thenif (rst = '1') then -- or if (rst = '0') then< sync reset statements>;else<function statements>;end if;end if;end if;
end process;

也可以写成如下形式:

process (clk, aRst) -- clk and asynchronous reset
begin  if (aRst = '1') then -- or if (aRst = '0') then <reset statements>;elsif (clk'event and clk = '1') then -- or elsif (clk'event and clk = '0') thenif (rst = '1') then -- or if (rst = '0') then< sync reset statements>;else<function statements>;end if;end if;
end process;

参考例子如下:

-- all signals are std_logic
process(clk, aRst)
begin
if (aRst = '1') thena <= '0';
elsif(clk'event and clk = '1') thenif (rst = '1') thena <= '1';else
a <= b and c;
end if;
end if;end process;

VHDL块语句

块语句即block语句,语法如下:
label:BLOCK <(expression)>

BEGIN
;
END BLOCK label;
关于block语句有几点说明:
首先,block中的语句都是并发执行的。
其次,关键字后紧跟的表达式逻辑是可选的,如果有表达式,那么当表达式为真时内部语句才执行;如果没有表达式,则语句一直执行。
第三,block中可以嵌套block。
最后,建议大家尽量不要用block语句。因为它的功能仅仅是对原有代码进行区域分割,增强整个代码的可读性和可维护性。当我们的设计真的需要分模块时,我们完全可以写多个entity,而没有必要用block;当我们需要让代码结构清晰时,我们完全可以用注释和空白,而没有必要用block。所以,建议大家对于block只做了解即可。

VHDL元件例化语句

元件例化语句即是instance语句。关于它的语法及相关知识已经在VHDL基本程序框架中做了比较详细的介绍.在这里,关于instance语句,我们再做两点说明:

  • 第一点,在某些情况下,例化元件时可以只对元件的部分端口进行映射赋值。道理很简单,对于那些你不需要使用的引脚,你可以不去管它(尤其是输出引脚,但输入引脚是否可以忽略不管则取决于功能),最形象的例子就是FIFO,关于空、满有非常多的信号,而我们的设计中一般只能用到其中的一部分。
  • 第二点,元件例化的时候,映射给输入端口的值也可以是常数或者非常简单的表达式,例如:
 -- all signals are of type std_logic_vector(3 downto 0)
m0: And3 PORT MAP(a => "0000",b => not b, -- this is ok!c => a and c, -- this is not allowed!d => d);

使用简单的表达式进行映射,有时候能够给我们带来一些便利,不过并不提倡大家这么去做,因为这样写有些不太规范。

VHDL生成语句

VHDL中的生成语句可分为三种,分别是参数生成、循环生成与条件生成,我们这里所说的并行语句主要指后两种。关于这三种生成语句分别介绍如下:

  • 参数生成
    参数生成的语法是generic,主要用在entity定义和元件例化时。

  • 循环生成
    循环生成也叫for-generate语句,主要用于生成一组信号赋值或元件例化语句。它的语法如下:

<generate_LABEL>:
for <name> in <lower_limit> to <upper_limit> generate
begin
<statements>;
end generate;

关于循环生成语句的语法,有一点需要注意,那就是<generate_LABEL>必须要有,也就是说一定要为循环生成语句定义一个标签,否则会被识别为for语句,而for语句是串行语句,不能单独出现在architecture中。
先看一个循环生成语句在信号赋值方面的例子:

 signal a, b : std_logic_vector(99 downto 0);
invertVector:
for i in 0 to 99 generate
begin
a(i) <= b(99 - i);
end generate;

由此可见,通过使用循环生成语句可以非常方便的实现a、b逻辑向量间的反转赋值,这样我们就不用写上100行啰嗦的直接信号赋值语句了。当然,这样的功能也可以通过在process中调用for循环语句来实现,不过下面这个利用循环生成语句进行元件例化的例子,就不那么容易找到同样简洁的替代方案了,代码入下:

COMPONENT cellAdd
PORT(a : IN std_logic_vector(7 downto 0);b : IN std_logic_vector(7 downto 0);          c : OUT std_logic_vector(7 downto 0));END COMPONENT;
type rt is array (7 downto 0) of std_logic_vector (7 downto 0);
signal arrayA, arrayB, arrayC: rt;adderGen : for i in 7 downto 0 generatebeginarrayAdder: cellAdd Port map(
a => arrayA(i),
b => arrayB(i),
c => arrayC(i));
end generate;

可见,本例的方式也极大的简化了我们的代码编写,并且这种代码节省更加不容易被替代,除非从cellAdd上下功夫,但是这样会复杂基本模块,不可取。

条件生成

条件生成语句也叫if-generate语句,主要用于一些预编译前的代码控制,类似于C语言中的条件选择宏定义,根据一些初始参数来决定载入哪部分代码来进行编译(即,有选择的让部分代码生效)。例如,我们有时候不确定这个地方是需要一个乘法还是一个除法,可是如果同时实现一个乘法器和一个除法器,那么资源的占用会很多,那么这个时候,可以通过条件生成语句,来方便的在乘法器与除法器之间切换,并且只占用一份资源。注意!这种切换不是动态的,它是通过修改设计中的参数来实现的,所以需要重新编译。if-generate语句的语法如下:

< generate_LABEL >:
if <condition> generate
begin
<statements>;
end generate;

举例如下:

constant sel : integer := 0;
signal a, b, c: std_logic_vector(15 downto 0);myMul:if sel = 1 generatebegin
c <= a * b; end generate;
myDiv:if sel = 0 generatebeginc <= a / b;end generate;

关于上例有四点需要注意:一、必须确保两个条件生成语句不能同时有效,否则就会出现c变量的赋值冲突错误。二、条件生成语句不支持else分支。三、判断条件必须为静态条件。四、标签不能省略。
请大家仔细思考第三点注意,绝对不能利用条件分支做一些动态生成的事情,因为硬件不像软件,不支持对象的动态生成与释放。条件生成语句是为了辅助编译器来预先知道到底该加载哪些语句去进行编译、综合的,而不能根据变量来在编译后动态决定现在选择哪一个代码结构。例如,如果把上例的
constant sel : integer := 0;
改为
signal sel : integer := 0;
那么编译会报错,表示判断条件不是一个静态条件。如果真的需要根据条件来判断做乘法还是做除法,应该写成这样:
signal sel : integer := 0;
cMul <= a * b;
cDiv <= a / b;
c <= cMul when sel = ‘1’ else
cDiv;
但是注意,这个时候,在FPGA中可是需要调用相应资源来同时实现一个乘法器与一个除法器的,只不过会根据sel来判断此时需要的是乘法器还是除法器的输出。而如果用条件生成语句的话,每一次实现FPGA的设计中,只会有一个乘法器或者一个加法器,资源方面会有很多节省,不过带来的不便就是如果需要另外一种功能时,需要修改代码重新编译实现新的FPGA配置文件。
需要强调一下,以上例子中,我们为了说明方便和代码简洁,直接使用了“*”、“/”符号来完成乘法与除法运算。在现实情况中,强烈不推荐如此简单的来处理乘、除运算.

VHDL函数调用语句

函数——function,是VHDL子程序的一种,函数的调用是一种并行的调用,它可以直接出现在architecture的语句部分当中,例如:
– e.g. function min() is predefined

smaller <= min(a, b);

FPGA之道(28)VHDL的并行语句相关推荐

  1. 硬件描述语言VHDL之并行语句基本使用介绍

    硬件描述语言VHDL之并行语句 1. process语句 1.1 基本介绍 1.2 基本格式 1.3 代码示例 2. 简单形式并行信号赋值语句 2.1 简单并行信号赋值语句说明 2.2 代码示例 3. ...

  2. FPGA之道(35)Verilog中的并行与串行语句

    文章目录 前言 Verilog的并行语句 Verilog连续赋值语句 普通连续赋值语句 条件连续赋值语句 Verilog程序块语句 沿事件 纯组合always 纯时序always 具有同步复位的alw ...

  3. FPGA之道(29)VHDL的串行语句

    文章目录 前言 VHDL的串行语句 VHDL直接信号赋值语句 VHDL变量赋值语句 VHDL条件语句 优先级条件语句 无优先级条件语句 优先级条件语句与无优先级条件语句的对比 case-when的一些 ...

  4. FPGA之道(30)编写自己的vhdl库文件

    文章目录 前言 编写自己的vhdl库文件 Work库 记录数据类型 子程序介绍 函数 过程 子程序使用总结 程序包 自定义程序包范例 前言 本文节选自<FPGA之道>来一起学习下高阶Ver ...

  5. FPGA之道(22)VHDL基本程序框架

    文章目录 前言 VHDL基本程序框架 VHDL基本程序框架模板 Library Entity Architecture 声明与定义部分 语句部分 VHDL基本程序框架范例 VHDL注释语法 前言 VH ...

  6. FPGA之道(38)VHDL与Verilog的比较

    文章目录 前言 VHDL与Verilog的比较 语法比较 基本程序框架比较 端口定义比较 范围表示方法比较 元件调用与实例化比较 Process与always比较 标准逻辑类型比较 逻辑常量赋值比较 ...

  7. FPGA之道(31)VHDL编写注意事项

    文章目录 前言 VHDL编写注意事项 大小写不敏感 VHDL中的关键字 多余的符号 纠结的downto 与to 数组范围混用 逻辑向量范围混用 范围中的变量 仿真雷区 进程敏感量表缺失 进程间语句顺序 ...

  8. FPGA之道(24)VHDL数据类型

    文章目录 前言 VHDL数据类型 常用数据类型 逻辑数据类型 std_logic std_logic_vector boolean bit bit_vector 数值数据类型 integer real ...

  9. FPGA之道(74)Verilog生成语句

    文章目录 前言 Verilog生成语句 循环生成 条件生成 generate-if语句 generate-case语句 前言 为什么要把这一节单独拎出来,因为个人原因,平时觉得用的Verilog生成语 ...

最新文章

  1. Linux中的文件描述符与打开文件之间的关系
  2. The 16th Zhejiang Provincial Collegiate Programming Contest Sponsored by TuSimple
  3. linux 系统arp检测工具,基于LinuxARP检测与防御系统.doc
  4. springboot项目 tomcat8.x 频繁宕机 原因分析
  5. java移动端接口测试_借助Charles来测试移动端-下篇
  6. 跟着阿里大牛捞干货:2019这5本书带你玩转大数据
  7. 论文写作思路_2018年的16个写作思路
  8. @清晰掉 C++ 中的 enum 结构在内存中是怎么存储的?
  9. python书写跨越多行的字符串的两种方式
  10. java俄罗斯方块代码_java俄罗斯方块代码.doc
  11. Seaborn绘图-绘制散点图,折线图-分类统计图
  12. A Piece of ODE
  13. C++ __builtin_函数
  14. 智慧城市同城V4 v1.7.1
  15. MySQL报错1677
  16. primocache学生党常用场景设置
  17. python简单爬虫 指定汉字的笔画动图下载
  18. Lync 2010升级到Lync 2013 之部署WAC 角色服务器!
  19. windows重装系统之后,开机显示“An operating system wasn't found,Try disconnecting any drives that...”(亲身遇到+解决方法)
  20. [医疗信息化][DICOM教程]DICOM标准简介

热门文章

  1. LINQ To DataSet 几个常用示例
  2. JSON 序列化和反序列化——JavaScriptSerializer实现
  3. 平板python_Wacom平板电脑的Python示例
  4. python里dir是什么意思_python中dir什么作用
  5. Jasperreport导出pdf内容展示不完全处理
  6. python reader循环_Python的for循环和while循环。
  7. Java设计模式(代理模式-模板方法模式-命令模式)
  8. 有STC制作一个手持微型示波器
  9. 反射式红外光电管 ITR8307
  10. 2021年春季学期-信号与系统-第七次作业参考答案-第七小题