Menu Close

VHDL IEEE库与std_logic数据类型

VHDL语言架构中定义了基本类型,并对基本数据类型操作定义了各种函数,这些数据类型和操作函数已经集成到standard库中。由于standard库作为VHDL语言的基本库,在使用VHDL语言时已经自动作为VHDL语言的一个部分,因此不需要使用library和use语句声明和打开该库。但由于standard库提供的基本类型对于电路的描述和仿真不够准确和丰富,功能有限,因此IEEE以及其它EDA软件开发上都一定程度上开发了支持VHDL语言可以综合和仿真的功能强大的库和数据包,供VHDL的用户使用。但除了Standard库中定义的数据类型和函数外,使用其它的任何库和数据包都要预先声明和打开,如使用IEEE定义的std_logic类型及操作,需要再实体文件的实体(entity)描述之前,使用如下语句:

library  ieee;

use  ieee.std_logic_1164.all;

其中ieee作为一个库,其中包含多个程序包,每个程序包中又包含多个数据类型,因此使用时一般采用all,指明可以使用该程序包中的所有内容。本文将介绍IEEE库中的程序包并着重介绍std_logic_1164程序包中std_logic数据类型。

1. IEEE库

在VHDL2008版本中,知名EDA软件商都支持IEEE库,并将IEEE库集成到软件中,如Vivado在安装后可以找到目录c:/Xilinx/Vivado/2021.2/data/vhdl/2008/IEEE,如图1所示。当然不同的EDA软件该库的路径可能不同,但IEEE库中的内容却是相同的。

%title插图%num

图1

从图1所示的内容可以看出,该库中包含许多程序包,其中包括浮点类型数据处理的程序包(float_pkg.vhdl),数值(numeric)到位(bit)的转换库,std_logic类型库(std_logic_1164.vhdl)等。如果要使用IEEE库了的任何程序包,需要在VHDL文件的实体之前使用libarary ieee;语句引用。之后选择要使用的程序包如std_logic_1164,则使用use语句打开该程序包。从图1显示的内容我们还可以看出,程序包一般由两个文件组成,如std_logic_1164程序包包含std_logic_1164.vhdl和std_logic_1164-body.vhdl两个文件, 其中std_logic_1164.vhd是程序包的头文件,std_logic_1164-body.vhd是程序包的包体,包体是包头中定义的操作函数的实现文件,这一点与C语言非常类似。程序包的头文件一般包括数据类型的定义,以及操作函数的函数名,而包体包含了操作函数的具体实现。在下面将要介绍的std_logic_1164程序包中可以清楚的看到这一点。

2. std_logic_1164程序包

  • std_ulogic及std_logic类型的必要性

在std_logic_1164程序包中定义了std_ulogic 和std_logic两种类型。在前面的文章中已经介绍了在standard库中已经有了bit类型,为什么还要定义std_logic类型?我们知道在数字电路的模型中除了0,1分别代表高低电平外,在接口电路还有高阻抗类型,高阻主要用来描述漏极或集电极开路以及三态电路模型。三态或开路模型可以实现总线共享。如图2-1,图2-2,图2-3所示。

%title插图%num

图2-1  三态输出并联连接

%title插图%num

图2-2 漏极开路并联上拉(线与)

%title插图%num

图2-3  漏极开路并联下拉(线或)

首先根据图2-1,图2-2,图2-3所示电路,我们分析如下几种在数字系统设计时需要处理情况,

(1)在输出端如果由两组或多组三态门共享电路的情况。如图2-1的电路端口a与b链接在一起,结果如何呢?

  • 分时复用,a 输出时,b的输出应为高阻,此时b端口可以作为输入端口,反之亦然。但如果使用语言描述,则b<=a_out & b_out; a_out输出为0或1, b_out输出应为高阻Z, 因此VHDL 语言应添加一个数据类型’Z’才能正确描述该电路行为。
  • 在端口a,b转换的交界处,a, b可能会同时处于输出状态,此时又如何呢?即a_out=0, b_out=1;如果想要正确描述该行为,应添加一个类型X,用来描述结果未知。

