Transcript Document
第2章 VHDL语言程序的基本结构
一个VHDL设计由若干个VHDL文件构成,每个文件主
要包含五个部分的一个或全部:在max+plusⅡ中后缀为
(VHD).
1.程序包 ( Package )
2.实体 (Entity)
3.结构体 (Architecture)
4.配置(configuration)
5.库(library)
其中1~4为可分别编译
的源设计单元。
库用来存放已编译过
的实体、构造体、包
和配置。
2.1 VHDL语言设计的基本单元
基本单元:基本设计实体,可很简单,如门,
也可很复杂,如包含CPU的系统。
设计一个数字系统,首先要解决两个问题:
1) 输入、输出是什么;
2)内部完成什么功能。
对于1,由实体(Entity)说明来描述;
对于2,由构造体(Architecture)来描述。
Entity mux is
Generic (m: Time:=1ns);
Port(d0,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;
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
1)VHDL语言书写不分大
[类属参数说明];
小写;(个别例外)
[端口说明];
END 实体名;
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_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>;
1.构造体名称的命名:一般以描述方法命名,描述方法一般有:
行为特性:behavioral 简写为beh
结构:
structural 简写为 str
数据流: dataflow
如: Architecture beh Of mux is
2. 定义语句:位于architecture和begin之间,用于对构造体内部使
用的信号、数据类型和函数定义。
Architecture beh Of mux is
signal n1:bit;
…
1)信号为内部使用,不须加方向
begin
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 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
Begin
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):指满足条件时,块语句执行,不满足
时不执行。
例:…
1)当卫式表达式为真时,
带guarded的语句被执行;
begin
2)卫式块不能综合;
G1: block(clk=‘1’)
3 )after语句不能综合;
begin
d
q<=guarded d after 5ns;
qb<=guarded not(d) after 7ns;
end block G1;
q
clk
qb
2.2.2进程(process)语句结构描述
1.process语言结构
[进程名]:process(信号1,信号2,…)
Begin
…
End process;
例如:
变量只在进程中
定义和使用。
Architecture connect Of mux is
Signal 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;
Begin
else
cale (d1,d2,q1,q2); --错误,并行语句。
max:=b;
end if;
end cale;
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
ieee
std_logic_1164
ieee
numeric_std
ieee
std_logic_arith
定义有符号与无符号类型,及基于
这些类型上的算术运算。
ieee
std_logic_signed
定义了基于std_logic与std_logic _
vector类型上的有符号的算术运算
ieee
std_logic_unsigned
定义了基于std_logic与std_logic_
vector类型上的无符号的算术运算
VHDL类型,如bit,bit_vector
定义std_logic,std_logic_vector
等
定义了一组基于std_logic_1164中
定义的类型的算术运算符,如“+”,
“-”,SHL,SHR等
面向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中,由于quartusⅡ中的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)
实数(real)
位(bit)
含 义
32位,-2147483647~ 2147483647
浮点数,-1.0E+38~+1.0E+38
逻辑“0”或“1”
位矢量(bit_vector)
布尔量(boolean)
字符(character)
多位“0”和“1”的组合
逻辑“真”或逻辑“假”: true 和 false
ASCII字符
时间(time)
错误等级(severity
level)
时间单位:fs,ps,ns,μs,ms,sec,min,hr
Note, warning,error,failure
自然数(natural)
正整数(positive)
字符串(string)
≥0的整数
>0的整数
字符矢量
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
Integer,unsigned,signed→
2)std_logic_arith包集合
Conv_std_logic_vector(A, Std_logic_vector
位长)
Conv_integer(A)
Unsigned,signed→ integer
3)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是决断类型
含义:当一个信号有多个驱动器驱动时,则调
用定义的决断函数以解决冲突,并决定给信号赋
什么值,这可用在三态总线中。
Library ieee;
Use ieee.std_logic_1164.all;
Entity ex is
port(d,c,en1,en2: in std_logic;
dbus: out std_logic);
End;
dbus
en1
d
en2
c
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类型,即如下形式:
3
2
“101”
1
0
“011”
4
3
2
1
a(1,2)
a(1,2)(0)
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);
‘-’(不可能情况)
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代入语言
一般格式: 信号量<= 敏感信号量表达式;
如: 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
a
b
b<=a after 5 ns;
b<= transport a after 5 ns;
b
0
5
10
15
20
25
30 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的含义:
例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 if ;
End process;
为表示多个寄存器可用多个进程描述.
2)禁止使用if 语句中的else项
(使用if 语句描述寄存器功能时)
例: process(clk)
begin
if (clk’event and clk=‘1’) then
y<=a;
a
else
--禁止使用
y<=b;
end if ;
End process;
clk
D
Q
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 为一个
二选一的例子。
d0
u3
&
aa
ab
1
nsel
u1
q=(d0 and sel) or (d1 and (not (sel)))
q
&
d1
sel
u4
≥1
u2
编程的思路为:
1)先说明要调用的三
d0
u3
&
aa
u4
≥1
个元件:
and、or2、inv
2)用 PORT MAP语句
进行连接元件。
&
d1
sel
q
ab
1
nsel
u2
u1
结构描述的三个层次:
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
and2
&
c
意思是将与门的输入端(a,b)接(nsel,d1),输出端(c)为ab.
也可写成:
u2: and2 port map (a=>nsel,b=>d1,c=>ab);
第一种写法为位置映射法,第二种写法为名称映射法。
第 5 章
VHDL语言的主要描述语句
VHDL 常用语句分并行(Concurrent)语句和顺序
(Sequential)语句:
并行语句(Concurrent):
并行语句总是处于进程(PROCESS)的外部。所有
并行语句都是并行执行的,即与它们出现的先后次
序无关。如when..else语句
顺序语句(Sequential):
顺序语句总是处于进程或子程序的内部,并且从仿
真的角度来看是顺序执行的。如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
3. Wait for
process
process
begin
begin
wait until a=‘1’;
c<=not a;
c<=not a;
wait until a=‘1’ for 10 ns;
end process;
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
clk
q
例5-7 为二选一数据选择器描述。
a
b
MUX
1
0
c
sel
例5-8 为四选一数据
选择器描述。
input(3)
input(2)
input(1)
input(0)
sel(1)
sel(0)
MUX
3
2
1
y
0
5.1.6 case 语句
格式: case 表达式 is
when 条件表达式=>顺序处理语句;
…
end case;
四种形式:
when
when
when
when
值=>顺序处理语句;
值|值|…|值=>顺序处理语句;(表示“或”
值 to 值=>顺序处理语句;
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译码器的例子
编程思路:
c
b
a
2
1
0
1)将码输入信号c,b,a合成为位矢量
(indata)(用并置符&);
2) 用if语句判断使能信号是否有效,
如有效,则进入3);
3)用case语句判断输出。
7
6
5
4
3
G2B
G2A
G1
&
2
EN 1
0
Y(7~0)
例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
块头
{说明语句};
1)块头通常用语信号的映射及参数
的 定义,常用下列语句:
generic,
generic_map
port,
port_map
2)说明语句和构造体语句说明语句
begin
相同,主要是对该块所要用到的客
{并发处理语句};
体加以说明。可说明的项目有:
end block 标号;
* use子句;
*子程序说明及子程序体;
3.并发语句常用于结构
体的结构化描述。
*类型;
*常量说明;
*信号说明; *元件说明。
例5-20 为一个简单CPU芯片设计实例框架。芯片
包含一个ALU和一个REG8。而REG8又由8个子模
块组成,子模块分别为:REG1,…,REG8。在
每一个块内有局部信号、数据类型、常数等说明。
1) 程序的前6行,定义了一个数组tw32(一维,32
个元素),存放在Bit32包中;
2) 实体为CPU,定义clk,interrupt为输入,adder
为输出,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
ibus
端
口
abus
dbus bbus
函
数
comt ctbus
D_out
BLOCK
构造体
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
如将 0 TO 9改为
I:=number’RIGHT; --I:=9 9 DOWNTO 0,
I:=number’HIGH; --I:=9 则情况就不一样了。
I:=number’LOW; --I:=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;--得到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语句,那么
’behavior将得到true信息。
3.如果在 块和构造体中只有component语句或
被动进程,那么属性’structure得到true信息。
例题5-27分析:描述了一个四位移位寄存器
1)程序开始说明了元件dff;
2)从第一个begin到q=>right描述了以下结构:
dff
left
d
q
cp
clk
dff
u1
i1
d
dff
q
cp
u2
i2
d
dff
q
cp
u3
i3
d
q
cp
u4
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
r
e
框图中的三个量分别用包中
定义的类型。
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:
data_in
R
data
addr
A
cs
M
r_wb
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’
Y
Data= -1
N
cs=‘0’
片选有效
Y
Data= -2
片选无效
N
N (写)
r_wb=‘1’
(读) Y
地址为
-1或-2
N
Y
Data= -1
将ram_data1中地址为
addr中的 数送到输出
端data.
地址为
-1或-2
Y
N
data_in=>ram_data1(addr)
ram_data1(addr)=>data
给出出错信息及等级
并将输出data置为-1。
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
end loop;
process(clk,resetn)
begin
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
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;
该进程完成将三位数并行读入
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 型状态机
Output
clk
Input
寄
存
器
组合逻辑
reset
当前状态
一个Mealy 型状态机的例子
其他/0000
S0
1/1001
其他/1001
S1
0/1100
0/0000
其他/1111
其他/1100
S3
程序见mealy.vhd
1/1111
S2
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
p0: process (clk,reset)
state<=s3;
begin
end if;
if reset='1' then
WHEN s3 =>if in1='0'then
state<=s0;
state<=s0;
elsif clk'event and clk='1'then
end if;
END CASE;
end if;
CASE state IS
WHEN s0 =>if in1='1'then
end process p0;
state<=s1;
end if;
WHEN s1 =>if in1='0'then
state<=s2;
end if;
该进程完成状态转换的描述
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型状态机
clk
input
组合逻辑
Process
p1
当前状态
Process
p0
次状态
reset
寄
存
器
output
组合逻辑
Process
p2
前一个例子的moore型形式:
S0
1
0000
1001
0
0
S2
S3
1111
S1
1
程序分析见moore.vhd
1100
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 CASE;
end process;
end if;
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
qcnt
nreset
clk
ci
计数器
co
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
R
D触发器dff: R为异步清零端,CLK上升沿触发;
PORT (D,R,CLK : in std_logic;
Q : out std_logic);
Q
CLK
library ieee;
process(clk,r)
use ieee.std_logic_1164.all;
begin
entity dff1 is
if r='1' then q<='0';
port(d,clk,r:in std_logic;
q:out std_logic);
elsif (clk'event and clk='1') then
q<=d;
end ;
end if;
architecture rtl of dff1 is
end process;
begin
end rtl;
见程序dff1.vhd
b) 串行输入、串行输出移位寄存器shift8
R
A
D
R
CLK
Q
D
R
CLK
Q
D
R
CLK
Q
D
R
CLK
Q
D
R
CLK
Q
D
R
CLK
Q
D
R
Q
CLK
CLK
方法一:调用dff1组成。(dff1和shift8在同一目录下)
D
R
CLK
Q
B
R
A
D
R
Q
CLK
D
R
Q
CLK
D
R
Q
CLK
D
R
CLK
Q
D
R
Q
D
CLK
R
Q
CLK
D
R
Q
CLK
D
R
Q
B
CLK
CLK
library ieee;
use ieee.std_logic_1164.all;
entity shift8 is
port(a,clk,r:in std_logic;
b:out std_logic);
end;
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;
architecture rtl of shift8 is
component dff1
b<=z(8);
end rtl;
port(d,clk,r:in std_logic;
q:out std_logic);
end component;
见程序shift8.vhd
方法二:直接利用信号来连接。注意信号赋值的特点。
if(clk'event and clk='1')then
library ieee;
use ieee.std_logic_1164.all;
d_1<=a;
entity shift8a is
d_2<=d_1;
port(a,clk : in std_logic;
b: out std_logic);
d_3<=d_2;
d_4<=d_3;
end;
d_5<=d_4;
architecture rtl of shift8a is
d_6<=d_5;
Signal d_1,d_2,d_3,d_4,d_5,d_6,
d_7<=d_6;
d_7,d_8 :std_logic;
d_8<=d_7;
b<=d_8;
begin
end if;
process(clk)
end process;
begin
程序见shift8a.vhd
end rtl;
c) 循环移位寄存器
在计算机的运算操作中经常用到循环移位。八位循环左移的寄
存器电路框图如下。电路有八个数据输入端din(7)~din(0),移位和置
数控制端enb,时钟信号输入端clk,移位位数控制输入端s(2)~s(0),
八位数据输出端dout(7)~dout(0).
dout(7)~dout(0)
7
6
s(2)
s(1)
s(0)
5
4
3
2
1
0
enb
循环移位寄存器
7
6
5
4
3
2
1
clk
0
din(7)~din(0)
功能:当enb=1时,根据s(2)~s(0)输入的数值,确定在时钟脉冲
作用下,循环左移几位;
当enb=0时,在时钟作用下,将数据din直接传输到dout。
例如:当enb=1时,s(2)s(1)s(0)=100时。
dout(7)~dout(0)
MSB
LSB 移位前
MSB
LSB 移位后
电路设计方法:
1)将循环左移寄存器描述为一个名为shiftp的过程(procedure);
2) 将过程shiftp定义在包名为cpac的包中;
3) 在实体描述中调用过程,实现移位。
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 'right) -1 ) <=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例子实现
方法:(改变参数可改变容量)
clk
1)把ROM中要存放的内容先定
义为一个数组,并存放在一个
包文件内;
2)在实体中调用数组,进行
初始化。
R
O
M
4×8
1 0
addr[1..0]
q[7..0]
library ieee;
use ieee.std_logic_1164.all;
clk
ROM
4×8
1 0
package rom is
constant rom_width:integer:=8;
q[7..0]
addr[1..0]
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
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
W
A
V
E
F
O
R
M
1 0
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;
addr[1..0]
q[7..0]
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个字; Din[7..0]
2) 8根数据输入线,即字长
为8;
3) wr为写控制线,rd为读控
制线,cs为片选控制线;
4) cs=1,wr信号由低变高时,
将din上的数据写入adr所
指定的单元;
cs=1,rd=0时,由adr所指
定单元的内容将从dout输
出。
wr
rd
cs
Adr[2..0]
8×8
SRAM
Dout[7..0]
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个字;
Din[7..0]
2) 8根数据输入线,即字长
为8;
3) wr为写控制线,rd为读控
制线,cs为片选控制线;
4) cs=1,wr=1时,clk的上升
沿来到时将din上的数据
写入adr所指定的单元;
cs=1,rd=0时, clk的上升
沿来到时将adr所指定单
元的内容送至dout输出。
wr
rd
cs
Adr[2..0]
clk
8×8
SRAM
Dout[7..0]
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。
Ser_out
ld
piso
Par_in
busy
clk
Sh_comp
8位Piso功能:
a) 在时钟上升沿,若
ld=1,则将8位并行输入
信号par_in加载到转换电路的内部寄存器,并将状态标志
busy置位为‘1’;在8位并行数据全部移出之前,busy保持
为‘1’,并禁止再次加载数据;
b) 在时钟上升沿, 若busy=1,则逐位将内部寄存器的数据移
出,在数据全部移出之前,移位终止信号sh_comp保持为‘0’,
在数据全部移后,将sh_comp置为‘1’,busy置为‘0’。
ld
Par_in
clk
piso
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;
Ser_out
busy
Sh_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) 双向电路和三态控制电路
enb
a) 三态门
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 ;
Dataout{7..0]
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输入。
原理示意图
control
in1{7..0]
[7..0]
[7..0]
[7..0]
[7..0]
out1{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 ;
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电源供电。
In3
主要控制信号说明:
In4
1)输入信号:
In5
START:转换启动信号,高电平有效;
ALE:3位通道地址锁存信号,高电平有效; In6
In7
OE : 输出使能,高电平有效。
START
EOC
2)输出信号:
ID4
EOC:转换状态信号,当START有效后约
IOE
(100μ)后,EOC产生一个负脉冲,以
示转换结束,在EOC上升沿后,可以读 CLK
VCC
出数据。
REF+
GND
D6
ADC
0809
In2
In1
In0
ADDA
ADDB
ADDC
ALE
D0
D1
D2
D3
D7
REFD5
START
ALE
EOC
OE
D[7..0]
DATA
ZZZZZZZ
ADC0809工作时序
CLK
控制电路
EOC
{
来自
0809
D[7..0]
LOCK
REGL
START
ALE
OE
ADDA
}
LOCK1
Q[7..0]
送到
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位加法器
9位
输出高8位
[15..8]
clk
被乘数
8位
并入串出
移位寄存器
8位
16位锁存器
右移寄存器
输出
[15..0]
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)
else
begin
dout<=din;
if abin='0' then dout<="00000000";
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后为正确值).
四位乘法器的例子:
解题思路:先将乘数放入一个累加器的低四位,然后从最低位逐
步判断是否为1,如是1,就将被加数移位相加;如是0,则仅移
位,不相加。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity mult4x4 is
port(clk,st:in std_logic;
--st为启动信号
mplier,mcand: in std_logic_vector(3 downto 0);--乘数,被乘数
done:out std_logic;
--done为结束标志
product :out std_logic_vector(7 downto 0)); --结果
end;
architecture beh of mult4x4 is
signal state:integer range 0 to 9;
signal acc :std_logic_vector(8 downto 0);--累加器9位
alias m: std_logic is acc(0);--m为累加器最低位
begin
product<=acc(7 downto 0); --并发语句
process(clk)
begin
if clk'event and clk='1' then
case state is
when 0=>
if st='1' then
acc(8 downto 4)<=“00000”;--累加器高5位清零
acc(3 downto 0)<=mplier;--将乘数送入累加器的低四位
state<=1;
end if;
when 1|3|5|7=>
if m=‘1’ then
--m=1,表示需要将被乘数相加移位
acc(8 downto 4)<=(‘0’&acc(7 downto 4))+mcand;--执行相加(m=1)
state<=state+1;
else acc<=‘0’&acc(8 downto 1); --m=0,仅移位
state<=state+2;
end if;
when 2|4|6|8=>
acc<=‘0’&acc(8 downto 1); --执行移位(m=1)
state<=state+1;
when 9=>
state<=0;
end case;
end if;
end process;
done<='1' when state=9 else '0';
end beh;
延时电路的几个例子
下例调用了一个定义在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 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
library ieee;
use ieee.std_logic_1164.all;
use work.mypack_1.all;
if xv(i)='0' then
xv(i):='1';
entity delay_2 is
exit;
port(reset,clk:in std_logic;
else
xv(i):='0';
time_out :out std_logic);
end;
end if;
end loop;
architecture beh of delay_2 is
return xv;
begin
end inc;
end mypack_1;
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;
下例采用移位方法求延时,移位算法:按下算法(四位)最长序列为15
Q3n 1Qn2 1Q1n 1Q0n 1 (Q1n Q0n )Q3n Qn2 Q1n
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
LPM_SIZE
Sel[ ]端口宽度
输入数据流的数目,等于2LPM——WIDTHS
另有清零和寄存设置
2.参数化加法器/减法器lpm_add_sub宏模快
功 能 描 述
端口名称
输入端口
输出端口
Dataa[ ]
被加数/被减数
Datab[ ]
加数/减数
Result[ ]
Dataa[ ]+ Datab[ ]+cin或Dataa[ ]- Datab[ ]+cin-1
Cout
Overflow
LPM-width
参数设置
进位和借位标志 Cout用于无符号数运算
溢出标志
Overflow用语有符号数运算
Cout和Overflow不同时出现
Dataa[ ] 、Datab[ ] 和Result[ ]端口宽度
ADD表示执行加法运算
LPM_DIRECTION SUB表示执行减法运算
DEFAULT缺省设置为加法器
LPM_REPRESEN 指定参与运算的数值是无符号数还是有符号数
TATION
另有清零和寄存设置
3.参数化乘法器lpm_mult宏模快
功 能 描 述
端口名称
输入端口
Dataa[ ]
被乘数
Datab[ ]
乘数
Sum[ ]
输出端口
参数设置
Result[ ]
部分和(可以不使用)
Result[ ] =Dataa[ ]×Datab[ ]+sum
LPM-WIDTHA
Dataa[ ] 端口宽度
LPM-WIDTHB
Datab[ ]端口宽度
LPM-WIDTHP
Result[ ]端口宽度
LPM-WIDTHS
SUM端口宽度
LPM_REPRESEN 指定参与运算的数值是无符号数还是有符号数
TATION
USE_EAB
选择使用EAB或逻辑单元实现乘法器,“on”
为使用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
LPM_WIDTHAD
参数设置
Data[] 和Q[ ]端口的数据线宽度
Address[ ]端口宽度
LPM_numwords RAM中存储单元的数目
USE_EAB
选择使用EAB或逻辑单元
下面为Lpm_ram_dq的参数表二
同步数据读/写操作
同步数据读取
异步存储器操作
inclock
we
功能描述
outclock
功能描述
we
功能描述
Not~
x
状态不变
Not~
状态不变
L
状态不变
~(写)
H
写入数据
~
读出数据
H
写入数据
~(读)
L
读出数据
“~”表示时钟发生变化,“not~”表示时钟不发生变化