第6章EDA应用

Download Report

Transcript 第6章EDA应用

第6章 EDA技术的应用
本章通过VHDL实现的设计实例,进一步介绍了EDA技术
在组合逻辑,时序逻辑,状态机设计和存储器设计方面的
应用。
学习目标
通过对本章内容的学习,学生应该能够做到:
了解:VHDL编程特点
理解:VHDL设计流程和层次化设计方法
应用:掌握常用数字逻辑部件VHDL建模方法与设计技巧。
主要内容
6.1组合逻辑电路的设计应用
6.2时序逻辑电路的设计应用
6.3状态机的设计
6.4存储器的设计
6.5EDA综合设计
6.1 组合逻辑电路的设计应用
在本节所要描述的组合逻辑电路有编码器、选择器、译
码器、加法器、三态门、奇偶检验电路、码制转换器
等。下面逐一地对它们进行介绍。
6.1.1 编码器设计
在数字系统中,往往需要改变原始数据的表示形式,以
便存储、传输和处理,这一过程称为编码。例如,将二
进制码变换为具有抗干扰能力的格雷码,能减少传输和
处理时的误码;对图像、语音数据进行压缩,使数据量
大大减少,能降低传输和存储开销。实现编码操作的数
字逻辑电路称为编码器,常见的有二进制码编码器和优
先编码器。优先编码器是对某一时刻输入信号的优先级
别进行识别和编码的数字逻辑器件,在优先编码器中优
先级别高的信号排斥级别低的,即具有单方面排斥的特
性,每一个信号都有一个优先级,编码器的输出指明具有
最高优先级的有效信号。当具有最高优先级的信号有效
时,其他优先级较低的信号无效。
例6-1一个8到3的优先级编码器功能真值表如表6-1所示。
其优先级别依次为DIN8D到DIN1(从高到低)。输出
DO[2..0]代表一个二进制数,指明被设置为1的输入信号
中优先级别最高者。E0(高电平有效)用于指示输入是
否为有效信号。请给出该8-3优先编码器的VHDL实现方
案。
例6-1一个8到3的优先级编码器功能真值表如表6-1所示。
其优先级别依次为DIN8D到DIN1(从高到低)。输出
DO[2..0]代表一个二进制数,指明被设置为1的输入信号
中优先级别最高者。E0(高电平有效)用于指示输入是
否为有效信号。请给出该8-3优先编码器的VHDL实现方
案。
表6-1,8-3优先编码器真值表
解:为便于理解优先编码器的功能,首先观察表6-1,可
知如DIN8=1时,则输出DO[2..0]=111,因为DIN8的级别最
高,只要DIN8=1,则DIN6~DIN1的取值就无关紧要。据
此可利用条件赋值语句IF-THEN-ELSE,其VHDL源程序
如下。在程序中,当DIN(8)=1时,不考虑其他情况直接将
输出DO置为111;依此类推当执行最后一个ELSE时,将
输出DO置为000。其仿真波形输出如图6-1所示。编码器
元件符号如图6-2所示。
ARCHITECTURE BEHAV OF CODER8_3 IS
BEGIN
PROCESS(DIN)
BEGIN
IF(DIN(8)='1') THEN DO<="111";
ELSIF(DIN(6)='1') THEN DO<="101";
ELSIF(DIN(5)='1') THEN DO<="100";
ELSIF(DIN(4)='1') THEN DO<="011";
ELSIF(DIN(3)='1') THEN DO<="010";
ELSIF(DIN(2)='1') THEN DO<="001";
ELSE
DO<="000";
END IF;
END PROCESS;
E0<='0' when DIN="00000000" ELSE '1';
END BEHAV;
IF(DIN(8)='1') THEN DO<="111";
ELSIF(DIN(6)='1') THEN DO<="101";
ELSIF(DIN(5)='1') THEN DO<="100";
ELSIF(DIN(4)='1') THEN DO<="011";
ELSIF(DIN(3)='1') THEN DO<="010";
ELSIF(DIN(2)='1') THEN DO<="001";
ELSE
DO<="000";
END IF;
END PROCESS;
E0<='0' when DIN="00000000" ELSE '1';
图6-1 8-3优先编码器仿真波形
图6-2编码器元件符号
6.1.2译码器的设计
译码是编码的逆过程,它的功能是把代码状态的特定含
义翻译出来,并转换成相应的控制信号,实现译码操作
的电路称为译码器。译码器分为两类,一类是唯一地址
译码,它是将一系列代码转换成与之一一对应的有效信号
;另一类是码制转换器,其功能是将一种代码转换成另一
种代码。
1.唯一地址译码器
常见的唯一地址译码有3-8译码器,其真值表如表6-2所示
。
表6-2 3-8译码器真值表
表6-2中输入变量为3个d0,d1,d2,输出变量有8个,即
y0~y7,对输入变量d0,d1,d2译码,就能确定输出端y0~
y7的输出端变为有效(低电平),从而达到译码目的。它常用
于计算机中对存储器单元地址译码,即将每一个地址代码转
换为一个有效信号,从而选中对应的单元。
ARCHITECTURE rtl OF decoder3_8 IS
SIGNAL indata:STD_LOGIC_VECTOR (2 DOWNTO 0);
BEGIN
Indata <= c & b & a;
PROCESS (indata,g1,g2a,g2b)
BEGIN
IF (g1='1' AND g2a='0' AND g2b='0') THEN
CASE indata IS
WHEN "000" => y <= "11111110" ;
WHEN "001" => y <= "11111101" ;
WHEN "010" => y <= "11111011" ;
WHEN "011" => y <= "11110111" ;
WHEN "100" => y <= "11101111" ;
WHEN "101" => y <= "11011111" ;
WHEN "110" => y <= "10111111" ;
WHEN "111" => y <= "01111111" ;
WHEN OTHERS=> y <= "XXXXXXXX" ;
END CASE;
ELSE Y <= "11111111" ;
END IF;
END PROCESS;
END rtl;
在例6-2中,y(0)对应真值表中的y0,y(1)对应y1,
依次类推。以上是利用VHDL语言的CASE-WHEN
语句实现的译码器电路。其波形仿真输出与元件
符号如图6-3所示。
图6-3
3-8译码器仿真输出
2.码制转换器
码制转换器有很多类型,如BCD码到七段数码管的译码
器,将一位BCD码译为驱动数码管各电极的7个输出量a
~g。输入量DCBA是BCD码,a ~g是7个输出端,分别
与数码管上的对应笔划段相连。在a ~g中,输出为1的
能使对应的笔划段发光,否则对应的笔划段熄灭。例如
,要使数码管显示“0”字形,则g段不亮,其它段都亮,
即要求abcdefg = 1111110。
例6-3 利用VHDL设计BCD码到七
段数码管的译码器,并添加一个使
能信号EN,该输入信号可以不顾
及BCD码的输入,使所有七段数码
管的灯都不亮,其真值表如表6-3
所示。(共阴极)
解:用四位二进制数表示一位十进
制数的编码,称为BCD(BinaryCoded-Decimal)码或二—十进制编
码。如表6-3所示,若要表示多个
十进制数位的信息,则需要用多组
4位码即可,每组对应一个十进制
数位数字。
表6-3七段译码器逻辑的真值表
ARCHITECTURE one OF BCDTOLED7 IS
BEGIN
PROCESS( A ,en)
BEGIN
if en='1' then
CASE A IS
WHEN "0000" => LED7S <= "0111111" ;
WHEN "0001" => LED7S <= "0000110" ;
WHEN "0010" => LED7S <= "1011011" ;
WHEN "0011" => LED7S <= "1001111" ;
WHEN "0100" => LED7S <= "1100110" ;
WHEN "0101" => LED7S <= "1101101" ;
WHEN "0110" => LED7S <= "1111101" ;
WHEN "0111" => LED7S <= "0000111" ;
WHEN "1000" => LED7S <= "1111111" ;
WHEN "1001" => LED7S <= "1101111" ;
WHEN OTHERS => LED7S <= "1000000" ; --“-”对应非法码
END CASE ;
else LED7s<="0000000" ;
end if;
END PROCESS ;
END one;
其中代码中"0111111"、"0000110"、"1011011"、"1001111"、
"1100110"、"1101101"、"1111101"、"0000111"、"1111111"、
"1101111"、"1000000"在数码管上分别为0、1、2、3、4、5、
6、7、8、9
仿真结果如下
图6-4 BCD码到七段数码管译码器仿真输出
6.1.3.多路选择器的设计
多路选择器是指经过选择,把多个通道的数据传送到唯
一的公共数据通道上去的数字逻辑电路,其功能相当于
多刀单值开关,也叫数据选择器,数据选择器常用于信
号的切换,数据选择,顺序操作,并-串转换,波形产生
和逻辑函数发生器。
表6-4 4选1多路选择器真值表
ARCHITECTURE rtl OF mux4 IS
SIGNAL SEL : STD_LOGIC_VECTOR(1 DOWNTO 0);
BEGIN
SEL<=B&A;
PROCESS(INPUT,SEL)
BEGIN
CASE SEL IS
WHEN "00" =>Y<=INPUT(0);
WHEN "01" =>Y<=INPUT(1);
WHEN "10" =>Y<=INPUT(2);
WHEN OTHERS =>Y<=INPUT(3);--用others表示选择条件,以表
示其他所有可能取值
END CASE;
END PROCESS;
END rtl;
SIGNAL SEL : STD_LOGIC_VECTOR(1 DOWNTO 0);
BEGIN
SEL<=B&A;
PROCESS(INPUT,SEL)
BEGIN
CASE SEL IS
WHEN "00" =>Y<=INPUT(0);
WHEN "01" =>Y<=INPUT(1);
WHEN "10" =>Y<=INPUT(2);
WHEN OTHERS =>Y<=INPUT(3);--用others表示选择条件,以
表示其他所有可能取值
图6- 5 4选1多路选择器仿真输出
例6-5用VHDL语言描述位宽w的2选1多路选择器,
并给出w=4的时序仿真波形。
解:本题考虑使用多路选择器在数据位宽为w的两
路编码数据源之间进行选择,如果数据长度为w
(每个数据有w位),我们可以用w个2选1多路
选择器实现之,也可以用多位信号和算术运算的
赋值语句实现(本例采用此方案)。
PACKAGE const IS
CONSTANT w :INTEGER:=4;
- set total number of bits
CONSTANT n :INTEGER:=w - 1;
-- MSB index number
END const;
USE work.const.all;
--库声明和实体
ARCHITECTURE rtl OF mux2to1_n IS
BEGIN
Y<=A0 WHEN S='0' ELSE A1;
END;
图6- 5 2选1多路选择器仿真输出(数据位宽为4)
6.1.4 加法器设计
1.半加器
半加器有两个二进制输入、一个和输出和一个进位输出。
其真值表如表6-5所示。
表6-5 半加器的真值表
例6-7 半加器的VHDL程序设计
ARCHITECTURE half1 OF half_adder IS
SIGNAL C,D:STD_LOGIC;
BEGIN
C<=A OR B;
D<=A NAND B;
CO<=NOT D;
S<=C AND D;
END half1;
图6- 6 半加器仿真输出
2.二进制加法器
使用VHDL设计加法器可采用层次化结构描述,首先创建
一个1位全加器实体,然后例化此1位全加器4次,建立
一个更高层次的4位加法器。
解:1位全加器的VHDL代码如下,其输入为CIN、X和Y,
输出为和S、进位输出COUT,S和COUT均以逻辑表达
式形式描述。
ARCHITECTURE logicfunc OF fulladd IS
BEGIN
S<=X XOR Y XOR CIN;
COUT<=(X AND Y) OR (CIN AND X) OR (CIN AND Y);
END logicfunc;
为使该程序可调用,其元件声明语句既可以放在顶层程序
的结构体内,也可放在VHDL的程序包内。例6-9给出了
fulladd_package的程序包声明。
解:以下代码定义了名为fulladd_package的程序包,该
VHDL代码可以和例6-8的fulladd存储在同一个文件中,
也可以存储在一个单独的文件中。VHDL语法要求程序
包声明要有自己的LIBRARY和USE子句,以下代码中包
含了这两个子句。在程序包内部,实体fulladd被声明为
一个元件。当该代码被编译时程序包fulladd_package被
创建并存储在工作目录下。
元件fulladd作为子电路使用。
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
package fulladd_package is
COMPONENT fulladd
PORT(CIN,X,Y:IN STD_LOGIC;
S,COUT :OUT STD_LOGIC);
END COMPONENT;
end fulladd_package;
以后任何实体都可以通过语句:LIBRARY WORK; USE
WORK. fulladd_package.ALL访问fulladd_package,从而把
元件fulladd作为子电路使用。
例6-10将1位全加器作为子电路使用,构建4位加法器的VHDL语言序。
解:4位加法器的VHDL程序设计如下
ARCHITECTURE structure OF adder4 IS
signal C: STD_LOGIC_VECTOR(3 DOWNTO 1);
COMPONENT fulladd
PORT(CIN,X,Y:IN STD_LOGIC;
S,Cout:OUT STD_LOGIC);
END COMPONENT;
BEGIN
U0:fulladd PORT MAP(CIN,X(0),Y(0),S(0),C(1));
U1:fulladd PORT MAP(C(1),X(1),Y(1),S(1),C(2));
U2:fulladd PORT MAP(C(2),X(2),Y(2),S(2),C(3));
U3:fulladd PORT MAP(C(3),X(3),Y(3),S(3),Cout);
END structure;
4位加法器功能模拟结果如图6- 7所示。在示例程序例6-9
中,STD_LOGIC_VECTOR
是数据对象STD_LOGIC的一维数组,程序中用C定义了
一个3位的STD_LOGIC信号,VHDL代码中可以用C或用
C(3)、C(2)、C(1)分别代表每一个单独的信号。根据
VHDL的语法规定“3 DOWNTO 1”指明C(3)是最高位,C(1)
是最低位,该声明常用于多位信号的二进制表示。同理,
声明“1TO 3”则指明C(1)是最高位,C(3) 是最低位。这点
在进行信号赋值时要特别注意。
图6- 7 4位加法器仿真输出
例6-11利用算术赋值语句设计一个16位的加法器。
解:VHDL除了提供加法运算符(+)外,本书4.2.4还提供
了其他的一些运算符,程序包STD_LOGIC_1164不允许
STD_LOGIC类型的信号作算术运算,而程序包
STD_LOGIC_signed允许作算术运算,其示例程序如下。
在EDA系统中,综合编译的结果将可以根据不同的优化
目标(造价或速度)产生不同的电路。
例6-11利用算术赋值语句设计一个16位的加法器。
解:VHDL除了提供加法运算符(+)外,本书4.2.4还提供
了其他的一些运算符,程序包STD_LOGIC_1164不允许
STD_LOGIC类型的信号作算术运算,而程序包
STD_LOGIC_signed允许作算术运算,其示例程序如下。
在EDA系统中,综合编译的结果将可以根据不同的优化
目标(造价或速度)产生不同的电路。
ARCHITECTURE Behavior OF adder16 IS
SIGNAL S: STD_LOGIC_VECTOR(16 DOWNTO 0);
BEGIN
S<=(‘0’&X)+Y+CIN;
SUM<=S(15 DOWNTO 0);
Cout<= SUM (16);
Overflow<= SUM (16)XOR X(15)XORY(15)XOR SUM (15);
END Behavior;
例6-11的VHDL结构体中定义了一个17位的信号S(16..0),
新增加的S(16)用于存储来自加法器S(15)的进位输
出。把X、Y和CIN相加的和赋给S,该算术赋值语句右
边有一个括号:(‘0’&X),本例利用连接运算符&,将16
位信号X最高位加一个‘0’形成一个17位信号,使之和赋
值语句左边的信号的位数一致。
为了允许算术赋值语句可以运用于STD_LOGIC类型的信
号,例6-11的VHDL代码中使用了程序包
STD_LOGIC_signed。该程序包实际使用了
STD_LOGIC_arith程序包中定义的数据类型SIGNED和
UNSIGNED,用于表示算术赋值语句中的有符号数和无
符号数。这两种数据类型和STD_LOGIC_VECTOR一样
是数据对象STD_LOGIC的一维数组。
3.8421码加法器
8421码加法器是实现十进制数相加的逻辑电路。8421码
用4个二进制位表示一位十进制数(0~9),4个二进制
位能表示十六个编码,但8421码只利用了其中的0000~
1010十个编码,其余6个编码为非法编码。尽管利用率
不高,但因人们习惯了十进制,所以8421码加法器也是
一种常用的逻辑电路。
例6-12请编写一个VHDL模型,该模型描述的是1位
8421码加法器。
解:8421码加法器与4位二进制数加法运算电路不同。
这里是两个十进制数相加,和大于9时应产生进位。设
参与相加的量为:被加数X、加数Y及来自低位8412码
加法器的进位C-1。设X、Y及C-1按十进制相加,产生
的和为Z,进位为W。X、Y、Z均为8421码。
先将X、Y及C-1按二进制相加,得到的和记为S。显然,若
S ≤9,则S本身就是8421码,S的值与期望的Z值一致,
进位W应为0;但是,当S >9时,S不再是8421码。此时,
须对S进行修正,取S的低四位按二进制加6,丢弃进位,
就能得到期望的Z值,而此时进位W应为1。1位8421码
加法器框图如图6-8所示
图6-8中,C3是X、Y及C-1按二
进制相加产生的进位。“4位二进
制加法器”已在前面进行了详细
讨论,因此本例的重点是“加6修
正”电路的设计。现在分析“加6
修正”电路的功能:① 应能判断
是否大于9,以决定是“加6”还是
“加0”。 ②要有一个二进制加法 图6-8一位8421码加法器
框图
器,被加数为,加数为6或0,其
VHDL描述如下。
ARCHITECTURE Behavior OF adder_8421 IS
SIGNAL S: STD_LOGIC_VECTOR(4 DOWNTO 0);
SIGNAL adjust: STD_LOGIC;
BEGIN
S<=(‘0’&X)+Y;
adjust<=’1’ when S>9 else ‘0’;--选择信号赋值语句
Z<=S when (adjust=’0’) else Z+6;
END Behavior;
例6-11中使用了选择信号赋值语句,它根据某种判据
从多种信号中选择一个给信号赋值,即其判据条件是,
S>9,若条件满足则将1赋给adjust;否则将0赋给adjust。
6.1.5数值比较器
数值比较器就是对两数A、B进行比较,并判断其大小的
数字逻辑电路。74系列的7485是常用的集成电路数值比
较器,其真值表如图6-9所示。在图6-9中,级联输入端
用作级联的控制输入,即当高一级芯片发现其输入数据
相等时,它将查看相邻下一级低位芯片的输出,并用这
些控制输入端做出最终决定。由于每个IF语句能判断两
个,所以最好使用IF/ELSE结构,这与CASE结构中查找
变量单一值相反,两个待比较的值需要声明为数值,为
清楚标明每一个位的用途,级联的控制输入与三个比较
输出端应作为独立的位来说明。数值比较器7485的
VHDL程序如例6-13所示。
例6-13数值比较器7485的VHDL实现
。
ARCHITECTURE vhdl OF T7485_V IS
BEGIN
PROCESS (a, b, gtin, ltin, eqin)
BEGIN
IF a < b THEN
altb <= '1';agtb <= '0';aeqb <= '0';
ELSIF a > b THEN
altb <= '0';agtb <= '1';aeqb <= '0';
ELSE
ltb <= ltin;agtb <= gtin;aeqb <= eqin;
图6-9数值比较器7485真值表
END IF;
END PROCESS;
END vhdl;
6.1.5 算术逻辑运算器(ALU)
表6-6 ALU181的运算功能表
例6-14集成ALU芯片74181的VHDL设计
设参加运算的两个8位数据分别为A[7..0]和B[7..0],运算
模式由S[3..0]的16种组合决定,此外,设M=0,选择算
术运算,M=1为逻辑运算,CN为低位的进位位;F[7..0]
为输出结果,CO为运算后的输出进位位。其VHDL源程
序如下:
ARCHITECTURE behav OF ALU181 IS
SIGNAL A9 : STD_LOGIC_VECTOR(8 DOWNTO 0);
SIGNAL B9 : STD_LOGIC_VECTOR(8 DOWNTO 0);
SIGNAL F9 : STD_LOGIC_VECTOR(8 DOWNTO 0);
BEGIN
A9 <= '0' & A ; B9 <= '0' & B ;
PROCESS(M,CN,A9,B9)
BEGIN
CASE S IS
WHEN "0000" => IF M='0' THEN F9<=A9 + CN ;
ELSE F9<=NOT A9;
END IF;
WHEN "0001" => IF M='0' THEN F9<=(A9 or B9) + CN ;
ELSE F9<=NOT(A9 OR B9);
END IF;
WHEN "0010" => IF M='0' THEN F9<=(A9 or (NOT B9))+ CN ;
ELSE F9<=(NOT A9) AND B9;
END IF;
WHEN "0011" => IF M='0' THEN F9<= "000000000" - CN ;
ELSE F9<="000000000";
END IF;
WHEN "0100" => IF M='0' THEN F9<=A9+(A9 AND NOT B9)+ CN ;
ELSE F9<=NOT (A9 AND B9);
END IF;
WHEN "0101" => IF M='0' THEN F9<=(A9 or B9)+(A9 AND NOT B9)+CN ;
ELSE F9<=NOT B9;
END IF;
WHEN "0111" => IF M='0' THEN F9<=(A9 or (NOT B9)) - CN ;
ELSE F9<=A9 and (NOT B9);
END IF;
WHEN "1000" => IF M='0' THEN F9<=A9 + (A9 AND B9)+CN ;
ELSE F9<=(NOT A9)and B9;
END IF;
WHEN "1001" => IF M='0' THEN F9<=A9 + B9 + CN
;
ELSE F9<=NOT(A9 XOR B9);
END IF;
WHEN "1010" => IF M='0' THEN F9<=(A9 or(NOT B9))+(A9 AND B9)+CN
;
ELSE F9<=B9;
END IF;
WHEN "1011" => IF M='0' THEN F9<=(A9 AND B9)- CN
;
ELSE F9<=A9 AND B9;
END IF;
WHEN "1100" => IF M='0' THEN F9<=(A9 + A9) + CN
;
ELSE F9<= "000000001";
END IF;
WHEN "1101" => IF M='0' THEN F9<=(A9 or B9) + A9 + CN
;
ELSE F9<=A9 OR (NOT B9);
END IF;
WHEN "1110" => IF M='0' THEN F9<=((A9 or (NOT B9)) +A9) + CN ;
ELSE F9<=A9 OR B9;
END IF;
WHEN "1111" => IF M='0' THEN F9<=A9 - CN
;
ELSE F9<=A9 ;
END IF;
WHEN OTHERS => F9<= "000000000" ;
END CASE;
END PROCESS;
F<= F9(7 DOWNTO 0) ; CO <= F9(8) ;
6.2时序逻辑电路的设计应用
6.2.1 触发器
触发器是跳变沿触发的,在每个时钟clk输入正跳变沿或
负跳变沿,输入触发器的当前值被存储到触发器中,并
且反映在该触发器的输出Q上。D触发器和JK触发器是
构成时序逻辑电路最基本存储元件。
1.D触发器
上升沿触发的D触发器有一个数据输入端D、一个时钟
输入端CLK及一个数据输出端Q。D触发器的输出只有
在正沿脉冲过后,其数据D才传递到输出。真值表如表
6-7所示。
ARCHITECTURE rtl OF dff1 IS
BEGIN
PROCESS(CLK)
BEGIN
IF(CLK'EVENT AND CLK='1')
THEN
Q<=D;
END IF;
END PROCESS;
END rtl;
表6-7 D触发器真值表
D触发器一般还带有复位或置位输入端,有的还带有
时钟使能信号输入端,后一种D触发器只有使能信号有
效时,时钟信号的边沿才有效,其VHDL语言描述如例616所示。
例6-16带有时钟使能信号输入端的D触发器VHDL设计
解:该D触发器的实体声明代码和结构体代码如下,
分析输出波形可知,该D触发器在时钟的上升沿时刻,
且当时钟使能信号ENA=1才能更新存储器的值。若时钟
的上升沿时刻,ENA=0,D触发器的值保持不变。因此
数据输入的值,必须在时钟的正跳变沿前后保持一段稳
定时间(即建立时间和保持时间)才能将该值稳定地存
入触发器。时钟的使能信号也需要类似的稳定时间限制
,实际上时钟的使能信号是一个同步控制输入
(synchronous control input)。
其仿真波形输出如图6-10所示
ARCHITECTURE rtl OF example_dffe IS
BEGIN
PROCESS(CLK,D)
BEGIN
IF(CLK'EVENT AND CLK='1') THEN
IF(ENA='1') THEN
Q<=D;
NQ<=not D;
END IF;
END IF;
END PROCESS;
END rtl;
图6- 10 D触发器仿真输出
例6-15和例6-16的D触发器的VHDL模板的差别就是多了
一条IF语句,程序中D和Q的位宽决定了该模板是一位触
发器模型还多位的寄存器模型。
例6-17请设计一个复位清0的D触发器的VHDL模板
解:对例6-16的D触发器作进一步的改进,即添加一个
复位输入信号,以便把存储器的值重新设为0。复位输
入是强制性的,无论时钟的使能信号还是数据输入都不
如它的优先级别高。触发器的复位时序有两种可能,一
种是同步清0,即把复位输入当作同步控制输入;另一
种是异步清0,即只要复位信号有效,不管其他时钟状
态,立即使输出为0。
(1)同步清0模板:
(2) 异步清0模板:
reg:PROCESS(CLK) IS
BEGIN
IF(CLK'EVENT AND CLK='1')
THEN
IF reset=’1’ THEN
Q<=0;
ELSIF(ENA='1') THEN
Q<=D;
END IF;
END IF;
END PROCESS reg;
reg:PROCESS(CLK) IS
BEGIN
IF reset=’1’
THEN
Q<=0;
ELSIF(CLK'EVENT AND CLK='1')
THEN
IF(ENA='1')
THEN
Q<=D;
END IF;
END IF;
END PROCESS reg;
2.JK触发器
JK触发器的输入端有一个置位输入、一个复位输入、两
个控制输入和一个时钟输入;输出端有正向输出断和反
向输出端。具有置位和清零端的JK触发器真值表如表
6-8所示:
表6-8 JK触发器真值表
解由真值表例6-18 JK触发器的VHDL程序设计如下:
ARCHITECTURE rtl OF jkff IS
SIGNAL Q_S,QB_S:STD_LOGIC;
BEGIN
PROCESS(PSET,CLR,CLK,J,K)
BEGIN
IF(PSET='0') THEN
Q_S<='1';QB_S<='0';--异步置1
ELSIF (CLR='0') THEN
Q_S<='0';QB_S<='1';--异步置0
ELSIF (CLK'EVENT AND CLK='1') THEN
IF(J='0')AND (K='1') THEN
Q_S<='0'; QB_S<='1';
ELSIF(J='1') AND (K='0') THEN
Q_S<='1'; QB_S<='0';
ELSIF(J='1') AND(K='1') THEN
Q_S<=NOT Q_S; QB_S<=NOT QB_S;
END IF;
END IF;
Q<=Q_S;QB<=QB_S;
END PROCESS;
END rtl;
综上所述,VHDL是一种灵活的硬件描述语言,允
许用程序对时序控制器件(如触发器)的功能进行
定义,而不用依靠逻辑原形,例6-15、例6-16、例
6-17、例6-18中描叙的VHDL触发器电路的关键字
是进程(PROCESS)。PROCESS后面的括号内包
括一个敏感参数表,参数表中所包括的变量只要有
一个发生变化,都将启动该进程,这与触发器直到
时钟状态改变时才启动输入端,并更新输出端的状
态的工作原理相同。
图6- 10 JK触发器仿真输出
6.2.2 锁存器和寄存器
1.锁存器(LATCH)
锁存器的功能同触发器相似,但有区别的是:触发器只在有效
时钟沿才发生作用,而锁存器是电平敏感的,只要时钟信号有效,
而不管是否处在上升沿或下降沿,锁存器都会起作用。用VHDL
语言描述的选通D锁存器的程序如例6-19所示:
ARCHITECTURE behavior OF latch IS
BEGIN
PROCESS(D,CLK)
BEGIN
IF CLK='1' THEN --CLK
Q<=D;
END IF;
END PROCESS;
END behavior;
图6- 11 选通D锁存器仿真输出
2.寄存器(Register)
寄存器是由具有存储功能的多个触发器组合起来构成的
。一个触发器可以存储1位二进制代码,存放n位二进制
代码的寄存器,需用n个触发器来构成。寄存器一般由
多个触发器连接而成。按照功能的不同,可将寄存器分
为基本寄存器和移位寄存器两大类。基本寄存器只能并
行送入数据,需要时也只能并行输出。移位寄存器中的
数据可以在移位脉冲作用下依次逐位右移或左移,数据
既可以并行输入、并行输出,也可以串行输入、串行输
出,还可以并行输入、串行输出,串行输入、并行输出
,十分灵活,用途也很广。
(1)具有异步清零功能的8位寄存器
描述n位寄存器的一个直截了当的方法是:写一段包含n个D触发器
实例的层次化的VHDL代码。因此具有异步清零功能的8位寄存器
VHDL代码如例6-20所示:
ARCHITECTURE Behavior OF reg8 IS
BEGIN
PROCESS(RESETN,CLOCK)
BEGIN
IF RESETN='0' THEN
Q<=(others =>’0’);
ELSIF CLOCK'EVENT AND CLOCK='1'
THEN Q<=D;
END IF;
END PROCESS;
END Behavior;
(1)具有异步清零功能的8位寄存器
描述n位寄存器的一个直截了当的方法是:写一段包含n个D触发器
实例的层次化的VHDL代码。因此具有异步清零功能的8位寄存器
VHDL代码如例6-20所示:
ARCHITECTURE Behavior OF reg8 IS
BEGIN
PROCESS(RESETN,CLOCK)
BEGIN
IF RESETN='0' THEN
Q<=(others =>’0’);
ELSIF CLOCK'EVENT AND CLOCK='1'
THEN Q<=D;
END IF;
图6-11 8位寄存器仿真输出
END PROCESS;
END Behavior;
(2) 4位移位寄存器
描述4位移位寄存器的一个简单方法是:写一个包含4个子电路的层
次化VHDL代码,每一个子电路都相同,子电路由1个D触发器和1
个连接到D端的2选1多路器组成。例6-21所示,实体muxdff代表此
子电路,D0和D1是数据输入端,SEL是选择输入端。时钟正沿到达
时如果SEL=0,则将D0的值赋给Q;否则将D1的值赋给Q。
例6-21 移位寄存器子模块的VHDL设计
ARCHITECTURE behavior OF muxdff IS
BEGIN
PROCESS(CLOCK)
BEGIN
IF CLOCK'EVENT AND CLOCK='1' THEN
IF SEL='0' THEN Q<=D0;
ELSE Q<=D1;
END IF;
END IF;
END PROCESS;
END behavior;
例6-22 四位通用移位寄存器的
VHDL代码如下,时序仿真输出如
图6-12所示。
ARCHITECTURE structure OF shift4 IS
COMPONENT muxdff
PORT(D0,D1,SEL,CLOCK: IN STD_LOGIC;
Q: OUT STD_LOGIC);
END COMPONENT;
BEGIN
STAGE3: muxdff PORT
MAP(W,R(3),L,CLOCK,Q(3));
STAGE2: muxdff PORT
MAP(Q(3),R(2),L,CLOCK,Q(2));
STAGE1: muxdff PORT
MAP(Q(2),R(1),L,CLOCK,Q(1));
图6-12
STAGE0: muxdff PORT
MAP(Q(1),R(0),L,CLOCK,Q(0));
END structure;
四位通用移位寄存器仿真输出
(3) 4位双向移位寄存器
例6-21,22是利用结构化的方法设计的一个4位通用移位
寄存器,该方法虽然直观但很复杂,程序较长。下面用
VHDL的CASE语句设计4位双向移位寄存器,该方法中
不把移位寄存器看作一个串行的触发器串,而是把它看
作是一个并行寄存器(DFF模型),寄存器中的存储信
息以并行方式传递到一个位集合,集合中的数据可以逐
位移动。
例6-23 4位双向移位寄存器的VHDL设计,该寄存器具
有四种工作方式:保持数据、右移、左移和并行输入。
时序仿真输出如图6-13所示。
ARCHITECTURE a OF T194 IS
SIGNAL ff: BIT_VECTOR (3 DOWNTO 0);
BEGIN
PROCESS ( clock)
BEGIN
IF (clock = '1' AND clock'event) THEN
CASE mode IS
WHEN 0 =>ff <= ff;
WHEN 1=>ff(2 DOWNTO 0)<= ff (3 DOWNTO 1);
ff(3) <= ser_in;
WHEN 2=>ff(3 DOWNTO 1) <= ff(2 DOWNTO 0);
ff(0) <= ser_in;
WHEN OTHERS=>ff<= din;
END CASE;
END IF;
END PROCESS;
q <= ff;
END a;
图6-13双向移位寄存器仿真输出
6.2.3 计数器
计数器是一种对输入脉冲进行计数的时序逻辑电路,被
计数的脉冲信号称作“计数脉冲”。计数器中的“数”是用触
发器的状态组合来表示的。计数器在运行时,所经历的
状态是周期性的,总是在有限个状态中循环,一次循环
所包含的状态总数称为计数器的“模”。
计数器的种类很多,通常有不同的分类方法。按其工作
方式可分为同步计数器和异步计数器;按其进位制可分
为二进制计数器、十进制计数器和任意进制计数器;
按其功能又可分为加法计数器、减法计数器和加/减可逆
计数器等。
1.同步计数器
所谓同步计数器,就是在时钟脉冲(计数脉冲)的控制
下,构成计数器的各触发器的状态同时发生变化的那一
类计数器。带异步复位,计数允许,4位二进制同步计
数器真值表如表6-9所示。
表6-9 4位二进制同步计数器真值表
例6-24 模16二进制同步计数器的VHDL设计。
ARCHITECTURE example OF count4_bin IS
SIGNAL count_4: STD_LOGIC_VECTOR (3 DOWNTO 0);
BEGIN
PROCESS (clk, clr)
BEGIN
IF (clr = '1' ) THEN
count_4 <= "0000";
ELSIF (clk 'EVENT AND clk = '1' )
THEN
IF (en = '1' )
THEN
IF(count_4="1111")
THEN count_4 <= "0000"; 图6-14模16进制同步计数器仿真输出
ELSE
count_4 <= count_4+1;
END IF; END IF; END IF;
END PROCESS;
qa <= count_4(0);qb <= count_4(1);
qc <= count_4(2); qd <= count_4(3);
END example;
例6-25在QuartusII中利用VHDL的元件例化语句设计一个有
时钟使能和异步清零的两位十进制计数器(即100分频),
并给出仿真结果。
解:本例题通过介绍一个2位有时钟使能和异步清零的十进
制计数器的全部设计过程,给出在QuartusII中利用
VHDL的元件例化语句设计较复杂数字电路的EDA方法
。
两位十进制计数器可由2个十进制计数器级联而成,根
据层次化设计思想,应首先设计一个具有计数使能、清
零控制和进位扩展输出十进制计数器底层元件cnt10_v,
此后再利用元件例化的方法完成两位十进制计数器的顶
层设计。下面将给出其设计流程和方法:
(1)十进制计数器cnt10_v的VHDL设计一个具有计数使能、清零控制和
进位扩展输出十进制计数器可利用两个独立的IF语句完成。一个IF
语句用于产生计数器时序电路,该语句为非完整性条件语句;另一
个IF语句用于产生纯组合逻辑的多路选择器。其VHDL代码如下:
ARCHITECTURE behav OF cnt10_v IS
BEGIN
PROCESS(CLK, RST, EN)
VARIABLE CQI : STD_LOGIC_VECTOR(3 DOWNTO 0);
BEGIN
IF RST = '1' THEN CQI := (OTHERS =>'0') ;
ELSIF CLK'EVENT AND CLK='1' THEN
IF EN = '1' THEN
IF CQI < 9 THEN CQI := CQI + 1;
ELSE CQI := (OTHERS =>'0');
END IF;
END IF;
END IF;
IF CQI = 9 THEN COUT <= '1';
ELSE COUT <= '0';
END IF;
CQ <= CQI;
END PROCESS;
END behav;
(2) 两位十进制计数器的顶层设计
两位十进制计数器的顶层原理
图如图6-15所示,根据此图编制的
两位十进制计数器的顶层VHDL源
程序如下。
ARCHITECTURE struc OF Counter_100 IS
COMPONENT cnt10_v
图6-15两位十进制计数
PORT ( CLK ,RST,EN: IN STD_LOGIC;
CQ : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
器的顶层原理图
COUT : OUT STD_LOGIC );
END COMPONENT;
SIGNAL DTOL,DTOH : STD_LOGIC_VECTOR(3 DOWNTO 0);
SIGNAL CARRY_OUT1 : STD_LOGIC;
BEGIN
U1 : cnt10_v
PORT MAP(CLK => CLK_IN,
RST => CLRN,
EN => CLK_EN,
CQ =>DTOL ,
COUT => CARRY_OUT1 );
U2 : cnt10_v
PORT MAP(CLK => CARRY_OUT1,
RST => CLRN,
EN => CLK_EN ,
CQ =>DTOH ,
COUT=> CCOUT );
QL <= DTOL;
QH <= DTOH;
END struc;
在此源程序中,定义了三个信号
作为电路的内部连线,
DTOL[3..0]、 DTOH[3..0]分别接
于十进制计数器cnt10_v的个位
和十位输出,CARRY_OUT1作
为两个十进制计数器cnt10_v的
级联信号。
图6-16两位十进制计数器仿真输出波形
(2)异步计数器
异步计数器又称行波计数器,它的低位计数器的输出作
为高位计数器的时钟信号,这一级一级串行连接起来构
成了一个异步计数器。异步计数器与同步计数器不同之
处就在于时钟脉冲的提供方式,除此之外就没有什么不
同,它同样可以构成各种各样的计数器。一个由8个触
发器构成的行波计数器的程序如例6-26,27所示:
例6-26 基于D触发器模型的一位计数器的VHDL程序设
计:
ARCHITECTURE rtl OF rdff IS
signal QB:STD_LOGIC;
BEGIN
Q<=QB;
NQ<=NOT QB;
PROCESS(CLK,CLR)
BEGIN
IF(clr='1') THEN QB<='0';
ELSIF(CLK'EVENT AND CLK='1') THEN
QB<=D;
END IF;
END PROCESS;
END rtl;
例6-27 利用VHDL的FOR生成语句设计由8个触发器构成的
行波计数器。
解:VHDL提供了适合于以层次化方式描述规则结构电路
的FOR生成语句。FOR生成语句必须有一个标号,本例
中用GENL作为标号,FOR生成语句在循环中使用循环
下标I(范围0到7)对元件rdff例化8次,循环中每一次迭
代都将标号为GENL元件rdff例化1次,如图6-17所示,变
量I没有被显式声明,而是自动被定义为局部变量,其作
用局限于FOR生成语句的循环之中。
ARCHITECTURE rtl_top OF rplcont IS
SIGNAL COUNT_IN_BAR: STD_LOGIC_VECTOR(8 DOWNTO 0);
COMPONENT rdff
PORT(CLK,CLR,D: IN STD_LOGIC;
Q,NQ : OUT STD_LOGIC);
END COMPONENT;
BEGIN
COUNT_IN_BAR(0)<=CLK;
GENL:FOR I IN 0 TO 7 GENERATE
U:rdff
PORT MAP(CLK=>COUNT_IN_BAR(I),
CLR=>CLR,
D=>COUNT_IN_BAR(I+1),
Q=>COUNT(I),
NQ=>COUNT_IN_BAR(I+1));
END GENERATE;
END rtl_top;
图6-17行波计数器的部分RTL图
图6-18例化4次后的仿真输出波形
(3) 环形计数器
利用移位寄存器把一个有效逻辑电平循环经过所有触发
器,从而使之实现计数功能的计数器可称之为环形计数
器。环形计数器的特点是模数等于寄存器中触发器的个
数,因此总有一些不用或无效的状态。
例6-28 4位环形计数器的VHDL建模。
例6-28 4位环形计数器的VHDL建模。
ARCHITECTURE VHDL OF COUNT4 IS
BEGIN
PROCESS(CLK)
VARIABLE FF: BIT_VECTOR(3 DOWNTO 0);
VARIABLE SER_IN: BIT;
BEGIN
IF(CLK’EVENT AND CLK=’1’) THEN
IF(FF(3 DOWNTO 1) = “000”) THEN
SER_IN:=’1’;
ELSE SER_IN:=’0’;
END IF;
FF(3 DOWNTO 0):=(SER_IN & FF(3 DOWNTO 1));
END IF;
Q<=FF;
END PROCESS;
END VHDL;
例6-28中,为使寄存器每来一个脉冲移位一次,采
用了例6-23中的移位寄存器的描述方法,即通过驱
动移位寄存器的SER_IN输入来实现“环形”移位。无
论初始状态如何,经过简单规划,就能确保计数器
最终能够进入所需的序列中。为了使计数器不使用
异步输入信号就能够自启动,此例运用IF/ELSE结
构来控制移位寄存器的SER_IN输入。当发现较高3
位都是低电平时,假设最低是高电平,并且在下一
个时钟脉冲时,把一个高电平移到SER_IN中。对所
有其它状态,都移入一个低电平,无论计数器的初
始状态是什么,它最终全都是0,移入一个高电平
以启动环形序列。其波形仿真如图6-19。
图6-19环形计数器仿真输出波形
(4) 可逆计数器
可逆计数器根据计数脉冲的不同,控制计数器在同步信
号脉冲的作用,进行加1操作,或者减1操作。假设可逆
计数器的计数方向,由特殊的控制端updown控制。当
updown = 1时,计数器加1操作;当updown = 0时,计数
器加1操作。下面以8位二进制可逆计数器设计为例,其
真值表如表6-10所示。示例程序如例6-10所示。
表6-10 8位二进制可逆计数器真值表
例6-29 8位可逆计数器的VHDL设计。
ARCHITECTURE example OF count8UP_Dn IS
SIGNAL count_B:STDa_LOGIC_VECTOR (5 DOWNTO 0);
BEGIN
Q0 <= count_B(0);
Q1 <= count_B(1);
Q2 <= count_B(2);
Q3 <= count_B(3);
Q4 <= count_B(4);
Q5 <= count_B(5);
Q6 <= count_B(6);
Q7 <= count_B(7);
PROCESS (clr,clk)
BEGIN
IF (clr = 1 ) THEN
Count_B <= (OTHERS => 0 );
ELSIF (clk' EVENT AND clk = 1 ) THEN
IF (updown = 1 ) THEN
Count_B <= count_B + 1 ;
ELSE
Count_B <= count_B - 1 ;
END IF;
END IF;
END PROCESS;
END example;
图6-20仿真输出波形
6.3状态机的设计
有限状态机(finite state machine)又称有限状态自动机或简称状态
机,它是一个有向图形,由一组输入、一组输出、一组状态(states)
和一组管理状态间转移的转移函数(transition function)组成。状态机
通过响应一系列事件而“运行”。每个事件都在属于“当前” 节点的转
移函数的控制范围内,其中函数的范围是节点的一个子集。它是表
示有限个状态以及这些状态之间的转移和动作等行为的数学模型。
有限状态机中的状态只是操作步骤的序列中用于对某个操作步骤作
标记的抽象值,在给定的时间周期有一个当前状态(current state),
转移函数可以根据当前状态及给定时间周期的输入值,来确定下一
个时间周期的下一个状态(next state)。输出函数可根据当前状态及
给定时间周期的输入值来确定给定时间周期的输出。
有限状态机通常分为两类:Moore状态机和Mealy状态机。图6-21给
出了有限状态机的结构示意图。
Moore状态机输出只是状态的
函数,因此在有效的时钟沿之后
,输出设置到其最后数值要几个
门的延时,即使输入的信号恰巧
在时钟周期内改变,输出信号在
时钟周期也将不会改变,要将输
入和输出隔离开。Mealy状态机输
出是输入和状态的函数,而且输
入变化,输出可能在时钟周期中
间发生变化,在整个的周期内输
出可能不一致。
图6-21有限状态机的结构示意图
理论上,任何一个Mealy状态机,都有一个等价的Moore状态机与
之对应,实际设计中,可能是Mealy状态机,也可能是Moore状态机。
Mealy状态机可以用较少的状态实现给定的控制序列,但很可能较难
满足时间约束。这是由于计算下一状态的输入到达延时所造成的。
6.3.1 有限状态机的VHDL建模
由于有限状态机是由寄存器,下一状态逻辑、和输出逻
辑组成,可以利用VHDL语言为寄存器及组合逻辑建模
的方法来为有限状态机建模。我们把状态编码的任务留
给EDA工具自动完成,用VHDL语言设计状态机,可通
过简便地定义状态变量,将状态描述成进程,要使用简
单的同步或异步重置,不要依赖“缺损”状态,使用枚举
数据类型来描述状态,从组合进程里头分离出时序进程
,刚才说的要保证组合进程和时序进程分开的话,组合
进程是纯组合逻辑的,使用 CASE声明来检查当前状态
和预判下一状态,使用CASE或者IF-THEN-ELSE语
句做输出逻辑。
1.用户自定义数据类型定义语句
用户自定义数据类型定义语句是用类型定义语句TYPE
和子类型SUBTYPE实现。TYPE的语句格式如下:
(1)TYPE 类型名 IS 基本数据类型 RANGE 约束范围;
(2)TYPE 数据类型名 IS 数据类型定义 ;
用TYPE语句进行数据类型定义有两种格式,但方法相
同,其中数据类型名由用户自定义,类型有枚举类型、
整数类型、数组类型、记录类型、时间类型、实数类型
。一般都是取已有的数据类型定义,如BIT,
STD_LOGIC,INTERGER等。
2.有限状态机的VHDL建模
用VHDL设计的有限状态机有多种形式:从信号输出方
式上分为Mealy状态机和Moore状态机;从结构上分为单
进程,两进程和三进程;从状态表达方式上分为符号化
有限状态机和确定状态编码的有限状态机;从编码方式
上分,有顺序状态编码机,一位热码状态编码机或其他
编码方式的状态编码机。但最一般和最常用的状态机通
常包含说明部分,主控时序进程,主控组合进程和辅助
进程几个部分。
(1)说明部分
说明部分中使用type语句定义新的数据类型,此数据类
型为枚举型,其元素通常都用状态机的状态名来定义。
状态变量定义为信号,便于信息传递,并将状态变量的
数据类型定义为含有既定状态元素的新定义的数据类型
。说明部分一般放在结构体的architecture和begin之间。
(2) 主控时序进程
主控时序进程是指负责状态机运转和在时钟驱动下负责
状态转换的进程。状态机随外部时钟信号以同步时序方
式工作,因此,状态机中必须包含一个对工作时钟信号
敏感的进程,作为状态机的“驱动泵”,当时钟发生跳变
时,状态机的状态才会发生改变。当时钟的有效跳变到
来时,时序进程将代表次态的信号next_state中的内容送
入现态信号current_state中,而next_state中的内容完全由
其他进程根据实际情况而定,此进程中往往也包括一些
清零或置位的控制信号。
(3) 主控组合进程
主控组合进程的任务是根据外部输入的控制信号(包括来自状态机
外部的信号和来自状态机内部其他非主控的组合或时序进程的信号
)和当前状态值确定下一状态next_state的取向,以及确定对外输出
或对内其他进程输出控制信号的内容。如图6-23所示,状态逻辑输
出为com_outputs。
(4)辅助进程
辅助进程是用于配合状态机工作的组合或时序进程。在一般状态机
的设计过程中,为了能获得可综合的,高效的VHDL状态机描述,
建议使用枚举数据类型来定义状态机的状态,并使用多进程方式来
描述状态机的内部逻辑。例如可使用两个进程来描述,—个进程描
述时序逻辑,包括状态寄存器的工作和寄存器状态的输出,另一个
进程描述组合逻辑,包括进程间状态值的传递逻辑以及状态转换值
的输出。必要时还可以引入第三个进程完成其它的逻辑功能。
例6-31试为图6-24的有限状态机编写VHDL模型。
解:根据图6-24所示,在异步复位信号reset控制
下,状态机进入空闲状态A,一旦A有效,
output=8,状态机进入B,其他依此类推。不失一
般性,为避免组合逻辑和时序逻辑之间的混乱,
建议采用两进程状态机VHDL模型,一个进程用
于实现时序逻辑,另一个进程实现组合逻辑。图
6-24的有限状态机VHDL模型如下。
ARCHITECTURE behv OF s_machine IS
TYPE FSM_ST IS (A, B, C, D);
SIGNAL current_state, next_state: FSM_ST;
BEGIN
REG: PROCESS (reset,clk)
BEGIN
IF reset = '1' THEN current_state <= A;
ELSIF clk='1' AND clk'EVENT THEN
current_state <= next_state;
END IF;
END PROCESS;
COM:PROCESS(current_state, state_Inputs)
BEGIN
CASE current_state IS
WHEN A => comb_outputs<= 6;
IF state_inputs = "00" THEN next_state<=A;
ELSE next_state<=B;
END IF;
WHEN B => comb_outputs<= 8;
IF state_inputs = "00" THEN next_state<=B;
ELSE next_state<=C;
END IF;
WHEN C => comb_outputs<= 13;
IF state_inputs = "11" THEN next_state <= A;
图6-25采用QuartusII综合后两进程状态
ELSE next_state <= D;
机的RTL线路图
END IF;
WHEN D => comb_outputs <= 15;
IF state_inputs = "11" THEN next_state <= D;
ELSE next_state <= D;
END IF;
采用QuartusII综合后生成的两进程状
END case;
态机的RTL线路图如图6-25所示,可
END PROCESS;
END behv;
以清楚的看到时序逻辑和组合逻辑分
成了两部分。
图6-24的有限状态机也可用三进程实现,即在例6-31的
基础上,将主控组合进程后再增加一级寄存器(辅助进程
)来实现时序逻辑的输出。这样一来可有效地滤除组合逻
辑的毛刺,同时增加一级寄存器可以有效进行时序计算
与约束,另外对于总线形式的输出信号来说,容易使总
线数据对齐,从而减少总线数据间的扁斜(skew),减少
接收端数据采样出错的概率。
三进程状态机的基本格式是:第一个进程实现同步状态
跳转;第二个进程实现组合逻辑;第三个进程实现同步
输出。组合逻辑采用的是current_state,同步输出采用的
是next_state。请读者自行完成三进程状态机的VHDL设
计。
6.3.2 Morre状态机VHDL设计
从信号输出方式上有限状态机分为Mealy状态机和Moore
状态机。从输出时序上看前者属于同步输出状态机,而
后者属于异步输出状态机。Moore状态机的输出仅为当
前状态函数,这类状态机在输入发生变化时还必须等待
时钟的到来,时钟状态发生变化时才导致输出的变化,
它比Mealy状态要多等一个时钟周期。例6-31实际是
Moore状态机,下面再通过一实例说明Moore状态机的
VHDL建模方法。 例6-32用Moore状态机实现11序列检测
解:“11”序列检测器要求在一个串行数据流中检测出”11”,
即在连续的两个时钟周期内输入为”1”,则在下一个时钟
周期输出”1”,用Moore状态机实现,需要3个状态,设
为:s0,s1,s2。s0表示已检测到0个1,s1表示已检测到1个1,
s2表示已检测到2以上个的1,其状态图如图6-26所示。
图6-26“11”序列检测器状态图
ARCHITECTURE beav OF FSM_moore IS
TYPE state_type IS(s0,s1,s2);
SIGNAL c_state: state_type;
BEGIN
update:PROCESS(clk,rst)
BEGIN
IF rst ='1' THEN c_state<=s0;
ELSIF clk ='1' AND clk'EVENT THEN
CASE c_state IS
WHEN s0=>IF ina= '1' THEN c_state<=s1;ELSE c_state<=s0;END IF;
WHEN s1=>IF ina= '1' THEN c_state<=s2; ELSE c_state<=s0;END IF;
WHEN s2=>IF ina= '0' THEN c_state<=s0; ELSE c_state<=s2;END IF;
WHEN others=>c_state<=s0;
END CASE;
END IF;
END PROCESS update;
output:PROCESS(clk,c_state,ina)
BEGIN
IF rst ='1' THEN outa<='0';
ELSE THEN IF (clk ='1' AND clk'EVENT =1) THEN
IF c_state=s2 THEN
outa<='1' ;
ELSE outa<='0';
END IF;
END IF;
END IF;
END PROCESS output;
END beav;
例6-32程序中,通过TYPR语句定义了状态机的3个状态
s0,s1,s2,并假定触发器的第一个状态s0为状态机的复位
状态,所有触发输出为0的状态赋值均用此状态。进程
update描述了状态间的转移。当rst=1时状态机进入复位
状态s0,因为IF语句的条件不依赖时钟信号,所以复位
是异步的,这就是为什么要把rst列入进程update的敏感
性信号表。当复位信号不起作用时ELSIF语句指定电路
等待时钟信号上升沿。CASE语句中的每个WHEN语句
表示状态机的一个状态。状态机的最后一部分指定:如
状态机仍处在状态s2,则输出为outa为1,否则outa为0。
采用QuartusII综合后生成的两进程状态机的RTL线路图
如图6-27所示,可以清楚的看到时序逻辑和组合逻辑分
成了两部分。其仿真波形如图6-28所示。
图6-27“11”序列检测器Moore状态机RTL线路图
图6-28“11”序列检测器Moore状态机仿真波形
6.3.3 Mealy状态机VHDL设计
Mealy状态机输出是输入和状态的函数,而且输入变化,
输出可能在时钟周期中间发生变化,在整个的周期内输
出可能不一致。但是,允许输出随着噪声输入而改变。
与Moore状态机相比,Mealy状态机输出的变化要领先
Moore状态机一个周期。其VHDL建模方法基本一样,
不同之处是,Mealy状态机组合进程中的输出信号是当
前状态和当前输入的函数。
例6-33用Mealy状态机实现11序列检测。
解:用Mealy状态机实现“11”序列检测器, 需要2个状态即
可,设为:s0,s1。s0表示前一个时钟周期的数据为0,s1表
示前一个时钟周期的数据为1,其状态图如图6-28所示。
其VHDL模型代码如下。
ARCHITECTURE beav OF FSM_mealy IS
TYPE state_type IS(s0,s1);
SIGNAL c_state: state_type;
SIGNAL q1 : STD_LOGIC;
BEGIN
update:PROCESS(clk,rst)
BEGIN
IF rst ='1' THEN c_state<=s0;
ELSIF clk ='1' AND clk'EVENT THEN
图6-28“11”序列检
CASE c_state IS
测器状态图
WHEN s0=>IF ina='1' THEN c_state<=s1;
ELSE c_state<=s0;END IF;
WHEN s1=>IF ina='0' THEN c_state<=s0;
ELSE c_state<=s1;END IF;
WHEN others=>c_state<=s0;
END CASE;
END IF;
END PROCESS update;
output:PROCESS(clk,c_state,ina)
variable q2 : STD_LOGIC;
BEGIN
CASE c_state IS
WHEN s0=>IF ina='1' THEN q2:='0'; ELSE q2:='0';END IF;
WHEN s1=>IF ina='0' THEN q2:='0'; ELSE q2:='1';END IF;
WHEN others=>q2:='0';
END CASE;
IF clk ='1' AND clk'EVENT THEN
q1<=q2;
END IF;
END PROCESS output;
outa <= q1;
END beav;
采用QuartusII综合后生成的Mealy状态机两进程状态机的RTL线路
图如图6-29所示,可以清楚的看到时序逻辑和组合逻辑分成了三部
分。其仿真波形如图6-30所示。
图6-29“11”序列检测器Mealy状态机RTL线路图
图6-30“11”序列检测器Mealy状态机仿真波形
6.4存储器的设计
存储器是一个用于存放数据的寄存器阵列或存放数据的
单元(locations),每一个单元有唯一的地址,地址是用来
确定单元位置的一个数据。存储器的地址通常从0开始
,每过一个单元,地址加1,一直到比地址单元的个数
少不了。储器可分为随机读写存储器(Random Access
Memory)和只读存储器(Read Only Memory)。
6.4.1ROM的设计
只读存储器ROM存放固定数据,事先写入,工作中可随
时读取,断电数据不会丢失。在数值是常数的情况下,
只读存储器非常有用,因为没有必要更新所存储的数据
值。可以用表格的形式来指定ROM的内容,每一个地址
列一行,地址的右边就是该地址的内容,即数据。简单
的ROM是一个组合电路,每个输入地址对应一个常数。
对于一个复杂的多输出组合逻辑,用ROM来实现比用逻
辑门电路实现更好。在复杂的状态机中,可用ROM产生
下一个状态的逻辑,或产生输出逻辑。
例6-34请根据图6-31用VHDL语言设计一个程序存储器
ROM16_8,该ROM可存储16个8位十六进制数,从地址
0到F该ROM所存的16个数为:09,1A,1B,2C,E0,
F0,00,00,10,15,17,20,00,00,00,00。
解:该ROM的地址位为4,数据位为8,结构体代码如下
,仿真输出波形图6-32所示。
ARCHITECTURE r OF rom16_8 is
BEGIN
DATAOUT<="00001001"
WHEN ADDRESS="0000" AND CE='0' ELSE "00011010"
WHEN ADDRESS="0001"AND CE='0'ELSE "00011011"
WHEN ADDRESS="0010"AND CE='0'ELSE "00101100"
WHEN ADDRESS="0011"AND CE='0' ELSE "11100000"
WHEN ADDRESS="0100"AND CE='0' ELSE "11110000"
WHEN ADDRESS="0101"AND CE='0' ELSE "00010000"
WHEN ADDRESS="1001"AND CE='0' ELSE "00010101"
WHEN ADDRESS="1010"AND CE='0' ELSE "00010111"
WHEN ADDRESS="1011"AND CE='0' ELSE "00100000"
WHEN ADDRESS="1100"AND CE='0' ELSE "00000000";
END r;
图6-32 ROM16_8 仿真输出波形
6.4.2 RAM的设计
RAM的逻辑功能是在地址信号的选择下对指定存储单元
进行相应的读写操作。RAM的VHDL模型可通过
QuartusII的MegaWizard Plug-In Manager工具中Memory
Compiler生成。然后通过例化该模块用于系统的设计。
这里给出一个直接用VHDL实现的RAM的例子。
例6-35: 图6-33为一双端口直通SSRAM,其容量为1Kx8
位,端口d_out1允许数据读/写,端口d_out2只允许读取
数据,请编写其VHDL模型。
解:RAM一般分为单端口存储器和多端口存储器。单端
口存储器只有一个读/写数据的端口,即使数据连接可分
为输入和输出,也只有一个地址输入,在同一个时间只
可以实现一次访问(或读或写)。多端口存储器有多个
地址输入,对应于多个数据输入和输出,如图6-33所示
,该模型的VHDL代码如下。
architecture rtl of dual_port_ssram is
type ram_1Kx8 is array(0 to 1023) of std_logic_vector(7
downto 0);
signal data_ram :ram_1Kx8 ;
begin
read_write_port: process(clk)is
begin
if rising_edge(clk) then
if en1='1' then
if wr1='1' then
data_ram(to_integer(a1))<=d_in1; d_out1 <=d_in1;
else
d_out1<=data_ram(to_integer(a1));
end if;
end if;
end if;
end process read_write_port;
read_only_port:process(clk)is
begin
if rising_edge(clk) then
if en2='1' then
d_out2<=data_ram(to_integer(a2));
end if;
end if;
end process read_only_port;
end rtl;
图6-33双端口存储器
6.4.3 FIFO的设计
先入先出(First-in first-out memory, FIFO)存储器是多端
口存储器的一个特例,FIFO被用来对来自源头到达的
数据进行排队,并依照数据到达的顺序由另一个子系
统加以处理,最先进入的数据最先出来。FIFO的一个
重要用途是用于不同时钟频率子系统间的数据传递。
例6-36请设计一个最多可存
储256X8位数据的FIFO,该
FIFO能提供状态输出,如
图6-34所示。如FIFO为空,
则禁止读取FIFO;如FIFO
为满,则禁止写入FIFO;
并且读写端口共用一个时钟。
图6-34具有空和满状态
的FIFO
architecture rtl of example_fifo is
type ram_256x8 is array(0 to 256) of std_logic_vector(7 downto 0);
begin
p1: process(clk,clr)
variable stack:ram_256x8;
variable cnt:integer range 0 to 255;
begin
if clr='1' then
d_out1<=(others=>'0');
full<='0';cnt:=0;
elsif rising_edge(clk) then
if push='1' and pop='0'and cnt/=255 then
empty<='0';stack(cnt):=d_in1;
cnt:=cnt+1;
d_out1<=(others=>'0');
elsif push='0' and pop='1'and cnt/=0 then
full<='0';
cnt:=cnt-1;
d_out1<=stack(cnt);
elsif push='0' and pop='0'and cnt/=0 then
d_out1<=(others=>'0');
elsif cnt=0 then
empty<='1';
d_out1<=(others=>'0');
elsif cnt=256 then
full<='1';
end if;
end if;
end process p1;
end rtl;
6.5 EDA综合设计
本节通过3个设计实例,说明怎样利用基于VHDL的层次
化结构的设计方法来构造较复杂的数字逻辑系统。通过
这些实例,逐步讲解设计任务的分解、层次化结构设计
的重要性、可重复使用的库、程序包参数化的元件引用
等方面的内容。进一步了解EDA技术在组合逻辑和时序
逻辑电路设计方面的应用,以及在计算机方面的应用。
6.5.1移位相加8位乘法器的VHDL设计
该乘法器是由8位加法器构成的以时序方式设计的8位
乘法器。乘法通过逐项移位相加来实现相乘,从被乘
数的最低位开始,若为1,则乘法左移后与上一次的
和相加;若为0,左移后以全零相加,直至被乘数的
最高位。8位移位相加乘法器的原理图如图6-34所示,
分解 8位乘法器的层次结构,可划分为以下几个结构
单元,并可根据分解的层次进行设计。
图6-34移位相加乘法器的原理图
①右移寄存器模块: 这是一个8位右移寄存器,可将乘法运
算中的被乘数加载于其中,同时进行乘法运算的移位操
作;
②加法器模块:这是一个8位加法器,进行操作数的加法
运算;
③乘1模块: 这是一个1位乘法器,完成8位与1位的乘法运
算;
④锁存器: 这是一个16位锁存器,同时也是一个右移寄存
器,在时钟信号作用下,进行输入值的移位与锁存;
1.右移寄存器的设计(SREG8B)
8位右移寄存器是在时钟(CLK'EVENT AND CLK = '1'
)信号作用下,当LOAD=‘1’时,将8位被乘数加载进入
;而当LOAD=‘0’时,数据进行移位操作;同时定义一
个信号REG8用来装载新数据及移位后的操作数,在完
成这些操作后,寄存器的最低位REG8(0)传送给QB输出
。该模块的VHDL程序如下。
ARCHITECTURE behav OF SREG8B IS
SIGNAL REG8 : STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
PROCESS (CLK, LOAD)
BEGIN
IF CLK'EVENT AND CLK = '1' THEN
IF LOAD = '1' THEN
REG8 <= DIN;
ELSE
REG8(6 DOWNTO 0) <= REG8(7 DOWNTO 1);
END IF;
END IF;
END PROCESS;
QB <= REG8(0);
END behav;
其仿真波形如图4-4所示:
图6-35 SREG8B模块仿真输出波形
2.加法器模块的设计(ADDER8B)
加法器模块是由两个4位二进制加法器U1和U2组成的8位
加法器逻辑电路,其中U1用来装载8位加法器中两个加
数的低四位,而U2则用来装载高四位。
(1) 4位二进制加法器设计
在设计4位加法器时,定义信号量SINT,AA及BB,将加
数A与0并置后赋给AA,加数B与0并置后赋给BB,形成
5位二进制数,这是为了在做加法时发生溢出所做的处
理,然后将加数AA与BB以及进位位CIN相加赋给SINT
,并将SINT的低4位赋给加数和S输出,同时将SINT最
高位传送给COUT输出。4位加法器的VHDL程序设计如
下:
ARCHITECTURE behav OF ADDER4B IS
SIGNAL SINT : STD_LOGIC_VECTOR(4 DOWNTO 0);
SIGNAL AA,BB : STD_LOGIC_VECTOR(4 DOWNTO 0);
BEGIN
AA<='0'&A;
BB<='0'&B;
SINT <= AA + BB + CIN;
S <= SINT(3 DOWNTO 0);
COUT <= SINT(4);
END behav;
(2)8位加法器设计
在设计8位加法器时,定义一个信号量CARRY_OUT,
将4位加法器U1的COUT赋给CARRY_OUT,再将
CARRY_OUT的值赋给4位加法器U2的进位位CIN,8位加
法器的高4位和低4位分别来自于4位加法器U2和U1。
该模块的VHDL程序如下。
ARCHITECTURE struc OF ADDER8B IS
COMPONENT ADDER4B
PORT ( CIN : IN STD_LOGIC;
A : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
B : IN STD_LOGIC_VECTOR(3 DOWNTO 0);
S : OUT STD_LOGIC_VECTOR(3 DOWNTO 0);
COUT : OUT STD_LOGIC );
END COMPONENT;
SIGNAL CARRY_OUT : STD_LOGIC;
BEGIN
U1 : ADDER4B
PORT MAP ( CIN => CIN,
A => A(3 DOWNTO 0),
B => B(3 DOWNTO 0), S => S(3 DOWNTO 0),
COUT => CARRY_OUT );
U2 : ADDER4B
PORT MAP ( CIN => CARRY_OUT, A => A(7 DOWNTO 4),
B => B(7 DOWNTO 4), S => S(7 DOWNTO 4),COUT => COUT );
END struc;
3.乘1模块设计(ANDARITH)
乘1模块即1位乘法器,可通过选通与门逻辑,利用FORLOOP循环语句完成8位二进制数与1位二进制数的乘法
运算,即8位二进制数DIN从最低位到最高位与1位二进
制数ABIN分别作与运算,最后将结果依次传送到DOUT
的最低位到最高位输出,即当ABIN为1时,DOUT直接
输出DIN,为0时DOUT输出全零。1位乘法器程序如下
ARCHITECTURE behav 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 behav;
4.锁存器模块设计(REG16B)
此处锁存器模块即16位右移寄存器,可利用IF语句来完成
其输入值的锁存,当清零(CLR = '1')信号到来时,定义
的信号量R16S锁存输入值,即R16S清零;否则在时钟信号
CLK上升沿作用下,将R16S的低8位进行移位操作,同时
将8位输入数据D锁存到R16S的高8位,最后传送给Q输出
。
在乘法器的顶层设计中,乘数与被乘数的乘积也将出现在
REG16B端口。16位锁存器的VHDL程序如下。
ARCHITECTURE behav OF REG16B IS
SIGNAL R16S : STD_LOGIC_VECTOR(15 DOWNTO 0);
BEGIN
PROCESS(CLK, CLR)
BEGIN
IF CLR = '1' THEN
R16S <= "0000000000000000";
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 behav;
5. 8位乘法器的顶层设计
根据图6-34 移位相加乘法器的原理图,利用元件例化的
方法可得乘法器的顶层设计的VHDL代码, 程序如下。
ARCHITECTURE struc OF MULTI8X8 IS
COMPONENT ANDARITH
PORT ( ABIN : IN STD_LOGIC;
DIN : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
DOUT : OUT STD_LOGIC_VECTOR(7 DOWNTO 0) );
END COMPONENT;
COMPONENT ADDER8B
PORT (CIN : IN STD_LOGIC;
A, B : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
S : OUT STD_LOGIC_VECTOR(7 DOWNTO 0);
COUT : OUT STD_LOGIC );
END COMPONENT;
COMPONENT SREG8B
PORT ( CLK, LOAD : IN STD_LOGIC;
DIN : IN STD_LOGIC_VECTOR(7 DOWNTO 0);
QB : OUT STD_LOGIC );
END COMPONENT;
COMPONENT REG16B
PORT ( CLK, CLR : IN STD_LOGIC;
D : IN STD_LOGIC_VECTOR(8 DOWNTO 0);
Q : OUT STD_LOGIC_VECTOR(15 DOWNTO 0) );
END COMPONENT;
SIGNAL GNDINT,NEWSTART, QB : STD_LOGIC;
SIGNAL ANDSD : STD_LOGIC_VECTOR(7 DOWNTO 0);
SIGNAL DTBIN : STD_LOGIC_VECTOR(8 DOWNTO 0);
SIGNAL DTBOUT : STD_LOGIC_VECTOR(15 DOWNTO 0);
BEGIN
DOUT<= DTBOUT; GNDINT <= '0';
PROCESS(CLKK,START)
BEGIN
IF
START='1' THEN NEWSTART<='1';
ELSIF CLKK='0' THEN NEWSTART<='0';
END IF;
END PROCESS;
U1 : SREG8B PORT MAP(CLK=>CLKK, LOAD=>NEWSTART,
DIN=>A, QB=>QB );
U2 : ANDARITH PORT MAP(ABIN => QB, DIN => B,DOUT =>
ANDSD);
U3 : ADDER8B PORT MAP(CIN => GNDINT, A=>
DTBOUT(15 DOWNTO 8), B=>ANDSD,
S => DTBIN(7 DOWNTO 0), COUT => DTBIN(8) );
U4 : REG16B PORT MAP(CLK=>CLKK, CLR=>NEWSTART,
D=>DTBIN, Q=>DTBOUT );
END struc;
在波形仿真时,我们选取9FH与FDH相乘,从仿真波
形可知第一个时钟上升沿后,其移位相加的结果(在
REG16B端口)是4F80H,第8个时钟上升沿后,最终
相乘结果为9D23H。仿真结果与元件符号图如图4-6:
图6-36移位相加乘法器仿真结果
6.5.2 序列计数器的设计
序列计数器是经常出现在通信协议编译码器电路中
的器件,其基本功能是对一个8bit宽二进制数中的
连续为0的个数的统计。
序列计数器主要由两个功能部件组成,分别为序列
计数器的逻辑功能实现模块和七段译码器模块。序
列计数器通过功能实现模块计算出0的个数,传送
给译码器,配对相应的0个数所对应的译码并且输
出该译码数。
序列计数器的逻辑原理图如图6-37所示,在单个时
钟脉冲时间内,完成8位二进制数a的统计后,将统
计结果ge传送给七段译码器的d[3..0],通过译码后
输出相应的结果dout[6..0],当计数值不合法时,给
出报错信号alm1。
1.序列计数器逻辑功能实现模块设计(zero1)
该模块设计时,要求在单个时钟(clk)脉冲时间内
,完成对8bit二进制数d[7..0]的统计,并且要求在
整个序列中只能有一串连0出现,既8bit中0是相
邻的,此时,我们认为输出有效,并且输出连0
的个数;
否则认为无效,连0计数
器清零,同时输出错误
指示信号。这里规定全1
的序列为有效序列,其
连0的个数为0个。序列
计数器逻辑功能实现模
图6-37序列计数器的逻辑原理图
块的VHDL程序如下。
architecture ze_arc of zero1 is
begin
process(clk,clr)
variable s:std_logic_vector(6 downto 0);
variable sd,ss:std_logic_vector(3 downto 0);
begin
if clr='0' then
alm<='0';
elsif clk'event and clk='1' then
s(0):=d(0) xor d(1);
if s(0)='1' then
ss:=ss+1;
end if;
s(1):=d(1) xor d(2);
if s(1)='1' then ss:=ss+1;
end if;
s(2):=d(2) xor d(3);
if s(2)='1' then ss:=ss+1;
end if;
s(3):=d(3) xor d(4);
if s(3)='1' then ss:=ss+1;
end if;
s(4):=d(4) xor d(5);
if s(4)='1' then ss:=ss+1;
end if;
s(5):=d(5) xor d(6);
if s(5)='1' then ss:=ss+1;
end if;
s(6):=d(6) xor d(7);
if s(6)='1' then ss:=ss+1;
end if;
if d(0)='1' then
end if;
if d(1)='1' then
end if;
if d(2)='1' then
end if;
if d(3)='1' then
end if;
if d(4)='1' then
end if;
if d(5)='1' then
end if;
if d(6)='1' then
end if;
sd:=sd+1;
sd:=sd+1;
sd:=sd+1;
sd:=sd+1;
sd:=sd+1;
sd:=sd+1;
sd:=sd+1;
if d(7)='1' then sd:=sd+1;
end if;
if d(0)='0' then
if ss>1 then alm<='1';
ge<="0000";
else
ge<=8-sd;
end if;
else
if ss>2 then alm<='1';
ge<="0000";
else
ge<=8-sd;
end if;
end if;
end if;
sd:="0000";
ss:="0000";
end process;
end ze_arc;
图6-38 序列计数器逻辑功能实现模块仿真输出
2.七段译码器设计(disp)
设计时用CASE语句实现其译码输出,通过零的个数来
设计相应的译码数q[6..0] 。七段译码器(本例使用的是共
阴级数码管)的VHDL程序如下。
architecture disp_arc of disp is
begin
process(d)
begin
case d is
when"0000"=>q<="0111111";
when"0001"=>q<="0000110";
when"0010"=>q<="1011011";
when"0011"=>q<="1001111";
when"0100"=>q<="1100110";
when"0101"=>q<="1101101";
when"0110"=>q<="1111101";
when"0111"=>q<="0100111";
when"1000"=>q<="1111111";
when
others=>q<="1101111";
end case;
end process;
end disp_arc;
3.序列计数器的顶层设计
根据图6-37 序列计数器的原理图,利用元件例化的方法可
得序列计数器的顶层设计的VHDL代码如下。
ARCHITECTURE arith_arc OF arith IS
COMPONENT zero1
port(d: in std_logic_vector(7 downto 0);
clk,clr: in std_logic;
ge: out std_logic_vector(3 downto 0);
alm: out std_logic);
END COMPONENT;
COMPONENT disp
port(d: in std_logic_vector(3 downto 0);
q: out std_logic_vector(6 downto 0));
END COMPONENT;
signal abin: std_logic_vector(3 downto 0);
BEGIN
U1: zero1 port map(clk=>clkk,clr=>start,d=>a,ge=>abin,alm=>alm1);
U2: disp port map(d=>abin,q=>dout);
END arith_arc;
图6-39序列计数器仿真输出波形
6.5.3 简易数字钟的设计
简易数字钟实际上是一个对标准1Hz秒脉冲信号进行计
数的计数电路,秒计数器满60后向分计数器进位, 分计
数器满60后向时计数器进位, 时计数器按24翻1规律计数,
计数输出经译码器送LED显示器,以十进制(BCD码)形
式输出时分秒。
根据上述简易数字钟功能的介绍可将该系统的设计分为
两部分,即时分秒计数模块和时分秒译码输出模块。其
原理框图如图6-40所示,秒计数器在1HZ时钟脉冲下开
始计数,当秒计数器值满60后进位输送到分计数器,同
时将数值送往秒译码器,以十进制BCD码分别显示输出
秒的十位与个位,同理,分计数器也在计数值满60后进
位输送到时计数器,经译码输出十位与个位计数值,而
时计数器则是模为24的计数器,当计数值满24后,计数
值置零,重新开始计数,如此循环计数。
图6-40数字钟的原理框图
1.时分秒计数模块
时分秒计数器模块由秒计数器、分计数器及时计数器模块
构成。其中:秒个计数器、分计数器为六十进制计数器,
而根据设计要求时计数器为二十四进制计数器。
(1)秒计数器模块设计
秒计数器模块的输入来自时钟电路的秒脉冲1Hz,是模
M=60的计数器,其规律为0001…585900…,在设计中
保留了一个异步清零端rst和进位输出端full,当计数器值
满计数到59时,进位位full输出为1。秒计数器模块的
VHDL程序代码如下。
ARCHITECTURE arch OF count60 IS
signal time : integer range 0 to 59;
BEGIN
process (rst,carry)
begin
if rst='1' then time <= 0; full<='0';
elsif rising_edge(carry) then
if time=59 then
time<=0;
full<='1';
else time<= time + 1;
full<='0';
end if;
end if;
end process;
times<=time;
end arch;
(2)分计数器模块设计(分计数器模块和秒计数器模块的程序
设计和工作原理完全相同)
(3)时计数器模块设计
时计数器模块能计数和显示0~23小时,是模M=24的计数
器,其规律为0001…222300…,即当数字钟运行到“23时
59分59秒”时,在下一个秒脉冲作用下,数字种显示“00
时00分00秒”。在设计中保留了一个异步清零端rst和进位
输出端full,当计数器值满计数到23时,进位位full输出为
1。时计数器模块的VHDL程序如下。
architecture arch of count24 is
signal time : integer range 0 to 23;
begin
process (rst,carry) --process for 60 seconds counting
begin
if rst='1' then time <= 0; full<='0';
elsif rising_edge(carry) then
if time=23 then time<=0;--over 24
full<='1';--carry_out signal
else time<= time + 1;--keep counting
full<='0';
end if;
end if;
end process;
times<=time;
end arch;
2.时分秒译码输出模块设计
该模块主要由秒个位、十位计数器、分个位、十位计数及时个
位、十位计数译码输出模块构成。其中:秒计数器、分计数器
为六十进制,而根据设计要求时个位和时十位构成为二十四进
制计数器,显示输出均为十进制BCD码。
(1)秒译码输出模块设计
在设计时通过CASE语句来实现译码转换功能,计数值
在0~59内变化时,输出对应译码,当为其它值时,似
为错误输出。秒译码输出模块的VHDL程序设计如下:
ARCHITECTURE arch OF i60bcd IS
begin
process(interg)
begin
case interg is
when 0|10|20|30|40|50 => one<="0000";
when 1|11|21|31|41|51 => one<="0001";
when 2|12|22|32|42|52 => one<="0010";
when 3|13|23|33|43|53 => one<="0011";
when 4|14|24|34|44|54 => one<="0100";
when 5|15|25|35|45|55 => one<="0101";
when 6|16|26|36|46|56 => one<="0110";
when 7|17|27|37|47|57 => one<="0111";
when 8|18|28|38|48|58 => one<="1000";
when 9|19|29|39|49|59 => one<="1001";
when others
=> one<="1110";
end case;
case interg is
when 0|1|2|3|4|5|6|7|8|9 => ten<="0000";
when 10|11|12|13|14|15|16|17|18|19 => ten<="0001";
when 20|21|22|23|24|25|26|27|28|29 => ten<="0010";
when 30|31|32|33|34|35|36|37|38|39 => ten<="0011";
when 40|41|42|43|44|45|46|47|48|49 => ten<="0100";
when 50|51|52|53|54|55|56|57|58|59 => ten<="0101";
when others
=> ten<="1110";
end case;
end process;
end arch;
(2)分译码输出模块设计(分译码输出模块与秒译码输出模块
设计完全相通)
(3)时译码输出模块设计
本设计中小时是以24小时为循环周期,故而在设计时计
数值在0~23内变化时,输出对应译码,而为其它值时
似为错误输出。时译码输出模块的VHDL程序如下。
ARCHITECTURE arch OF i24bcd IS
begin
with interg select
one<="0000" when 0;
"0001" when 1;
"0010" when 2;
"0011" when 3;
"0100" when 4;
"0101" when 5;
"0110" when 6;
"0111" when 7;
"1000" when 8;
"1001" when 9;
"0000" when 10;
"0001" when 11;
"0010" when 12;
"0011" when 13;
"0100" when 14;
"0101" when 15;
"0110" when 16;
"0111" when 17;
"1000" when 18;
"1001" when 19;
"0000" when 20;
"0001" when 21;
"0010" when 22;
"0011" when 23;
"1110" when others;
WITH interg SELECT
ten<="0000" when 0;
"0000" when 1;
"0000" when 2;
"0000" when 3;
"0000" when 4;
"0000" when 5;
"0000" when 6;
"0000" when 7;
"0000" when 8;
"0000" when 9;
"0001" when 10;
"0001" when 11;
"0001" when 12;
"0001" when 13;
"0001" when 14;
"0001" when 15;
"0001" when 16;
"0001" when 17;
"0001" when 18;
"0001" when 19;
"0010" when 20;
"0010" when 21;
"0010" when 22;
"0010" when 23;
"1110" when others;
end arch;
3.数字钟的顶层设计
根据图6-40 数字钟的原理图,利用元件例化的方法可得
数字钟顶层设计的VHDL代码。
ARCHITECTURE clock_arc OF clock IS
COMPONENT count60
PORT(carry,Rst: in std_logic;
times: out integer range 0 to 59;
full: out std_logic);
END COMPONENT;
COMPONENT count24
port(carry,Rst: in std_logic;
times: out integer range 0 to 23;
full: out std_logic);
END COMPONENT;
COMPONENT i60bcd
port(interg: in integer range 0 to 59;
one,ten: out std_logic_vector(3 downto 0));
END COMPONENT;
COMPONENT i24bcd
port(interg: in integer range 0 to 23;
one,ten: out std_logic_vector(3 downto 0));
END COMPONENT;
signal carry1,carry2,newRst: std_logic;
signal abin1,abin2: integer range 0 to 59;
signal abin3: integer range 0 to 23;
begin
u1:count60 port
map(carry=>clk,Rst=>newRst,times=>abin1,full=>carry1);
u2:count60 port
map(carry=>carry1,Rst=>newRst,times=>abin2,full=>carry2);
u3:count24 port
map(carry=>carry2,Rst=>newRst,times=>abin3,full=>newRst);
u4:i60bcd port map(interg=>abin1,ten=>sH,one=>sL);
u5:i60bcd port map(interg=>abin2,ten=>mH,one=>mL);
u6:i24bcd port map(interg=>abin3,ten=>hH,one=>hL);
end clock_arc;
6.5.4出租车自动计费器EDA设计
设计一个出租车自动计费器,计费包括起步价、行车里
程计费、等待时间计费三部分,用三位数码管显示金额
,最大值为999.9元,最小计价单元为 0.1元,行程 3公
里内,且等待累计时间3分钟内,起步费为8元,超过3
公里,以每公里1.6元计费,等待时间单价为每分钟1元
。用两位数码管显示总里程。最大为99公里,用两位数
码管显示等待时间,最大值为59min。
根据层次化设计理论,该设计问题自顶向下可分为分频
模块,控制模块 计量模块、译码和动态扫描显示模块,
其系统框图如图6-41所示。
图6-41出租车自动计费器系统框图
(2)计量控制模块
(3)译码显示模块
1.出租车自动计费器系统的主体FPGA电路txai的
VHDL设计该电路的核心部分就是计数分频电路,分频
模块对频率为240Hz的输入脉冲进行分频,得到的频率
为16Hz,10Hz和1Hz的三种频率。该模块产生频率信号
用于计费,每个1HZ脉冲为0.1元计费控制,10HZ信号
为1元的计费控制,16Hz信号为1.6元计费控制。
计量控制模块是出租车自动计费器系统的主体部分,该
模块主要完成等待计时功能、计价功能、计程功能,同
时产生3分种的等待计时使能控制信号en1, 行程 3公里外
的使能控制信号en0。其中计价功能主要完成的任务是:
行程 3公里内,且等待累计时间3分钟内,起步费为8元;
3公里外以每公里1.6元计费,等待累计时间3分钟外以每
分钟1元计费;计时功能主要完成的任务是:计算乘客
的等待累计时间,计时器的量程为59分,满量程自动归
零;计程功能主要完成的任务是:计算乘客所行驶的公
里数。计程器的量程为99公里,满量程自动归零。本设
计通过VHDL语言的顺序语句IF-THEN-ELSE根据一个
或一组条件来选择某一特定的执行通道,生成计费数据、
计时数据和里程数据。其VHDL源程序如下。
architecture behav of taxi is
signal f_10,f_16,f_1:std_logic;
--频率为10Hz,16Hz,1Hz的信号
signal q_10:integer range 0 to 23;
--24分频器
signal q_16:integer range 0 to 14;
--15分频器
signal q_1:integer range 0 to 239;
--240分频器
signal w:integer range 0 to 59;
--秒计数器
signal c3,c2,c1,c0:std_logic_vector(3 downto 0); --十进费用计数器
signal k1,k0:std_logic_vector(3 downto 0);
--公里计数器
signal m1:std_logic_vector(2 downto 0);
--分的十位计数器
signal m0:std_logic_vector(3 downto 0);
--分的个位计数器
signal en1,en0,f:std_logic;
--使能信号
begin
feipin:process(clk_240,start)
begin
if clk_240'event and clk_240='1' then
if start='0' then q_10<=0;q_16<=0;f_10<='0';f_16<='0';f_1<='0';f<='0';
else
if q_10=23 then q_10<=0;f_10<='1'; --得到频率为10Hz的信号
else q_10<=q_10+1;f_10<='0';
end if;
if q_16=14 then q_16<=0;f_16<='1'; --得到频率为16Hz的信号
else q_16<=q_16+1;f_16<='0';
end if;
if q_1=239 then q_1<=0;f_1<='1'; --得到频率为1Hz的信号
else q_1<=q_1+1;f_1<='0';
end if;
if en1='1' then f<=f_10;
--得到计费脉冲f
elsif en0='1' then f<=f_16;
else f<='0';
end if;
end if;
end if;
end process;
main:process(f_1)
begin
if f_1'event and f_1='1' then
if start='0' then w<=0;en1<='0';en0<='0';
m1<="000";m0<="0000";k1<="0000";k0<="0000";
elsif stop='1' then
if w=59 then w<=0;
--完成等待计时
if m0="1001" then m0<="0000";
--完成分计数
if m1<="101" then m1<="000";
else m1<=m1+1;
end if;
else m0<=m0+1;
end if;
if m1&m0>"0000010"then en1<='1'; --得到en1使能信号
else en1<='0';
end if;
else w<=w+1;en1<='0';
end if;
elsif fin='1' then
if k0="1001" then k0<="0000"; --此完成公里脉冲计数
if k1="1001" then k1<="0000";
else k1<=k1+1;
end if;
else k0<=k0+1;
end if;
if k1&k0>"00000010" then en0<='1'; --得到en0使能信号
else en0<='0';
end if;
else en1<='0';en0<='0';
end if;
cha3<=c3;cha2<=c2;cha1<=c1;cha0<=c0;
--费用数据输出
km1<=k1;km0<=k0;min1<='0'&m1;min0<=m0; --公里、分钟输出
end if ;
end process main;
jifei:process(f,start)
begin
if start='0' then c3<="0000";c2<="0000";c1<="1000";c0<="0000";
elsif f'event and f='1' then
if c0="1001" then c0<="0000";
--对费用的计数
if c1="1001" then c1<="0000";
if c2="1001" then c2<="0000";
if c3<="1001" then c3<="0000";
else c3<=c3+1;
end if;
else c2<=c2+1;
end if;
else c1<=c1+1;
end if;
else c0<=c0+1;
end if;
end if;
end process jifei;
end behav;
该源程序包含3个进程模块。fenpin进程对240Hz的输入
脉冲进行分频,得16Hz,10Hz和1Hz的三种计费频率信
号,供main进程和jifei进程进行计费、计时、计程之用
;main进程完成等待计时功能、计程功能,该模块将等
待时间和行驾公里数变换成脉冲个数计算,同时产生3
分种的等待计时使能控制信号en1, 行程 3公里外的使能
控制信号en0;jifei进程将起步价8元预先固定在电路中
,通过对计费脉冲数的统计,计算出整个费用数据。
在图6-42中,stop=0即全程无停止等待时间,因此
计时显示输出为00,该图中出租车总行驶5公里,
等待累计时间为0分钟,总费用为11.2元;图6-43中
共有3次停车等待累计时间为3分钟,出租车总行驶
21公里,总费用为57.6元,仿真结果正确。
图6-42出租车自动计费器系统的主体电路仿真输
出波形(1)
(2) 译码显示模块扫描显示电路
该模块经过8选1选择器将计费数据(4位BCD码)、计
时数据(2位BCD码)、计程数据(2位BCD码)动态选
择输出。其中计费数据jifei4至jifei1送入显示译码模块进
行译码,最后送至百元、十元、元、角为单位对应的数
码管上显示,最大显示为999.9元;计时数据送入显示译
码模块进行译码,最后送至分为单位对应的数码管上显
示,最大显示为59秒;计程数据送入显示译码模块进行
译码,最后送至以公里为单位的数码管上显示,最大显
示为99公里。该模块包含8选1选择器,模8计数器,七
段数码显示译码器三个子模块。
①8选1选择器VHDL源程序
when"100"=>d<=b1;
architecture rt1 of mux8_1 is
dp<='0';
begin
when"101"=>d<=b2;
process(c,a1,a2,a3,a4,b1,b2,b3,b4)
dp<='0';
variable comb:std_logic_vector(2 downto 0); when"110"=>d<=b3;
begin
dp<='1';
when"111"=>d<=b4;
comb:=c;
dp<='0';
case comb is
when others=>null;
when"000"=>d<=a1;
end case;
dp<='0';
end process;
when"001"=>d<=a2;
end rt1;
dp<='0';
when"010"=>d<=a3;
dp<='1';
when"011"=>d<=a4;
dp<='0';
从这里开始程序没怎么贴了
②模8计数器VHDL源程序
③七段数码显示译码器VHDL源程序参见6.5.2节的disp程
序。
3.出租车自动计费器顶层电路的设计和仿真
根据图6-41出租车自动计费器系统框图,出租车自动计费
器顶层电路分为四个模块,它们是出租车自动计费器系
统的主体FPGA电路txai模块,8选1选择器mux8_1模块,
模8计数器se模块,七段数码显示译码器di_LED模块,
生成动态扫描显示片选信号的3-8译器模块decode3_8,
本例使用原理图输入法完成图6-44所示出租车自动计费
器顶层电路设计。
图6-44出租车自动计费器顶层电路原理图
按已确立的层次化设计思路,在QuartusII图形编缉器中分别
调入前面的层次化设计方案中所设计的低层模块的元件符
号txai.sym、mux8_1.sym、se.sym、di_LED.sym、并加入输
入输出引脚与辅助元件。而3-8译码器模块decode3_8.sym可
利用宏功能向导MegaWizard Plug-In Manager定制(详细步
骤参见第3章3.5节)。正确编译后仿真输出波形和元件符号
如图6-45所示。 在图6-45(a)中,K2=0即全程无停止等待时间
,因此计时显示输出为3F(00),该图中出租车总行驶3F(0)
5B(2)(即2公里),等待累计时间为3F (0)3F (0)(0
分钟),总费用为7F.3F(8.0元),仿真结果正确。
图6-45出租车自动计费器顶层电路
4.硬件测试
为了能对所设计的出租车自动计费器电路进行硬件测试
,应将其输入输出信号锁定在开发系统的目标芯片引脚
上,并重新编译, 然后对目标芯片进行编程下载,完成
出租车自动计费器电路的最终开发,其硬件测试示意图
如图6-46。不失一般性,本设计选用的DE2-70开发平台
,选择目标器件为EP2C70F896C7芯片。图6-46中,clk
是基准时钟,锁定引脚时将clk接至clk_28(接受28MHz
的时钟频率);计价使能信号K1(1:开始计价、0停止计
价)SW0相连;停车等待信号K2(1: 停车等待、0:正常
行驶)SW1;公里脉冲信号clk_R(每按一次就输出一个
脉冲)接key3;输出显示分别接到DE2-70数码管
HEX7~HEX0
图6-46出租车自动计费器硬件测试示意图
6.5.5数字密码锁EDA设计
数字密码锁亦称电子密码锁,其锁内有若干位密码,所
用密码可由用户自己选定。数字锁有两类:一类并行接
受数据,称为并行锁;另一类串行接受数据,称为串行
锁,本设计为串行锁。如果输入代码与锁内密码一致时,
锁被打开;否则,应封闭开锁电路,并发出告警信号。
随着数字技术的飞速发展,具有防盗报警功能的数字密
码锁代替安全性差的机械锁已成为必然的趋势。数字密
码锁不但可以用来保管物品,还可以防止越权操作,例
如银行自动柜员机、自动售货机、门卡系统等。
本节将设计一种数字密码锁,密码由3位十进制数字组
成,初始设定为“000”。可由用户任意设置密码,密码输
入正确时开锁,密码连续输入错误3次报警。其原理框
图如图6-47所示。
控制器是整个系统的功能核心,接收按键和其它模块传
来的信号,再根据系统功能产生相应的控制信号送到相
关的模块,并控制钥匙信号(开锁/安锁)和报警信号。
图6-47数字密码锁原理框图
编码器接受键盘的数字输入信号(用0~9号开关代替),
并编码后输出给比较器和寄存器,并提供密码脉冲信号
给控制器;比较器用来比较编码器输出和寄存器输出数
据是否相等,结果送给控制器;计数器I用来给寄
存器提供地址信号并记录密码输入位数用于比较;计数
器II记录错误次数,达到规定次数输出报警信号;寄存
器在密码校验是,输出密码以供比较,在修改密码时,
保存新密码。钥匙信号控制打开/关闭,报警信号可以接
LED或其它安防设备。
按“安锁”键,将锁闭合;开锁时,先按“输入密码”键,
输入密码,再按“确认”键;若输入密码内容或者长度有
误,则计数器II累计一次,达到3次时报警;只有在开锁
状态下才可以设置新密码,先按“修改密码”键,输入新
密码,再按“确认”键。
1.数字密码锁层次化设计方案
系统由6个模块组成:控制模块、计数器I模块、计数器
II模块、寄存器模块、比较器模块以及编码器模块。
(1) 控制模块VHDL设计
控制模块采用有限状态机设计,将系统分为7个状态,即开
密码状态(PS_INPUT)密
码初验正确状态(PS_RIGHT)
密码初验错误状态
(PS_WRONG)报警状态
(ALARM)及修改密码状态
(PS_CHANGE),状态转移
如图6-48所示。
系统上电时,处于开锁状
态(OUTLOCK)、当输入
ps_ch信号时,系统进入修改
密码状态(PS_CHANGE);
若输入lock信号,进入安锁
状态(INLOCK),锁闭合;
图6-48控制模块状态转移如图
在安锁状态,输入start信号,进入密码输入状态
(PS_INPUT);在输入密码状态,由ps_i密码脉冲作为计
数时钟,计数值输出作为寄存器地址,当计数器计到3
时,返回计数满信号cin,如果密码内容和长度均正确
,进入密码初验正确状态(PS_RIGHT),如果密码错误
,进入密码初验错误状态(PS_WRONG);在密码初验错
误状态,输入确认信号enter时,进入开锁状态;在密码
初验错误状态,输入确认信号enter时,如果错误次数没
有达到3次,则进入安锁状态并输出错误信号(wro_count
加1),如果错误次数达到3次,进入报警状态;在报警
状态, warn信号等于‘1’,如果输入清除警报信号off_al
,进入安锁状态。
(2)计数器I模块VHDL结构体dl_counter
(3)计数器II模块VHDL结构体dl_counter2
(4)寄存器模块VHDL结构体
(5)比较器模块VHDL结构体dl_cmp
(6)编码器模块VHDL结构体dl_coder
2.数字密码锁顶层设计方案
按已确立的层次化设计思路,根据图6-49数字密码锁
顶层设计图,可构建顶层VHDL代码如下。
图6-49数字密码锁顶层设计
6.6实验
6.6.1 实验6-1多功能算术逻辑运算单元的设计
1.实验目的
利用74181设计一个带
进位控制的8位算术逻
辑运算单元ALU_8该
算术逻辑运算单元具
有16个数据通路,实
现表6-11所示基本算
术运算功能和逻辑运
算功能。
表6-11 ALU_8的运算功能表
2 实验原理描述
计算机的一个最主要功能就是处理各种算术和逻辑运算
,该功能要由CPU中的运算器来完成。运算器也称算术
逻辑运算单元(ALU)。其主要功能包括:
①执行数值数据的算术加减乘除等运算,执行逻辑数据
的与或非等逻辑运算,
②暂时存放参加运算的数据和中间结果,由多个通用寄
存器来承担。
③运算器通常也是数据传输的通路 。
根据设计要求,可得带进位控制的8位算术逻辑运算单元
的结构框图和数据通路如图6-81所示。其中8位ALU运
算器模块,是利用2片4位ALU芯片74181级联构成的8位
字长ALU。为进行双操作数运算,运算器模块的两个8
位数据由数据输入(总线)分别通过两个电平锁存器74373
锁入。16路通道计数将根据计数脉冲选择表6-12所示的
16种运算模式。在8位ALU运算器模块设置两个控制输入
信号,一个为进位控制信号,一个为算术运算和逻辑运算
的功能选择信号。
为实现进位控制,可将运算器74181的进位位cout送入D锁
存器,由进位脉冲T4和使能信号CN控制其写入,这时,
CN的功能是电平控制信号(高电平时,CN有效),控制是否
允许将进位信号coout加入下一运算周期的最低进位位,从
而可实现带进位控制运算。通过进位控制可实现多个8位数
据的算术运算。
图6-50 8位算术逻辑运算单元的结构框图
3.实验内容
(1) ALU运算器模块ALU_8的设计
该模块是多功能算术逻辑运算单元的主体模块,原理
图如图6-51,其中进位控制信号CP和输出CO信号的逻辑
表达式为:
CP=NOT(CN)•T4,CO=NCN•QD (6-8)
图6-51 运算器模块ALU_8原理图
(2) 16路通道计数模块CNT_16的设计
CNT_16实际上为一模16的二进制计数器, 可利用
QuartusII的兆功能设计向导 MegaWizard Plug-In
Manager定制模16的二进制计数器,其定制的界面如图
6-52所示,clock为计数输入脉冲,q[3..0]为计数的二进
制数输出,供ALU_8选择不同的运算模式。
图6-52定制模16的二进制计数器CNT_16
(3)数据寄存器模块REG_A_B
数据寄存器模块REG_A_B的原理图如图6-53所示。
为进行双操作数运算,运算器模块的两个8位数据由数
据输入总线分别通过数据寄存器模块REG_A_B两个电
平锁存器74373锁入。该模块的输入全部连在数据总线
Data_bus[7..0]中,通过数据选择开关A0_B0,依次选
择输出数据A[7..0]、B[7..0]给运算器模块ALU_8。
图6-53数据寄存器模块REG_A_B原理图
(4) 完成多功能算术逻辑运算单元的顶层设计和仿真
多功能算术逻辑运算单元顶层电路的原理图如图6-54所示
。请根据图6-54完成多功能算术逻辑运算单元顶层电路的原
理图输入,编译和仿真。
图6-54多功能算术逻辑运算单元顶层电路原理图
(5) 硬件测试
为了能对所设计的多功
能算术逻辑运算单元进行硬
件测试,应将其输入输出信
号锁定在开发系统的目标芯
片引脚上,并重新编译,然
后对目标芯片进行编程下载
,完成的多功能算术逻辑运
算单元最终开发。其硬件测
试示意图如图6-55。
图6-55多功能算术逻辑运算单元
硬件测试示意图
6.6.2实验6-2电梯控制器VHDL设计
1.设计要求
设计一个4层楼的电梯控制器,该控制器满足以下要求
:
①每层电梯入口设有上下请求开关,电梯内设有乘客到达
层次的停站请求开关;
②设有电梯所处位置指示装置及电梯运行模式(上升或下
降)指示装置;
③电梯每秒升(降)一层楼;
④电梯到达有停站请求的楼层后,经过1秒钟电梯门打开
,开门指示灯亮,开门4s后,电梯门关闭(开门指示灯灭
),电梯继续运行,直至执行完最后一个请求信号后停在
当前层;
⑤能记忆电梯内外的所有请求信号,并按照电梯运行规则
⑥电梯运行规则:当电梯处于上升模式时,只响应比电梯
所在位置高的上楼请求信号,由下而上逐个执行,直到
最后一个上楼请求执行完毕,如更高层有下楼请求,则
直接升到有下楼请求的最高楼层接客,然后便进入下降
模式。当电梯处于下降模式时则与上升模式相反;
⑦电梯初始状态为一层开门,到达各层时有音乐提示,有
故障报警。
2.功能说明
根据设计要求可得电梯控制器系统组成框图如图6-56所
示:
该控制器可控制电
梯完成4层楼的载客服
务而且遵循方向优先
原则,并能响应提前
关门延时关门,并具
有超载报警和故障报
警;同时指示电梯运
行情况和电梯内外请
求信息。
图6-57电梯控制器系统组成框图
方向优先控制是指电梯运行到某一楼层时先考虑这一
楼层是否有请求:有,则停止; 无,则继续前进。停下
后再启动时的控制流程为:
①考虑前方(上方或下方)是否有请求;有,则继续前进;
无,则停止;
②检测后方是否有请求, 有请求则转向运行, 无请求则维
持停止状态。这种运作方式下,电梯对用户的请求响应率
为100%,且响应的时间较短。
本系统的输出信号有两种: 一种是电机的升降控制信号(
两位)和开门/关门控制信号;另一种是面向用户的提示信
号(含楼层显示、方向显示、已接受请求显示等)。
电机的控制信号一般需要两位,本系统中电机有3种工作
状态: 正转、反转和停转状态。 两位控制信号作为一个
三路开关的选通信号。系统的显示输出包括数码管楼层显
示、数码管请求信号显示和表征运动方向的箭头形指示灯
的开关信号。
3.设计指导
控制器采用FPGA作为系统控制的核心,系统时钟频率
是20MHz,完全可以满足实时采集数据的要求。由于电
路中毛刺现象的存在,信号的纯净度降低,单个的毛刺
往往被误作为系统状态转换的触发信号,严重影响电梯
的正常工作。可以采用多次检测的方法解决这个问题,
对一个信号进行多次采样以保证信号的可信度。外部请
求信号的输入形式为按键输入,到达楼层信号来自光敏
传感器,关门中断信号及超载信号则产生于压力传感器
。
电梯控制器的请求输入信号有12个(电梯外有4个上升请
求和4个下降请求的用户输入断口,电梯内有4个请求用
户输入断口),由于系统对内、外请求没有设置优先级,
各楼层的内、外请求信号被采集后可先进行运算,再存
到存储器内。
电梯运行过程中,由于用户的请求信号的输入是离散的
,且系统对请求的响应也是离散的,因此请求信号的存
储要求新的请求信号不能覆盖原来的请求信号,只有响
电梯工作过程中共有9种状态:等待、上升、下降、开
门、关门、停止、休眠、超载报警以及故障报警状态。
一般情况下,电梯工作起始点是第一层,起始状态是等
待状态,启动条件是收到上升请求。
超载状态时电梯关门动作取消,同时发出警报,直到警
报被清除; 故障时电梯不执行关门动作,同时发出警报,
直到警报被清除(看门狗信号有效的条件是一层楼连续发
生关门中断情况超过3次)。本系统由请求信号启动,运
行中每检测到一个到达楼层信号,就将信号存储器的请
求信号和楼层状态信号进行比较,再参考原方向信号来
决定是否停止,转向等动作。其VHDL参考源程序如下。
6.6.3实验6-3自动售饮料控制器VHDL设计
1.设计要求
采用EDA层次化设计方法,基于VHDL设计一个自动售
饮料控制器系统。具体要求为:
①该系统能完成货物信息存储,进程控制,硬币处理,余
额计算,显示等功能。
②该系统可以销售四种货物,每种的数量和单价在初始化
时输入,在存储器中存储。用户可以用硬币进行购物,
按键进行选择。
③系统根据用户输入的货币,判断钱币是否够,钱币足够
则根据顾客的要求自动售货,钱币不够则给出提示并退
出。
④系统自动的计算出应找钱币余额、库存数量并显示
2.功能描述
①该饮料机销售三种罐装饮料:纯净水、可乐和红牛(以
00,01,10表示),售价分别为2元、3元、6元,数量无
限。购买时通过三个按键select_0 、select_1、select_2来
选择。
②该饮料机设有两个投币孔,分别接受伍角和一元两种币
值。顾客可分别投入一种或多种面额的值,但投入的总
币值不可超过9元。
③该饮料机设有一个输出口,每次只能出一罐饮料;设有
提示灯,当出货时对应提示灯会以2Hz的频率闪烁。
④为明确具体的投币或退币金额,本机采用1个七段显示
数码管来显示已投入的金额或退还的金额,并有三个指
示灯led_total、led_rest、led_change显示当前数码管的显
示状态。1ed_total亮表示当前显示已投入的总金额,
led_rest亮表示当前显示选择饮料之后的剩余金额,
led_change亮表示当前显示找零或退币过程,三个指示
灯中有且只有一灯亮。
⑤本机设有set键和sel键, 首先由售货员把自动售货机里的
每种商品的数量和单价通过set键和sel键置入到RAM里
。然后顾客通过sel键对所需要购买的商品进行选择,选
定以后通过get键进行购买,再按finish键取回找币,同
时结束此次交易。
⑥本机以1024Hz的时钟信号(clk)控制,时钟的输入端由外
加的时钟发生器提供,上升沿有效.按get键时,如果投
的钱数等于或则大于所购买的商品单价,则自动售货机
会给出所购买的商品;如果投的钱数不够,自动售货机
不做响应,继续等待顾客的下次操作。顾客的下次操作
可以继续投币,直到钱数到达所要的商品单价进行购买
;也可以直接按finish键退币。
⑦本机设有复位信号(reset),高电平有效。
3.设计指导
系统按功能分为:分频模块、控制模块、译码模块
、译码显示模块。系统组成框图如图6-58。在QuartusII
软件下设计,将整个电路划分成若干子模块分别描述并
设计成若干个相对独立的程序,分别编译仿真。
图6-58自动售饮料控制器系统组成框图
6.6.4实验6-4乐曲硬件演奏电路EDA设计
1.设计要求
了解电子音乐电路的实现原理;掌握数控分频器VHDL
设计。利用可编程逻辑器件FPGA,设计一个乐曲硬件演
奏电路。由键盘输入控制音响,同时可自动演奏乐曲。演
奏时可选择键盘输入乐曲或者已存入的乐曲,并配以一个
小扬声器。
2.实验原理
产生音乐的两个因素是音乐频率和音乐的持续时间,以
纯硬件完成演奏电路比利用微处理器(CPU)来实现乐曲演
奏要复杂的多,如果不借助于功能强大的EDA工具和硬件
描述语言,凭借传统的数字逻辑技术,即使最简单的演奏
电路也难以实现。根据6.4.1的设计要求,乐曲硬件演奏电
路系统主要由数控分频器和乐曲存储模块组成。数控分频
器对FPGA的基准频率进行分频,得到与各个音阶对应
的频率输出。乐曲存储模块产生节拍控制和音阶选择信
号,即在此模块中可存放一个乐曲曲谱真值表,由一个计
数器来控制此真值表的输出,而由计数器的计数时钟信号
作为乐曲节拍控制信号。
(1)音名与频率的关系
音乐的十二平均率规定:每两个八度音(如简谱中的中音
1与高音1)之间的频率相差一倍。在两个八度音之间,又
可分为十二个半音,每两个半音的频率比为4。另外,音名
A(简谱中的低音6)的频率为440Hz,音名B到C之间,E到
F之间为半音,其余为全音,由此可以计算出简谱中从低
音1到高音1之间每个音名的频率如表6-12所示.
由于音阶频率多为非整数,而分频系数又不能为小
数,故必须将得到的分频数四舍五入取整。若基准频率
过低,则由于分频系数过小,四舍五入取整后的误差较
大,若基准频率过高,虽然误码差变小,但分频结构将
变大。实际的设计应综合考虑两方面的因素,在尽量减小
频率误差的前提下取舍合适的基准频率。
表6-12 简谱中的音名与频率的关系
本例中选取4MHz的基准频率,若无4MHz的时钟频
率,实际上,只要各个音名间的相对品频率关系不变,C作1
与D作1演奏出的音乐听起来都不会“走调”。
各音阶频率及相应的分频系数如表6-13所示。为了减
少输出的偶次谐波分量,最后输出到扬声器的波形应为对
称方波,因此在到达扬声器之前,有一个二分频的分频器
。
表6-13中的分频系数就是从4MHZ频率二分频得到的2MHZ
频率基础上计算得出的。
表6-13 各音阶频率对应的分频值
由于最大的分频系数为7644,故采用13位二进制计数器
已能满足分频要求。在表6-12,除给出了分频比以外,给出
了对应于各个音阶频率时计数器不同的初始值,对于乐曲
中的休止符,要将分频系数设为0,即初始值为8191即可,
此时扬声器将不会发声。对于不同的分频系数,加载不同
的初始值即可。用加载初始值而不是将分频输出译码反
馈,可以有效地减少本设计占用可编程逻辑器件的资源,
也是同步计数器的一个常用设计技巧。
表6-13 各音阶频率对应的分频值
(2)控制音长的节拍发生器
该电路演奏的乐曲是“梁祝”片段,其最小的节拍为1拍。
将1拍的时长定为0.25秒,则只需要再提供一个4Hz的时钟
频率即可产生1拍的时长,演奏的时间控制通过ROM查表
的方式来完成。对于占用时间较长的节拍(一定是拍的整数
倍),如全音符为4拍(重复4),2/4音符为2拍(重复2),1/4音
符为1拍(重复1)。
要求演奏时能循环进行,因此需另外设置一个时长计数
器,当乐曲演奏完成时,保证能自动从头开始演奏。该计
数器控制真值表按顺序输出简谱。
3.实验指导
根据设计要求可得乐曲演奏电路的结构方框图如图6-59
图6-59 乐曲演奏电路结构方框图
根据层次化的设计思路,可把乐曲硬件演奏电路分为三个
模块,音乐节拍发生器NoteTabs模块,音符译码电路
Tonetaba模块,数控分频模块(speaker)。下面给出其
EDA设计过程:
(1)音乐节拍发生器NoteTabs
该模块将利用FPGA的片内ROM存放乐曲简谱真值表,
由一个二进制计数器为乐曲数据存储器ROM的地址发生
器。该计数器的计数频率为4Hz,即每一计数值的停留时
间为0.25秒,随着NoteTab中计数器按4Hz的时钟频率作
加法计数时,即随地址值递增时,乐曲数据ROM中的音
符数据,将从ROM中的输出口输向音符译码电路
Tonetaba,所存储乐曲就开始连续自然地演奏起来。二
进制计数器的位数将根据所存放乐曲简谱基本节拍数来
决定,对于乐曲“梁祝”片段其最小节拍数为138,即选择
计数器的位数为8即可,另外在此模块上增加一手动/自
动选择按扭auto,auto=1时为自动演奏,auto=0时为手动
输入。其设计流程如下:
①利用MegaWizard Plug-In Manager定制音符数据存储
器musica1在定制中选择ROM的数据位宽为8,地址位宽
为8(共计256个字),ROM的类型选择为Auto,并指定其
初始化数据文件名为data1.mif,ROM模块的初始化数据
文件data1.mif如图6-60所示。
图6-60数据存储器musica1的初始
化数据文件内容
③音乐节拍发生器NoteTabs的VHDL设计
在源程序中Tone是音乐节拍发生器输出的音符数据
; clk4hz是计数时钟输入端,该信号作为输出音符的快
慢信号, 此处选择4Hz频率,即每一计数值的停留时间
为0.25秒计1拍,四四拍的四分音符的持续时间为1
秒,频率越高,时钟的输出节拍速度就快,演奏的速度
就越快,反之演奏的速度就变慢;index2为手控输入的
音符数据;auto为手动/自动选择按扭,auto=1时为自动
演奏,auto=0时为手动输入。
(2)音符译码电路Tonetaba模块
音符译码电路即音调发生器实际上是一个查表电路,放
置21个音乐简谱对应的频率表,根据该表为数控分频模块
(speaker)提供所发音符频率的初始值(该初始值可参照表
6-12),而此数在数控分频模块入口的停留时间即为此音
符的节拍数,不失一般性,以下VDHL程序中仅设置了“梁
祝”乐曲全部音符所对应的音符频率的初始值,共16个,每
个音符停留时间由音乐节拍发生器的时钟频率决定,在此
输入值Index[3..0]确定,该值中音。符的停留时间由音乐
节拍发生器中的音符数据决定,该数据重复的次数为该
音符的节拍数,如为2则为四二拍,如为4则为四四拍即
全音符。其VHDL源程序如下
音符译码电路Tonetaba模块中,Index[3..0]是音乐节拍
发生器输出的音符数据; TONE[12..0]是为数控分频模块
提供的音符频率初始值,为方便测试,特设置一个音名代
码显示输出CODE[3..0]和音高指示信号HIGH,可以通过
一个数码管或LED来显示乐曲演奏时对应的音符和高音名
。例如当输入Index=8,产生的分频系数便是6280,CODE
输出对应该音阶简谱的显示数码1,high输出为高电平,
指示音阶为高音,high输出为低电平时则指示音阶为中音。
3)数控分频模块(speaker)设计
数控分频器对FPGA的基准频率进行分频,得到与各个
音阶对应的频率输出。数控分频模块是由一个初值可变的
13位加法计数器构成。该计数器的模为8192,当计数器计
满时,产生一个进位信号FullSpkS,该信号就是用作发音
的频率信号(其频率值参见表6-12)。在计数器的预置端
给定不同的初值,其输出将产生不同的频率信号,频率信
号初值Tone就是前级音符译码电路Tonetaba的输出,它计
满所需要的分频比可由下式决定:
Tone[12..0]+ 分频比=8192+进位信号FullSpkS(6-7)
结合表6-12,分析式(6-7)可知,低音时,Tone值
小,分频比大,进位信号SpkS的周期长,扬声器发出的声
音低,Tone随音乐的乐谱而变化,自动控制分频比,从
而实现数控分频,发生信号的频率与Tone成正比,这就
是利用数控分频器自动演奏音乐的原理。数控分频器的输
入时钟频率为4MHz,通过分频后其进位信号FullSpkS是一
周期脉冲信号,为有利于驱动扬声器,在音调输出时再进
行二分频,将脉冲展宽,使之占空比为50%,扬声器这样
就有足够的发声功率。其VHDL源程序如下:
(4)乐曲硬件演奏电路顶层电路的设计
乐曲硬件演奏电路顶层电路如图6-61所示。图6-61中
,CLK为音调频率信号为4MHz,CLK8HZ是乐曲硬件演
奏电路节拍频率信号为8Hz;index为手控输入的音符数据
;auto为手动/自动选择按扭,auto=1时为自动演奏,
auto=0时为手动输入。CODE简谱码输出显示,HIGH为
高8度指示,Sp为声音频率输出。
(5)硬件测试
为了能对所设计
的乐曲硬件演奏电路
进行硬件测试,应将
其输入输出信号锁定
在开发系统的目标芯
片引脚上(请参考附录
A),并重新编译,然
后对目标芯片进行编
程下载,完成乐曲硬
件演奏电路的最终开
发,其硬件测试示意
图如图6-62。
图6-61乐曲硬件演奏电路顶层原理图
图6-62乐曲演奏电路硬件测试示意图
6.6.5简易微处理器的EDA设计
1.设计要求
设计一个能执行8条指令的简单CPU,该微处理器
由算术逻辑单元、寄存器阵列、控制单元、总线和总线
缓冲器4个部分组成, 参考MIPS指令格式,采用VHDL语
言,搭建一个单周期“玩具CPU”,使其支持加、减、移
位等,将该CPU下载到实验箱中验证运行结果。
2.原理说明
(一) 微处理器结构
(1)算术逻辑单元(ALU)
在CPU中,算术逻辑单元是对二进制进行算术运算
和逻辑运算的部件。在算术运算中,由于带符号数采用
补码表示,减法可转化为加法,乘除法可以通过多次重
复的加减和移位来实现,而只要具备“或”、“非”、“与”
、“异或”等功能的部件就能实现各种复杂的逻辑运算,
因而从原理上讲,在不涉及数据信息如何表示的情况下
计算机只要具备加法、“与”、“非”、“或”等运算功能,
再加上“移位”操作功能,就能实现各种算术运算和逻辑
运算。
(2)控制器
控制器是发布操作命令的机构,是微机的指挥中心
。计算机程序和原始数据的输入、CPU内部的信息处理
、处理结果的输出、外设与主机之间的信息交换等,都
是在控制器的控制下实现的。而计算机是按照存储程序
和程序控制的原理工作的,程序本身由一系列指令所组
成,每条指令又由操作码和地址码(或操作数)所组成
。当计算机执行指令时,控制器的任务就是逐条地取指
令、分析指令、执行指令。为了完成上述功能,控制器
至少必须具有指令部件、时序部件和微操作控制部件。
①指令部件
指令部件一般包括程序计数器、指令寄存器和指令译器。
程序计数器(PC:Program Counter)是指令的有序集合。计算
机运行时,通常按照顺序执行放在存储器中的程序。先由
PC指出要执行指令的首地址,每当指令取出后,PC的内容
就自动增加,指向按顺序排列的下一条指令的首地址。在
正常情况下,CPU总是按顺序逐条执行指令的。指令寄存器
(IR: Instruction Register),用来存放当前要执行的指令的内
容,它包括操作码和地址码两部分。操作码将指令送往指
令译码器;地址码送至操作数地址电路。指令译码器(ID:
Instruction Decoder),是分析指令的部件。操作码经译码后
产生相应操作的控制电位。
②时序部件
计算机的工作是周期性的,需经过取指令、分析指令、
执行指令、再取指令等操作。这一系列操作的顺序都需要
精确的定时。时序部件就是用来产生计算机各部件所需要
的定时信号的部件。它由时钟系统、时钟脉冲分配器等部
件所组成。
③微操作控制部件
微操作控制部件的主要功能是:根据指令产生计算机各
部件所需要的控制信号。这些控制信号是由指令译码器的
输出电位、节拍发生器产生的节拍电位、节拍脉冲以及位
部的状态信号等进行组合产生的。它按一定的时间顺序,
发出一系列微操作控制信号,来完成指令所规定的全部操
作。
(3)总线
所谓总线是指计算机传送信息的一组通信导线,它将各
个部件连接成一个整体。在微处理器内部各个单元之间传
送信息的总线称为片内总线;在微处理器与各个外部部件
之间传送信息的总线称为片外总线。
片内总线分为单总线、双总线和多总线结构。在微处理
器内部究竟采取哪一种总线结构,主要从集成电路的制造
工艺和器件的工作速度来考虑。低档的微处理器大多采用
单总线结构,微处理器内部各部件如累加器、算术逻辑单
元、各寄存器与标志寄存器都挂在内部总线上。寄存器将
数据加到ALU的输入端或ALU将运算结果送回到寄存器都
是通过这一总线进行。
由于在同一时刻单一数据总线上只能传送一个操作
数,所以当利用ALU作加法运算时,输入到ALU的两个操
作数和ALU的运算结果不能同时出现在数据总线上,而必
须按一定顺序分时进行处理,这样就降低了操作速度。单
总线结构工作速度较慢,但它节省了芯片面积且价格低廉
。
为了提高器件的工作速度,可采用双总线或多总线结构。
双总线结构把内部总线分为输入总线与输出总线,通过内
部输入总线将数据从各个寄存器送到ALU,而ALU的输出
则通过内部输出总线送至各寄存器的输入端。这样可以提
高CPU的工作速度,但占用的芯片面积较多。
片外总线又称为系统总线。这种总线用来连接CPU与
内存储器或I/O接口电路等部件。通常系统总线分为地址总
采用总线结构可以减少信息传输线的数目,提高系统的
可靠性,增加系统的灵活性,便于实现系统标准化。
(4)寄存器阵列
在微处理器内部,有一个临时存放数据和地址的寄存器
阵列,这个寄存器阵列随CPU的不同而不同,有的CPU内部
寄存器多一些,有的少一些,不管是多是少,其功能相
似。
CPU内部的各寄存器一般分为4类:存放待处理数据的寄
存器、存放地址码的寄存器、存放控制信息的寄存器和在数
据传送过程中起缓冲作用的寄存器。
① 存放待处理数据的寄存器:这类寄存器主要包括累加器和通
用寄存器组。
累加器:一个CPU中至少要有一个累加器,数据运算加工
处理大部分要使用累加器。
通用寄存器组:是在数据处理过程中可以被指定为各种不
同用途的一组寄存器。为了快速处理数据,在CPU内通常设
置通用寄存器组,用来临时存放数据和地址。
② 存放地址码的寄存器:主要有程序计数器和堆栈指针
程序计数器(PC:Program Counter):每当取出行指令
后,PC就自动加1(除转移指令外),以指向下一个指令地
址。如果指令是多字节的,则每取一个字节,PC就增1,取
出一指令所有字节之后,PC便指向下一条指令地址。一般指
令是按顺序执行的,故PC可用来控制程序执行的顺序。
堆栈指针(SP: Stack Pointer):是一个专用寄存器,用来
指示内存中堆栈栈顶的地址,每次压入或弹出一个数据时,
它能自动修改SP的值,以便保证SP始终指向栈顶。
③存放控制信息的寄存器:主要包括指令寄存器和标志寄存
器。
指令寄存器(IR: Instruction Register):在CPU中,指
令寄存器专用于存放指令的代码,一直保存到指令译码器
译码完成为止。
标志寄存器(FR: Flag Register):用来保存ALU操作结
果的条件标志,它可以用专门的指令来测试,判断程序是
否转移。
④起数据缓冲作用的寄存器:主要指数据总线缓冲器和地址
总线缓冲器
数据总线缓冲器(DBUF: Data Bus Buffer):是在CPU
内部数据总线和外部数据总线之间起缓冲作用的三态双
向缓冲器。CPU送出的数据,先保存在DBUF中,待外部
数据总线允许传送时,再把数据送至外部数据数据总线
上;或者当外部数据总线向CPU送入数据时,先把数据送
入DBUF中,待CPU内部接收该数据的寄存器准备好时,
或内部数据总线允许传送时,再把数据送至相应的寄存器。
地址总线缓冲器(ABUF: Address Bus Buffer):是具有
三态控制的单向缓冲器,用于在CPU内部地址总线与外部
地址总线之间起缓冲作用。
(二) 微处理器指令系统设计
微处理器CPU在工作过程中内部信息有两类:一类是被
处理的信息(数据),一类是控制信息(指令)。各种
CPU都有自己的指令系统,不同类型的CPU其指令系统也是
不同的。
CPU中的控制信息就是使计算机进行某种操作的命令,这些
命令就称为指令。从形式上看,各种指令都是一组二进制
编码。计算机根据二进制代码去完成所需的操作。
按照一条指令中出现的操作数地址个数,可以将指令分
为:单地址指令、双地址指令、三地址指令和多地址指令
。
常用的指令寻址方式有:立即寻址、寄存器寻址、寄
存器间接寻址、直接寻址、变址寻址和基址加变址。此
外,还有隐含寻址、位寻址、相对寻址等等。
本设计中,为简单起见采用“类似直接寻址”的方式。
对于直接寻址,是指操作数的16位偏移量直接包含在指令
中,它与操作码一起存放在代码段区域中。而操作数一般
在数据段区域中,操作数的地址为数据寄存器DS左移4位
加上16位偏移量。由于在这个设计中使用的是16×8的
ROM,不是寻址范围很大的内存,因此采用“类似直接寻
作数就占用一个存储单元,例如:
MOV AX,[1000B](操作数地址就是1000B,操作数占1000B
一个存储单元)
本设计中,假设指令共有8个且分成两种类型,如表6-14、
表6-15所示。
表6-14 零位寻址法
表6-15 类似直接寻址法
(三)微处理器指令周期
在CPU中,指令周期(即一条指令从读取到该指令执
行结束为止的时间)基本上都是6个时钟周期。
每条指令都是经过读取指令和执行指令两个过程,都
要经过6个时钟周期,只是不同种类的指令在6个时钟周期中
的动作稍有不同,假设指令周期用6个状态实现。这6个状态
分别为:S0,S1,S2,S3,S4和S5,分别代表6个时钟周期
。
在前3个时钟周期,即状态S0,S1和S2,为指令读周期,而
后3个时钟周期,即状态S3,S4和S5,为指令执行周期。
1)指令读取周期
①状态S0(寻址状态):在这个状态下,“程序计数器”负责将
所要执行的指令地址传送至MAR存放。
②状态S1(增加状态):在这个状态下,“程序计数器”值加
1,代表计数器将指针指向下一个要执行的指令地址值
。
③状态S2(记忆状态)在这个状态下,将把记录在“MAR”里
哪一种指令,它的状态S0到S2的动作方式都是相同的,不
过状态S3到S5的动作方式就因指令的不同而不同。
2)指令执行周期
(1)LDA指令
为了说明方便,假设状态S2后的“指令寄存器”是存放
着“0000 1001”,即CPU即将执行“LDA 09H”指令。
①状态S3:在这个状态下,上述的09H数据将传入MAR,
以便下个状态能取出该数值代表的地址里的内容值。
②状态S4:这个状态是将存放在“MAR”里的09H数据,通
过程序存储器ROM读出09H地址内的数据,比如数值10H,
再存放10H数据至“累加器”。
③状态S5:这个状态下没有动作。
(2)ADD指令
不失一般性,假设状态S2后的“指令寄存器”里存放着
“0001 1010”,表示CPU即将执行“ADD AH”指令。
①状态S3:在这个状态下,上述的AH数据将传入MAR,
以便下个状态能取出该数值代表的地址里的内容值。
②状态S4:这个状态是将存放在“MAR”里的AH数据,通
过程序存储器ROM读出AH地址内的数据,比如数值15H,再
存放15H数据至“B寄存器”。
③状态S5:这个状态是将存放在“累加器”和“B寄存器”的数
值内容放入“运算器”相加后,再将相加结果放回“累加器”。
(3)SUB指令
不失一般性,假设状态S2后的“指令寄存器”存放着“0010
1011”,表示CPU即将执行“SUB BH”指令。
①状态S3:在这个状态下,上述的BH数据将传入MAR
,
以便下个状态能取出该数值代表的地址里的内容值。
②状态S4:这个状态是将存放在“MAR”里的BH数据,通
过程序存储器ROM读出BH地址内的数据,比如数值17H,
再存放10H数据至“B寄存器”。
③状态S5:这个状态是将存放在“累加器”和“B寄存器”的
数值内容放入“运算器”相减后,再将相减结果放回“累加器”
。
(4)MUL指令
不失一般性,假设状态S2后的“指令寄存器”存放着
“00111011”,即CPU即将执行“MUL BH”指令。
①状态S3:在这个状态下,上述的BH数据将传入MAR
②状态S4:这个状态是将存放在“MAR”里的BH数据,通
过程序存储器ROM读出BH地址内的数据,比如数值17H,
再存放17H数据至“B寄存器”。
③状态S5:这个状态是将存放在“累加器”和“B寄存器”的
数值内容放入“运算器”相乘后,再将结果放回“累加器”。
(5)SHL指令
为了说明方便,假设状态S2后的“指令寄存器”存放着
“0100 1100”,即CPU即将执行“SHL CH”指令。
①状态S3:在这个状态下,上述的CH数据将传入MAR
,
以便下个状态能取出该数值代表的地址里的内容值。
②状态S4:这个状态是将存放在“MAR”里的CH数据,通
过程序存储器ROM读出CH地址内的数据,比如数值02H,
③状态S5:在这个状态下,如果“B寄存器”中的数据不
为0H,那么将“累加器”中的数据左移一位,最右边一位添
0,同时“B寄存器”中的数据减1。也就是说每次指令周
期,只能移位一次,要多次移位,那就需要多个指令周期。
(6)SHR指令
假设状态S2后的“指令寄存器”存放着“0101 1100”,即
CPU执行“SHL CH”指令。
①状态S3:在这个状态下,上述的CH数据将传入MAR,
以便下个状态能取出该数值代表的地址里的内容值。
②状态S4:这个状态是将存放在“MAR”里的CH数据,通
过程序存储器ROM读出CH地址内的数据,比如数值02H,
再存放02H数据至“B寄存器”。
③状态S5:在这个状态下,如果“B寄存器”中的数据不
为0H,那么将“累加器”中的数据右移一位,最左边一位添
0,同时“B寄存器”中的数据减1。也就是说,每次指令周
期,只能移位一次,要多次移位,那就需要多个指令周期。
(7)OUT指令
在状态S2后的“指令寄存器”存放着“1110 0000”,即CPU
即将执行“OUT”指令。
①状态S3:这个状态下,“累加器”的内容将传送至“输出
寄存器”,然后显示在二进制显示装置中。
②状态S4:这个状态下OUT指令没有动作。
③状态S5:这个状态下OUT指令没有动作。
(8)HLT指令
在状态S2后的“指令寄存器”存放着“1111 0000”,即CPU
即将执行“HLT”指令。
①状态S3:这个状态下,“控制器/序列发生器”将停止送
出脉冲信号CLK,这时CPU停止工作。
②状态S4:这个状态下HLT指令没有动作。
③状态S5:这个状态下HLT指令没有动作。
(四) 微处理器程序存储器的设计
本设计中,采用的是ROM,即只读存储器,将程序和
数据事先写入,以完成所要完成的功能。不失一般性,假
设所设计的CPU完成如下的运算(十六进制):
10+15+17-20=1C
首先应将所要求的运算写成汇编语言,然后翻译成机
械码,再写入程序存储器ROM里。 程序存储器地址线位
宽为4位,数据位宽为8位,汇编程序和指令码的对照如表
6-16所示。
表6-16 10+15+17-20汇编程序和机械码对照
3.设计指导
全部设计只包含一个程序存储器ROM16_8(参见6.4.1)和
主程序mycpu, mycpu设计源程序如下。