(2)在图2-2的电路中,是漏极(或集电极)开路共享总线的情况,也是常用的电路,著名的I2C的总线就采取这种类型。分析如下:

  • a,b同时为输出的时,且a, b都意图输出高电平(a,b对于的MOS管的栅极都为低电平),但由于MOS管的输出端没有驱动,因此在a,b的短接处应该输出Z。
  • 如果a,b端口出接上拉电阻,此时端口处的结果应该出现三者参与线与运算,即a_out, b_out, 以及上拉电阻的输出Vpull_up, 此时Vpull_up应为高电平, 因此在输出端可以的如下运算结果:输出端啊,b任何一个为低电平,结果为低电平,只要两个同时为高电平(高阻)时,输出为高电平。输出端线与是多重驱动的一种,这种线与需要决断,可以采用决断函数解决多重驱动问题。可见虽然Vpull_up为高电平,但当其中有一个为低电平时,输出端决定低电平,而不是由Vpull_up决定。因此同是高低电平的多重驱动,其强弱也是不同的。为了合理描述这种行为,VHDL语言在std_logic类型中引入了’H’类型,即高电平,但又弱于‘1’, 因此称为弱‘1’。

(3)在图2-3所示电路中,如果a,b端口出接下拉电阻

  • 此时端口处的结果应该出现三者参与线或运算,即a_out, b_out, 以及下拉电阻的输出Vpull_down, 此时Vpull_down应为低电平, 因此在输出端可以的如下运算结果:当两个输出端a,b任何一个为高电平时,输出为高电平,只要两个输出端都为高阻时,输出为低电平。可见下拉电阻与a,b输出端之间也有强弱之分,VHDL语言在std_logic类型中引入了’L’类型,即低电平,但又弱于‘0’, 因此称为弱‘0’。输出端线与是多重驱动的一种,这种线与需要决断,可以采用决断函数解决多重驱动问题。

其次在逻辑化简时有无关项的使用,在存储器和变量的使用时又会出现初始化和未初始化的情况等类型,因此在std_logic类型中引入’U’表示未初始化,‘-’表示无关,‘W表示弱未知。

  • std_ulogic与std_logic的定义

在std_logic_1164的程序包中,std_ulogic及std_logic的定义如下:

type std_ulogic is (  'U',             -- Uninitialized,
                      'X',             -- Forcing  Unknown
                      '0',             -- Forcing  0
                      '1',             -- Forcing  1
                      'Z',             -- High Impedance
                      'W',             -- Weak     Unknown
                      'L',             -- Weak     0
                      'H',             -- Weak     1
                      '-'              -- Don't care
                      );

在std_logic_1164的程序包中首先定义了std_ulogic类型,是采用枚举类型定义的,总共九个状态。需要注意,std_ulogic定义的9态中的字符都是大写字符, 虽然VHDL语言中的标识符和关键字一般不区分大小写,但单引号括起来的字符是区分大小写的。虽然定义了9态的std_ulogc类型,但还不足以完成对图2-1.2-2.2-3的各种描述。主要原因是,std_ulogic只定义了信号的各种状态,但对于多重驱动的结果尚未给出明确的结果,因此在std_logic_1164的程序包中又给出了std_logic的定义。std_logic的定义如下:

subtype std_logic is resolved std_ulogic;

可见std_logic并不是一个全新的数据类型,而是对std_ulogic进行约束的一个子集。其中resolved是一个函数,及当使用std_logic声明的信号或端口,当发生多重驱动时如何解决多驱动下的输出。见VHDL中std_ulogic与std_logic的区别。

  • std_ulogic_vector 及std_logic_vector矢量类型

在std_logic_1164程序包中不仅定义了std_ulogic及std_logic 数据类型,决断函数,还定义了std_ulogic_vector和std_logic_vector矢量类型。std_ulogic_vector及std_logic_vector的定义格式如下:

type    std_ulogic_vector  is  array (natural range <>)  of  std_ulogic;

subtype std_logic_vector   is (resolved) std_ulogic_vector;

可见std_logic_vector也是std_ulogic_vector子类型,并不是一个全新的矢量类型。在std_logic_vector基础上又定义了几种子类型:

 

subtype X01 is resolved std_ulogic range 'X' to '1'; -- ('X','0','1')
subtype X01Z is resolved std_ulogic range 'X' to 'Z'; -- ('X','0','1','Z')
subtype UX01 is resolved std_ulogic range 'U' to '1'; -- ('U','X','0','1')
subtype UX01Z is resolved std_ulogic range 'U' to 'Z'; -- ('U','X','0','1','Z')

 

  • 程序包std_logic_1164中的函数

