重拾VHDL和Verilog系列(一)——VHDL编写结构

已经有几年没有接触过VDHL或者Verilog了,在大二时,对VHDL是如此的热爱,疯狂得不用看仿真只通过看代码就能知道问题所在,在那一年,我喜欢FPGA,喜欢了VHDL。

就在那一年,老师给我的项目失败了,可能是自己技术不到家(那时连SDRAM工作原理还不懂,却说要用VHDL实现SDRAM读写,当年还是有很多东西不了解,也没有自己的一套学习方法),为了不让老师失望,我决意转向ARM,从此,我与FPGA、VHDL失去了交集,渐渐地,我把VHDL遗忘了。。。。。

其中在那一年,虽然主攻VHDL,但对Verilog也有作过少许学习(毕竟Verilog学习资料多),只是随着时间的推移,Verilog与VHDL的转换已成为过去。

今年,我又有机会与VHDL产生交集,其实是我主动向上司要求,我想研究FPGA、VHDL,可以减轻团队的压力。

好了,费话了一堆。现在的我又要从头开始捡起VHDL了。

 

VHDL中的库文件包含:

在VHDL中,少不了一些标准库,如:std_logic这类声明,都是来源于ieee这个库的。

library ieee;
use ieee.std_logic_1164.all;

 

VHDL中实体声明:

和高级语言一样,VHDL也要声明,这时有点不同的是,这种声明是用于对外的接口,即输入/输出都在这里声明的。

entity CRC_Unit is
port(
      iBitVal : in std_logic;
      iClock : in std_logic;
      iClear : in std_logic;
      oCRC : out std_logic_vector(4 downto 0)
);
end CRC_Unit;

 

VHDL结构功能:

有了对外的接口外,还得有内部的处理,这样才能算是一个整体。architecture 就是对实体的内部功能的描述。

architecture ClacCRC of CRC_Unit is
signal inv : std_logic;
signal CRC : std_logic_vector(4 downto 0);

begin

inv <= iBitVal xor CRC(4);

process(iClock,iClear)
begin
      if iClear = '1' then
            CRC <= (others =>'0');
      elsif falling_edge(iClock) then
            CRC(4) <= CRC(3);
            CRC(3) <= CRC(2) xor inv;
            CRC(2) <= CRC(1);
            CRC(1) <= CRC(0) xor inv;
            CRC(0) <= inv;
      end if;
end process;

oCRC <= CRC;

end ClacCRC;

到此,就把VHDL的结构简述完毕。

别急,我还没有说完,下面还会对各个部分进行分析。由于代码已经在上文给出,下文将不会再重复代码。

VHDL中的库

VHDL中的库有哪些?

std_logic_1164
std_logic_arith
std_logic_unsigned
std_logic_signed

除了系统自带的库外,自己也可以编写自己的,编写格式如下:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;

package PackageName is 

component Component1 is 
    PORT
    (    
          ...
    );
end component;

component Component2 is 
    PORT
    (    
         ...
    );
end component; 

end package;

格式和写一个普通的VHDL文件差不多,不同的是,这个没有实体,也没有结构,只有包(component后面将描述)。

VHDL如何使用库?

库可以分为二大类,一类是系统自带的标准库,另一类的用户自己编写的,两种类调用方式不太一样。

上面代码讲到如何调用库,如果使用标准库,一般如下:

library ieee;     --表示使用什么库
use ieee.std_logic_1164.all;    --表示使用库中的具体的库

其中std_logic_1164是在ieee库中的,一般情况下,上而两行代码是必需的。

如果使用的是用户自编写库,就要:

use work.PackageName.all;  --work表示当前工作目录

使用用户自编写的库看起来就简单多了,只要使用use就可以了,值得注意的是,work是指当前工作目录,而PackageName就是包的名字,前面的讲述到。

VHDL中的实体

VHDL中的实体就简单多了,主要是对引脚(或接口)的输入、输出或者双向作定义。

其中port();中的为对外引脚。

引脚分三种:

