第八讲状态机的VHDL设计教学课时:3学时教学内容:1、状态机概述2、状态机的结构(1学时)3、状态机的VHDL设计方法举例(1学时)4、课堂练习:编写“1010”序列检测器的程序(1学时)1、状态机概述数字系统一般可分为控制单元和数据通道,数据通道通常由组合逻辑电路构成,而控制单元通常由时序逻辑电路构成.数字电路按逻辑功能的不同,可分成组合逻辑电路和时序逻辑电路两大类。组合电路是指现时刻输出只和现时刻输入有关的电路,也即它是无记忆功能的电路。时序电路的特点:任一时刻,输出不仅取决于该时刻的输入,而且还与电路原来的状态有关。因此,时序电路中必须包含具有记忆功能的存储电路。有限状态机可以描述和实现大部分的时序电路。这里所谓的有限状态机实际上就是一种算法思想,它能够根据控制信号按照有序方式遍历预先定义的状态序列,它由一组状态、一个初始状态、输入和根据输入及现有状态转换为下一个状态的转换函数组成。有限状态机根据输出信号与当前状态以及输入信号的关系来分,可以分为Moore型和Mealy型两种。输出信号只和当前状态有关的状态机称为Moore型状态机;输出信号不仅与当前与状态有关,而且也和输入信号有关的状态机称为Mealy型状态机。从结构上,有限状态机可分为:单进程状态机和多进程状态机。从编码方式上,有限状态机可分为:顺序编码状态机、one-hot编码状态机和其他编码方式状态机。无论是何种类型的状态机,一般都是由组合逻辑进程和时序逻辑进程两部分构成。其结构如图所示。2、一般状态机的结构组合逻辑进程时序逻辑进程inputoutputcurrent_stateclockresetnext_state其中,组合逻辑进程用于实现状态机的状态选择和信号输出。该进程根据当前状态信号current_state的值确定输出信号,同时确定下一个状态,即next_state的取值。组合逻辑进程的VHDL代码process(input,current_state)begincasecurrent_stateiswhenstate0=if(input=...)thenoutput=value;next_state=state1;else...endif;whenstate1=if(input=...)thenoutput=value;next_state=state2;else...endif;...endcase;endprocess;这段代码的目的:(1)对输出赋值(2)确定状态机的下一个状态在整个代码中,没有任何信号的赋值是通过其它某个信号的跳变来触发的。时序逻辑进程的VHDL代码process(reset,clock)beginifreset=‘1’thencurrent_state=state0;--state0是系统的初始状态elsif(clock’eventandclock=‘1’)thencurrent_state=next_state;endif;endprocess;时序逻辑进程用于实现状态机的状态转化。状态机是随外部时钟信号clock,以同步时序方式工作的。该进程保证状态的跳变与时钟信号同步,在时钟发生跳变时,状态机的状态才发生变化。当复位信号有效时,时序逻辑对状态机进行复位;当时钟的上升沿到来时,时序进程将next_state的值赋给current_state.状态机的VHDL代码process(input,current_state)begincasecurrent_stateiswhenstate0=if(input=...)thenoutput=value;next_state=state1;else...endif;whenstate1=if(input=...)thenoutput=value;next_state=state2;else...endif;...endcase;endprocess;process(reset,clock)beginifreset=‘1’thencurrent_state=state0;--state0是系统的初始状态elsif(clock’eventandclock=‘1’)thencurrent_state=next_state;endif;endprocess;--转右边libraryieee;useieee.std_logic_1164.all;entityentity_nameisport(input:indata_type;reset,clock:instd_logic;output:outdata_type);endentity_name;architecture结构名of实体名istypestateis(state0,state1,state2,...);signalcurrent_state,next_state:state;end结构名;如何定义状态机的状态方法1:在结构体的architecture和begin之间,定义一个新的数据类型,如下例:typestateis(s0,s1,s2,s3,s4);signalcurrent_state,next_state:state;(P239)这是用户自定义的枚举类型,用文字符号s0~s4表示5个状态,这些状态可由3位二进制数进行编码。在VHDL综合过程中,将第1个元素编码为0,后面元素的编码依次加1。如何定义状态机的状态方法2:在结构体的architecture和begin之间,用关键词constant逐一列出指定状态的二进制编码,如下例:(a)用顺序编码进行定义siganecurrent_stae,next_state:std_logic_vector(1downto0);constantstate0:std_logic_vector(1downto0):=“00”;constantstate1:std_logic_vector(1downto0):=“01”;constantstate2:std_logic_vector(1downto0):=“10”;constantstate3:std_logic_vector(1downto0):=“11”;若有n个触发器,就可以对2n个状态进行编码。编码方式简单,但从一个状态向另一个状态转化的译码电路复杂。(b)用one-hot(一位热码)编码进行定义signalcurrent_stae,next_state:std_logic_vector(3downto0);constantstate0:std_logic_vector(3downto0):=“0000”;constantstate1:std_logic_vector(3downto0):=“0010”;constantstate2:std_logic_vector(3downto0):=“0100”;constantstate3:std_logic_vector(3downto0):=“1000”;对n个状态进行编码需要n个触发器。编码方式简单,且从一个状态向另一个状态转化的译码电路简单,状态的转换速度快。许多面向CPLD/FPGA的VHDL综合器将符号化的状态机自动优化设置为一位热码编码。3、状态机的VHDL设计方法举例例1:用状态机的方法设计格雷码计数器。格雷码计数器计数时,相邻的数之间只有一个bit发生了变化。例如,数位0-9的格雷码:0000-0001-0011-0010-0110-0111-0101-0100-1100-1101。编码规律:原码p(n-1downto0),格雷码c(n-1downto0),则c(n-1)=‘0’xorp(n-1);c(n-2)=p(n-1)xorp(n-2);c(n-3)=p(n-2)xorp(n-3);...c(0)=p(1)xorp(0);采用常用方法设计格雷码计数器的VHDL源代码如下:architectureoneofgray_cnt1issignalq:std_logic_vector(3downto0);beginprocess(clk,clr)beginifclr='1'thenq=0000;elsifclk'eventandclk='1'thenifq=1001thenq=0000;elseq=q+1;endif;endif;y(3)='0'xorq(3);y(2)=q(3)xorq(2);y(1)=q(2)xorq(1);y(0)=q(1)xorq(0);endprocess;endone;libraryieee;useieee.std_logic_1164.all;useieee.std_logic_unsigned.all;entitygray_cnt1isport(clk,clr:instd_logic;y:outstd_logic_vector(3downto0));endgray_cnt1;设计思路:先编写计数器,其计数范围为0-9.再将计数值转变为格雷码gray_cnt1的时序仿真波形图观察波形图,发现每一计数状态持续的时间长短不同。若采用状态机设计可解决该问题。采用状态机方法设计格雷码计数器的VHDL源代码如下:libraryieee;useieee.std_logic_1164.all;useieee.std_logic_unsigned.all;entitygray_cnt2isport(clk,clr:instd_logic;y:outstd_logic_vector(3downto0));endgray_cnt2;architectureoneofgray_cnt2is--状态说明部分constants0:std_logic_vector(3downto0):=0000;constants1:std_logic_vector(3downto0):=0001;constants2:std_logic_vector(3downto0):=0011;constants3:std_logic_vector(3downto0):=0010;constants4:std_logic_vector(3downto0):=0110;constants5:std_logic_vector(3downto0):=0111;constants6:std_logic_vector(3downto0):=0101;constants7:std_logic_vector(3downto0):=0100;constants8:std_logic_vector(3downto0):=1100;constants9:std_logic_vector(3downto0):=1101;signalcurrent_state,next_state:std_logic_vector(3downto0);编程思路:用双进程实现。将0-9的格雷码定义为状态s0-s9.beginprocess(clk,clr)beginifclr='1'thencurrent_state=s0;elsifclk'eventandclk='1'thencurrent_state=next_state;endif;endprocess;process(current_state)begincasecurrent_stateiswhens0=next_state=s1;whens1=next_state=s2;whens2=next_state=s3;whens3=next_state=s4;whens4=next_state=s5;whens5=next_state=s6;whens6=next_state=s7;whens7=next_state=s8;whens8=next_state=s9;whens9=next_state=s0;whenothers=next_state=s0;endcase