第2章 VHDL语言程序的基本结构 一个VHDL设计由若干个VHDL文件构成,每个文件主要包含五个部分的一个或全部:在max+plusⅡ中后缀为(VHD). 其中1~4为可分别编译 的源设计单元。 1.程序包 ( Package ) 2.实体 (Entity) 3.结构体 (Architecture) 4.配置(configuration) 5.库(library) 库用来存放已编译过 的实体、构造体、包 和配置。
2.1 VHDL语言设计的基本单元 基本单元:基本设计实体,可很简单,如门, 也可很复杂,如包含CPU的系统。 设计一个数字系统,首先要解决两个问题: 1) 输入、输出是什么; 2)内部完成什么功能。 对于1,由实体(Entity)说明来描述; 对于2,由构造体(Architecture)来描述。
实体说明部分 构造体说明部分 Entity mux is Generic (m: Time:=1ns); Port(do,d1,sel: IN Bit; q: out Bit); End mux; Architecture connect Of mux is Signal tmp: Bit; Begin cale: Process(d0,d1,sel) Variable tmp1,tmp2,tmp3:Bit; 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 实体说明 实体的格式 1.类属参数说明 实体中定义电路单元和使用环境的接口,实体名必须与电路名相同。 ENTITY 实体名 IS [类属参数说明]; [端口说明]; END 实体名; 1)VHDL语言书写不分大 小写;(个别例外) 2)[ ]中内容有时可不要; 3)END后的实体名可省。 1.类属参数说明 1)类属参数说明(generic)用来为设计引入信息,如时间; 2)类属参数说明(generic)必须放在端口之前;
2.端口说明 3)类属参数说明(generic)常用来设计通用元件。 格式: 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种数据类型,但逻辑设计只用两种,另在库中还定 义了多种数据类型: Bit 2. bit_vector Bit :位逻辑数据类型,取值为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 is Port(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>;
如: Architecture beh Of mux is 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 之间,描述构造体的行为和电路 连接关系。 所谓并行,指多个语句不以书写顺序执行。
y=a0s1s0+a1s1s0+a2s1s0+a3s1s0 =(a0s0+a1s0)s1+(a2s0+a3s0)s1 一数据选择器的构造体: 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 语言构造体的子结构 2.2.1 BLOCK语句结构描述 一个构造体可以用几个子结构来构成,即一个系统可以用几个比较独立的模快来构成。 BLOCK语句结构 PROCESS语句结构 SUBPROGRAMS语句结构 2.2.1 BLOCK语句结构描述 1.BLOCK语句的结构 格式: 块结构名; block begin … end block 块结构名;
Entity mux is Port(d0,d1,sel: IN Bit; q: out Bit); End mux; Architecture connect Of mux is Signal tmp1,tmp2,tmp3 : Bit; Begin cale: block tmp1<=d0 AND sel; tmp2<=d1 AND (NOT sel); tmp3<= tmp1 OR tmp2; q<=tmp3 ; End block cale; END CONNECT; 一个二选一数据选择器的描述
2.块(block)和子原理图的关系:一个block相当于总图中的一个 子图,分块设计有利于编辑查错。 4.卫式block(Guarded block):指满足条件时,块语句执行,不满足 时不执行。 1)卫式块不能综合; 2)after语句不能综合; 3)当满足clk=1时执行。 例:… begin G1: block(clk=‘1’) q<=guarded d after 5ns; qb<=guarded not(d) after 7ns; end block G1; d q qb clk
2.2.2进程(process)语句结构描述 例如: 变量只在进程中定义和使用。 1.process语言结构 Begin … End process; Architecture connect Of mux is Signal tmp: Bit; Begin cale: Process(d0,d1,sel) Variable tmp1,tmp2,tmp3:Bit; tmp1:=d0 AND sel; tmp2:=d1 AND (NOT sel); tmp3:= tmp1 OR tmp2; tmp<=tmp3; q<=tmp AFTER m; END PROCESS; END CONNECT; 例如: 变量只在进程中定义和使用。
2.2.3 子程序(subprogram)语句结构描述 2. process中语句的顺序性:process中的语句按顺序执行。 process语句的启动:process( )括号内的量称为敏感量, 敏感量发生变化,启动进程。 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; cale(d3,d4,a,b);--正确 …
2.函数语句 子程序可定义在进程、包和构造体中。例2-9为定义在包中的例子。定义了一 个max 函数。 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包须说明。
VHDL类型,如bit,bit_vector 库名 程序包名 包中预定义内容 std standard VHDL类型,如bit,bit_vector ieee std_logic_1164 定义std_logic,std_logic_vector等 numeric_std 定义了一组基于std_logic_1164中定义的类型的算术运算符,如“+”,“-”,SHL,SHR等 std_logic_arith 定义有符号与无符号类型,及基于这些类型上的算术运算。 std_logic_signed 定义了基于std_logic与std_logic _ vector类型上的有符号的算术运算 std_logic_unsigned 定义了基于std_logic与std_logic_ vector类型上的无符号的算术运算
由工具商提供的库,在MAX-PLUSⅡ中,有ALTERA公司自己定义的库,名为ALTERA.里面 面向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)
包集合中存放信号定义、常量、数据类型、元件语句、函数、过程等,它可以编译,使用时用use语句。 2.3.2 包集合 包集合中存放信号定义、常量、数据类型、元件语句、函数、过程等,它可以编译,使用时用use语句。 如: use ieee.std_logic_1164.all; 包结构: package 包集合名 is [说明语句]; end 包集合名; Package body 包集合名 is 包的说明部分(包头) 包体(可选)
--包头说明 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位计数器; 如编译: 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语言的数据类型及运算操作符
例 constant vcc: real:=5.0; 3.1 VHDL语言的客体及其分类 在逻辑设计中,VHDL语言常用的数据对象为信号、常量、变量,数据对象称为客体。 3.1.1常量(或常数) 常量在设计描述中保持某一规定类型的特定值不变 。如利用它可设计不同模值的计数器,模值存于常量中,不同的设计,改变模值仅需改变此常量值。 格式:CONSTANT 常量名:数据类型:=表达式; 常量赋值符号为“ : = ”。 例 constant vcc: real:=5.0;
例:variable cnt: integer range 0 to 255 :=10; 变量只在给定的进程中用于声明局部值或用于子程序中,可以是任意类型。赋值符号为“ : = ”。 变量说明格式: variable 变量名 :数据类型 约束条件:=表达式; 例:variable cnt: integer range 0 to 255 :=10; 变量赋值立即生效,不产生附加延时, 不能写成:y:=x after 10ns;
信号赋初值 用“:=” 程序中信号代入用“<=” 例: signal a: bit; 3.1.3 信号(Signal) 信号表示一条连线,通常在构造体、包集合和实体中说明, 信号是全局量,内部信号说明不要注明数据流向,外部信号(外部信号对应为in,out,inout,buffer)说明时signal省略。 信号也可在状态机中表示状态变量。信号赋值符号为“<=”。 信号说明格式: signal 信号名:数据类型 约束条件:=表达式; 信号赋初值 用“:=” 程序中信号代入用“<=” 例: signal a: bit;
2)信号的代入和语句的处理在时间上是分开的。 3.1.4 信号和变量值代入的区别 1)变量赋值是立即执行的; 2)信号的代入和语句的处理在时间上是分开的。 在例3-1的前部分,A,B,C,D为信号,当语句处理时,信号并不立即代入,当结束进程时,信号才被代入。 在例3-1的前部分,A,B,C,D为变量,当语句处理时,变量立即赋值。所以前后两部分结果不同。 下面是一个加法器的例子:
Port(op1,op2 :in integer range 0 to 15; 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; --定义一个信号,以保存两数二进制相加的和.
binadd<=op1+op2; --信号赋值 process(binadd) 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) 字符矢量
格式:type 数据类型名 {,数据类型名} 数据类型定义; 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_vector std_logic_vector→ Bit_vector Bit → std_logic Std_logic→ bit 2)std_logic_arith包集合 Conv_std_logic_vector(A,位长) Conv_integer(A) Integer,unsigned,signed→ Std_logic_vector Unsigned,signed→ integer 3)std_logic_unsigned包集合 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包中定义了 std_ulogic类型 具有9种不同的值(见p44) Std_logic 类型 是std_ulogicd的决断子类型
含义:当一个信号有多个驱动器驱动时,则调用定义的决断函数以解决冲突,并决定给信号赋什么值,这可用在三态总线中。 4) Character 字符型 由ASCII码表示的128个字符,要用单引号标注,如‘c’,多数综合工具支持VHDL-87定义的字符,可综合。 5) std_logic是决断类型 含义:当一个信号有多个驱动器驱动时,则调用定义的决断函数以解决冲突,并决定给信号赋什么值,这可用在三态总线中。
Use ieee.std_logic_1164.all; Entity ex is 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’; en2 en1 c d dbus
使用std_logic型后,缺点是如误将两个驱动器驱动同一信号,也不会有出错报告。 6)关于数组(array) type 类型名 is array 范围 of 原数据类型名 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 2 1 4 3 2 1 0 “011” a(1,2) a(1,2)(0)
如: type state_type is (start,idle,waiting,run,error); 7) 枚举类型 格式:type 名 is (.., .., ..); 枚举类型经常用时序电路的设计中,时序电路有许多状态,这些 状态在设计中可编码,如用枚举类型,就可以自己不去编码,而 交给工具。大多数综合工具都支持枚举类型。 如: type state_type is (start,idle,waiting,run,error); signal state: state_type; 表示state可取5个值,综合工具将每个状态转换为3位矢量,表示5种不同值。
如信号 A 为bit_vector类型,下列的赋值均为正确的: A<=“10011” (二进制) 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位矢量。
在VHDL语言中,有时可以用所描述的上下关系来判断某一数据 的数据类型。 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); ‘-’(不可能情况)
3.3 VHDL语言的运算操作符 ·算术运算符(Arithmetic operators) + 加 - 减 * 乘 / 除 ** 乘方 + 加 - 减 * 乘 / 除 ** 乘方 mod 求模 rem 求余 ** 指数 abs 求绝对值 + 正(一元运算) 负(一元运算)
·关系运算符 = 等于 /= 不等于 < 小于 <= 小于或等于 > 大于 >= 大于或等于 注:其中‘ <=’ 操作符也用于表示信号的赋值操作
·并置运算符 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乘方时的“/”
第 4 章 VHDL语言构造体的描述方法 4.1 构造体的行为描述方法 4.1.1代入语言 行为描述是对系统的数学模型的描述,较抽象。 第 4 章 VHDL语言构造体的描述方法 4.1 构造体的行为描述方法 行为描述是对系统的数学模型的描述,较抽象。 行为描述的程序特点是大量采用算术运算、关系运算、惯性延时和传输延时,有些描述难以综合。 4.1.1代入语言 一般格式: 信号量<= 敏感信号量表达式; 如: a<= b; (只要b变化,就代入新的值) 如: z<= a nor(b nand c); (只要a、b、c变化,就代入新的值)
a<=b after 5ns; (b发生变化后5ns代入新值) 具有延时的代入语句: 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的默认延时; 尖峰脉冲不能传输(如果使用after语句) 常用作元件延时 2)传输延时(transport) a)脉冲均可传输,与宽度无关 可以很好地表示接连线延时 q1<=a after 5 ns; 惯性延时 q2<=transport a after 5ns; 传输延时
(综合工具不支持延时) a b b<=a after 5 ns; b<= transport a after 5 ns; a b
generic (类属说明语句)用于不同层次之间的信息传递。 如:位矢量长度,数组长度,器件延时时间。 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.2.2 使用RTL描述方式应注意的几个问题 例4-8是二选一数据选择器的例子,用了寄存器硬件的一一对应的直接描述;(描述电路的结构) 1)“X”状态的传递 “X”状态的传递是指不确定信号的传递,它使逻辑电路产生不确定的结果。这种不确定的结果,,对RTL仿真是允许的,但对综合后的门级电路仿真是不允许的。 例4-9的含义: 当sel=1 则 y=0, 否则 y=1; 这意味着当sel=‘X’时,y=1。 其实设计者要想表达的意思是相同的,但得到的结果不同。在编程时要注意。 例4-10下一段程序为改进方法。 例4-10的含义: 当sel=0 则 y=1, 否则 y=0; 这意味着当sel=‘X’时,y=0。
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 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. 关联性强的信号应放在一个进程中 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构造体结构描述的基本框架 aa u1 u3 u2 u4 ab d0 d1 sel & 1 ≥1 q nsel 例4-16 为一个二选一的例子。 q=(d0 and sel) or (d1 and (not (sel)))
1. ASIC级结构描述:一般是门级或更低层次 编程的思路为: 1)先说明要调用的三 个元件: and、or2、inv 2)用 PORT MAP语句 进行连接元件。 aa u1 u3 u2 u4 ab d0 d1 sel & 1 ≥1 q nsel 结构描述的三个层次: 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(<端口列表>) --元件例化: <例化名>:<实体名,即元件名>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); 第一种写法为位置映射法,第二种写法为名称映射法。 & a b c and2
第 5 章 VHDL语言的主要描述语句
VHDL 常用语句分并行(Concurrent)语句和顺序(Sequential)语句: 并行语句总是处于进程(PROCESS)的外部。所有并行语句都是并行执行的,即与它们出现的先后次序无关。如when..else语句 顺序语句(Sequential): 顺序语句总是处于进程或子程序的内部,并且从仿真的角度来看是顺序执行的。如if-then-else语句
5.1顺序描述语句 5.1.1 wait 语句 wait 语句的四种类型: wait 无限等待 wait on 敏感信号量变化 wait until 条件满足 wait for 时间到
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 3. Wait for process begin wait until a=‘1’; c<=not a; end process; 可综合 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 语句 5.1.4 变量赋值语句 变量赋值只能在进程或子程序中使用,无法传递到进程之外。 格式: 目的变量 := 表达式; 例: a:=2; b:=“11101011”; 5.1.5 if 语句 2 . 二选择控制 If 条件 then 顺序处理语句; else end if ; 门闩控制 If 条件 then 顺序处理语句; end if ;
算:=,/=,>, <等,也可用 逻辑运算操作的组合表达式。 3 . 多选择控制 If 条件 then 顺序处理语句; elsif 条件 then … else end if ; If 语句常用于选择、比较和 译码等场合; *if 后的条件判断,输出为逻 辑量,即“真”或“假”,故条 件表达式中只能使用关系运 算:=,/=,>, <等,也可用 逻辑运算操作的组合表达式。 例5-6 为一个D触发器的描述。 d q clk
例5-8 为四选一数据 选择器描述。 例5-7 为二选一数据选择器描述。 MUX a b sel c 1 MUX input(0) 例5-8 为四选一数据 选择器描述。 MUX input(0) sel(1) y 1 sel(0) 2 3 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值,决定选择什么数据。
1)sel<=‘0’;(因为sel为整型数,而‘0’表示0为位量) 2)程序中sel为信号,并在进程中使用,而在进程中 例5-9 有两处错误: 1)sel<=‘0’;(因为sel为整型数,而‘0’表示0为位量) 2)程序中sel为信号,并在进程中使用,而在进程中 信号值的改变要等进程执行结束后进行,这和编 程的要求相异。 * 应把sel在进程中定义为变量,并把所有的sel<= 改为sel:= 。 例5-10 为3-8译码器的例子 2 1 5 4 3 7 6 Y(7~0) c b a & EN G2B G2A G1 编程思路: 1)将码输入信号c,b,a合成为位矢量(indata)(用并置符&); 2) 用if语句判断使能信号是否有效,如有效,则进入3); 3)用case语句判断输出。
例5-11 为二--十进制编码器的例子。 1)为普通编码器,不能同时多个信号有效; 2)当无信号输入或有多个信号有效时,程序处理为使 y=“XXX”,可使电路简单。 例5-12 为二--十进制优先编码器的例子。 本例使用多条件if语句进行逐条判断,完成优先编码,例 中input(0)优先级最高。
格式: 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语句的区别: 5.2.1 选择信号代入 If 只能用在进程内部,为顺序语句; 条件代入when后一定要有else,而if 后可以没有else,当if 后没有else时,可以是电路具有保持功能,形成锁存器。由于条件代入中不能自身代入,故不能形成锁存器。 5.2.1 选择信号代入 格式: with 表达式 select 目的信号量<= 表达式 1 when 条件1, 表达式 2 when 条件2, … 表达式 n when 条件n;
5.2.5 并发过程调用语句 例5-18和5-19功能相同,均为描述数据选择器。选择条件代入语句和顺序语句case类似。 在例2-7中定义了一个名为vector_to_int的过程,一个过程有完整的输入和输出,在调用时: *在前面加标号; *并发过程调用语句应带有in,out或inout参数, 参数放在( )内; * 并发过程调用可有多个返回值; *并发过程调用时,返回量一定要是信号; *在进程中也可调用过程。
5.2.6 块(block)语句 格式: 标号:block 块头 {说明语句}; begin {并发处理语句}; end block 标号; 1)块头通常用语信号的映射及参数 的 定义,常用下列语句: generic, generic_map port, port_map 格式: 标号:block 块头 {说明语句}; begin {并发处理语句}; end block 标号; 2)说明语句和构造体语句说明语句 相同,主要是对该块所要用到的客 体加以说明。可说明的项目有: * use子句; *子程序说明及子程序体; *类型; *常量说明; *信号说明; *元件说明。 3.并发语句常用于结构 体的结构化描述。
例5-20 为一个简单CPU芯片设计实例框架。芯片包含一个ALU和一个REG8。而REG8又由8个子模块组成,子模块分别为:REG1,…,REG8。在每一个块内有局部信号、数据类型、常数等说明。 程序的前6行,定义了一个数组tw32(一维,32个元素),存放在Bit32包中; 实体为CPU,定义clk,interrupt为输入,adder为输出,data为inout(双向); 构造体名为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语句可以实现块内和块外信息传递 语句把块内的信号和块外的信号相连接。 函 数 ALU BLOCK abus ibus bbus dbus ctbus comt 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) 块的数值属性。
如将 0 TO 9改为 9 DOWNTO 0, 则情况就不一样了。 一般数据的数值属性 (共4种) 格式:客体’属性名。 一般数据的数值属性 (共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, 则情况就不一样了。
Tim1<=tim’left;--得到sec Tim2<=reverse_tim’left;--得到min(应该为month) 例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;--得到sec Tim2<=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语句,那么
3.如果在 块和构造体中只有component语句或 被动进程,那么属性’structure得到true信息。 ’behavior将得到true信息。 3.如果在 块和构造体中只有component语句或 被动进程,那么属性’structure得到true信息。 例题5-27分析:描述了一个四位移位寄存器 1)程序开始说明了元件dff; 2)从第一个begin到q=>right描述了以下结构: d q d q cp left right dff clk i1 i2 i3 u1 u2 u3 u4
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 e r 框图中的三个量分别用包中 定义的类型。
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: R A M data_in addr cs 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’ Y 或r_wb=‘x’ Data= -1 N cs=‘0’ Data= -2 片选无效 片选有效 (写) r_wb=‘1’ 地址为 -1或-2 片选有效 片选无效 (写) (读) 将ram_data1中地址为 addr中的 数送到输出 端data. 给出出错信息及等级 并将输出data置为-1。 data_in=>ram_data1(addr) ram_data1(addr)=>data
3)信号属性函数 信号属性函数得到信号行为信息。 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 end loop; process(clk,resetn) end if; end process; if resetn='0' then for i in 0 to 3 loop s_d(i)<="000"; end loop; elsif clk'event and clk='1'then 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 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); 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 当前状态
一个Mealy 型状态机的例子 S1 S0 S2 S3 程序见mealy.vhd 1/1001 0/1100 0/0000 1/1111 其他/0000 其他/1001 其他/1100 其他/1111 1/1001 0/1100 1/1111 0/0000 程序见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;
该进程完成状态转换的描述 WHEN s2 =>if in1='1'then begin state<=s3; p0: process (clk,reset) 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; WHEN s2 =>if in1='1'then state<=s3; end if; WHEN s3 =>if in1='0'then state<=s0; END CASE; 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"; out1 <="1001";
该进程完成由状态和输入决定输出 when s2=> if in1='1' then out1 <="1111"; else end if; when s3 => if in1='0' then out1 <="0000"; out1 <="1111"; end case; end process; end bhv; 该进程完成由状态和输入决定输出
5) Moore型状态机 组合逻辑 寄存器 input output clk reset 当前状态 次状态 Process p1 p0 p2
前一个例子的moore型形式: S0 S1 S2 S3 1 1111 0000 1001 1100 程序分析见moore.vhd
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) --时钟进程 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 ci clk 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) if(nreset='0')then qcnt<=(others=>'0'); elsif(clk'event and clk='1')then if(ci='1')then qcnt<=qcnt+1; end if; end process; end behave;
7) 寄存器和移位寄存器 下面的实例介绍触发器、移位寄存器的设计, 说明元件、过程调用等方面知识。
a) 一个带异步清零的D触发器 见程序dff1.vhd 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 方法一:调用dff1组成。(dff1和shift8在同一目录下)
见程序shift8.vhd 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) 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。
dout ( 7 ) ~ 例如:当enb=1时,s(2)s(1)s(0)=100时。 电路设计方法: MSB LSB 移位前 移位后 电路设计方法: 1)将循环左移寄存器描述为一个名为shiftp的过程(procedure); 将过程shiftp定义在包名为cpac的包中; 在实体描述中调用过程,实现移位。
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 signal dout :out std_logic_vector)is
程序见cpac.vhd 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) if (clk'event and clk='1') then if (enb='0') then dout<=din; else shiftp(din,s,dout); end if; end process; end rtl; 程序见bsr.vhd,由于maxplusII 不支持过程调用语句,该程序 可利用quartusII运行。
8) 存储器 存储器分为: 只读存储器(ROM) 随机存取存储器(RAM) 下面是两个可综合的ROM和RAM的例子。
R O M 一个容量为4×8的rom例子实现 方法:(改变参数可改变容量) 1)把ROM中要存放的内容先定 义为一个数组,并存放在一个 包文件内; 2)在实体中调用数组,进行 初始化。 clk addr[1..0] 1 0 q[7..0] R O M 4×8
ROM clk 4×8 1 0 q[7..0] addr[1..0] library ieee; 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; 说明:1)该包可以单独保存在当前目录下,也可以直接放在下面的实体前; 2)本设计定义了一个常量型数组,即为ROM中内容; 3)常量型数组的这种定义方式,maxplusII不支持,quartusII支持。
clk q[7..0] 1 0 addr[1..0] library ieee; use ieee.std_logic_1164.all; 1 0 q[7..0] W A V E F O R M 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;
architecture test of waveform is signal tmp: rom_word; begin tmp<=rom(conv_integer(addr)); process(clk) if clk='1' then q<=tmp; end if; end process; end test;
一个容量为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] wr rd cs 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) if(wr'event and wr='1‘ and cs=‘1’) then sram(adr_in)<=din ; end if; end process;
见程序sram64.vhd,程序在quartusII上运行。 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] wr rd cs 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) if( wr='1' and cs='1') then if(clk'event and clk='1') then sram(adr_in)<=din ; end if; end process;
程序见sram64clk.vhd, 在quartusII上运行。 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 8位Piso功能: 在实际电路系统的应用中,当需要远距离通信传输时,常需要 将A/D转换过的并行信号先加载,然后再一串行信号的形式传送 到远方,需要使用PISO。 piso ld Par_in clk Ser_out busy Sh_comp 8位Piso功能: 在时钟上升沿,若 ld=1,则将8位并行输入 信号par_in加载到转换电路的内部寄存器,并将状态标志 busy置位为‘1’;在8位并行数据全部移出之前,busy保持 为‘1’,并禁止再次加载数据; b) 在时钟上升沿, 若busy=1,则逐位将内部寄存器的数据移 出,在数据全部移出之前,移位终止信号sh_comp保持为‘0’, 在数据全部移后,将sh_comp置为‘1’,busy置为‘0’。
piso ld Par_in clk Ser_out busy Sh_comp 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;
architecture alg of par_to_ser is signal reg:std_logic_vector(7 downto 0); begin process(clk,reg,ld) variable i:integer ; 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 process ; end alg; 程序见par_to_ser.vhd
10) 双向电路和三态控制电路 a) 三态门 library ieee; use ieee.std_logic_1164.all; Dataout{7..0] enb Datain{7..0] [7..0] a) 三态门 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) if enb='1' then dataout<=datain; else dataout<="ZZZZZZZZ"; end if ; end process; end beh; 程序见tri_gate.vhd
b) 双向端口电路 原理示意图 结构图 (图中in1和out1可以合在一起) Control=1: in/out1输入, [7..0] In/out2[7..0] 原理示意图 Control=0: in/out1输出, in/out2输入。 out1{7..0] control in1{7..0] [7..0] In/out2[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 ;
程序见tri_state1.vhd 原理图文件见tri1.bdf architecture beh of tri_state1 is begin process(control,inout2,in1) 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路模拟开关,可 转换时间约100μ含锁存控制的 8路多路开关,输出有三态缓冲器 控制,单5V电源供电。 In3 In4 In5 In6 In7 START EOC ID4 IOE CLK VCC REF+ GND D6 In2 In1 In0 ADDA ADDB ADDC ALE D0 D1 D2 D3 D7 REF- D5 ADC 0809 主要控制信号说明: 1)输入信号: START:转换启动信号,高电平有效; ALE:3位通道地址锁存信号,高电平有效; OE : 输出使能,高电平有效。 2)输出信号: EOC:转换状态信号,当START有效后约 (100μ)后,EOC产生一个负脉冲,以 示转换结束,在EOC上升沿后,可以读 出数据。
} { START ALE EOC OE D[7..0] ZZZZZZZ ADC0809工作时序 START CLK ALE 送到 控制电路 DATA ADC0809工作时序 D[7..0] EOC CLK START ALE OE ADDA LOCK1 Q[7..0] LOCK REGL 控制电路 { 来自 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为低电平 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的 上升沿,将转换好的数据保存并输出 if (lock='1' and lock'event) then regl<=d; end process pr2; q<=regl; end beh;
12)移位相加型乘法器(8位)设计 乘法器以8位加法器为核心,辅以移位寄存器组成。乘法原理: 乘法通过逐项移位相加原理实现,从被乘数的 最低位开始,若为1,则乘数 左移后与上一次的 和相加;若为0,乘数左移后加0,直至被乘数的 最高位。 并入串出 移位寄存器 8位 被乘数 乘法器 1×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) 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) 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) 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);
if clr='1' then r16s<=(others=>'0'); begin process(clk,clr) 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后为正确值).
延时电路的几个例子
下例调用了一个定义在process中的函数inc实现二进制计数器, 最终实现输出信号延时。 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);
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 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 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 process ; end beh;
下例采用移位方法求延时,移位算法:按下算法(四位)最长序列为15 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 process; end beh;
use ieee.std_logic_1164.all; use ieee.std_logic_unsigned.all; 下例采用一般计数器的设计方法,实现延时: 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); 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 PROCESS; END BEH;
Data[ ][ ]和 Result[ ]端口宽度 输入数据流的数目,等于2LPM——WIDTHS MAX+PLUSII 开发软件中的参数化模块 1.参数化数据选择器lpm_mux宏模快 端口名称 功 能 描 述 输入端口 Data[ ][ ] 数据流输入端口 Sel[ ] 地址选择线 输出端口 Result[ ] 数据输出线 参数设置 LPM_WIDTH Data[ ][ ]和 Result[ ]端口宽度 LPM_WIDTHS Sel[ ]端口宽度 LPM_SIZE 输入数据流的数目,等于2LPM——WIDTHS 另有清零和寄存设置
Dataa[ ]+ Datab[ ]+cin或Dataa[ ]- Datab[ ]+cin-1 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_DIRECTION ADD表示执行加法运算 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或逻辑单元实现乘法器,“on”为使用EAB, “ off”为使用逻辑单元。 另有清零和寄存设置
4.参数化译码器lpm_decode宏模快 端口名称 功 能 描 述 输入端口 data[ ] 输出端口 eq[ ] 参数设置 数据输入 输出端口 eq[ ] 译码输出 参数设置 LPM_WIDTH Data[ ] 端口宽度 LPM_DECODES 译码器输出的端口数目 等于2LPM_WIDTHS 另有清零和寄存设置
参数化RAM可以随时在任一指定地址写入或读出 数据 。有多个模块 模块名 功能描述 Csdpram 参数化循环共享双端口RAM Lpm_ram_dp 参数化双端口RAM Lpm_ram_dq 参数化RAM,输入/输出端口分离 Lpm_ram_io 参数化RAM,输入/输出端口共用
下面为Lpm_ram_dq的参数表一 端口名称 功能描述 输入端口 Data[] 输入数据 Address[ ] 地址端口 we Inclock 同步写入时钟 Outclock 同步读取时钟 输出端口 Q[ ] 数据输出端口 参数设置 LPM_WIDTH Data[] 和Q[ ]端口的数据线宽度 LPM_WIDTHAD Address[ ]端口宽度 LPM_numwords RAM中存储单元的数目 USE_EAB 选择使用EAB或逻辑单元
下面为Lpm_ram_dq的参数表二 同步数据读/写操作 同步数据读取 异步存储器操作 inclock we 功能描述 Not~ x outclock Not~ x 状态不变 L ~(写) H 写入数据 ~ 读出数据 ~(读) “~”表示时钟发生变化,“not~”表示时钟不发生变化