一个 VHDL 设计由若干个 VHDL 文件构成,每个文件主要包含五个部分的一个或全部:在 max+plusⅡ中后缀为( VHD).
1. 程序包 ( Package )2. 实体 ( Entity)3. 结构体 (Architecture)4. 配置( configuration)5. 库( library)
第 2 章 VHDL 语言程序的基本结构
其中 1~4 为可分别编译的源设计单元。库用来存放已编译过的实体、构造体、包和配置。
2.1 VHDL 语言设计的基本单元基本单元:基本设计实体,可很简单,如门, 也可很复杂,如包含 CPU 的系统。设计一个数字系统,首先要解决两个问题: 1 ) 输入、输出是什么; 2 )内部完成什么功能。对于 1 ,由实体 (Entity) 说明来描述;对于 2 ,由构造体( Architecture) 来描述。
Entity mux isGeneric (m: Time:=1ns);Port(do,d1,sel: IN Bit; q: out Bit);End mux;
Architecture connect Of mux isSignal tmp: Bit;Begin cale: Process(d0,d1,sel) Variable tmp1,tmp2,tmp3:Bit; Begin tmp1:=d0 AND sel; tmp2:=d1 AND (NOT sel); tmp3:= tmp1 OR tmp2; tmp<=tmp3; q<=tmp AFTER m; END PROCESS;END CONNECT;
实体说明部分
构造体说明部分
一个二选一数据选择器的描述
2.1.1 实体说明 实体中定义电路单元和使用环境的接口,实体名必须与电路名相同。实体的格式ENTITY 实体名 IS
[ 类属参数说明 ] ;[ 端口说明 ] ;END 实体名;
1 ) VHDL 语言书写不分大 小写;(个别例外)2 ) [ ] 中内容有时可不要;3 ) END 后的实体名可省。
1. 类属参数说明1 )类属参数说明( generic) 用来为设计引入信息,如时间;2 )类属参数说明( generic) 必须放在端口之前;
3 )类属参数说明( generic) 常用来设计通用元件。2. 端口说明格式: Port( 端口名 { ,端口名 } :方向 数据类型名;
… 端口名 { ,端口名 } :方向 数据类型名 ) ;1) 端口名 电路外部引脚的名称,通常用英文字母加数字命名,如 d0,A1,
En,clk,LD.2) 端口方向(模式) 端口方向定义外部引脚信息的方向,共有五种:in, out, inout, buffer, linkage 常用前 4 种Linkage: 不指定方向,任何方向均可连接 , 只在文挡中使用。
●IN 信号进入实体但并不输出;●OUT 信号离开实体但并不输入;并且不能在有内部反 馈情况下使用;●INOUT 信号是双向的(既可以进入实体,也可以离开实 体);●BUFFER 信号输出到实体外部,同时也可在实体内部反馈; BUFFER (缓冲)是 INOUT (双向)的子集,但不是由外部 驱动。端口模式可用下图说明 : (黑框代表一个设计或模块)
IN OUT BUFFER INOUT
3 )数据类型VHDL 中有 10 种数据类型,但逻辑设计只用两种 , 另在库中还定义了多种数据类型:1. Bit 2. bit_vectorBit : 位逻辑数据类型,取值为 0 或 1 ;bit_vector :位矢量,取值为一组二进制位。Port(do,d1,sel: IN Bit; q: out Bit ; bus:out bit_vector(7 downto 0));
Library ieee; 在编译时在指定的库、Use ieee.std_logic_1164.all 包中寻找这种数据类型Entity mu isPort(do,d1,sel: IN std_logic; q: out std_logic ; bus:out std_logic__vector(7 downto 0));End mu;
2.1.2 构造体构造体 (Architecture) 定义实体的实现,即电路的具体描述 .
构造体的一般格式如下:Architecture<architecture_name 构造体名 > of <entity_name> is
begin – 以下开始构造体,用于描述设计的功能--concurrent signal assignments 并行语句信号赋值--processes 进程(顺序语句描述设计)--component instantiations 元件例化
end<architecture_name> ;
-- 构造体声明区域 -- 声明构造体所用的内部信号及数据类型-- 如果使用元件例化,则在此声明所用的元件
定义语句
1. 构造体名称的命名:一般以描述方法命名,描述方法一般有: 行为特性: behavioral 简写为 beh 结构: structural 简写为 str 数据流: dataflow
如: Architecture beh Of mux is
2. 定义语句:位于 architecture 和 begin 之间,用于对构造体内部使用的信号、变量、数据类型和函数定义。 Architecture beh Of mux is signal n1:bit; … begin …
1) 信号为内部使用,不须加方向2) 信号应有名和数据类型
3. 并行处理语句:位于 begin 和 end 之间,描述构造体的行为和电路 连接关系。所谓并行,指多个语句不以书写顺序执行。
一数据选择器的构造体:architecture arch of mux4 is
begin
y<=((((a0 and not (s(0))) or (a1 and s(0)))) and not (s(1))) or (((a2 and not s(0))) or (a3 and s(0))) and s(1));
end archmux;
• y=a0s1s0+a1s1s0+a2s1s0+a3s1s0
=(a0s0+a1s0)s1+(a2s0+a3s0)s1
2.2 VHDL 语言构造体的子结构一个构造体可以用几个子结构来构成,即一个系统可以用几个比较独立的模快来构成。1. BLOCK 语句结构2. PROCESS 语句结构3. SUBPROGRAMS 语句结构
2.2.1 BLOCK 语句结构描述1.BLOCK 语句的结构格式: 块结构名; block begin … end block 块结构名;
Entity mux isPort(d0,d1,sel: IN Bit; q: out Bit);End mux;Architecture connect Of mux isSignal tmp1,tmp2,tmp3 : Bit;Begin cale: blockBegin tmp1<=d0 AND sel; tmp2<=d1 AND (NOT sel); tmp3<= tmp1 OR tmp2; q<=tmp3 ;End block cale;END CONNECT;
一个二选一数据选择器的描述
2. 块( block )和子原理图的关系:一个 block 相当于总图中的一个 子图,分块设计有利于编辑查错。3. 块( block )中语句的并发性: block 中的语句为并发的。4. 卫式 block ( Guarded block): 指满足条件时,块语句执行,不满足 时不执行。例:… begin
G1: block(clk=‘1’)
begin
q<=guarded d after 5ns;
qb<=guarded not(d) after 7ns;
end block G1;
1) 卫式块不能综合;2 ) after 语句不能综合;3 )当满足 clk=1 时执行。
d q
qbclk
2.2.2 进程( process) 语句结构描述1.process 语言结构[ 进程名 ] : process( 信号 1 ,信号 2,…)
Begin
…
End process;
Architecture connect Of mux isSignal tmp: Bit;Begin cale: Process(d0,d1,sel) Variable tmp1,tmp2,tmp3:Bit; Begin tmp1:=d0 AND sel; tmp2:=d1 AND (NOT sel); tmp3:= tmp1 OR tmp2; tmp<=tmp3; q<=tmp AFTER m; END PROCESS;END CONNECT;
例如:变量只在进程中定义和使用。
2. process 中语句的顺序性: process 中的语句按顺序执行。3. process 语句的启动: process ( )括号内的量称为敏感量, 敏感量发生变化,启动进程。4. Process 的同步描述:当一个构造体内含有多个 process 时,进 程之间为并行的,进程之间能通信。2.2.3 子程序( subprogram) 语句结构描述子程序有两类: 1 )过程( procedure)
2) 函数( function)
1. 过程语句格式
Procedure 过程名(参数 1 ,参数 2 ,…) is
[ 定义语句 ] ;(变量等定义)Begin
[ 顺序处理语句 ] ; (过程语句)End 过程名;过程中的参数可以是输入,也可以是输出。见教材例 2-7
z: 输入,位矢量 x_flag: 输出 ,布尔量q: 输入输出,整数该过程实现将二进制数转换为整型数, x_flag 为出错标志在过程中,如不作说明,则认为 in 为常量, out 和 inout 为变量。
如在过程调用后要将属性为 in 和 inout 的参数传递给信号,则要事先在过程中说明。(见例 2-8 )2 )过程语句中的顺序性 过程语句按顺序执行 调用:①将初始值传递给过程的输入参数 ②执行语句 ③将输出值拷贝到 out 和 inout 所定义的变量和信号 中去
Architecture rtl of ex is procedure cale (a,b : in integer; avg,max: out integer) is – 默认为变量 begin avg:=(a+b)/2 if a>b then max:=a; else max:=b; end if; end cale;
如定义过程:
调用 过程Begin cale (d1,d2,q1,q2); -- 错误,并行语句。
Process(d3,d4)Variable a,b: integer;Begin cale(d3,d4,a,b);--正确 …
2. 函数语句1 )格式: function 函数名 (参数 1 , 2…)
return 数据类型名 is
[ 定义语句 ]
begin
顺序语句 [返回变量名 ]
end 函数名;子程序可定义在进程、包和构造体中。例 2-9 为定义在包中的例子。定义了一 个 max 函数。
2 )函数调用及结果返回 ①函数调用和一般高级语言相同; ②函数调用既可在并行语句中,也可在顺序语句中; ③函数和过程通常不必指定参数的矢量长度; ④例 2-9 是将max 函数放在了名为 bpac 的包中,而bpac
包应放在库中。 ⑤例 2-10 第 1 行应写为 library ieee;
library newlib;
⑥由例 2-10 可知, bpac 包存放在 newlib 库中。
2.3 包集合、库及配置 包集合、库及配置是三个可独立编译的源设计单元。
2.3.1 库 (Library)
库专门存放预先编译好的程序包、实体、构造体和配置等,这样它们就可以在其它设计中被调用。库的功能类似一个子目录或文件夹。使用库时,要进行库说明。LIBRARY ieee ; library newlib ;
1. 库的种类有 5 种: ieee; std; 面向 ASIC 的库; work; 用户定义库。其中: ieee 库为 ieee正式认可的库,使用库中包时要说明; std 库为 VHDL 的标准库,使用该库中数据可不必说明;但 使用库中 TEXTIO 包须说明。
库名 程序包名 包中预定义内容std standard VHDL 类型,如 bit , bit_vectorieee std_logic_1164 定义 std_logic , std_logic_vect
or 等ieee numeric_std 定义了一组基于 std_logic_1164 中定义的类型的算术运算符,如“ +” ,“ -” , SHL , SHR 等ieee std_logic_arith 定义有符号与无符号类型,及基于这些类型上的算术运算。ieee std_logic_signed 定义了基于 std_logic 与 std_logic
_ vector 类型上的有符号的算术运算ieee std_logic_unsigned 定义了基于 std_logic 与 std_logic
_ vector 类型上的无符号的算术运算
面向 ASIC 库: 由工具商提供的库,在 MAX-PLUSⅡ中,有 ALTERA公司自己定义的库,名为 ALTERA.里面存放两个程序包。1 ) maxplus2; 2) megacore.WORK 库:现行作业库,使用不必说明。用户定义库:由用户自己定义,使用需要说明。使用工作 界面窗口中的 options 选项,在 user libraries
选项中选择你所要存放库的路径。
2. 库的使用1 )库的说明 如: library ieee;
use ieee.std_logic_1164.all;
2) 库说明的作用范围 作用范围为它下面的一个设计(包括实体、构造体和配置等)。 当有两个实体时,应有两个库使用说明。(如例 2-11 )
2.3.2 包集合 包集合中存放信号定义、常量、数据类型、元件语句、函数、过程等,它可以编译,使用时用use 语句。如: use ieee.std_logic_1164.all;包结构:
package 包集合名 is
[ 说明语句 ] ; end 包集合名;Package body 包集合名 is
[ 说明语句 ] ; end 包集合名;
包的说明部分(包头)包体(可选)
-- 包头说明PACKAGE Logic IS
TYPE Three_level_logic IS (‘0’, ‘1’, ‘Z’);
CONSTANT Unknown_Value:Three_level_logic:=‘0’;
FUNCTION Invert (input:Three_level_logic) RETURN Three_level_logic;
END Logic;
-- 包体说明PACKAGE BODY Logic IS
-- 如下是函数的子程序体 FUNCTION Invert (input:Three_level_logic) RETURN Three_level_logic;
BEGIN
CASE input IS
WHEN ‘0’=>RETURN ‘1’;
WHEN ‘1’=>RETURN ‘0’;
WHEN ‘Z’=>RETURN ‘Z’;
END CASE;
END Invert;
END Logic;
关于包:1 )一个元件、函数或过程如只在包体中定义,则只能在 本包体中调用(例 2-12 ) ,如要在其它设计中调用, 必须在包头中说明,建议函数和过程在包中定义;2 )包可以只有包头,无包体;(例 2-13 ) 例 2-13 在包 upac 中,定义了 k: 常量; instruction: 枚举类型(一种数据类型) cpu_bus: 4 位位矢量。
2.3.3 配置 配置语句描述层与层之间,实体与结构体之间的连接关系。 如:一个电路,实体是一个(表示框图),但构造体可有多个(实现方法多种),可利用配置语句把不同的构造体连接起来,验证其性能。格式: Configuration 配置名 of 实体名 is
[ 语句说明 ] ;(如 for 选配构造名 end 选配构造名 ;)
end 配置名;
关于配置: ①配置只用于模拟仿真; ②综合工具忽略所有的配置,只对最后输入的结构体进行综合; 见例 2-14 ,实体是一个计数器,构造体 small_count 为 8 位计数器,构造体 big_count 为 16 位计数器。 如编译 :
Configuration small_count of counter is
…
end small_count;
则实现 8 位计数器;
如编译 :
Configuration big _count of counter is
…
end big_count;
则实现 16 位计数器;③在例 2-14 中,由于 max-plusⅡ中的 std_std_logic 包中无 T_wlogic 类 型,可改用 ieee 库中的 std_logic_1164 包,用 std_logic 类型④在例 2-14 中,实体中 data_in 和 data_out 均为整数类型( integer) , 则自动设置为 32 位(由计算机定);⑤例 2-14 ,综合结果为 32 位输出的模 216 计数器。
第 3 章 VHDL 语言的数据类型及运算操作符
3.1 VHDL 语言的客体及其分类 在逻辑设计中, VHDL 语言常用的数据对象为信号、常量、变量,数据对象称为客体。3.1.1 常量(或常数) 常量在设计描述中保持某一规定类型的特定值不变 。如利用它可设计不同模值的计数器,模值存于常量中,不同的设计,改变模值仅需改变此常量值。格式: CONSTANT 常量名:数据类型: = 表达式; 常量赋值符号为“ : = ” 。例 constant vcc: real:=5.0;
3.1.2 变量 (variable)
变量只在给定的进程中用于声明局部值或用于子程序中 , 可以是任意类型。赋值符号为“ : = ” 。 变量说明格式: variable 变量名 :数据类型 约束条件: = 表达式;例: variable cnt: integer range 0 to 255 :=10;
变量赋值立即生效,不产生附加延时,不能写成: y:=x after 10ns;
3.1.3 信号( Signal ) 信号表示一条连线,通常在构造体、包集合和实体中说明, 信号是全局量,内部信号说明不要注明数据流向,外部信号(外部信号对应为 in , out ,inout , buffer )说明时 signal 省略。 信号也可在状态机中表示状态变量。信号赋值符号为“ <=” 。信号说明格式: signal 信号名:数据类型 约束条件: = 表达式;
信号赋初值 用“ :=”
程序中信号代入用“ <=” 例: signal a: bit;
3.1.4 信号和变量值代入的区别1 )变量赋值是立即执行的;2 )信号的代入和语句的处理在时间上是分开的。
在例 3-1 的前部分, A , B , C , D 为信号,当语句处理时,信号并不立即代入,当结束进程时,信号才被代入。在例 3-1 的前部分, A , B , C , D 为变量,当语句处理时,变量立即赋值。所以前后两部分结果不同。下面是一个加法器的例子:
Entity bcdadder is Port(op1,op2 :in integer range 0 to 15; result :out integer range 0 to 31 );End dcdadder;
Architecture behavior of bcdadder is
constant adjustnum :integer:=6
-- 定义一常量 :整数型 , 值为 6
signal binadd :integer range 0 to 18; -- 定义一个信号 , 以保存两数二进制相加的和 .
Begin binadd<=op1+op2; -- 信号赋值 process(binadd) variable tmp : integer:=0; -- 定义一个变量 , 并赋初值为 0 begin if binadd>9 then tmp:=adjustnum; -- 变量赋值 , 立即起作用 else tmp:=0; end if; result<=binadd+tmp; end process;End behavior;
3.2 VHDL 语言的数据类型3.2.1 标准的数据类型 标准的数据类型共 10 种,见下表。
数据类型 含 义整数( integer) 32 位, -2147483647~ 2147483647实数 (real) 浮点数, -1.0E+38~+1.0E+38位 (bit) 逻辑“ 0” 或“ 1”位矢量 (bit_vector) 多位“ 0” 和“ 1” 的组合布尔量 (boolean) 逻辑“真”或逻辑“假” : true 和 false字符 (character) ASCII 字符时间 (time) 时间单位: fs,ps,ns,μs,ms,sec,min,hr错误等级 (severity level)
Note, warning,error,failure
自然数 (natural)正整数( positive)
≥0 的整数>0 的整数
字符串 (string) 字符矢量
3.2.2 用户定义的数据类型VHDL允许用户自己定义数据类型:格式: type 数据类型名 { ,数据类型名 } 数据类型定义; 由用户定义的数据类型可有多种:枚举;整数;实数;浮点数;数组;存取;文件;记录;时间3.2.3 用户定义的子类型VHDL允许用户自己给数据类型加以限制,形成子类型:格式 subtype 子类型名 is 数据类型名 范围;
3.2.4 数据类型的转换函数名 功能
1) std_logic_1164包集合To_stdlogicvector(A)To_bitvector(A)To_stdlogic(A)To_bit(A)
Bit_vector → std_logic_vectorstd_logic_vector→ Bit_vector Bit → std_logicStd_logic→ bit
2)std_logic_arith包集合Conv_std_logic_vector(A,位长)Conv_integer(A)
Integer,unsigned,signed→Std_logic_vector
Unsigned,signed→ integer3)std_logic_unsigned包集合Conv_integer(A) Std_logic_vector → integer
数据类型的说明:1 ) boolean 型 常量、信号和变量均可说明为 boolean 型,综合工具将 false 译为 0 ,将 true 译为 1 。2 ) integer 型 没有定义长度,由工具而定,一般为 32 位。不用 32位时,可采用 :
a)自定义类型,如: type digit is integer range 0 to 9;
b) 直接注明范围,如: port( x: in integer range 0 to 9);
3) 位和位矢量 VHDL标准中只定义了 bit 和 bit_vector,而 bit 只能取“ 0” 和“ 1” ,给设计带来限制: a) 不能描述三态 b) 不能使同一信号具有多个驱动源 c) 不能给信号赋未知值 d) 不能给信号赋无关值解决方法:由 ieee 制定了标准化数据类型。 在 ieee.std_logic_1164 包中定义了a) std_ulogic 类型 具有 9 种不同的值(见 p44)
b) Std_logic 类型 是 std_ulogicd 的决断子类型
4) Character 字符型 由 ASCII码表示的 128 个字符,要用单引号标注,如‘ c’ ,多数综合工具支持 VHDL-87 定义的字符,可综合。5) std_logic 是决断类型 含义:当一个信号有多个驱动器驱动时,则调用定义的决断函数以解决冲突,并决定给信号赋什么值,这可用在三态总线中。
en2
en1
c
d
dbus
Library ieee;
Use ieee.std_logic_1164.all;
Entity ex is
port(d,c,en1,en2: in std_logic;
dbus: out std_logic);
End;
Architecture rtl of ex is
Begin
dbus<=d when en1=‘1’ else ‘Z’;
dbus<=c when en2=‘1’ else ‘Z’;
End;
使用 std_logic 型后,缺点是如误将两个驱动器驱动同一信号,也不会有出错报告。6) 关于数组( array)
type 类型名 is array 范围 of 原数据类型名a) Type A_4 is array (3 downto 0) of std_logic;
表示一维数组( 4 行 1列,每个元素为一位)b) Type A_43 is array (3 downto 0) of std_logic_vector(2 downto 0);
表示一维数组( 4 行 1列,每个元素为三位的位矢量)c) Type A_453 is array (3 downto 0, 4 downto 0) of std_logic_vector
(2 downto 0);
表示二维数组( 4 行 5列,每个元素为三位的位矢量)
如一个信号 a, 为 A_453 类型,即如下形式:“101”3
210
4 3 2 1 0
“011”
a(1,2)a(1,2)(0)
7) 枚举类型 格式: type 名 is (.., .., ..);
枚举类型经常用时序电路的设计中,时序电路有许多状态,这些状态在设计中可编码,如用枚举类型,就可以自己不去编码,而交给工具。大多数综合工具都支持枚举类型。如: type state_type is (start,idle,waiting,run,error);
signal state: state_type;
表示 state 可取 5 个值,综合工具将每个状态转换为 3位矢量,表示 5 种不同值。
8) 关于转换函数如信号 A 为 bit_vector 类型,下列的赋值均为正确的:A<=“10011” ( 二进制)A<=B”10011” ( 二进制,和上面等价)A<=O”456” (八进制)A<=X”FFA6” (十六进制)A<=259 (十进制,必须为常量)A<=4.6E-4 (综合工具不支持)为改善可读性,可加下划线:A<=B”1100_0110_1011” 等价于 A<=B”110001101011”
A<=X”C3_D8” 等价于 A<=X”C3D8”
* 有下划线时,前面的进位标志不能省略,下面是错的:A<=”1100_0110_1011”
VHDL 语言为强类型语言,不允许不经转换而把Bit_vector 赋给 std_logic_vector, 如: A 为 Bit_vector , B 为 std_logic_vector ,当把 A赋给 B 时,必须使用转换函数 to_stdlogicvector(A)
9) 关于记录类型:格式: type 数据类型名 is record
记录定义; end record;
例如:Architecture beh of ex is
Type data_data is record
Year: integer range 1996 to 2099;
Month: integer range 1to 12;
Date:integer range 1 to 31;
End record;
Signal d: data_data;
Begin
d.year<=1999;
d.month<=4;
d.date<=8;
End;
等效为:D<=(1999,4,8);
高级综合工具支持记录类型,但对记录中的数据类型有限制,故在仿真中用的更多。
9) 关于子类型子类型通常是对已有的一些类型作一些限制。格式: subtype 名 is 数据类型名 [范围 ] ; 如: subtype abus is std_logic_vector(7 downto 0);
则 abus 类型为 8 位矢量。
3.2.5 数据类型的限定 在 VHDL 语言中,有时可以用所描述的上下关系来判断某一数据 的数据类型。
(1) 用文字的上下关系判断 signal a : std_logic_vector(7 downto 0);
a<=“10011010”; ( 则“ 10011010” 必为 std_logic_vector型)(2) 在数据前加类型名 a<=std_logic_vector“10011010”;
3.2.6 IEEE标准“STD_LOGIC” 、” STD_LOGIC_VECTOR”
Std_logic 型数据可有 9 种值‘U’ (初始值);‘ X’ (不定);‘ 0’ ;‘ 1’ ;‘ Z’ (高阻);‘W’ (弱信号不定);‘ L’ (弱信号 0 );‘ H’ (弱信号 1 );‘-’( 不可能情况)
·算术运算符 (Arithmetic operators)+ 加- 减* 乘/ 除** 乘方mod 求模rem 求余** 指数abs 求绝对值+ 正(一元运算)- 负(一元运算)
3.3 VHDL 语言的运算操作符
· 关系运算符= 等于/= 不等于< 小于<= 小于或等于> 大于>= 大于或等于
注:其中‘ <=’ 操作符也用于表示信号的赋值操作
逻辑运算符
and 逻辑与or 逻辑或nand 与非nor 或非xor 异或xnor 同或not 逻辑非
· 并置运算符& 连接,将两个对象或矢量连接成维数更大的矢量
说明:关系运算:关系运算产生一个 boolean 值,即 ture 或 false, 关系运算符可以直接用于 integer,bit_vector 和 std_logic_vector等。运算符 =
和 /= 可用于所有已定义的数据类型。大多数综合工具都支持所有的关系运算。算术运算符:算术运算符适用于整数、实数和时间等数据类型,如要对 std_logic_vector 类型进行算术运算,则必须使用程序包 Ieee.std_logic_unsigned 或 ieee.std_logic_signed
综合工具一般支持“ +” 、“ -” 、“ *” 和分母为 2乘方时的“ /”
VHDL 语言构造体的描述方法4.1 构造体的行为描述方法
第 4 章
行为描述是对系统的数学模型的描述,较抽象。行为描述的程序特点是大量采用算术运算、关系运算、惯性延时和传输延时,有些描述难以综合。
4.1.1 代入语言一般格式: 信号量 <= 敏感信号量表达式;
如: a<= b ; (只要 b 变化,就代入新的值) 如: z<= a nor(b nand c) ; (只要 a 、 b 、 c 变化,就代入新的值)
具有延时的代入语句: a<=b after 5ns; (b 发生变化后 5ns 代入新值) 例 4-2 为有条件的代入语句: with sel select
q<=i0 after 10 ns when 0,
i1 after 10 ns when 1,
i2 after 10 ns when 2,
i3 after 10 ns when 3,
‘X’ after 10 ns when others;
sel<=0 when a=‘0’ and b=‘0’ else
1 when a=‘1’ and b=‘0’ else
2 when a=‘0’ and b=‘1’ else
3 when a=‘1’ and b=‘1’ else
4;
4.1.2 延时语句 1)惯性延时 (inertial)
a )为 VHDL 的默认延时 ;
b)尖峰脉冲不能传输(如果使用 after 语句)c)常用作元件延时 2)传输延时 (transport)
a )脉冲均可传输,与宽度无关b)可以很好地表示接连线延时 q1<=a after 5 ns; 惯性延时 q2<=transport a after 5ns; 传输延时
a b
0 5 10 15 20 25 30 ns
a
b
b
b<=a after 5 ns;
b<= transport a after 5 ns;
(综合工具不支持延时)
4.1.3 多驱动描述语句创建一个驱动器可以由一条信号代入语句来实现。当出现下例情况,称为多个驱动器 b 、 d 共同驱动一个信号 a.
a<=b after 5 ns;
a<=d after 5 ns;
这时, a 的值由判决函数来确定。(见例 4-3 ) (综合不支持判决函数) 4.1.4 generic ( 类属说明语句) generic ( 类属说明语句)用于不同层次之间的信息传递。如:位矢量长度,数组长度,器件延时时间。
例 4-4 定义了一个与门,与门输出的上升和下降延时时间用类属说明 generic 定义了两个参数: (rise,fall).
在例 4-5 中,描述一个由三个与门构成的电路,当调用例 4-4 定义的与门时,用语句: U0: and2 generic map(5 ns,5 ns)
U1: and2 generic map(8 ns,10 ns)
U2: and2 generic map(9 ns,11 ns)
这里三个门的延迟时间均不相同。
4.2 构造体的寄存器传输( RTL )描述方式 行为描述的可综合性差, RTL 描述方式是真正的可以进行逻辑综合 的描述方式, RTL 描述也称为数据流描述。4. 2 .1 RTL 描述方式的特点 1 )采用寄存器硬件的一一对应的直接描述; 2 )采用寄存器功能描述。RTL 常用句法:Case---when ; with—select—when; 布尔方程。例 4-6 为四选一数据选择器的 RTL 描述。属寄存器功能描述方法。(用了 when—else 语句)
例 4-8 是二选一数据选择器的例子,用了寄存器硬件的一一对应的直接描述;(描述电路的结构)4.2.2 使用 RTL 描述方式应注意的几个问题1 )“ X”状态的传递 “X”状态的传递是指不确定信号的传递,它使逻辑电路产生不确定的结果。这种不确定的结果,,对 RTL仿真是允许的,但对综合后的门级电路仿真是不允许的。例 4-9 的含义: 当 sel=1 则 y=0, 否则 y=1;
这意味着当 sel=‘X’ 时, y=1 。例 4-10 的含义: 当 sel=0 则 y=1, 否则 y=0;
这意味着当 sel=‘X’ 时, y=0 。
其实设计者要想表达的意思是相同的,但得到的结果不同。在编程时要注意。例 4-10 下一段程序为改进方法。
2. 寄存器 RTL 描述的限制(指对寄存器的描述)1 )禁止在一个进程中存在两个寄存器描述例: process(clk1,clk2)
begin
if (clk1’event and clk1=‘1’) then
y<=a;
end if ;
if (clk2’enent and clk2=‘1’) then
z<=b;
end if ;
End process;
2 )禁止使用 if 语句中的 else项 (使用 if 语句描述寄存器功能时)例: process(clk1)
begin
if (clk’event and clk=‘1’) then
y<=a;
else --禁止使用 y<=b;
end if ;
End process;
D Q
clk
a y
3 )寄存器描述中必须代入信号值见例 4-13 (即寄存器作为一个实体,要随变量变化。)例中, tmp 为变量,而 y 为寄存器的输出信号,当变量 tmp
变化时, y 要跟着变化。3. 关联性强的信号应放在一个进程中 在图 4-7 中,输入有 5 个信号,输出有 4 个信号,其中 a,zin,yin 和 dout 和 eout 关联, a,b,c 和 gout 关联,b 和 fout 关联。则在写程序时,将着三种情况分别 写在三个进程中。例 4-14 和例 4-15 描写的结果相同,但 4-15要好。
4.3 构造体的结构描述方式所谓构造体的结构描述,就是在多层次的设计中,高层次的设计模块调用低层次的设计模块,或者直接调用门电路来设计复杂逻辑电路。这种描述结构清晰,对设计人员的要求较高。4.3.1 构造体结构描述的基本框架例 4-16 为一个二选一的例子。
aa
u1
u3
u2
u4
ab
d0
d1
sel
&
&
1
≥1q
nsel
q=(d0 and sel) or (d1 and (not (sel)))
aa
u1
u3
u2
u4
ab
d0
d1
sel
&
&
1
≥1q
nsel
编程的思路为: 1 )先说明要调用的三 个元件: and 、 or2 、 inv
2) 用 PORT MAP 语句 进行连接元件。结构描述的三个层次:
1. ASIC级结构描述:一般是门级或更低层次例 4-17 是 ASIC级结构描述的一个例子(门级描述),形成了多个块( block) ,每个 block 为一个 ASIC芯片。将这些 ASIC芯片放入库中,以备调用。
2.插件板级结构描述:由多个 ASIC芯片形成插件板。如例 4-18 ,一个插件板为一个构造体。存入库中时将其视作元件。3. 系统级结构描述:由多个插件板形成系统。如例 4-19 。
在实际设计中一个元件,或一个 BLOCK ,或一个实体,经编译后均可认为是一个设计单元。
4.3.2 元件说明语句和元件例化语句 元件说明是对 VHDL 模块的说明,使之可在其它模块中使用,元件说明可放在程序包中,也可以在某个设计的结构体中声明。元件例化指元件的调用。元件说明语法:
Component< 元件实体名 > Generic < 参数说明 >; port < 元件端口信息,同该元件实现时 的实体的 port 部分 >;End component;
-- 元件例化:< 例化名 >:< 实体名 , 即元件名 >port map(< 端口列表>)例如:
u2: and2 port map (nsel,d1,ab);
意思是将与门的输入端 (a,b) 接 (nsel,d1), 输出端 (c) 为ab.
也可写成: u2: and2 port map (a=>nsel,b=>d1,c=>ab);
第一种写法为位置映射法,第二种写法为名称映射法。
&ab
c
and2
第 5 章VHDL语言的主要描述语句
VHDL 常用语句分并行( Concurrent )语句和顺序( Sequential )语句:并行语句( Concurrent ) :
顺序语句( Sequential ) :
并行语句总是处于进程( PROCESS )的外部。所有并行语句都是并行执行的,即与它们出现的先后次序无关。如 when..else 语句
顺序语句总是处于进程或子程序的内部,并且从仿真的角度来看是顺序执行的。如 if-then-else 语句
5.1 顺序描述语句5.1.1 wait 语句
wait 语句的四种类型: wait 无限等待 wait on 敏感信号量变化 wait until 条件满足 wait for 时间到
1. Wait on
格式: wait on 信号 [ ,信号 ] ;下面两段程序等效: process(a,b) process
begin begin
y<=a and b; y<=a and b;
end process; wait on a,b;
end process;
可综合 高级工具可综合不能在一段程序中既用进程敏感量又用 wait on 语句。
2. Wait until
process
begin
wait until a=‘1’;
c<=not a;
end process;
可综合
3. Wait for
process
begin
c<=not a;
wait until a=‘1’ for 10 ns;
end process;
不可综合,在仿真中使用4. 多条件 wait 语句用的不多; 5. 超时等待是处理等待时间过长的方法。 *综合工具对时间量不支持。
5.1.2 断言 ( assert) 语句断言语句用于仿真,便于调试中进行人机会话。格式: ASSERT 条件 [report 输出信息 ][severity 级别 ]
条件为真,向下执行;条件为假,输出错误信息,信息中的字符串用“ ”,以及错误等级。VHDL 错误级别有: failure, error, warning, note
5.1.3 信号代入语句格式: 目的信号量 <= 信号量表达式;1 )“ <= ” 和小于等于号相同,由文中内容区别;2 )代入符号两边的信号量的位长度应一致。
5.1.4 变量赋值语句变量赋值只能在进程或子程序中使用,无法传递到进程之外。格式: 目的变量 := 表达式;例: a:=2; b:=“11101011”;
5.1.5 if 语句 1.门闩控制 If 条件 then 顺序处理语句; end if ;
2 . 二选择控制 If 条件 then 顺序处理语句; else 顺序处理语句; end if ;
3 . 多选择控制 If 条件 then 顺序处理语句; elsif 条件 then 顺序处理语句; … else 顺序处理语句; end if ;
•If 语句常用于选择、比较和 译码等场合;*if 后的条件判断,输出为逻 辑量,即“真”或“假”,故条 件表达式中只能使用关系运 算: = , /= , >, <等,也可用 逻辑运算操作的组合表达式。
例 5-6 为一个 D触发器的描述。d q
clk
例 5-7 为二选一数据选择器描述。MUX
ab
sel
c10
例 5-8 为四选一数据 选择器描述。
MUX
input(0)
sel(1)
y10
sel(0)
23
input(1)input(2)input(3)
5.1.6 case 语句格式: case 表达式 is when 条件表达式 => 顺序处理语句; … end case;
四种形式: when 值 => 顺序处理语句; when 值 | 值 |…| 值 => 顺序处理语句;(表示“或”) when 值 to 值 => 顺序处理语句; when others=> 顺序处理语句;例 5-9 为一个数据选择器程序 , 编程思路:1 ) 将位信号 a,b转换为整型数 sel;2) 用 case 语句判断 sel 值,决定选择什么数据。
例 5-9 有两处错误: 1 ) sel<=‘0’;(因为 sel 为整型数,而‘ 0’ 表示 0 为位量) 2 )程序中 sel 为信号,并在进程中使用,而在进程中 信号值的改变要等进程执行结束后进行,这和编 程的要求相异。 * 应把 sel 在进程中定义为变量,并把所有的 sel<= 改为 sel:= 。
例 5-10 为 3-8 译码器的例子 210
210
543
76
Y(7~0)
cba
&EN
G2BG2AG1
编程思路:1 )将码输入信号 c,b,a合成为位矢量( indata)( 用并置符&);
2) 用 if 语句判断使能信号是否有效,如有效,则进入 3 );3 )用 case 语句判断输出。
例 5-11 为二 --十进制编码器的例子。 1 )为普通编码器,不能同时多个信号有效; 2 )当无信号输入或有多个信号有效时,程序处理为使 y=“XXX” ,可使电路简单。例 5-12 为二 --十进制优先编码器的例子。 本例使用多条件 if 语句进行逐条判断,完成优先编码,例中 input(0)优先级最高。
5.1.7 Loop 语句 (循环) 1. For 循环变量 格式: for 循环变量 in 离散变量 loop
顺序处理语句; end loop[标号 ] ; 例: asum: for i in 1 to 9 loop
sum:=i+sum;
end loop asum;
其中: i 为循环变量,循环变量不必说明。
例 5-13 描述一个奇偶校验电路:• i 为循环变量(整数),不必说明;• tmp 为变量,不能出进程;• y 为信号,可以在进程之外;• 只有单循环时,标号可不要。2) While 条件 格式: [标号 ] : while 条件 loop
顺序处理语句; end loop;
例: i:=1;
sum:=0;
sbcd: while (i<10) loop
sum:=i+sum;
i:=i+1;
end loop sbcd;
例 5-14 同样是一个奇偶校验电路的描述:•使用了 while…loop 语句;•在进程 中 i作为整型变量不必要定义(如定义也可);•For…loop 语句较 while…loop 语句使用的多。
5.1.8 next 语句格式: next [标号 ][when 条件 ] ; 在 loop 语句中 Next 语句用来跳出本次循环。 Next 语句执行时将停止本次迭代,而转入下一次迭代。 Next 后的标号表明下一次迭代的起始位置,而 when 条件表明 next 语句执行的条件。 如果 next 语句后面既无标号,又无 when 条件说明,则只要执行到该语句就立即无条件地跳出本次循环,从 loop 语句的起始位置进入下一次迭代。
5.1.9 exit 语句格式: exit [标号 ][when 条件 ] ; exit 语句也是 loop 语句中使用的循环控制语句。与Next 语句不同的是,执行 exit 语句将结束循环状态,从 loop 语句中跳出。 如果 exit 语句后面既无标号,又无 when 条件说明,则只要执行到该语句就立即无条件地从 loop 语句中跳出,结束循环状态。继续执行 loop 语句后继语句。
5.2 并发描述语句5.2.1 进程( process) 语句进程语句的几个特点:* 一个构造体中可以有几个进程,它们并发运行,进程中 可以存取构造体或实体中所定义的信号;* 进程内的语句都是顺序执行的;* 为启动进程,应包含一个显式的敏感表,或包含一个 wait 语句;* 进程间的通信是通过信号量传递的。
5.2.2 并发代入语句( <= )信号代入语句在进程内使用,作为顺序语句;在进程外使用时,作为并发语句。
5.2.3 条件代入语句格式: 目的信号量 <= 表达式 1 when 条件 1 else
表达式 2 when 条件 2 else
…
else
表达式 n;例 5-17 为用条件代入语句描述数据选择器的例子。
条件代入语句和 if 语句的区别:•If 只能用在进程内部,为顺序语句;• 条件代入 when 后一定要有 else ,而 if 后可以没有 else ,当 if 后没有 else 时,可以是电路具有保持功能,形成锁存器。由于条件代入中不能自身代入,故不能形成锁存器。5.2.1 选择信号代入格式: with 表达式 select
目的信号量 <= 表达式 1 when 条件1 , 表达式 2 when 条件 2 , …
表达式 n when 条件 n;
例 5-18 和 5-19 功能相同,均为描述数据选择器。选择条件代入语句和顺序语句 case 类似。5.2.5 并发过程调用语句在例 2-7 中定义了一个名为 vector_to_int 的过程,一个过程有完整的输入和输出,在调用时: * 在前面加标号; * 并发过程调用语句应带有 in,out 或 inout 参数, 参数放在( )内; * 并发过程调用可有多个返回值; * 并发过程调用时,返回量一定要是信号; * 在进程中也可调用过程。
5.2.6 块( block) 语句格式:标号: block
块头 { 说明语句 } ; begin
{ 并发处理语句 } ; end block 标号;
1 )块头通常用语信号的映射及参数 的 定义,常用下列语句: generic, generic_map
port, port_map
2 )说明语句和构造体语句说明语句 相同,主要是对该块所要用到的客 体加以说明。可说明的项目有: * use 子句; * 子程序说明及子程序体; * 类型; * 常量说明; * 信号说明; * 元件说明。
3. 并发语句常用于结构 体的结构化描述。
例 5-20 为一个简单 CPU芯片设计实例框架。芯片包含一个 ALU 和一个 REG8 。而 REG8又由 8个子模块组成,子模块分别为: REG1 ,…, REG8 。在每一个块内有局部信号、数据类型、常数等说明。1)程序的前 6 行,定义了一个数组 tw32( 一维, 3
2 个元素),存放在 Bit32 包中;2)实体为 CPU ,定义 clk,interrupt 为输入, adde
r 为输出, data 为 inout( 双向);3)构造体名为 cpu_blk, 内部包括两个大的 block( ALU 和 REG8 ) , 其中 REG8 块中又包含 8个子块( REG1 ,…, REG8 );
说明:1 ) clk, intrrupt, adder, data, 为端口信号,全局使用;2 )信号 ibus,dbus 是在构造体名和 begin 之间定义的,可以 在构造体内部使用;3 ) qbus 是在 ALU 块内部定义的,只能在 ALU 内部使用, 另外在 REG1 中也定义了一个 qbus, 这两个信号不相同 (建议不要采用同名定义);4 ) block 中可以嵌套,内层 block 可使用外层块的信号,但 外层块不能使用内层块的信号。
5 )块是一个独立的子结构,通过 port map 和 generic map 语句可以实现块内和块外信息传递例 5-21 说明:这是一个不完整的例子,说明通过 port map
语句把块内的信号和块外的信号相连接。函数
ALU
BLOCK
abusibus
bbus
ibus
dbus
ctbuscomt D_out
构造体data
端口端口
5.3 其它语句和有关规定5.3 .1 命名规则和注释的标记1 ) std_logic 和 std_logic_vector 中的不定值‘ X’ 要大写;2) 在 VHDL 中使用的名字: 1. 首位一定是英文字母; 2. 只能使用英文字母和数字,以及‘ _’ ,字名最后不能用 ‘_’ ; 3. 不能连续使用‘ _’ 。
5.3.2 attribute( 属性)描述与定义语句 属性描述与定义语句可以从所指定的客体中获得关心的数据或信息。 通过预定义属性描述语句,可以得到客体的有关值、功能、类型和范围。 预定义的属性类型有: 数值类,函数类,信号类,数据类型类和数据范围类。 1. 数值类属性 用于得到数组,块或者数据的有关值。分为 3 个子类: a) 一般数据的数值属性; b) 数组的数值属性; c) 块的数值属性。
1)一般数据的数值属性 (共 4 种) 格式:客体’属性名。 1. T’LEFT——得到数据类或子类区间的最左端的值; 2. T’RIHHT——得到数据类或子类区间的最右端的值; 3. T’HIGH——得到数据类或子类区间的最高端的值 ;
4. T’LOW——得到数据类或子类区间的最低端的值 .
例: TYPE number IS 0 TO 9;
则: I:=number’LEFT; --I:=0
I:=number’RIGHT; --I:=9
I:=number’HIGH; --I:=9
I:=number’LOW; --I:=0
如将 0 TO 9改为 9 DOWNTO 0 ,则情况就不一样了。
例 5-23 是枚举类型的属性分析TYPE tim IS (sec, min, hous, day, month, year);
这种枚举,将左( sec)视为低位,右( year)视为高位 .
TYPE reverse_tim IS tim RANGE month DOWNTO min;
Tim1<=tim’left;--得到 secTim2<=reverse_tim’left;--得到 min( 应该为 month)*教材 (p96) tim5 和 tim6 可能有误。2) 数组的数值属性
A’length—得到数组 A 的长度。例: Type bit4 is array (0 to 3)of bit; len1:=bit4’length; ---len1=4
数值属性也可用于枚举类型,见例 5-25 :1. t_4val 类型为位,有四种取值 :‘X’,’0’,’1’,’Z’ 。2. t_4valx1 类型为一维数组,其中 (t_4val’low to t_val4’high) 和( 0 to 3)等效。 t_4valx1 型数组表示:数组中有四个元素,每个 元素为一位,取值为 t_4val 型。3. t_4valx2 类型为一维数组, 4×1 ,其中每个元素 为四位,取值为 t_4valx1 型。4. t_4valmd 类型为二维数组, 4×4 ,每个元素为 一位,取值为 t_4val 型。5. Andsd 为常量,类型为 t_4valx2 。(用数组表示 ‘X’ 、’ 0’ 、’ 1’ 、’ Z’四个两之间的“与”函数值)
5. Andmd 为常量,类型为 t_4valmd 。(用数组表 示‘ X’ 、’ 0’ 、’ 1’ 、’ Z’四个两之间的“与”函数值)在例 5-26 中: len1 和 len2 均得到一维数组的长度 =4 ;len3得到得是二维数组的第一区间(行)长度 =4 ;len4得到得是二维数组的第二区间(列)长度 =4 ;3) 块的数组属性 ’① structure ’behavior②1. 用于块的构造体中
2. 如块有标号说明,或构造体有构造体说明, 并在块和构造体内不存在 component 语句,那么
’behavior将得到 true 信息。3. 如果在 块和构造体中只有 component 语句或 被动进程,那么属性’ structure得到 true 信息。
例题 5- 27 分析:描述了一个四位移位寄存器
d q d q d q d q
cp cp cpcp
left rightdff dff dffdff
clk
i1 i2 i3
u1 u2 u3 u4
1) 程序开始说明了元件 dff;2)从第一个 begin 到 q=>right 描述了以下结构:
3 )进程 checktime 用来检测时钟跳变间隔是否为 20ns, 如不是,输出错误信息和错误级别 spike on clock ( 时钟破坏) 错误级别: warning (警告) 其中: last_time 是时间型变量;
4 )在构造体中,第一个 begin 中只有元件说明, 进程 checktime 中无代入语句,(这种进程称 为被动进程或无源进程),所以如对构造体 施加‘ behavior 和’ structure 属性,则 structural’behavior-----得到“假”; structural’structure-----得到“真”。 用来检测构造体的描述方式。
2. 函数类属性 属性以函数的形式,让设计人员得到有关数据类型、数组、信号的某些信息:1 )数据类型属性函数首先应指定一个输入自变量,如 x 。则:’ pos(x) ----得到 x 值的位置序号 ’val(x) ----得到位置序号为 x 的值 ’succ(x) ----得到输入 x 值的下一个值 ’pred(x) ----得到输入 x 值的前一个值 ’leftof(x) ----得到邻接输入 x 的左边值 ’rightof(x) ----得到邻接输入 x 的右边值
例 5- 28 说明:将物理量 μA 、 μV 、 ohm转换为 整数的实例。1 )包 ohms_law 定义了 current,voltage ,resistance 三种数据类型及基本单位,如 mA,V等。2 )实体部分
i
er 框图中的三个量分别用包中定义的类型。
3 )构造体定义三个变量 (整型数): convi, conve, int_r 然后将输入量转换为整型数进行运算,最后将 运算结果为电阻量输出。程序中: convi:=current’pos( i ) --得到输入 i 的位置序号 ,由于 i 的基本单位为微安,范围为 0- 1000000 ,所以当输入为 10μA 时,序号为 10 , convi=10.
resistance’Val(int_r) 将整数 int_r转换为单位为ohm 的电阻量。其他属性比较容易理解,请参考例 5- 29 。
2 )数组属性函数: 利用数组属性函数,可得到数组的区间信息。’left(n) –得到所引号为 n 的区间的左端位置号。 n 指多维数组中所定义的多维区间的序号, n缺省时代表对一维区间操作。
’right(n) –得到所引号为 n 的区间的右端位置号。’high(n) –得到所引号为 n 的区间的高端位置号。’low(n) –得到所引号为 n 的区间的低端位置号。
在递增区域:数组’ low=数组‘ left; 数组’ high=数组‘ right 。
在递减区域:数组’ low=数组’ right; 数组’ high=数组’ left 。例 5- 30 说明:随机存取存储器
1 )包 p_ram: 定义: a) 一维数组: ram_data ( 0- 511 ) ( 每个元素 为整型数) ; b) 常量 : x_val= -1; c) 常量 : z_val= -2 .
2 )实体 ram:RAM
data_in
addrcs
r_wb
data
3) 构造体 a) 进程: main_proc,敏感量( cs,add,r_wb) b) 定义变量 ram_data1, 数组 ,暂存存储器内容; ram_init, 清零标志,布尔量,初值为‘假’。 c)给数组 ram_data1清零: (应用 ram_data1’low to ram_data1’high loop) d) 以下流程图为存取过程:
cs=‘x’或 r_wb=‘x’Data= -1
Data= -2
Data= -1
cs=‘0’
N
Y
Y
r_wb=‘1’
地址为- 1 或- 2
NN
片选有效 片选无效
地址为- 1 或- 2
(写)Y(读)
将 ram_data1 中地址为addr 中的 数送到输出端 data.
给出出错信息及等级并将输出 data 置为- 1 。
data_in=>ram_data1(addr)ram_data1(addr)=>data
N
Y
Y
N
3 )信号属性函数 信号属性函数得到信号行为信息。a) s’event 返回布尔值。反映在当前相当小的一 段时间内,是否有事件发生。(含义更广泛)b)s’active 返回布尔值。反映在当前相当小的一 段时间内,是否信号发生变化。c)s’last_event 返回时间值。反映信号前一个事件 发生到现在所经过的时间。d)s’last_value 返回一个值。反映信号最后一次 改变前的值。e)s’last_active 返回时间值。反映信号前一次改变 到现在所经过的时间。
例 5- 31 :想用来检测上升沿,即 0→1 ,但如出现由 X →1,仍然作为条件满足。P105页,最后三行,增加了( clk’last_value=‘0’),则,如条件满足,一定是 0→1 。
例 5- 32 :利用‘ last_event 属性对 d触发器信号变化 的建立时间进行检查的实例。 1 )在实体中引入了一个无源进程(进程中没有 代入语句),检查上一次 d 的 变化到 clk 的上 升沿时间是否大于 setup_time. 2) 实体中引入进程,可以被所有构造体共享。 (本例的 检查也可以放在构造体中进行)
•属性’ active 和’ last_active 由信号发生变化或事件 发生时被触发,当一个模块的 输入或输入输出 端口发生某一事件时,将启动模块执行。( VHDL 对信号有严格说明)3. 信号类属性 信号类属性用于产生一种特别的 信号,这个特别的信号是以所加属性的信号为基础而形成的 。
4 种信号类属性•s’delayed[(time)]----产生一个延时信号,延时信 号特征与属性所加信号相同。
• s’stable[(time)]----返回布尔值,在括号内的时间 表达式所说明的时间内,若参 考信号没有发生事件,得到“真”。• s’quiet[(time)]----返回布尔值,在括号内的时间 表达式所说明的时间内,若参 考信号没有发生转换或其他事件, 得到“真”。• s’transaction---- 可建立一个 bit 型信号,当属性所加 信号发生转换或事件时,其值都将 发生改变。
设计举例
1) 多数决定的数字滤波器( 4 位)滤波器输出信号 d_f 的取值由滤波器输入信号前N次采样值表决而定,原则是多数取胜。假定采样次数 N 为 3 ,若 (d_in(N-2)+d_in(N-1)+d_in≥2则 d_f 的取值为‘ 1’ ,否则为‘ 0’ 。提示:设计要利用数组和循环语句。见文件 majority.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity majority is
port (clk,resetn: in std_logic;
d_in: in std_logic_vector(3 downto 0);
d_f : out std_logic_vector(3 downto 0));
end;
architecture rtl of majority is
type array_4 is array(3 downto 0)of std_logic_vector(2 downto 0);
signal s_d:array_4;
signal d_f_i:std_logic_vector(3 downto 0);
begin
process(clk,resetn)
begin
if resetn='0' then
for i in 0 to 3 loop
s_d(i)<="000";
end loop;
elsif clk'event and clk='1'then
for i in 0 to 3 loop
s_d(i)(0)<=d_in(i);
for j in 0 to 1 loop
s_d(i)(j+1)<=s_d(i)(j);
end loop;
end loop;
end if;
end process;
该进程完成将三位数并行读入
process (s_d)
type array_42 is array(3 downto 0)of std_logic_vector(1 downto 0);
variable ct:array_42;
begin
for i in 0 to 3 loop
ct(i) :=('0'&s_d(i)(2))+('0'&s_d(i)(1))+('0'&s_d(i)(0));
if ct(i)>=2 then
d_f_i(i)<='1';
else
d_f_i(i)<='0';
end if;
end loop;
end process;
该进程完成输出数据计算
process (clk,resetn)
begin
if resetn='0' then
d_f<=(others=>'0');
elsif clk'event and clk='1' then
d_f<=d_f_i;
end if;
end process;
end;
该进程完成输出赋值
2) 二进制转换为格雷码( 8 位)提示:设二进制码为 A=a7a6a5a4a3a2a1a0 格雷码为 Y=y7y6y5y4y3y2y1y0
则: y7=a7 ; yi=ai+1 ai ; i≠7
见文件: bintogray.vhd
library ieee;
use ieee.std_logic_1164.all;
entity bintogray is
port (a: in std_logic_vector(7 downto 0);
y: out std_logic_vector(7 downto 0));
end;
architecture rtl of bintogray is
begin
process (a)
variable tmp:std_logic_vector(7 downto 0);
begin
tmp(7):=a(7);
for i in 6 downto 0 loop
tmp(i):=a(i) xor a(i+1);
end loop;
y<=tmp;
end process;
end rtl;
3) 设计一个乘常数的电路 从资源和速度考虑,常系数乘法运算可用移位相加来实现。 ( 下例为乘 71 电路设计)算法: 71=26 + 23 – 1
下面是一个 9 位数 din 和 71 相乘的例子,结果舍去了最后一位。程序见 cx71.vhd
LIBRARY ieee;
USE ieee.std_logic_1164.all;
USE ieee.std_logic_arith.all;
ENTITY cx71 is
PORT
( clk : IN STD_LOGIC;
Din : IN SIGNED (8 DOWNTO 0);
Dout : OUT SIGNED (14 DOWNTO 0)
);
END cx71;
ARCHITECTURE a OF cx71 IS
SIGNAL s1 : SIGNED (11 DOWNTO 0);
SIGNAL s2 : SIGNED (11 DOWNTO 0);
SIGNAL s3 : SIGNED ( 9 DOWNTO 0);
SIGNAL s4 : SIGNED (14 DOWNTO 0);
BEGIN
s1(11 DOWNTO 3)<=Din;
s1( 2 DOWNTO 0)<="000";
--implementing 2^3*Din - Din
s2<=(s1 - Din);
--implementing 2^6*Din + 2^3*Din - Din
s3<=(Din + s2(11 DOWNTO 6));
s4(14 DOWNTO 5)<=s3;
-- truncating one bit
s4( 4 DOWNTO 0)<=s2(5 DOWNTO 1);
-- pipeling
dff: PROCESS
BEGIN
WAIT UNTIL clk = '1';
Dout<= s4;
END PROCESS;
END a;
4 ) Mealy 型状态机
组合逻辑 寄存器Input
Output
clk
reset当前状态
S0 S1
S2S3
其他 /0000 其他 /1001
其他 /1100其他 /1111
1/1001
0/1100
1/1111
0/0000
一个 Mealy 型状态机的例子
程序见mealy.vhd
library ieee;
use ieee.std_logic_1164.all;
ENTITY mealy IS
PORT(clk,in1,reset: IN STD_LOGIC;
out1: OUT STD_LOGIC_vector(3 downto 0));
END ;
architecture bhv of mealy is
type state_type is (s0,s1,s2,s3);
signal state:state_type;
begin
p0: process (clk,reset)
begin
if reset='1' then
state<=s0;
elsif clk'event and clk='1'then
CASE state IS
WHEN s0 =>if in1='1'then
state<=s1;
end if;
WHEN s1 =>if in1='0'then
state<=s2;
end if;
WHEN s2 =>if in1='1'then
state<=s3;
end if;
WHEN s3 =>if in1='0'then
state<=s0;
end if;
END CASE;
end if;
end process p0;
该进程完成状态转换的描述
out_p:process(state,in1)
begin
case state is
when s0 => if in1='1' then out1 <="1001";
else
out1 <="0000";
end if;
when s1 => if in1='0' then out1 <="1100";
else
out1 <="1001";
end if;
when s2=> if in1='1' then out1 <="1111";
else
out1 <="1100";
end if;
when s3 => if in1='0' then out1 <="0000";
else
out1 <="1111";
end if;
end case;
end process;
end bhv;
该进程完成由状态和输入决定输出
5 ) Moore 型状态机
组合逻辑 组合逻辑寄存器input output
clk
reset当前状态
次状态Process
p1
Processp0
Processp2
S0 S1
S2S3
1
0
1111
0000 1001
11001
0
程序分析见moore.vhd
前一个例子的 moore 型形式:
library ieee;
use ieee.std_logic_1164.all;
ENTITY moore IS
PORT(
clk,in1,reset : IN STD_LOGIC;
out1: OUT STD_LOGIC_vector(3 downto 0));
END ;
architecture bhv of moore is
type state_type is (s0,s1,s2,s3); -- 状态说明 signal current_state,next_state:state_type;
begin
p0: process (clk,reset) -- 时钟进程 begin
if reset='1' then
current_state <= s0;
elsif clk'event and clk='1'then
current_state<=next_state;
end if;
end process;
p1: process(current_state,in1) -- 组合进程begin
CASE current_state IS
WHEN s0 =>if in1='1'then
next_state<=s1; end if;
WHEN s1 =>if in1='0'then
next_state<=s2; end if;
WHEN s2 =>if in1='1'then
next_state<=s3; end if;
WHEN s3 =>if in1='0'then
next_state<=s0; end if;
END CASE;
end process;
p2:process(current_state) -- 组合进程 begin
case current_state is
when s0 => out1 <="0000";
when s1 => out1 <="1001";
when s2 => out1 <="1100";
when s3 => out1 <="1111";
end case;
end process;
end bhv;
6 )带有类属参数的计数器通过类属参数,可以方便地改变计数器的模。分析见程序 cntnbits.vhd
nreset
ciclk
co
qcnt
计数器
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity cntnbits is
generic(cwh:integer:=5);
port(ci,nreset,clk : in std_logic;
co : out std_logic;
qcnt :buffer std_logic_vector(cwh-1 downto 0));
end cntnbits;
architecture behave of cntnbits is
constant allis :std_logic_vector(cwh-1 downto 0):=(others=>'1');
begin
co<='1' when(qcnt=allis and ci='1') else '0';
process(clk,nreset)
begin
if(nreset='0')then
qcnt<=(others=>'0');
elsif(clk'event and clk='1')then
if(ci='1')then
qcnt<=qcnt+1;
end if;
end if;
end process;
end behave;
7) 寄存器和移位寄存器 下面的实例介绍触发器、移位寄存器的设计,说明元件、过程调用等方面知识。
a) 一个带异步清零的 D 触发器D
CLK
QR
D触发器dff: R为异步清零端,CLK上升沿触发;PORT (D,R,CLK : in std_logic; Q : out std_logic);
library ieee;
use ieee.std_logic_1164.all;
entity dff1 is
port(d,clk,r:in std_logic;
q:out std_logic);
end ;
architecture rtl of dff1 is
begin
process(clk,r)
begin
if r='1' then q<='0';
elsif (clk'event and clk='1') then
q<=d;
end if;
end process;
end rtl;
见程序 dff1.vhd
b) 串行输入、串行输出移位寄存器 shift8
D
CLK
QR
D
CLK
QR D
CLK
QR D
CLK
QR
D
CLK
QR
D
CLK
QR
D
CLK
QR
D
CLK
QRA
CLK
RB
方法一:调用 dff1 组成。( dff1 和 shift8 在同一目录下)
D
CLK
QR
D
CLK
QR D
CLK
QR D
CLK
QR
D
CLK
QR
D
CLK
QR
D
CLK
QR
D
CLK
QRA
CLK
RB
library ieee;
use ieee.std_logic_1164.all;
entity shift8 is
port(a,clk,r:in std_logic;
b:out std_logic);
end;
architecture rtl of shift8 is
component dff1
port(d,clk,r:in std_logic;
q:out std_logic);
end component;
signal z :std_logic_vector(0 to 8);
begin
z(0)<=a;
g1:for i in 0 to 7 generate
dffx: dff1 port map (z(i),clk,r,z(i+1));
end generate;
b<=z(8);
end rtl;
见程序 shift8.vhd
方法二:直接利用信号来连接。注意信号赋值的特点。library ieee;
use ieee.std_logic_1164.all;
entity shift8a is
port(a,clk : in std_logic;
b: out std_logic);
end;
architecture rtl of shift8a is
Signal d_1,d_2,d_3,d_4,d_5,d_6,
d_7,d_8 :std_logic;
begin
process(clk)
begin
if(clk'event and clk='1')then
d_1<=a;
d_2<=d_1;
d_3<=d_2;
d_4<=d_3;
d_5<=d_4;
d_6<=d_5;
d_7<=d_6;
d_8<=d_7;
b<=d_8;
end if;
end process;
end rtl;程序见 shift8a.vhd
c) 循环移位寄存器 在计算机的运算操作中经常用到循环移位。八位循环左移的寄存器电路框图如下。电路有八个数据输入端 din(7)~din(0), 移位和置数控制端 enb, 时钟信号输入端 clk, 移位位数控制输入端 s(2)~s(0),八位数据输出端 dout(7)~dout(0).
功能:当 enb=1 时,根据 s(2)~s(0) 输入的数值,确定在时钟脉冲 作用下,循环左移几位; 当 enb=0 时,在时钟作用下,将数据 din 直接传输到 dout 。
7 6 5 4 3 2 1 0
dout(7)~dout(0)
din(7)~din(0)
s(2)s(1)s(0)
enb
clk循环移位寄存器
7 6 5 4 3 2 1 0
例如:当 enb=1 时, s(2)s(1)s(0)=100 时。
电路设计方法:1 )将循环左移寄存器描述为一个名为 shiftp 的过程( procedure);2) 将过程 shiftp 定义在包名为 cpac 的包中;3) 在实体描述中调用过程,实现移位。
dout(7)~dout(0)
MSB
MSB
LSB
LSB
移位前
移位后
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
package cpac is
procedure shiftp(din,s :in std_logic_vector;
signal dout :out std_logic_vector);
end cpac;
package body cpac is
procedure shiftp(din,s :in std_logic_vector;
signal dout :out std_logic_vector)is
variable sc :integer;
begin
sc:=conv_integer(s);
for i in din'range loop
if(sc+i<=din'left)then
dout(sc+i)<=din(i);
else
dout(sc+i-din'left)<=din(i);
end if;
end loop;
end shiftp;
end cpac; 程序见 cpac.vhd
八位移位寄存器描述:library ieee;
use ieee.std_logic_1164.all;
use work.cpac.all;
entity bsr is
port(din:in std_logic_vector(8 downto 1);
s:in std_logic_vector(2 downto 0);
clk,enb:in std_logic;
dout :out std_logic_vector(8 downto 1));
end;
architecture rtl of bsr is
begin
process(clk)
begin
if (clk'event and clk='1') then
if (enb='0') then
dout<=din; else
shiftp(din,s,dout);
end if;
end if;
end process;
end rtl;
程序见 bsr.vhd, 由于 maxplusII不支持过程调用语句,该程序可利用 quartusII 运行。
8 ) 存储器 存储器分为 : 只读存储器( ROM) 随机存取存储器 (RAM)
下面是两个可综合的 ROM 和 RAM 的例子。
a) 一个容量为 4×8 的 rom 例子实现 方法: ( 改变参数可改变容量 ) 1 )把 ROM 中要存放的内容先定 义为一个数组,并存放在一个 包文件内; 2 )在实体中调用数组,进行 初始化。
clk
addr[1..0]
1 0
q[7..0]
ROM
4×8
library ieee;
use ieee.std_logic_1164.all;
package rom is
constant rom_width:integer:=8;
constant rom_length :integer:=4;
subtype rom_word is std_logic_vector(rom_width-1 downto 0);
type rom_table is array(0 to rom_length-1)of rom_word;
constant rom: rom_table :=rom_table'("00101111","11010000","01101010",
"11101101");
end;
clk
addr[1..0]
1 0 q[7..0]
ROM4×8
说明: 1 )该包可以单独保存在当前目录下,也可以直接放在下面的实体前; 2 )本设计定义了一个常量型数组,即为 ROM 中内容; 3 )常量型数组的这种定义方式, maxplusII 不支持, quartusII 支持。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use work.rom.all;
entity waveform is
port(clk:in std_logic;
addr: in std_logic_vector(1 downto 0);
q: out rom_word);
end;
clk
addr[1..0]
1 0
q[7..0]
WAVEFORM
architecture test of waveform is
signal tmp: rom_word;
begin
tmp<=rom(conv_integer(addr));
process(clk)
begin
if clk='1' then q<=tmp;
end if;
end process;
end test;
b) 一个容量为 8×8 的 RAM
例子实现方法: ( 改变参数可改变容量 )
1) 有 3 根地址线,可选 8 个字; 2) 8 根数据输入线,即字长 为 8 ; 3) wr 为写控制线, rd 为读控制线, cs 为片选控制线; 4) cs=1,wr 信号由低变高时,将 din 上的数据写入 adr所指定的单元; cs=1,rd=0 时,由 adr 所指定单元的内容将从 dout输出。
Dout[7..0]
Din[7..0]
wrrdcs
Adr[2..0]
8×8
SRAM
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity sram64 is
generic(k:integer:=8;
w:integer:=3);
port (wr,rd,cs:in std_logic;
adr:in std_logic_vector(w-1 downto 0);
din:in std_logic_vector(k-1 downto 0);
dout:out std_logic_vector(k-1 downto 0));
end sram64;
architecture beh of sram64 is
subtype word is std_logic_vector(k-1 downto 0);
type memory is array(0 to 2**w-1)of word;
signal adr_in :integer range 0 to 2**w-1;
signal sram :memory;
begin
adr_in<=conv_integer(adr);
process(wr)
begin
if(wr'event and wr='1‘ and cs=‘1’) then
sram(adr_in)<=din ;
end if;
end process;
process(rd,cs)
begin
if(rd='0' and cs='1')then
dout<=sram(adr_in);
else
dout<="ZZZZZZZZ";
end if ;
end process;
end beh;
见程序 sram64.vhd ,程序在 quartusII 上运行。
c) 一个带时钟的容量为 8×8的 RAM 例子实现方法: ( 改变参数可改变容量 )
1) 有 3 根地址线,可选 8个字; 2) 8 根数据输入线,即字长 为 8 ; 3) wr 为写控制线, rd 为读控制线, cs 为片选控制线; 4) cs=1,wr=1 时, clk 的上升沿来到时将 din 上的数据写入 adr 所指定的单元; cs=1,rd=0 时, clk 的上升沿来到时将 adr 所指定单元的内容送至 dout 输出。
Dout[7..0]
Din[7..0]
wrrdcs
Adr[2..0]
8×8
SRAM
clk
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity sram64clk is
generic(k:integer:=8;
w:integer:=3);
port(clk,wr,rd,cs:in std_logic;
adr:in std_logic_vector(w-1 downto 0);
din:in std_logic_vector(k-1 downto 0);
dout:out std_logic_vector(k-1 downto 0));
end ;
architecture beh of sram64clk is
subtype word is std_logic_vector(k-1 downto 0);
type memory is array(0 to 2**w-1)of word;
signal adr_in :integer range 0 to 2**w-1;
signal sram :memory;
begin
adr_in<=conv_integer(adr);
process(clk)
begin
if( wr='1' and cs='1') then
if(clk'event and clk='1') then
sram(adr_in)<=din ;
end if;
end if;
end process;
process(clk)
begin
if(clk'event and clk='1' )then
if(rd='0' and cs='1')then
dout<=sram(adr_in) ;
else dout<="ZZZZZZZZ";
end if;
end if ;
end process;
end beh;
程序见 sram64clk.vhd, 在 quartusII 上运行。
9 ) 并行输入、串行输出的寄存器 PISO 在实际电路系统的应用中,当需要远距离通信传输时,常需要将 A/D 转换过的并行信号先加载,然后再一串行信号的形式传送到远方,需要使用 PISO 。
pisold
Par_inclk
Ser_outbusySh_comp8 位 Piso 功能:
a) 在时钟上升沿,若 ld=1, 则将 8 位并行输入 信号 par_in 加载到转换电路的内部寄存器,并将状态标志 busy 置位为‘ 1’ ;在 8 位并行数据全部移出之前, busy 保持 为‘ 1’ ,并禁止再次加载数据;
b) 在时钟上升沿, 若 busy=1 ,则逐位将内部寄存器的数据移 出,在数据全部移出之前,移位终止信号 sh_comp 保持为‘ 0’ , 在数据全部移后,将 sh_comp 置为‘ 1’ , busy 置为‘ 0’ 。
library ieee;
use ieee.std_logic_1164.all;
entity par_to_ser is
port(clk,ld:in std_logic;
par_in:in std_logic_vector(7 downto 0);
busy: buffer std_logic;
ser_out:out std_logic;
sh_comp: out std_logic);
end;
pisold
Par_inclk
Ser_outbusySh_comp
architecture alg of par_to_ser is
signal reg:std_logic_vector(7 downto 0);
begin
process(clk,reg,ld)
variable i:integer ;
begin
if( clk'event and clk='1') then
if (ld='1' and busy='0') then
i:=0;
reg<=par_in;
busy<='1';
elsif (busy='1') then
if i<=7 then
sh_comp<='0';
ser_out<=reg(0);
reg<='0'®(7 downto 1);
i:=i+1;
else sh_comp<='1';
busy<='0';
end if;
end if ;
end if;
end process ;
end alg; 程序见 par_to_ser.vhd
10 ) 双向电路和三态控制电路a) 三态门
Dataout{7..0]
enb
Datain{7..0][7..0] [7..0]
library ieee;
use ieee.std_logic_1164.all;
entity tri_gate is
port(enb :in std_logic;
datain:in std_logic_vector(7 downto 0);
dataout :out std_logic_vector(7 downto 0));
end ;
architecture beh of tri_gate is
begin
process(enb,datain)
begin
if enb='1' then dataout<=datain;
else dataout<="ZZZZZZZZ";
end if ;
end process;
end beh;
程序见 tri_gate.vhd
b) 双向端口电路control
In/out1[7..0] [7..0] [7..0] In/out2[7..0]
原理示意图
Control=1: in/out1 输入, in/out2 输出。Control=0: in/out1 输出, in/out2 输入。
out1{7..0]
control
in1{7..0][7..0] [7..0] [7..0]
In/out2[7..0][7..0]
结构图 (图中 in1 和 out1 可以合在一起)
library ieee;
use ieee.std_logic_1164.all;
entity tri_state1 is
port(control :in std_logic;
in1:in std_logic_vector(7 downto 0);
inout2 :inout std_logic_vector(7 downto 0);
out1:out std_logic_vector(7 downto 0));
end ;
architecture beh of tri_state1 is
begin
process(control,inout2,in1)
begin
if control='0' then
out1<=inout2;
inout2<="ZZZZZZZZ";
else inout2<=in1; out1<="ZZZZZZZZ";
end if ;
end process;
end beh;程序见 tri_state1.vhd原理图文件见 tri1.bdf
11) A/D0809采样控制电路 ADC0809 是 CMOS 的 8 位 A/D 转换器,片内有 8 路模拟开关,可控制 8 个模拟量中的一个进入转换器中。 ADC0809 的精度为 8 位,转换时间约 100μ 含锁存控制的 8 路多路开关,输出有三态缓冲器控制,单 5V 电源供电。
In3In4In5In6In7
STARTEOCID4IOECLKVCC
REF+GND
D6
In2In1In0ADDAADDBADDCALED0D1D2D3D7REF-D5
ADC0809
主要控制信号说明:1 )输入信号:START: 转换启动信号,高电平有效;ALE : 3 位通道地址锁存信号,高电平有效;OE : 输出使能,高电平有效。2 )输出信号:EOC :转换状态信号,当 START 有效后约 ( 100μ )后, EOC产生一个负脉冲,以 示转换结束,在 EOC 上升沿后,可以读 出数据。
STARTALEEOC
OE
D[7..0] ZZZZZZZ DATA
ADC0809工作时序
D[7..0]
EOC
CLK STARTALEOEADDA
LOCK1
Q[7..0]
LOCK
REGL
控制电路
{来自0809
}送到0809
library ieee;
use ieee.std_logic_1164.all;
entity adcint is
port(d:in std_logic_vector(7 downto 0); --0809 的 8 位数据输出 clk,eoc:in std_logic;
lock1,ale,start,oe,adda:out std_logic; --lock1 为输出数据锁存信号 q:out std_logic_vector(7 downto 0));
end;architecture beh of adcint is
type states is (st0,st1,st2,st3,st4,st5,st6); -- 定义各状态(枚举类型)signal current_state,next_state:states:=st0;
signal regl :std_logic_vector(7 downto 0);
signal lock :std_logic; -- 转换后数据输出锁存时钟begin
adda<='1';lock1<=lock;
pr0: process(current_state,eoc)
Begin -- 规定各状态转换方式case current_state is
when st0=>ale<='0';start<='0';oe<='0';lock<='0';next_state<=st1;
when st1=>ale<='1';start<='0';oe<='0';lock<='0';next_state<=st2;
when st2=>ale<='0';start<='1';oe<='0';lock<='0';next_state<=st3;
when st3=>ale<='0';start<='0';oe<='0';lock<='0';
if(eoc=‘1’)then next_state<=st3; --测试 EOC 的下降沿 else next_state<=st4;-- 下降沿到 end if;
when st4=>ale<=‘0’;start<=‘0’;oe<=‘0’;lock<=‘0’;--EOC 为低电平 -- 测试 EOC 的上升沿,表明转换结束 if(eoc='0')then next_state<=st4;
else next_state<=st5; --EOC 上升沿到 end if;
when st5=>ale<=‘0’;start<=‘0’;oe<=‘1’; -- 转换结束,输出使能有效 lock<='0';next_state<=st6;
when st6=>ale<='0';start<='0';oe<='1';
lock<=‘1’;next_state<=st0; --lock 的上升沿,将数据存入 REGL
when others=>ale<='0';start<='0';oe<='0';lock<='0';next_state<=st0;
end case;
end process pr0;
pr1:process(clk)
begin
if(clk'event and clk='1')then current_state<=next_state;-- 在时钟上升沿,转换到下一个状态 end if;
end process pr1;-- 由信号 current_state 将当前状态值带出此进程,进入进程 pro
pr2:process(lock)—此进程中,在 LOCK 的 上升沿,将转换好的数据保存并输出begin
if (lock='1' and lock'event) then
regl<=d;
end if;
end process pr2;
q<=regl;
end beh;
12 )移位相加型乘法器( 8 位)设计乘法器以 8 位加法器为核心,辅以移位寄存器组成。乘法原理:乘法通过逐项移位相加原理实现,从被乘数的 最低位开始,若为 1 ,则乘数左移后与上一次的 和相加;若为 0 ,乘数左移后加 0 ,直至被乘数的 最高位。
并入串出移位寄存器 8 位被乘数
8 位
乘法器 1×8 位
乘数 8 位 8 位加法器
8 位
输出[15..0]
16 位锁存器右移寄存器
9 位 输出高 8 位 [15..8]
clk
a)8 位右移寄存器
library ieee;
use ieee.std_logic_1164.all;
entity sreg8b is
port(clk,load:in std_logic;
din:in std_logic_vector(7 downto 0);
qb :out std_logic);
end;
architecture beh of sreg8b is
signal reg8: std_logic_vector(7 downto 0);
begin
process(clk,load)
begin
if load='1' then reg8<=din;
elsif clk'event and clk='1' then
reg8(6 downto 0)<=reg8(7 downto 1);
end if;
end process;
qb<=reg8(0); --- 输出最低位end beh;
b) 1×8 位乘法器(可有多种结构)library ieee;
use ieee.std_logic_1164.all;
entity andarith is—结构( 1 ) port(abin:in std_logic;
din:in std_logic_vector(7 downto 0);
dout :out std_logic_vector(7 downto 0));
end;
architecture beh of andarith is
begin
process(abin,din)
begin
for i in 0 to 7 loop
dout(i)<=din(i) and abin;
end loop;
end process;
end beh;
library ieee;
use ieee.std_logic_1164.all;
entity andarith1 is—结构( 2 ) port(abin:in std_logic;
din:in std_logic_vector(7 downto 0);
dout :out std_logic_vector(7 downto 0));
end;
architecture beh of andarith1 is
begin
process(abin,din)
begin
if abin='0' then dout<="00000000";
else
dout<=din;
end if;
end process;
end beh;
library ieee;
use ieee.std_logic_1164.all;
entity andarith2 is --结构 (3)
port(abin:in std_logic;
din:in std_logic_vector(7 downto 0);
dout :out std_logic_vector(7 downto 0));
end;
architecture beh of andarith2 is
begin
dout<="00000000" when (abin='0') else din;
end beh;
c) 8 位加法器library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity adder8 is
port(a,b :in std_logic_vector(7 downto 0);
s :out std_logic_vector(8 downto 0));
end;
architecture beh of adder8 is
begin
s<='0'&a+b;
end beh;
d) 16 位锁存器 /右移寄存器library ieee;
use ieee.std_logic_1164.all;
entity reg16b is
port(clk,clr:in std_logic;
d:in std_logic_vector(8 downto 0);
q :out std_logic_vector(15 downto 0));
end;
architecture beh of reg16b is
signal r16s: std_logic_vector(15 downto 0);
begin
process(clk,clr)
begin
if clr='1' then r16s<=(others=>'0');
elsif clk'event and clk='1' then
r16s(6 downto 0)<=r16s(7 downto 1);
r16s(15 downto 7)<=d;
end if;
end process;
q<=r16s;
end beh; 8 位乘法器可用上面四各电路组成,原理图文件见 mult8.bdf, 在 quartusII上运行。 (8 个 clk 后为正确值 ).
延时电路的几个例子
library ieee;
use ieee.std_logic_1164.all;
entity delay is
port(reset,clk:in std_logic;
time_out :out std_logic);
end;
architecture beh of delay is
Begin
process(reset,clk)
variable count:std_logic_vector(3 downto 0);
下例调用了一个定义在 process 中的函数 inc 实现二进制计数器,最终实现输出信号延时。
function inc(x:in std_logic_vector) return std_logic_vector is
variable xv:std_logic_vector(x'length-1 downto 0);
begin
xv:=x;
for i in 0 to xv'high loop
if xv(i)='0' then
xv(i):='1';
exit;
else
xv(i):='0';
end if;
end loop;
return xv;
end inc;
begin
if reset='1' then
count:="0000";time_out<='0';
elsif clk'event and clk='1' then
count:=inc(count);
end if;
if(count="1111")then
time_out<='1';
end if;
end process ;
end beh;
下例同样调用函数 inc 实现二进制计数器,和上例不同的是先将函数定义在包 mypack_1 中,然后调用,最终实现输出信号延时。library ieee;
use ieee.std_logic_1164.all;
package mypack_1 is
function inc(x:in std_logic_vector)
return std_logic_vector ;
end;
package body mypack_1 is
function inc(x:in std_logic_vector)
return std_logic_vector is
variable xv:std_logic_vector(x'length-1 downto 0);
begin
xv:=x;
for i in 0 to xv'high loop
if xv(i)='0' then
xv(i):='1';
exit;
else
xv(i):='0';
end if;
end loop;
return xv;
end inc;
end mypack_1;
library ieee;
use ieee.std_logic_1164.all;
use work.mypack_1.all;
entity delay_2 is
port(reset,clk:in std_logic;
time_out :out std_logic);
end;
architecture beh of delay_2 is
begin
process(reset,clk)
variable count:std_logic_vector(3 downto 0);
begin
if reset='1' then
count:="0000";time_out<='0';
elsif (clk'event) and (clk='1') and (clk'last_value='0')then
count:=inc(count); if(count="1111") then time_out<='1';
end if;
end if;
end process ;
end beh;
下例采用移位方法求延时,移位算法:按下算法(四位)最长序列为 15n 1 n 1 n 1 n 1 n n n n n3 2 1 0 1 0 3 2 1Q Q Q Q (Q Q )Q Q Q
library ieee;
use ieee.std_logic_1164.all;
entity delay_1 is
port(reset,clk:in std_logic;
time_out :out std_logic);
end;
architecture beh of delay_1 is
begin
process(reset,clk)
variable count:std_logic_vector(3 downto 0);
begin
if reset='1' then
count:="0001"; time_out<='0';
elsif clk'event and clk='1' then
count:=(count(1)xor count(0))&count(3 downto 1);
end if;
if(count="0011")then
time_out<='1';
end if;
end process;
end beh;
下例采用一般计数器的设计方法,实现延时:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity delay_3 is
port(CLK,CLRN :IN STD_LOGIC;
CO:OUT STD_LOGIC);
END;
ARCHITECTURE BEH OF delay_3 IS
BEGIN
PROCESS(CLK,CLRN)
variable q :std_logic_vector(3 downto 0);
BEGIN
IF (CLRN='1') THEN q:="0000";co<='0';
ELSIF(CLK'EVENT AND CLK='1') THEN
IF (q="1111")THEN q:="0000"; co<='1';
ELSE q:=q+1;
END IF;
END IF;
END PROCESS;
END BEH;
MAX+PLUSII 开发软件中的参数化模块1. 参数化数据选择器 lpm_mux宏模快
端口名称 功 能 描 述输入端口 Data[ ][ ] 数据流输入端口
Sel[ ] 地址选择线输出端口 Result[ ] 数据输出线
参数设置LPM_WIDTH Data[ ][ ] 和 Result[ ] 端口宽度
LPM_WIDTHS Sel[ ] 端口宽度LPM_SIZE 输入数据流的数目,等于 2LPM——WIDTHS
另有清零和寄存设置
2. 参数化加法器 /减法器 lpm_add_sub宏模快端口名称 功 能 描 述
输入端口 Dataa[ ] 被加数 /被减数Datab[ ] 加数 /减数
输出端口Result[ ] Dataa[ ]+ Datab[ ]+cin 或 Dataa[ ]- Datab[ ]+cin-
1
Cout 进位和借位标志 Cout 用于无符号数运算 Overflow 用语有符号数运算 Cout和 Overflow 不同时出现
Overflow 溢出标志
参数设置LPM-width Dataa[ ] 、 Datab[ ] 和 Result[ ] 端口宽度
LPM_DIRECTIONADD表示执行加法运算SUB表示执行减法运算DEFAULT缺省设置为加法器
LPM_REPRESENTATION
指定参与运算的数值是无符号数还是有符号数另有清零和寄存设置
3. 参数化乘法器 lpm_mult宏模快端口名称 功 能 描 述
输入端口Dataa[ ] 被乘数Datab[ ] 乘数Sum[ ] 部分和 ( 可以不使用)
输出端口 Result[ ] Result[ ] =Dataa[ ]×Datab[ ]+sum
参数设置
LPM-WIDTHA Dataa[ ] 端口宽度LPM-WIDTHB Datab[ ] 端口宽度LPM-WIDTHP Result[ ] 端口宽度LPM-WIDTHS SUM 端口宽度
LPM_REPRESENTATION
指定参与运算的数值是无符号数还是有符号数USE_EAB 选择使用 EAB 或逻辑单元实现乘法器,“ o
n” 为使用 EAB , “ off” 为使用逻辑单元。另有清零和寄存设置
4. 参数化译码器 lpm_decode宏模快端口名称 功 能 描 述
输入端口 data[ ] 数据输入输出端口 eq[ ] 译码输出
参数设置LPM_WIDTH Data[ ] 端口宽度
LPM_DECODES译码器输出的端口数目
等于 2LPM_WIDTHS
另有清零和寄存设置
5. 参数化 RAM宏模快 参数化 RAM 可以随时在任一指定地址写入或读出数据 。有多个模块
模块名 功能描述Csdpram 参数化循环共享双端口 RAM
Lpm_ram_dp 参数化双端口 RAM
Lpm_ram_dq 参数化 RAM ,输入 / 输出端口分离Lpm_ram_io 参数化 RAM ,输入 / 输出端口共用
下面为 Lpm_ram_dq 的参数表一端口名称 功能描述
输入端口
Data[] 输入数据Address[ ] 地址端口
we 写使能端口,高电平时向 RAM 写入数据Inclock 同步写入时钟
Outclock 同步读取时钟输出端口 Q[ ] 数据输出端口
参数设置LPM_WIDTH Data[] 和 Q[ ] 端口的数据线宽度
LPM_WIDTHAD Address[ ] 端口宽度LPM_numwords RAM 中存储单元的数目USE_EAB 选择使用 EAB 或逻辑单元
下面为 Lpm_ram_dq 的参数表二同步数据读 / 写操作 同步数据读取 异步存储器操作
inclock we 功能描述 outclock 功能描述 we 功能描述Not~ x 状态不变 Not~ 状态不变 L 状态不变
~(写) H 写入数据~ 读出数据 H 写入数据
~(读) L 读出数据“~”表示时钟发生变化,“ not~”表示时钟不发生变化