VHDL与可编程逻辑器件设计详解
- 格式:doc
- 大小:2.38 MB
- 文档页数:20
VHDL与可编程逻辑器件设计
山西师范大学物理与电子信息工程学院
李竹
Email:sxlizhu@
目录
第一章可编程逻辑器件和VHDL简介 (2)
1.1 可编程逻辑器件 (2)
1.2 VHDL简介 (5)
1.3 VHDL设计过程 (6)
第二章VHDL程序基本结构 (7)
2.1 库(Library) (7)
2.1.1库的种类 (8)
2.1.2库的使用 (9)
2.2 程序包(Package) (10)
2.3 实体(Entity) (12)
2.3.1类属和端口说明 (12)
2.3.2端口模式 (13)
2.3.3数据类型(TYPES) (13)
2.4 结构体(Architecture) (15)
2.4.1结构体命名 (16)
2.4.2定义语句 (16)
附录A词汇索引 (19)
参考文献及相关网站 (20)
第一章可编程逻辑器件和VHDL简介
本章主要介绍可编程逻辑器件和EDA发展,可编程逻辑器件的设计流程,最后简要介绍VHDL在可编程逻辑器件设计中的应用。
1.1 可编程逻辑器件
在20世纪中期之后,数字集成电路经历了小规模集成电路(SSI,Small Seale Integrated Circuit )、中规模集成电路(MSI,Middle Seale Integrated Circuit)、大规模集成电路(LSI,Large Seale Integrated Circuit)、超大规模集成电路(VLSI,Very Large Seale Integrated Circuit)以及许多具有特定功能的专用集成电路(ASIC,Application Specific Integrated Circuit)的演变历程。
随着微电子技术的发展,设计集成电路的任务已经不能也没有必要全部由器件生产商来独自承担,而许多研发单位和科研机构的工程师都可参与设计,因此出现了可编程逻辑器件(PLD, Programmable Logic Device)。
同时,随着世界电子产业的快速发展,电子设计自动化(EDA,Electronic Design Automation)也得到了充分的促进。
可编程逻辑器件PLD是20世纪80年代发展起来的器件,是一种由用户根据自己的需求来设计逻辑功能并可对此器件进行编程的器件。
目前我们常用的可编程逻辑器件具有体系结构和逻辑单元灵活、集成度高以及实用范围宽等特点。
它们又具有研发周期短、电路成本
低、开发便利等优点。
这些器件的出现使得我们的电子电路系统的设计有了很大的方便。
具体它有如下优点:
(1)电子系统的器件使用大大减小。
目前器件的生产成本中最大部分是封装和测试,利用一片集成度高的可编程逻辑器件可以代替许多个TTL逻辑器件,这样带来的好处是:实现同样的逻辑功能可编程逻辑器件所花费的成本较低,而且随着目前系统的逐渐扩大化,利用可编程逻辑器件也可以使得电路系统的面积减小,电路板的布局和布线简单、电源功耗降低、调试方便。
(2)设计灵活
如果用分立的TTL元件来设计电路,一旦做好了印刷电路板(PCB,Printed Circuit Board),要想更改其功能,必须通过跳线。
而且作为一个成品,为了系统的稳定安全,一般不允许跳线。
而用可编程逻辑器件代替分立元件,即使有部分功能需要更改,也不需要对器件的外部管脚进行处理,而是通过对器件的内部功能进行重新编程即可。
(3)高性能和高可靠性
可编程逻辑器件采用了最新的生产工艺和技术,性能优于一般的器件,速度比一般器件甚至高2个数量级。
采用可编程逻辑器件,可以使得电路板上的器件大大减少,自然稳定性也有很高的提高。
下面介绍目前常用的可编程逻辑器件,且简要介绍它们的结构。
1.复杂可编程逻辑器件(CPLD,Complex Programmable Logic Device)
CPLD允许具有许多的输入输出信号、乘积项和宏单元,内含多个逻辑块。
这些逻辑块可以利用可编程内连线的布线来实现相互间的连接,它有效节约了硅片使用面积,提高性能,降低成本。
CPLD的结构如图1-1
图 1-1 CPLD结构
由CPLD的结构图可知,其内部主要包含:可编程内连线(Programmable Interconnect)、逻辑块(Logic Block)和输入/输出单元(I/O cells)三部分。
(1)可编程内连线
可编程内连线用于I/O到逻辑块输入、逻辑块的输出到自身输入、逻辑块的输出到其它逻辑块的输入的信号连线。
有的逻辑块有自身的内部反馈,不需要把输出反馈到可编程内连线上。
(2)逻辑块
CPLD中的一个逻辑块就类似于一个PLD,它包含乘积项阵列(Product-Term Array)、
乘积项分配机构(Product-Term Distribution Scheme)、宏单元(Macro-cell)。
乘积项阵列说明的是可编程与门(乘积项)。
其阵列的容量大小是一个重要的指标,它定义了每个宏单元乘积项的平均数量和每个逻辑块乘积项的最大数量。
乘积项分配机构是分配乘积项到各个宏单元的规定和机构。
乘积项分配机构允许一个扩展乘积项(Expander Product Terms)可以单独地分配给某一个宏单元或者多个宏单元。
这就给设计者的设计但来很好的灵活性,而且这些机构对那些用于如何利用逻辑资源的软件算法也带来灵活性。
宏单元通常包含一个寄存器(触发器)和具有极性控制的组合通路,以及一个和多个反馈通路。
所谓的极性控制就是指能够实现一个表达式的“原函数”或它的“反函数”,以便采用最少的乘积项来实现逻辑功能。
通常CPLD还包含I/O宏单元、隐埋宏单元和输入宏单元。
逻辑块的主要指标是逻辑块的大小,逻辑块的大小是指逻辑块的逻辑容量,就是在其中能够实现多少逻辑。
用宏单元的数目典型的表示逻辑块的大小,一般一个逻辑块包含4~20个宏单元,当逻辑块中所包含的宏单元高于16个时,意味着16位的函数就可以在单个逻辑块中实现。
(3)输入输出单元
输入输出单元是用来描述I/O缓冲器结构和输出使能控制的灵活性的。
大多数的输入/输出单元仅仅用来根据其输出使能状态来驱动信号从器件输出,以及为输入的外来信号提供一个输入数据通路。
2.现场可编程门阵列(FPGA,Field Programmable Gate Array)
如图1-2所示,FPGA是由一系列逻辑模块的阵列构成,通过可编程连线阵列可以将逻辑模块与逻辑模块、逻辑模块与可编程I/O模块进行互连。
FPGA利用密布的可编程开关来实现布线的连接。
水平通路
垂直通路
逻辑模块
图1-2 FPGA结构
它主要由三个基本部分组成:可配置逻辑模块CLB(Configurable Logic Block)、输入/输出模块I/OB(Input/Output Block)、可编程内连线PI(Programmable Interconnect)以及由它组成的编程开关矩阵PSM(Programmable Switch Matrix)。
可配置逻辑模块以方阵的形式布置在器件的中央,它包含多种逻辑功能部件,使它既能实现组合逻辑电路和时序逻辑电路,又能实现包括静态随机存储器的各种运算电路。
输入/输出模块分布在芯片的四周,它是提供外部封装引脚和内部信息的接口电路。
可编程内连线分布在可配置逻辑模块的周围和可配置逻辑模块与输入/输出模块之间,它们的主要作用是完成可配置逻辑模块之间的逻辑连接以及将信息传递到输入/输出模块。
目前,主要有两类主流技术可供在FPGA的开发中选择,一种是基于静态随机存储器(SRAM,Static Random Access Memory)工艺技术的FPGA,另一种是基于反熔丝工艺技术的FPGA。
市场上相对而言,基于SRAM工艺技术的FPGA器件所占份额相对较多。
尽管FPGA和CPLD都是可编程逻辑器件,但是由于它们结构上的差异,因此很多方面还有一定的差异:
1>应用领域:CPLD是属于粗粒结构的可编程逻辑器件,它具有丰富的逻辑资源(即逻辑门与寄存器的比例高)和高度灵活的路由资源,适合完成各种算法和组合逻辑;FPGA 是属于细粒结构的可编程逻辑器件,其基本单元和路由结构都比CPLD的小,它具有丰富的寄存器资源(即寄存器与逻辑门的比例高),更适合于完成时序逻辑。
2>布线方面:CPLD是基于逻辑块编程的,通过修改具有固定可编程内连线的逻辑功能来编程,其连续式布线结构决定了它的时序延迟是均匀的和可预测的;FPGA是基于逻辑门编程的,主要通过改变内部连线的布线来编程,其分段式布线结构决定了其延迟的不可预测性。
3>编程方式:CPLD主要是基于E2PROME或FLASH存储器编程,编程次数可达1万次,优点是系统断电时编程信息也不丢失,CPLD又可分为在编程器上编程和在系统编程两类;FPGA大部分是基于SRAM编程,编程信息在系统断电时丢失,每次上电时,需从器件外部将编程数据重新写入SRAM中,其优点是可以编程任意次,可在工作中快速编程,从而实现板级和系统级的动态配置。
4>其它方面:一般情况下,CPLD的功耗要比FPGA大,且集成度越高越明显;FPGA 的集成度比CPLD高,具有更复杂的布线结构和逻辑实现;CPLD保密性好,FPGA保密性差。
1.2 VHDL简介
VHDL(Very High Speed Integrated Circuit Hardware Description Language,超高速集成电路硬件描述语言)最早是由美国国防部为描述电子电路所开发的一种语言。
电路设计的表示可分为不同的层次,一般有5个抽象的层次:系统级(System Level)、算法级(Algorithmic Level)、寄存器传输级(Register Level)、门级(Gate Level)、电路级(Circuit Level),VHDL 囊括了如上的所有层次的设计。
VHDL提供高阶电路描述语言的方式可以让复杂的电路通过它轻而易举得到实现,因此它毫无疑问成为硬件设计工程师的必备工具。
VHDL作为硬件描述语言,具有如下特点:
1>功能与灵活性
VHDL具有功能强大的语言结构,可用简洁明确的代码描述来进行复杂控制逻辑的设计。
为了有效控制设计的实现,它还具有多层次的设计描述功能,支持设计库和可重复使用的元件生成,它支持阶层设计,且提供模块设计的创建。
2>非依赖器件
VHDL不需要首先选择一个用来实现设计的器件,而是可以直接先生成一个设计。
而且对于同一个设计描述,也可以采用多种不同器件结构和方法来实现其功能。
若需对设计进行优化,主要精力可集中到设计构思上,同时它也支持多种形式的设计描述。
3>可移植性
VHDL允许设计者可对需要综合的设计描述进行仿真,如果功能不是很完善,可以通过修改就可以在设计实现之前解决了问题,因为它是一个标准的语言,所以不同的工具不影响设计的正确性。
因此移植性指的就是从一个设计工具到另一个设计工具的移植、一个工作平台到另一个工作平台的移植。
4>性能评估
对设计的文件通过编译后,可以分析器件硬件资源的占用率,从而可适当的选择器件。
对算法进行设计的时候,可通过多次更改设计技术(如流水线技术)来分析延时和工作频率,
尤其对于数字信号处理方面更是需要注意的地方。
5>设计周期
在传统的硬件设计过程中,往往要求设计者在设计电路之前写出该电路的逻辑表达式或真值表(或时序电路的状态表)。
这一工作是相当困难和繁杂的,特别是当系统比较复杂时更是如此。
而且利用小规模的集成电路时,还有PCB制作过程中封装、布局、布线等必不可少的工作量。
而利用VHDL语言设计硬件电路时,就可以使设计者免除编写逻辑表达式或真值表之苦,从而大大降低了设计的难度,也缩短了设计的周期。
1.3 VHDL设计过程
利用VHDL设计一般需要如下几个设计过程:设计输入、编译、仿真、编程与验证。
设计过程如图1-3所示:
图 1-3 VHDL设计过程
1>设计输入
在从事设计进行编写代码工作之前,必须先对你的设计目的和要求有个确切的认识。
例如:要设计的功能是什么?系统工作的频率要求多高?是否需要采用模块化设计?是否需要参数化设计?只有明确了这些需求,才会在设计过程中不会走弯路,然后才能选择到适当的设计方式和相应的器件。
有了设计的需求分析后,可以尝试编写设计代码。
许多设计人员往往只是简单地参照和修改一些现成的设计方案来实现目的,因此为了目前的工作成果以后可以便利的使用,因此在设计过程中最好使用模块化和参数化的设计方法是值得提倡的。
2>编译
根据VHDL的语法和语义结构设计完成文本文件之后,需要检测是否有语法错误,此时需要采用编译的措施。
一个复杂的VHDL程序往往对于一般的设计者而言,总是难免有一定的语法错误,此时根据编译所报告的错误针对性的进行修改,每纠正一处语法错误,随后再次编译,再次纠正,反反复复,直到不再有语法错误的报告出现。
作为一个学习或者是使用VHDL 的人员,应该出现错误之后,记录出错的报告文字和纠正的措施,为以后进一步设计打下基础。
3>仿真
虽然编译通过,但是并不一定代表所设计的文本文件符合要求,还必须通过仿真才能给出判断。
仿真包括功能仿真和时序仿真两种。
功能仿真又叫前仿真,这种仿真不考虑信号的延时,主要检验逻辑功能的正确性。
时序仿真又叫后仿真,是进行布局布线后进行的仿真。
它在进行仿真时将信号在器件中的延时考虑进去,因此可以模拟器件实际工作时的情况。
在仿真过程中先进行功能仿真,随后再进行时序仿真,任何一种仿真不能符合目的要求,都需要重新设计。
重新设计后再仿真,直到仿真达到目的要求。
4>编程和验证
器件的编程是设计的最终目的,需要器件生产商提供的专用编程器,当然现在许多器件生产商提供了编程器的电路原理图和参数,设计人员也可以自己制作比较廉价的器件编程器。
将编程电缆和计算机正确连接之后,PCB加电就可以对器件进行编程。
编程以后还需要验证,在加入实际激励的情况下,检验是否设计能够完成预定的功能。
如果不能完成预定的功能需要重新进行如上的过程。
一般仿真通过的设计,都可以通过实际的验证。
第二章VHDL程序基本结构
一个完整的VHDL程序,或者说设计实体,通常包含5个部分:库(Library)、程序包(Package)、实体(Entity)、结构体(Architecture)、配置(Configuration)。
库存放已经编译的实体、结构体、包集合和配置,库可以重复使用。
程序中所使用的library,就如同C语言程序中的include。
在设计过程中,设计一个大规模的硬件电路,不需要从门级逐步设计,而是可以利用在库中保存的预先设计的或者软件自身所带的模块,这样可以使得设计成果达到共享,因此可以大大减少了设计的工作量,缩短了开发周期。
程序包集合存放各设计模块都能共享的数据类型、常数、子程序和元件定义。
多个程序包可以并入一个VHDL库中,使之适用于更一般的访问和调用。
实体是一个VHDL程序的基本单元,表现为一个设计的外貌,它是设计实体对外的一个通信界面,它用于描述所设计的系统的外部输入输出接口以及一些用于结构体的参数定义。
VHDL程序结构的一个显著特点就是任何一个完整的设计实体都可以分成内外两个部分,外面的部分成为可视部分,实体名和端口组成了设计实体的外面部分。
结构体和实体构成了设计实体的基本组成部分。
它用于描述系统内部的结构和行为、系统数据的流程或者系统组织结构形式。
每个实体可以有多个结构体,每个结构体对应着实体不同的结构和算法实现方案,它们的地位是同等的,共同来实现实体的行为。
配置用于描述层与层之间的连接关系和实体与结构体之间的连接关系。
2.1 库(Library)
在利用VHDL语言设计工程时,库主要用来存放已经编译的实体、结构体、程序包和配置。
为了提高设计效率且遵循统一的语言标准和数据格式,就有必要利用一个或者几个库来包含有用的信息,这些信息可以是数据类型、子程序包、各种已经设计好设计实体,因此也可以将库看作一个用来存放预先设计好的程序包和数据类型包的仓库。
当一个设计需要使用库中的单元时,要在每个设计的源代码的起始部分说明所引用的库,同时使用use子句指明要使用库中的哪一个设计单元。
2.1.1库的种类
VHDL语言中的库包含STD库、IEEE库、WORK库、VITAL库和用户自定义库,它们可以分为两大类:设计库和资源库,设计库对当前设计实体是永远可见的,如STD库和WORK库;资源库用来存放常规元件和模块,它和器件的厂商有直接的联系,在使用该库的时候,必须在VHDL的源代码起始部分显式表达出来,如IEEE库、VITAL库和用户自定义库。
下面对它们分别介绍。
1)STD库
STD库是VHDL的标准库,包含了两个标准的程序包STANDARD和TEXTIO。
程序包STANDARD中定义了BIT、BIT_VECTOR、CHARACTER、TIME等数据类型;程序包TEXTIO主要包含了文本文件进行读写操作的过程和函数。
因为程序包STANDARD符合VHDL语言标准,在使用时不需要说明,但是在使用程序包TEXTIO时,库和程序包必需说明。
如:程序包TEXTIO的说明
LIBRARY STD;
USE STD.TEXTIO.ALL;
该程序包主要在测试中使用。
而没有必要对程序包STANDARD进行说明,如:
LIBRARY STD;
USE STD. STANDARD.ALL;
2)IEEE库
IEEE库是VHDL设计时,应用频率最高的库,它包含符合IEEE标准的程序包和非IEEE 标准但支持工业标准的程序包。
符合IEEE标准的程序包包含STD_LOGIC_1164、NUMERIC_BIT、NUMERIC_STD等,其中程序包STD_LOGIC_1164是设计是最常用和最重要的包。
非IEEE标准但是并入IEEE库的程序包有STD_LOGIC_ARITH、STD_LOGIC_SIGNED、STD_LOGIC_UNSIGNED等。
一般VHDL设计时,主要用到了四个程序包:STD_LOGIC_1164、STD_LOGIC_ARITH、STD_LOGIC_SIGNED、STD_LOGIC_UNSIGNED。
值得注意的时,符合IEEE标准的程序包并非符合VHDL语言标准,因此使用程序包STD_LOGIC_1164时,需要显式表达出来。
如
LIBRARY IEEE;
USE STD_LOGIC_1164.ALL;
3)WORK库
WORK库是使用者现行工作库,当设计者保存和编译一个设计时,自动默认为存放在WORK库中,设计者就可以将已经编译过的元件和模块保存到WORK库中,以便以后设计时调用该库中的元件和模块。
因为该库中的元件和模块是设计者在VHDL环境下生成的,所以该库是符合VHDL语言标准的,而且该库是可见的,所以在使用该库时,不需要显式说明,实际上VHDL的源代码起始部分已经隐含了如下代码:
LIBRARY WORK;
4)VITAL库
VITAL(VHDL initiative towards ASIC library)库,用来提高仿真VHDL门级时序的精度,它只是在仿真器中使用,库中包含了两个程序包VITAL_TIMING和VITAL_PRIMITIVES,VITAL库已经并入到IEEE库中,成为IEEE标准。
实际上各可编程器件生产厂商都能为自己生产的芯片生成含有时序信息的门级网表,用这些网表就可以得到非常精确的时序仿真结果,因此,在FPGA/CPLD设计开发设计中,一般不需要VITAL库
中的程序包。
5)自定义库
就像设计者设计实体一样,设计者也可以设计自己的库,这种库称为自定义库或者用户库。
自定义库主要包含公用包集合、实体或者通过交流得到的设计实体。
它可以灵活地使用用户自己定义的一些单元,在使用自定义库时,需要在VHDL源代码的起始部分显式表达出来。
2.1.2库的使用
库说明语句的书写格式如下:
LIBRARY <库名>;
以保留字LIBRARY开始,紧跟其后的就是设计实体需要可见的库的名字。
除了将库打开,对库中的哪一个设计单元调用时,还需要在设计的VHDL源代码的起始部分进行说明,说明语句为USE语句,USE语句的书写格式如下:
USE <库名>.<程序包>.ALL;
USE <库名>.<程序包>.<项目名>;
其中库名就是前面库说明语句中已经说明过的库;程序包名就是设计实体要使用的库中的设计单元;ALL表示使用程序包中的所有项目;项目名表示使用程序包中的特定项目。
值得注意的是,程序包名所标志的程序包必须存放在前面所说明的库中,否则编译出错。
具体实例如下:
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.STD_LOGIC_1164.STD_ULOGIC;
另外,库语句和USE语句一旦说明之后,整个设计实体就可以访问和调用。
当一个设计系统要求多个设计实体时,必须每一个设计实体都有自身的库语句和USE语句。
具体实例如下:
LIBRARY IEEE; --第一个设计实体库使用说明
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY half_adder IS
......
END half_adder;
ARCHITECTURE a OF half_adder IS
......
END a;
LIBRARY IEEE; --第二个设计实体库使用说明
USE IEEE.STD_LOGIC_1164.ALL;
ENTITY xor_gate IS
......
END xor_gate;
ARCHITECTURE b OF xor_gate IS
......
END b;
2.2 程序包(Package)
在实体说明和结构体内部定义的数据类型、常量及子程序对其它设计单元是不可见的,即不可以在其它设计单元中使用,为了使数据类型、常量及子程序对若干个设计单元可见,VHDL提供了程序包机制。
程序包是一个库单元,也就是设计单元,它包含有可用于其它设计单元的一系列说明。
程序包的内容主要由以下四种基本结构组成,因此一个程序包中至少应包含以下结构中的一种。
常数说明:在程序包中的常数说明结构主要用于预定义系统的宽度,如数据或地址总线通道的宽度。
数据类型说明:主要用于在整个设计中通用的数据类型,例如通用的地址总线数据类型定义。
元件定义:元件定义主要规定在设计中参与元件例化的对外接口界面。
子程序:并入程序包的子程序有利于在设计中任一处进行方便地调用。
一个程序包可以分为两个单元:说明单元与包体单元。
说明单元为程序包定义接口,其方式与实体定义模块接口相类似;包体单元规定程序的实际功能,其方式与模块的结构体语句方法相类似。
程序包说明是主设计单元,它可以独立编译并插入设计库中。
程序包体是次级设计单元,它可以在其对应的主设计单元编译并插入设计库之后独立进行编译并也插入设计库中。
程序包说明单元及其对应的包体单元的一般格式如下所示:
PACKAGE 程序包名IS
--说明单元
END [PACKAGE] [程序包名];
PACKAGE BODY 程序包名IS
--说明单元
END [PACKAGE BODY] [程序包名];
程序包结构中,程序包包体并非是必须的,程序包说明可以独立定义和使用。
【例2.1】不需要包体的完整程序包
Library ieee;
Use ieee.std_logic_1164.all;
Use ieee.std_logic_unsigned.all;
package mypack1 is --程序包说明开始
constant pai:real:=3.1415; --定义常数圆周率
type bcd is range 0 to 9; --定义数据类型
subtype doublebit is bcd range 0 to 3; --定义子类型
signal aa: doublebit; --定义信号
end mypack1; --程序包说明结束
本程序包中,因为没有定义元件和子程序,所以不需要程序包体来具体规定实现的功能。
【例2.2】需要包体的完整程序包
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
package mypack2 is
max(in1,in2:in std_logic_vector) return std_logic_vector;--定义函数
procedure vec_to_int (input: in std_logic_vector(3 downto 0);
output:out integer); --定义过程end mypack2; --程序包说明结束package body mypack2 is --程序包包体开始function max(in1,in2:in std_logic_vector) return std_logic_vector is --函数描述
variable maximum:std_logic_vector(3 downto 0);
begin
if (in1<in2) then maximum:=in2;
else maximum:=in1;
end if;
return maximum;
end max;
procedure vector_to_int(signal input: in std_logic_vector(3 to 0); --过程描述
output: out integer) is
variable power:integer:=1;
variable temp:integer:=0;
begin
for i in 1 to 3 loop
power:=power*2;
if input(i)='1' then
temp:=temp+power;
end if;
end loop;
if input(0)='1' then
temp:=temp+1;
end if;
output:=temp;
end procedure;
end mypack2; --包体结束
例2.2中定义了一个取最大值的函数和一个将向量转换为整数的过程。
因为在程序包的说明中,只定义了接口对于函数和过程而言,只是提供了接口,设计时还必须将其内部的功能行为描绘出来,因此本程序包必需包含程序包包体。
包体说明的标识符是不可见的,只有在程序包说明单元中说明的标识符才在程序包之外可见。
另外,程序包中说明的标识符也不是自动对其它的设计可见的,而是需要使用USE 子句调用的。
使用方法同在库章节中讨论的一样。
下面给出一个访问例2.2的例子:
【例2.3】调用例2.2中的取最大值函数
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use work.mypack2.all;
entity mypack2_exam1 is
port (a,b: in std_logic_vector(3 downto 0);。