程序包一般会分成两个部分,即程序包的包首(包头)和包体, 一般把数据类型的定义以及函数的定义部分放在在程序包的包首中,而把函数的实现部分放在程序包的包体中。在程序包引用时只需要用USE语句打开程序包的包首即可。例如std_logic_1164程序包在IEEE库中就有两个文件分别为:

            std_logic_1164.vhdl和std_logic_1164-body.vhdl, 这两个文件分别为程序包std_logic_1164的包首和包体, 但在引用时只需USE std_logic_1164.all即可,无需再单独使用USE语句打开包体。

由于VHDL是一种强类型语言,即不同的数据类型之间不能直接参与运算,不同位宽的矢量也不能直接参与运算,同时std_logic_1164程序包定义的数据类型又不是VHDL的预定义类型,因此在该程序包中还定义了大量的函数用于该程序包中定义的数据类型的操作。程序包中的函数多数是操作函数及其重载函数,更确切的说是操作符和重载操作符,如:

(1)逻辑操作符:

 (1) std_ulogic_vector 逻辑运算符,
function "and"  (l, r : std_ulogic_vector) return std_ulogic_vector;
function "nand" (l, r : std_ulogic_vector) return std_ulogic_vector;
function "or"   (l, r : std_ulogic_vector) return std_ulogic_vector;
function "nor"  (l, r : std_ulogic_vector) return std_ulogic_vector;
function "xor"  (l, r : std_ulogic_vector) return std_ulogic_vector;
function "xnor" (l, r : std_ulogic_vector) return std_ulogic_vector;
function "not"  (l    : std_ulogic_vector) return std_ulogic_vector;
(2)std_ulogic_vector逻辑运算符重载
function "and"  (l : std_ulogic_vector; r : std_ulogic) return std_ulogic_vector;
function "and"  (l : std_ulogic; r : std_ulogic_vector) return std_ulogic_vector;

function "nand" (l : std_ulogic_vector; r : std_ulogic) return std_ulogic_vector;
function "nand" (l : std_ulogic; r : std_ulogic_vector) return std_ulogic_vector;

function "or"   (l : std_ulogic_vector; r : std_ulogic) return std_ulogic_vector;
function "or"   (l : std_ulogic; r : std_ulogic_vector) return std_ulogic_vector;

function "nor"  (l : std_ulogic_vector; r : std_ulogic) return std_ulogic_vector;
function "nor"  (l : std_ulogic; r : std_ulogic_vector) return std_ulogic_vector;

function "xor"  (l : std_ulogic_vector; r : std_ulogic) return std_ulogic_vector;
function "xor"  (l : std_ulogic; r : std_ulogic_vector) return std_ulogic_vector;

function "xnor" (l : std_ulogic_vector; r : std_ulogic) return std_ulogic_vector;
function "xnor" (l : std_ulogic; r : std_ulogic_vector) return std_ulogic_vector;

