祈祷不会问到FPGA 和 VHDL
这门课讲了什么?
课时较少的缘故,仅仅浅显的讲解了FPGA与VHDL。
(FPGA 简介)fpga是什么?fpga现状?
fpga简单的说,就是现场可编程逻辑阵列。它的内部是逻辑单元,它们之间可以用线连接,至于以怎样的形式相连,则可以根据应用者写入的逻辑决定。每次布线都会重新组合逻辑单元,从而可以任意的编写不同的逻辑。当然,前提是定义的逻辑块不超出它可读写的最大值。
应用范围遍及航空航天、医疗、通讯、网络通讯、安防、广播、汽车电子、工业、消费类市场、测量测试等多个热门领域。并随着工艺的进步和技术的发展,向更多、更广泛的应用领域扩展
区别于C语言等是软件语言,芯片执行的时候是一条条执行,而VHDL是硬件语言,执行的时候是并行的,就是所有的语句块同时执行。VHDL是一种语言,是一种硬件语言,可以编出我们要的电路图。FPGA是一种芯片,里面全是门电路,触发器,通过VHDL程序的要求完成门电路的连接。
使计算机的能力越来越强,方法一:通过提高工艺来提高工作频率;方法二:通过优化系统体系,并行!
时序性能的调整提高是
fpga
开发能力的标志
常数、信号和变量是 VHDL 中最主要的对象,分别代表一定的物理意义。常数对应于数字电路中的电源或地;信号对应某条硬件连线;变量通常指临时数据的局部存储。信号和变量功能相近,用法上却有很大不同。
bit 或其矢量形式 bit_vector只有’0’和’1’两种状态,数字电路中也只有’0’和’1’两种逻辑,因此会容易有误区,认为采用位(矢量)则足够设计之用,而不必像std_logic那样出现’X’,’U’,’W’各种状态,增加编程难度。但实际情况却并非如此,以一个最简单 D型触发器设计为例
… …
① process(clk)
② begin
③ if clk’event and clk=’1’ then
④ Q<=D;
⑤ end if;
⑥ end process;
… …
实际中 clk 对数据端 D的输入有一定的时间限制,即在 clk 上升沿附近(建立时间和保持时间之内),D必须保持稳定,否则 Q输出会出现亚稳态,如下图所示。
当 clk 和 D时序关系不满足时,由于 bit 只有’0’或’1’,系统只能随机的从’0’和’1’中给 Q 输出,这样的结果显然是不可信的;而采用 std_logic 类型,则时序仿真时会输出为一个’X’,提醒用户建立保持时间存在问题,应重新安排 D和 clk 之间时序关系。
此外,对于双向总线设计(前面已提及)、 FPGA/CPLD上电配置等问题,如果没有’Z’,’X’等状态,根本无法进行设计和有效验证。
进程(Process)是 VHDL 中最为重要的部分,大部分设计都会用到 Process 结构
在设计时往往会遇到这种情况,需要对外部某个输入信号进行判断,当其出现上跳或下跳沿时,执行相应的操作,而该信号不像正常时钟那样具有固定占空比和周期,而是很随机,需要程序设计判断其上跳沿出现与否。这时,很容易写出如下程序:
① process(Ctl_a) -- Ctl_a即为该输入信号
② begin
③ if Ctl_a’event and Ctl_a=’1’ then
④ … … ; --执行相应操作
⑤ end if ;
⑥ end process;
由于出现第③行这类语句,综合工具自动默认 Ctl_a 为时钟,某些 FPGA 更会强行将该输入约束到时钟引脚上。而设计者的初衷只是想将其作为下位机的状态输入以进行判断。上面的程序容易造成多时钟现象,增加设计的难度。解决的办法可以如下,将 Ctl_a 增加一级状态
Ctl_areg 寄存,通过对 Ctl_a 和Ctl_areg 状态判断上跳与否,改正程序如下:
① process(clk)
② begin
③ if clk’event and clk=’1’ then
④ Ctl_areg<=Ctl_a;--产生相邻状态
⑤ if Ctl_areg=’0’ and Ctl_a=’1’ then--上跳判断
⑥ … … ; --执行相应操作
⑦ end if;
⑧ end if;
⑨ end process;
程序中第④行用以产生两个相邻状态,第⑤行对前后状态进行判断是否有上跳现象发生。其中,需注意的是 clk 的时钟频率应明显快于 Ctl_a信号的变化频率,以保证正确采样。
参考:http://blog.sina.com.cn/s/blog_72cd3a5c01014wl1.html
参考:http://blog.csdn.net/shanekong/article/details/42686135
一个VHDL程序代码包含实体(entity)、结构体(architecture)、配置(configuration)、程序包(package)、库(library)等。
一、数据类型
1.用户自定义数据类型
使用关键字TYPE,例如:
TYPEmy_integer IS RANGE -32 TO 32;
–用户自定义的整数类型的子集
TYPEstudent_grade IS RANGE 0 TO 100;
–用户自定义的自然数类型的子集
TYPEstate IS (idle, forward, backward, stop);
–枚举数据类型,常用于有限状态机的状态定义
一般来说,枚举类型的数据自动按顺序依次编码。
2.子类型
在原有已定义数据类型上加一些约束条件,可以定义该数据类型的子类型。VHDL不允许不同类型的数据直接进行操作运算,而某个数据类型的子类型则可以和原有类型数据直接进行操作运算。
子类型定义使用SUBTYPE关键字。
3.数组(ARRAY)
ARRAY是将相同数据类型的数据集合在一起形成的一种新的数据类型。
TYPEtype_name IS ARRAY (specification) OF data_type;
–定义新的数组类型语法结构
SIGNALsignal_name: type_name [:= initial_value];
–使用新的数组类型对SIGNAL,CONSTANT, VARIABLE进行声明
例如:
TYPEdelay_lines IS ARRAY (L-2 DOWNTO 0) OF SIGNED (W_IN-1 DOWNTO 0);
–滤波器输入延迟链类型定义
TYPEcoeffs IS ARRAY (L-1 DOWNTO 0) OF SIGNED (W_COEF-1 DOWNTO 0);
–滤波器系数类型定义
SIGNALdelay_regs: delay_lines; – 信号延迟寄存器声明
CONSTANTcoef: coeffs := ( ); –常量系数声明并赋初值
4.端口数组
在定义电路的输入/输出端口时,有时需把端口定义为矢量阵列,而在ENTITY中不允许使用TYPE进行类型定义,所以必须在包集(PACKAGE)中根据端口的具体信号特征建立用户自定义的数据类型,该数据类型可以供包括ENTITY在内的整个设计使用。
—————————————PACKAGE———————————-
libraryieee;
useieee.std_logic_1164.all;
——————————————
PACKAGEmy_data_types IS
TYPE vector_array IS ARRAY (natural range<>) OF STD_LOGIC_VECTOR(7 DOWNTO 0); –声明8位的数组
ENDmy_data_types;
———————————–MainCode—————————————
libraryieee;
useieee.std_logic_1164.all;
usework.my_data_types.all; –用户自定义包集
——————————————————————
ENTITYmux IS
PORT(inp: IN vector_array(0 to 3);
ENDmux;
——————————————————————————-
5.有符号数和无符号数
要使用SIGNED和UNSIGNED类型数据,必须在代码开始部分声明ieee库中的包集std_logic_arith。它们支持算术运算但不支持逻辑运算。
libraryieee;
useieee.std_logic_1164.all;
useieee.std_logic_arith.all;
……
SIGNALa: IN SIGNED (7 DOWNTO 0);
SIGNALb: IN SIGNED (7 DOWNTO 0);
SIGNALx: IN SIGNED (7 DOWNTO 0);
……
v<= a + b;
w<= a AND b; –非法(不支持逻辑运算)
——————————————————————————-
STD_LOGIC_VECTOR类型的数据不能直接进行算术运算,只有声明了std_logic_signed和std_logic_unsigned两个包集后才可以像SIGNED和UNSIGNED类型的数据一样进行算术运算。
6.数据类型转换
在ieee库的std_logic_arith包集中提供了许多数据类型转换函数:
1.conv_integer(p): 将数据类型为INTEGER,UNSIGNED,SIGNED,STD_ULOGIC或STD_LOGIC的操作数p转换成INTEGER类型。不包含STD_LOGIC_VECTOR。
2. conv_unsigned(p,b):将数据类型为INTEGER,UNSIGNED,SIGNED或STD_ULOGIC的操作数p转换成位宽为b的UNSIGNED类型数据。
3. conv_signed(p,b):将数据类型为INTEGER, UNSIGNED,SIGNED或STD_ULOGIC的操作数p转换成位宽为b的SIGNED类型的数据。
4.conv_std_logic_vector(p, b):将数据类型为INTEGER,UNSIGNED, SIGNED或STD_LOGIC的操作数p转换成位宽为b的STD_LOGIC_VECTOR类型的数据。
二、运算操作符和属性
.运算操作符
赋值运算符
赋值运算符用来给信号、变量和常数赋值。
<= 用于对SIGNAL类型赋值;
:= 用于对VARIABLE,CONSTANT和GENERIC赋值,也可用于赋初始值;
=> 用于对矢量中的某些位赋值,或对某些位之外的其他位赋值(常用OTHERS表示)。
例:
SIGNALx: STD_LOGIC;
VARIABLEy: STD_LOGIC_VECTOR(3 DOWNTO 0); –最左边的位是MSB
SIGNALw: STD_LOGIC_VECTOR(0 TO 7); –最右边的位是MSB
x<= ‘1’;
y:= “0000”;
w<= “1000_0000”; – LSB位为1,其余位为0
w<= (0 => ‘1’, OTHERS => ‘0’); –LSB位是1, 其他位是0
逻辑运算符
操作数必须是BIT, STD_LOGIC或STD_ULOGIC类型的数据或者是这些数据类型的扩展,即BIT_VECTOR,STD_LOGIC_VECTOR,STD_ULOGIC_VECTOR。
VHDL的逻辑运算符有以下几种:(优先级递减)
Ÿ NOT —— 取反
Ÿ AND —— 与
Ÿ OR —— 或
Ÿ NAND —— 与非