您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 项目/工程管理 > 三输入与非门VHDL讲解
贴心建议:初学时,对于简单的程序,先尽自己努力看懂每一句话,从字面上先去理解,通过英文单词的意思,自己先去琢磨该段程序所要实现的功能,然后再去和正确的意思相比对,这样比一开始就去看解释来的记忆深刻,这些是我自己的切身体会。1.三输入与非门在数字电路设计中,门电路是最基本的电路单元。在这里我们挑选了比较典型的三输入的与非门,完成我们的第一个设计。三输入与非门的逻辑表达式:FABC逻辑符号为:源代码:逐行解释:1:库声明。告诉编译器,我要使用这个库里的内容。语法是:LIBRARY库名;(结束有个分号的,别丢了,这个分号是每条语句的结束标志,每条语句最后都是要有分号的,这是它们的标配)。2~4:声明所选择的程序包名称,ALL就是打开整个程序包。一个库里当然有很多的程序包了,给编译器指明一下那个包要用,好缩小它的搜寻范围。别让它满库的找,怪费俺们的CPU的。语法:USE库名.程序包.程序包的组成部分;。一句话总结:1和2两句其实相当于C中的“#include”,使被声明的库和库中的元件对当前设计项目可见。发散:IEEE库是最重要的资源库,我们经常使用其中的一些信号定义和数据的定义。列举一下其中比较重要的几个程序包:(1)STD_LOGIC_1164:指定了STD_LOGIC和STD_ULOGIC逻辑系统&(2)STD_LOGIC_ARITH:包含SIGNED和UNSIGNED数据类型定义和相应的算术和比较操作还包含了几个数据转换函数,允许数据从一个类型转换为另一个类型。(3)STD_LOGIC_UNSIGNED:CONV_INTEGER(A)由INTEGER,UNSDGNED,SIGNED转换成STD_LOGIC_VECTOR由UNSIGNED,SIGNED转换成INTEGER(4)STD_LOGIC_SIGNED:包含了STD_LOGIC和STD_LOGIC_VECTOR其中,在一个程序中只要包含(1),(2),(3)就足够能应付绝大多的应用了。所以,我们建议你在程序库上和程序包的声明上可统一写成:把三个程序包全部打开(在综合时不会耗去太多的资源的),而不必再为使用哪些库,哪些程序包而大费脑子了.6~12:实体描述部分.6:实体名。语法:ENTITY实体名IS。也不知道是哪门子的法:竟然要求实体名和所在的vhdl文本名是一样的,或者Quaruts会报错的.没办法,Quaruts是人家编的,人家不去改进,咱只能顺着他们了.就像我们要好好学习VHDL,变成高手,到时候就不会任用人单位摆布了.7~11:端口说明.就相当于一个芯片的引脚了.a,b,c是输入引脚(IN),f是输出引脚(OUT).当然都有类型了,就象一个芯片手册里写的一样,有些是通用IO(即GPIO),有些是时钟输入脚,有些是地址总线.我们这里都是STD_LOGIC类型的.外部调用的话,就可根据要求直接”连接”这些引脚就行了.有点象OOP(面向对象设计)里的封装.呵呵.语法:PORT(端口名A:信号模式(即端口的数据流向)类型;端口名B:信号模式(即端口的数据流向)类型(最后一个没有分号));(这儿有分号)发散:信号的模式包括IN(输入),OUT(输出),inout(双向),buffer(缓冲).注意:out是不能在程序中读的,inout是双向的,可以反馈内部而被程序可读.假设O是输出端口,S是程序里面的一个信号,你想着程序中看看这个输出对不对,于是这样写S=O,你会得到一个error:Error(10309):VHDLInterfaceDeclarationerrorinnand3_gate.vhd(19):interfaceobjectOofmodeoutcannotberead.Changeobjectmodetobufferorinout.看看其建议是:Changeobjectmodetobufferorinout---改成buffer或inout模式,这样就以在程序中可读了。Buffer我在以后用到的时候再讲解。一点小的建议(也是为了程序的美观和规范):在书写端口时,输入端口先在前,再写双向端口,最后写输出端口。数据类型我们最常用的是STD_LOGIC和STD_LOGIC_VECTOR。STD_LOGIC中文名叫标准逻辑位,有九种可选值,包括(‘U’,‘X’,‘0’,‘1’,‘Z’,‘W’,‘L’,‘H’,‘-’),各种值得代表含义是:‘U’:未初始化的,‘X’:强未知的,‘0’:强0,‘1’:强1,‘Z’:高阻态,‘W’:弱未知的,‘L’:弱0,‘H’:弱1,‘-’:忽略。我们最常用的是0,1和Z这三种状态。STD_LOGIC_VECTOR叫标准逻辑矢量,说白了就是STD_LOGIC的集合,即相当于C中的数组,由STD_LOGIG组成的数组。区别:BIT和BIT_VECTOR只有0和1两种状态,其它相同。那如何定义STD_LOGIC_VECTOR的大小呢?用TO和DOWNTO这两个关键字。前者表示以升序排列信号,最高位在右边,后者表示以降序排列信号,最高位在左边。举个例子:SIGNALDATA_ASTD_LOGIC_VECTOR(7DOWNTO0);SIGNALDATA_BSTD_LOGIC_VECTOR(0TO7);-----------DATA_A=”1000_1110”-----即DATA_A[7…0]=10001110;DATA_B=”1000_1110”-----即DATA_A[7…0]=01110001;一组位数据要用双引号(“”),单个的位数据用单引号(‘’),而且数据的位数和你所定义的位数要一致,就象这个车载重量只能是5顿,你偏偏要载10顿,这样的话交警可是不会让你通过的。12.实体描述结束.。语法:END实体名;。14~18:结构体,是描述该实体的功能的。相当于C中的main()函数了。14:结构体名。语法:ARCHITECTURE机构体名OF实体名IS,就是指明该结构体是那个归那个实体所管。一个实体可有好多个结构体。15:结构体描述区.就是要定义一些在这个程序里要用的SIGNAL(信号),componet(元件)等信息.相当于C中的定义变量.在这个程序中我们没用这块区域.(已用”--”给注释掉了)16:开始标志。用BEGIN来标志.17:结构体的描述。包括元件映射语句,信号赋值语句,进程语句和子程序。在这个程序中就是一个信号赋值语句。发散:在这里介绍两个重要的数据对象:SIGNAL(信号)和VARIABLE(变量)。首先要说明一下:数据对象和数据类型还是两个不同的概念。数据对象只有常量(CONSTANT)、信号和变量三种,而常用的数据类型包括INTEGER(整数),REAL(实数),BIT(位),BIT_VECTOR(位矢量),STD_LOGIC(标准逻辑位),STD_LOGIC_VECTOR(标准逻辑矢量位),CHAR(字符),STRING(字符串)。先说SIGNAL和VARIABLE的不同:(1)语法定义:SIGNAL信号名1[,信号名2,…]:信号类型[:=初始值];VARIABLE变量名1[,变量名2,…]:变量类型[:=初始值];方括号里是指可选的,其中初始值只能在行为仿真时起作用,所以基本上没什么用。这个初始化值,可在Quartus里设置,但也是针对某些FPGA,很多FPGA在上电后,其内部的信号,变量的初始值是不定的。(2)赋值符号:信号为“=”,变量为“:=”。符号两边的数据类型要一致,因为VHDL是强类型语言。信号类似于电路内部的传输线,所以有传输延时,即赋值不能立即生效,要等一个所谓的&时延,要等到进程挂起的时候信号值才代入,换句话说,这个时刻进程改变的一个信号量要在下一个时刻的进程里才能起作用,而变量的赋值时立即生效的,脑子里要有这个意识.(3)变量顺序语句中使用,如进程,过程,函数(这三个概念在后面会介绍的)等,而信号在结构体描述区里定义(即程序中15句话的位置),它在该结构体内的任何位置都是有效的.(4)进程对变量敏感,而对信号不敏感.(敏感信号也会在下面介绍的)(6)信号要占用更多的存储器(5)在仿真的时候,信号可以在仿真波形图中可见,但变量却是不可见的,所以变量的调试变的困难.也是基于这个原因,好多人建议使用信号,少用变量.这个也因具体情况具体分析,不能一棒子把变量打死.若变量真的没用,那制定VHDL的那帮人岂不是白吃饭的?对于信号还有一个注意点,也是很多初学者容易犯的毛病,不能在不同的进程中对同一个信号进行赋值。这么想吧,若两个进程同时发生对同一个信号的赋值,那这个信号的值到底是哪一个呢?所以这种情况是应该避免的。我们说了,信号的赋值要在下一次进程动作时才能奇效,那么若你在上个时刻对同一个信号赋了多次值,那么有效的总是最后一次赋予的值。因为毕竟只有一个坑啊(信号的空间),只能放一个萝卜啊(信号值),而且信号赋值不是立即见效,那就只能是后面一个值覆盖前面一个值,只剩下最后一个值了。概括的说就是在同一个进程中,信号的多次赋值,起作用的只是最后一次。如:SIGNALA,B,CLK,S:STD_LOGIC;PROCESS(CLK,A)BEGIANIFA=’1’THENS=’1’;ENDIF;IFB=’1’THENS=’0’;ENDIF;ENDPROCESS;假设此时A=’1’,B=’1’,那么先执行S=’1’,然后S=’0’,S的第一次’1’值被后面的’0’值覆盖。我们就列出了这些关键不同点,还有一些不同点,在遇到的时候再去细细体会.顺便说一下常量吧,别冷落人家了.使用语法:CONSTANT常量名1[,常量名2,…]:常量类型:=常量值.如CONSTANTPI:=REAL:=3.1415926,这样程序中就可以用PI这个来代表这串小数了,增加了程序的可读性和可移植性,其实就类似于C中的宏定义”#define”17:结构体功能描述语句.这儿因为功能简单,所以只有一句话,就是一个简单的与或操作.发散:说说运算操作符吧.(1)逻辑运算符:其运算符的作用也可直接从字面意思上去理解.如NOT-反操作,AND-与操作,OR-或操作,NAND-与非操作,XOR-异或等.有两点需要说明:首先,其使用范围包括BIT,BIT_VECTOR,STD_LOGIC,STD_LOGIC_VECTOR,别把两个INTEGER做逻辑运算,这是不行的.其次,若运算对象是BIT_VECTOR和STD_LOGIC_VECTOR这种数组型的,则按位运算,所以要求两边的长度要一致;最后,就是多个运算符在一起时,关于如何结合的,VHDL有些规定.在这里我们只有一个建议:勤加括号,别让它产生含糊不明的意思.(2)算术运算符包括”+”,”-”,”/(除法)”,”*(乘法)”等,大家可以直接找本书看看,有些综合上的限制(3)关系运算符,有”=(是否相等)”,”/=(是否不相等)”,”=(是否小于等于)”等,这个关系运算结果只有”TRUE(真)”和”FALSE(假)”两种(4)移位运算符.如”SLL(逻辑左移)”,”SRL(逻辑右移)”,SRA(算术右移)”等,其中有个如何补位的问题,我们在碰到时再详解.(5)连接运算符”&”.这个很重要,用处也很多。其作用就是把多个元素或矢量合并.如两个信号A,B,C:SIGNALA,B,C:STD_LOGIC_VECTOR(7DOWNTO0)想要把A的高4位和B的低4位合成C,A的在高位,B的在低位就可以用下面一句话:C=A[7DOWNTO4]&B[3DOWNTO0];这种在提取数据并生产新数据时非常有用。呵呵,VHDL就擅长做这个。18:结构体描述结束。语法:END结构体名。第一节主要是刚开始,发散的知识点比较多。不要求全记下的,只要到知道在哪可以查到,忘了时再查看就行了,反复几次就能全记住了。其实语言只是思维的一种载体,我们学VHDL,用VHDL最终是锻炼了我们的逻辑思维。当我们有较强的逻辑思维后,所有的语言对于我们来说就只是工具了。良好的开始是成功的一半,努力!!!
本文标题:三输入与非门VHDL讲解
链接地址:https://www.777doc.com/doc-2334408 .html