输入使用关键字:in

输出使用关键字:out

双向使用关键字:inout

对不同引脚要定义具体类型,引脚常用只有两种类型,一种是单点引脚,一种是多点引脚。(单点、多点引脚是我的说法,不一定正常,但能表示其意思)

单点引脚使用:std_logic

多点引脚使用:std_logic_vertor(x downto 0)

有点类似普通变量和数组变量,一个表示单线、一个表示集合了多条单线(类似总线)。

注:在port();中,最后一个引脚不要加分号!

 

 

VHDL中的architecture

在architecture中且在begin前声明

1、信号。信号如其名,就是传递信号用的。

2、组件(component),组件就是其他已经写好的VHDL,组件只是把其引脚复述一遍,用于后期数据处理。

architecture XXX of XXX_Unit is
signal One:std_logic;    --声明信号

component Component1 is  --声明组件
    port
    (    
          ...  --具体一个实体的引脚
    );
end component;

begin
     ...
end XXX;

组件是将一个已经写好的VHDL模块(实现某一功能的VHDL文件) ,加入本VHDL中的方式,但加入还不够,还要使用port map,下文将描述。

在architecture中且在begin后

在begin后常用的有语句不多,主要有if...else...end if,if...elsif...elsif...end if,process,port map等(这些语句能实现大部分逻辑)。

architecture XXX of XXX_Unit is

component CRC_Unit is
port(
      iBitVal : in std_logic;
      iClock : in std_logic;
      iClear : in std_logic;
      oCRC : out std_logic_vector(4 downto 0)
);
end component;

signal bitVal : std_logic;
signal clock  : std_logic;
signal clr    : std_logic;
signal crc    : std_logic_vector(4 downto 0);

begin

    oOut <= One;

    process(rst)      --敏感信号列表
    begin
         if rst = '0' then
           ...
         elsif
           ...
         end if;
    end process;

   u1:CRC_Unit port map(iBitVal => bitVal ,iClock => clock ,iClear => clr ,oCRC =>crc);
end XXX;

在VHDL中,只要在architecture中的语句都会被同时执行,但process一点特别,同时执行的是整个process,而不是process里面的各行语句。process其实更像是一个块,一个对外同时执行,对内顺序执行的一个单元。

在process的括号中的rst,被称为敏感信号列表,只要放在这括号中的数据发生变化,就会同时执行期间触发process内部操作。即oOut <= One、process及port map同时执行。

 port map是将原来component进architecture的组件进行使用,port map 后,会将对应的信号输入或输出。

VHDL architecture中的变量

变量需要声明在process中,而且只能在process中被赋值,被调用。变量声明在process中begin前。

process(rst)
variable val : integer ;
begin
      val := 10;
end process;

VHDL architecture中的赋值 

VHDL中有两种赋值方式,一种是直接赋值,一种是延时赋值。还有一种不太像赋值,而是像指向的方式,port map (符号是"=>"),这里不把此方式当作赋值。

直接赋值:(赋值符号为":=" )

variable 就是直接的代表,当赋值后,左值将等于右值。

延时赋值:(赋值符号为"<=“ )

所有信号、引脚被赋值都是延时赋值。那什么是延时赋值?个人认为可以与实际电路理解(虽然不知是否正确)。信号可以看成一条线(引脚也是),当我在线的右端给出高电平的瞬间,左端的电平还没有变化,因为从右到左需要一定的时间(那时间是光速),所以在同一周期作出了操作,但信号的值还没有来得及改变,所以出现了延时赋值。

在VHDL中只有两种赋值操作,如果想和高级语言一样使用"="一般会出错,因为在VHDL中"="是比较操作。

总结:

由于边幅太长不利浏览,因此对VHDL、Verilog将以一个系列来讲述。局限于本人技术有限,可能上文会有表达不通,或者表达不清的情况,如果有看不懂的,或者找出错处的,欢迎大家提出。

 

原文地址:https://www.cnblogs.com/bakasen/p/2647799.html