(3)规约运算符(缩减运算符

function "and"  (l : std_ulogic_vector) return std_ulogic;
function "nand" (l : std_ulogic_vector) return std_ulogic;
function "or"   (l : std_ulogic_vector) return std_ulogic;
function "nor"  (l : std_ulogic_vector) return std_ulogic;
function "xor"  (l : std_ulogic_vector) return std_ulogic;
function "xnor" (l : std_ulogic_vector) return std_ulogic;

(2)移位运算符

function "sll" (l : std_ulogic_vector; r : integer) return std_ulogic_vector;
function "srl" (l : std_ulogic_vector; r : integer) return std_ulogic_vector;
function "rol" (l : std_ulogic_vector; r : integer) return std_ulogic_vector;
function "ror" (l : std_ulogic_vector; r : integer) return std_ulogic_vector;

(3)类型转换函数

function to_bit (s : std_ulogic; xmap : bit := '0') return bit;
function to_bitvector (s : std_ulogic_vector; xmap : bit := '0') return bit_vector;

function to_stdulogic       (b : bit) return std_ulogic;
function to_stdlogicvector  (b : bit_vector) return std_logic_vector;
function to_stdlogicvector  (s : std_ulogic_vector) return std_logic_vector;
function to_stdulogicvector (b : bit_vector) return std_ulogic_vector;
function to_stdulogicvector (s : std_logic_vector) return std_ulogic_vector;

alias to_bit_vector is to_bitvector[std_ulogic_vector, bit return bit_vector];
alias to_bv is to_bitvector[std_ulogic_vector, bit return bit_vector];

alias to_std_logic_vector is to_stdlogicvector[bit_vector return std_logic_vector];
alias to_slv is to_stdlogicvector[bit_vector return std_logic_vector];

alias to_std_logic_vector is to_stdlogicvector[std_ulogic_vector return std_logic_vector];
alias to_slv is to_stdlogicvector[std_ulogic_vector return std_logic_vector];

alias to_std_ulogic_vector is to_stdulogicvector[bit_vector return std_ulogic_vector];
alias to_sulv is to_stdulogicvector[bit_vector return std_ulogic_vector];

alias to_std_ulogic_vector is to_stdulogicvector[std_logic_vector return std_ulogic_vector];
alias to_sulv is to_stdulogicvector[std_logic_vector return std_ulogic_vector];

(4)关系运算符

function "?=" (l, r : std_ulogic) return std_ulogic;
function "?=" (l, r : std_ulogic_vector) return std_ulogic;

function "?/=" (l, r : std_ulogic) return std_ulogic;
function "?/=" (l, r : std_ulogic_vector) return std_ulogic;

function "?<" (l, r  : std_ulogic) return std_ulogic;
function "?<=" (l, r : std_ulogic) return std_ulogic;
function "?>" (l, r  : std_ulogic) return std_ulogic;
function "?>=" (l, r : std_ulogic) return std_ulogic;

(5)字符串及写操作

-- string conversion and write operations
 -------------------------------------------------------------------
 -- the following operations are predefined

 -- function to_string (value : std_ulogic) return string;
 -- function to_string (value : std_ulogic_vector) return string;

 -- explicitly defined operations

 alias to_bstring is to_string [std_ulogic_vector return string];
 alias to_binary_string is to_string [std_ulogic_vector return string];

 function to_ostring (value : std_ulogic_vector) return string;
 alias to_octal_string is to_ostring [std_ulogic_vector return string];

 function to_hstring (value : std_ulogic_vector) return string;
 alias to_hex_string is to_hstring [std_ulogic_vector return string];

 procedure read (l : inout line; value : out std_ulogic; good : out boolean);
 procedure read (l : inout line; value : out std_ulogic);

 procedure read (l : inout line; value : out std_ulogic_vector; good : out boolean);
 procedure read (l : inout line; value : out std_ulogic_vector);

 procedure write (l : inout line; value : in std_ulogic; justified : in side := RIGHT; field : in width := 0);
 procedure write (l : inout line; value : in std_ulogic_vector; justified : in side := RIGHT; field : in width := 0);

 alias bread is read [line, std_ulogic_vector, boolean];
 alias bread is read [line, std_ulogic_vector];
 alias binary_read is read [line, std_ulogic_vector, boolean];
 alias binary_read is read [line, std_ulogic_vector];

 procedure oread (l : inout line; value : out std_ulogic_vector; good : out boolean);
 procedure oread (l : inout line; value : out std_ulogic_vector);
 alias octal_read is oread [line, std_ulogic_vector, boolean];
 alias octal_read is oread [line, std_ulogic_vector];

 procedure hread (l : inout line; value : out std_ulogic_vector; good : out boolean);
 procedure hread (l : inout line; value : out std_ulogic_vector);
 alias hex_read is hread [line, std_ulogic_vector, boolean];
 alias hex_read is hread [line, std_ulogic_vector];

 alias bwrite is write [line, std_ulogic_vector, side, width];
 alias binary_write is write [line, std_ulogic_vector, side, width];

 procedure owrite (l : inout line; value : in std_ulogic_vector; justified : in side := RIGHT; field : in width := 0);
 alias octal_write is owrite [line, std_ulogic_vector, side, width];

 procedure hwrite (l : inout line; value : in std_ulogic_vector; justified : in side := RIGHT; field : in width := 0);
 alias hex_write is hwrite [line, std_ulogic_vector, side, width];

由于运算符及重载都是由函数实现,在后续章节会结合std_logic_1164-body 详细介绍函数的实现以及使用方法。由于VHDL内容过于丰富和细节繁杂,因此本教材内容都是循序渐进的方法介绍各个知识点,并结合大量实例和操作练习,做到由浅入深,逐步掌握利用VHDL语言进行IC电路设计。

 

 

Posted in FPGA, FPGA 教材教案, VHDL, VHDL, 开发语言, 教材与教案, 文章, 编程语言

发表回复

相关链接