文章目录

  • 前言
  • 编写自己的vhdl库文件
    • Work库
    • 记录数据类型
    • 子程序介绍
      • 函数
      • 过程
    • 子程序使用总结
    • 程序包
    • 自定义程序包范例

前言

本文节选自《FPGA之道》来一起学习下高阶Verilog内容,编写自己的VHDL库文件。

编写自己的vhdl库文件

Work库

在VHDL基本程序框架中,我们介绍过work库,在那里,我们说“这个库一般不用显式声明,因为FPGA开发工具一般会自动帮我们完成这个工作”。这也是为什么一个FPGA工程下的一个VHDL文件中可以例化另外一个VHDL文件中描述的元件而不需要在代码的最开始加上声明:
Library work;
不过,有“一般”就会有“特殊”。我们都知道,库文件为我们的代码开发带来了非常大的便利,否则我们必须自己定义数据结构、定义相关的基本函数、过程等。如果VHDL中没有库,就好比C语言中没有int类型,没有print函数一样,会让人觉得两眼一摸黑,即使实现一个非常简单的功能也要摆出万里长征的架势还不一定能完成。那么,由于我们在编写代码时碰到的情况总是多种多样的,尤其是有一些情况并不是普遍情况,而几个标准库中定义的都是一些最通用、最基础的内容,不见得能很好的满足我们的编程需求。尤其是当我们的工程结构比较大、比较复杂、包含了成百上千个VHDL文件时,如果能够定义一些可供工程中所有文件共同调用的常数、数据类型、函数或进程的话,那该有多方便啊!要知道,一个实体中定义的常量、数据类型和子程序等对于其它实体是不可见的,于是,VHDL提供了自定义库的方法来解决我们的困扰。自定义库,其实主要指的就是自定义work库中的程序包,而要使用work库中的程序包时,就是本段开头所说的“特殊”情况。 如果哪个VHDL文件要使用自定义的程序包,一定要在代码最开始的库声明中加上:
use work.<package_name>.all;

记录数据类型

一般来说,VHDL的几个标准库中给我们提供的常用数据类型已经完全满足我们使用了,所以我们几乎不需要也没有必要定义新的基本数据类型。但是有一种情况比较特殊,那就是在我们的元件中,总是有几个数据是被同时传递的,这时候可以用记录数据类型将它们封装起来,从而简化代码并提高可读性。
例如,处理图像时,非常多的元件都需要知道图像的长、宽、颜色类型、颜色深度等等信息,按照通常的做法,我们可能需要在几十个VHDL的entity中都加上如下若干行定义:

width : in std_logic_vector(15 downto 0);
height : in std_logic_vector(15 downto 0);
colorMode : in std_logic;
colorDepth : in std_logic_vector(3 downto 0);……

VHDL是一个比较严谨的语言,严谨到让人觉得繁琐,所以上述定义语句还需要在使用它们的父元件的architecture的声明部分声明一次,还需要在父元件的architecture的语句部分实例化一次!怎么样,是不是有点崩溃?这个时候记录类型就体现出它的优势,我们只需要定义一个类似名为pictureParaType的记录类型,然后在entity的定义中仅添加一行定义:

pictureParameter : in pictureParaType;

即可!注意,记录类型为VHDL语法带来了更高的抽象能力,仅适合高级用户使用,入门级用户请在高级用户的陪同下谨慎学习和使用,否则造成软、硬件编程思路混淆导致精神崩溃本书概不负责!

子程序介绍

VHDL语言中也可以定义子程序,它们是过程(Procedure)和函数(Function)。分别介绍如下。

函数

函数即function,只能用来计算数值,而不能改变与函数形参相关的对象的值。所以,函数的参数类型只能是方向为in的信号或者常量。而函数的计算结果通过return语句返回,这点与C语言非常类似。Function的一般语法如下:

Function <function_name> (signal <parameter> : in <paramter_type>; <other parameters>) Return <result_type> ISvariable result : <data_type>; <other variable declare>
Begin<statements> -- 串行语句Return result;
End <function_name>;

关于function的语法,有以下几点说明:
1、参数列表中只能是signal,不能使variable。这点很好理解,因为function调用语句是并行的,除此以外,signal的方向只能是in。
2、函数返回值<result_type>的类型如果是逻辑向量类型的话,请直接写明std_logic_vector即可,如果加上范围约束的话会报错。
3、函数体内只能定义variable,不能定义signal,这跟process一样。
4、函数支持嵌套,即函数里面可以调用别的函数。因为function内部其实也是顺序语句,所以函数 a调用了函数b,跟在a内展开b的代码结果是一样的。虽然这违背了function调用语句是并行的概念,但是编译器一般是能够通过的。
5、函数中可以调用过程,但是注意,函数中调用的过程的输出参数必须是variable类型的,因为函数体中没有可供过程输出所用的signal。
6、函数不支持递归。首先,函数的参数列表必须是signal类型的,所以在递归调用自己时,必须传递signal类型的参数;第三,函数体内部只能定义variable类型的中间变量,所以如果需要signal类型的参数,只能从参数列表来;最后,参数列表中的signal方向都是in,即不能再function内部进行修改;最后,如果同样的参数和内容被递归调用,那么该怎么设置递归结束条件呢?所以,这样只能是一个死循环,编译器无法通过,即使通过了,仿真器也会卡死。
7、函数调用总体来说是并行语句。但是有时候也可以出现在串行语句中,例如另一个函数体内或另一个过程体内。

过程

过程即procedure,它的参数可以是in,out或者inout方式,但是不能为buffer方式。所以过程没有返回值,但可以通过改变参数来向调用方返回相关信息。Procedure的一般语法如下:

Procedure <procedure_name> (signal/variable <signal/variable _name> : <direction> <type>; <other signal or variable>) IS<variable declare>
Begin
<statements>; -- 串行语句
End <procedure_name>;

关于procedure的语法有以下几点说明:
1、参数列表可以是signal也可以是variable;
2、过程语句体内只能定义variable;
3、过程支持嵌套,即过程里面可以调用别的过程。
4、过程里面可以调用函数,相当于把函数里面的语句平铺到过程语句中。虽然这与函数调用语句是并行的不相符,不过编译器一般是可以通过的。
5、过程支持递归调用。即过程可以调用它自己,不过此时过程的输入类型参数必须为variable,否则也会由于无法修改而导致无法设置循环结束条件。
6、过程调用是串行语句,不能单独出现在architecture下。

子程序使用总结

子程序可以出现在architecture的声明与定义部分,也可以出现在库的程序包中。它们常用于多层次的电路综合设计,这点与元件例化的功能从本质上来说是一样的,只不过调用时更加方便、简练,尤其是对定义在库中的子程序来说。但是子程序的抽象级别比较高,不方便写出一些硬件方面的优化,也不方便很好的去掌控硬件,而且概念接近于软件,它更像是为整个VHDL程序体系打基础所用,为编译器、仿真器而服务,而不像为了具体设计硬件代码而出现。因此,一般情况下,即使再复杂的系统,都是通过元件例化来实现层次化电路综合设计的。所以,对于初级用户,建议不要使用子程序,而对于中、高级用户,请在修炼前做好充分准备,否则很容易走火入魔呦!

程序包

程序包即库中的package,它就是VHDL为了使一组常量、数据类型、子程序甚至元件等内容能够被多个实体可见而提供的一种结构。也许大家会有疑问,自己编写的元件不是会自动放在work库中的供别的VHDL代码调用么,为什么还要放在package中呢?首先,我们是可以显式的把元件添加到work库中某一个package的,虽然感觉有些画蛇添足,但这不错;其次,有些元件并不是我们在代码中自己编写的元件,而是一些在其他程序中预定义的元件,例如每个FPGA厂商都有自己的原语库,如果要使用这些原语,必须声明这些库中的程序包。例如编程时需要用到xilinx的原语,必须声明:

library UNISIM;
use UNISIM.VComponents.all;

那么,这个VComponents程序包中必然包含了元件的声明。
Package的语法如下:

library <library_name>;
use <library_name>.<packege_name>.<function_name>;package <Package_Name> is
-- new type declare use record statement
-- Declare constants
-- Declare functions and procedure
-- Declare component
end <Package_Name>;package body <Package_Name> is
-- funtion
-- Procedure
end <Package_Name>;

可见,程序包主要分为包头和包体两部分。
包头主要用于常量、数据类型、子程序甚至元件的声明,而包体主要用于子程序的具体实现。
子程序的声明和实现类似C语言中函数的声明和定义。
Function的声明语法如下:
Function <function_name> (signal : in <paramter_type>; ) Return <result_type>;
Procedure的声明语法如下:
Procedure <procedure_name> (signal/variable <signal/variable _name> : ; );

自定义程序包范例

关于自定义库文件,我们通过介绍一个自定义程序包的设计和使用范例,来给大家加深一下印象,并且大家可以参考范例复习一下自定义库中的各种语法。范例代码如下:
– 自定义程序包 testPack.vhd文件

library IEEE;
use IEEE.STD_LOGIC_1164.all;
use IEEE.STD_LOGIC_ARITH.ALL;package testPack is
-- Define new data type  type person isrecordid        : std_logic_vector(7 downto 0);sex       : std_logic;salary    : std_logic_vector(15 downto 0);end record;
-- Declare constantsconstant average_salary : std_logic_vector(15 downto 0) := conv_std_logic_vector(3500, 16);
-- Declare functions and procedurefunction income_level_func (signal salary : in std_logic_vector(15 downto 0)) return std_logic;procedure income_level_pro (signal salary : in std_logic_vector(15 downto 0); signal result : out std_logic);
end testPack;package body testPack isfunction income_level_func(signal salary : in std_logic_vector(15 downto 0)) return std_logic isvariable result : std_logic;beginif (salary >= conv_std_logic_vector(3500, 16)) thenresult := '1';elseresult := '0';end if;return result; end income_level_func;procedure income_level_pro (signal salary : in std_logic_vector(15 downto 0); signal result : out std_logic) is    beginif (salary >= conv_std_logic_vector(3500, 16)) thenresult <= '1';elseresult <= '0';end if;end income_level_pro;
end testPack;-- Desire.vhd文件
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use work.testPack.all;entity Desire is
port (husband : in person;wife : in person; husband_salary_level : out std_logic;wife_salary_level : out std_logic;family_mode : out std_logic;family_salary_level : out std_logic
);
end Desire;architecture Behavioral of Desire is
signal family_income : std_logic_vector(15 downto 0);
signal family_salary : std_logic_vector(15 downto 0);
begin
husband_salary_level <= income_level_func(husband.salary);process(wife)
beginincome_level_pro(salary => wife.salary,result => wife_salary_level);
end process;family_income <= husband.salary + wife.salary;
family_salary <= '0' & family_income(15 downto 1);
family_salary_level <= '1' when family_salary >= average_salary else'0';
family_mode <= wife.sex xor husband.sex;
end Behavioral;
上述例子完成了两个功能:

一、判断家庭收入在我国2011年年中调整工资收税起征点到3500后的收入水平的功能。包括丈夫的收入水平、妻子的收入水平以及家庭平均水平。通过逻辑值’1’表示收入高于社会平均水平,’0’表示低于社会平均水平。
二、判断家庭组成状况的功能。family_mode为’1’表示一男一女组成的正常家庭,为’0’表示同性恋家庭。

FPGA之道(30)编写自己的vhdl库文件相关推荐

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

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

  2. FPGA之道(43)编写纯净的组合或时序逻辑

    文章目录 前言 编写纯净的组合或时序逻辑 组合逻辑描述方法 范例介绍 注意事项 注意语句顺序 纯时序逻辑描述方法 范例介绍 注意事项 避免敏感双沿 注意语句顺序 清晰的时序逻辑描述方法 范例介绍 无伤 ...

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

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

  4. FPGA之道(37)Verilog中的编写注意事项

    文章目录 前言 Verilog中的编写注意事项 大小写敏感 Verilog中的关键字 范围定义的正确使用 不要省略begin与end 注释中斜杠的方向 编译指令中的前导符号 混用阻塞和非阻塞赋值的危害 ...

  5. FPGA之道(28)VHDL的并行语句

    文章目录 前言 VHDL的并行语句 VHDL直接信号赋值语句 VHDL条件式信号设置语句 VHDL选择式信号设置语句 VHDL进程语句 时钟事件表示方法 纯组合process 纯时序process 具 ...

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

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

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

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

  8. FPGA之道(84)功能仿真之Verilog Test Fixture

    文章目录 前言 Verilog Test Fixture "Hello world"之Verilog Test Fixture 待仿真设计 仿真示例 示例详解 仿真结果 继承描述语 ...

  9. FPGA之道(58)关于外界接口的编程思路

    文章目录 前言 关于外界接口的编程思路 按传递方向分类 输入接口 输出接口 双向接口 原理简介 工作模式 主从模式 对等模式 简单示例 按电气特性分类 单端接口 差分接口 无线接口 按功能特性分类 时 ...

最新文章

  1. 数据库期末复习之并发控制
  2. php mcript(),PHP基于mcript扩展实现对称加密功能
  3. 他爬取了B站所有番剧信息,发现了这些……
  4. spring常见面试问题_Spring面试问题
  5. 普通话/汉语发音口型大全
  6. 03_zookeeper伪集群安装
  7. 专访阿里数据库备份专家 教你pick最有效的备份系统
  8. Kubernetes 1.13 版本发布:Kubeadm简化群集管理、容器存储接口(CSI)和CoreDNS作为默认DNS现已普遍可用
  9. 神经网络中的稀疏编码和自动编码了解一下
  10. 教你分清敏感度和特异度
  11. 电气版CAD学习笔记
  12. 01 JavaScript的前世今生
  13. 在线英文打字测试(php)
  14. 鼠标式光流传感器与多传感器融合
  15. 华为可以更新鸿蒙系统,华为手机如何升级鸿蒙系统 步骤如下
  16. 2022-2027年中国非标自动化设备行业市场深度分析及投资战略规划报告
  17. 【Luogu P4766】 [CERC2014]Outer space invaders(区间dp)
  18. 现代控制理论第一章学习笔记
  19. SqlSugar 1.基础查询
  20. 禁用 Firefox 自动更新(macOS 版)

热门文章

  1. .htaccess 禁止IP访问
  2. HTC Element Behaviors in Internet Explorer.
  3. 华为java安全编码规范_Java安全编码之SQL注入
  4. 炫酷大屏demo_可视化大屏动态效果
  5. python打印表格_使用 Python 打印漂亮的表格,这两项基本功你可会?
  6. 不间断电源ups标准_UPS不间断电源全套基础知识
  7. reddit android app,reddit安卓版app
  8. php 降序 保留索引,PHP asort():对数组排序(升序),并保持索引关系
  9. linux下软件编译终止,[2018年最新整理]linux下编译运行程序命令大全.ppt
  10. 基于英飞凌AURIX的平衡单车组逐飞BLDC项目开源