状态机的VHDL设计基础知识编辑
已有 1828 次阅读 2009-12-21 16:59一.一般状态机的VHDL设计
为了能获得可综合的,高效的VHDL状态机描述,建议使用枚举类数据类型来定义状态机的状态,并使用多进程方式来描述状态机的内部逻辑。例如可以使用两个进程来描述,一个进程描述时序逻辑,包括状态寄存器的工作和寄存器的状态输出,另一个进程描述组合逻辑,包括进程间状态值的传递逻辑以及状态转换值的输出。必要时还可以引入第三个进程完成其它的逻辑功能。
状态机的设计模板:
-- s_machine.vhd
library ieee;
use ieee.std_logic_1164.all;
entity s_machine is
port(clk,reset: in std_logic;
state_inputs: in std_logic_vector(0 to 1);
comb_outputs: out std_logic_vector(0 to 1));
end entity s_machine;
architecture behav of s_machine is
type states is (st0,st1,st2,st3); --定义states为枚举型数据类型
signal current_state,next_state: states;
begin
reg: process(reset, clk) --时序逻辑进程
begin
if reset='1' then
current_state <= st0; --异步复位
elsif clk= '1' and clk'EVENT then
current_state <= next_state; --当测到时钟上升沿时转换至下一状态
end if;
end process reg; --由信号current_state将当前状态值带出此进程,进入进程COM
com: process(current_state, state_inputs) --组合逻辑进程
begin
case current_state is --确定当前的状态的状态值
when st0=>comb_outputs <= "00"; --初始状态译码输出“00”
if state_inputs = "00" then --根据外部的状态控制输入"00"
next_state <= st0; --在下一时钟后,进程reg状态维持为st0
else
next_state <= st1; --否则,在下一时钟后,进程reg的状态将为st1
end if;
when st1 => comb_outputs <= "01"; --对应状态st1的译码输出为"01"
if state_inputs = "00" then --根据外部的状态控制输入"00"
next_state <= st1; --在下一时钟后,进程reg的状态将维持为st1
else
next_state <= st2; --否则,在下一时钟后,进程reg的状态将为st2
end if;
when st2 => comb_outputs <= "10"; --以下依次类推
if state_inputs ="11" then
next_state <= st2;
else
next_state <= st3;
end if;
when st3 => comb_outputs <= "11";
if state_inputs ="11" then
next_state <= st3;
else
next_state <= st0; --否则,在下一时钟,进程reg的状态返回st0
end if;
end case;
end process com; --由信号next_state将下一状态值带出此进程,进入进程reg
end architecture behav;
状态机运行中,信号传递的反馈机制的作用是实现当前状态的存储和下一个状态的译码设定等功能。在VHDL中可以有两种方式来创建反馈机制:即使用信号的方式和使用变量的方式。通常倾向于使用信号的方式。一般而言,在进程中使用变量传递数据,然后使用信号将数据带出进程。
例2是一个利用状态机工作方式运行的实用电路的VHDL描述,是一个对A/D转换器件AD574进行采样控制电路的应用实例。例2与例1的程序模型基本是一致的,只是多了一个数据锁存进程”LATCH”,目的是将转换好的数据锁入12bits的reg中,以便得到正确和稳定的输出。在组合逻辑进程”COM”中,根据AD574的工作时序,对6种状态的转换方式和控制数据的输出做了设定,其设定方式在程序中作了详细注释。需要注意,转换好的数据锁入寄存器的锁存时钟信号”LOCK“是在状态”st3“向”st4”转换的时候产生的。这有利于正确数据被稳定的锁入。
例2:
-- AD574.vhd
library ieee;
use ieee.std_logic_1164.all;
entity AD574 is
port(D: in std_logic_vector(11 downto 0); --AD574变换数据读入端口
clk, status: in std_logic; --clk: 工作时钟; status:转换结束状态位
cs, a0, rc, k12_8: out std_logic; --cs: 片选信号 ; a0: 12位A/D转换启动和12w位输出控制信号;
--rc:A/D转换和数据输出控制信号 ; k12_8:12位或8位输出有效控制信号:
q: out std_logic_vector(11 downto 0)); --A/D转换数据输出显示
end entity AD574;
architecture behav of AD574 is
type states is (st0,st1,st2,st3,st4,st5); --定义状态子类型
signal current_state, next_state: states := st0;
signal REGL: std_logic_vector(11 downto 0); --A/D转换数据锁存器
signal LOCK: std_logic; --转换后数据输出锁存时钟信号
---------------------------------------------------------------------------------------
--优化代码提高综合后目标器件的资源利用率和运行速度。各状态明确定义为Std_logic_vector矢量数据类型
--同时具体规定各状态的值,使任意两相邻的状态转换只有一位发生变换,这十分有利于状态译码组合逻辑的简化。
--signal current_state, next_state: std_logic_vector(2 downto 0);
--constant st0: std_logic_vector(2 downto 0) := "000";
--constatn st1: std_logic_vector(2 downto 0) := "001";
--constant st2: std_logic_vector(2 downto 0) := "011";
--constant st3: std_logic_vector(2 downto 0) := "111";
--constant st4: std_logic_vector(2 downto 0) := "110";
--constant st5: std_logic_vector(2 downto 0) := "010";
--signal REGL: std_logic_vector(11 downto 0);
--signal LOCK: std_logic;
--
--
--------------------------------------------------------------------------------------
begin
k12_8 <= '1'; --12位并行输出有效
COM: process(current_state, status) is
begin --规定各状态转换方式
case current_state is
when st0 => cs <= '1'; a0 <= '0'; rc <='0'; LOCK <= '0';
next_state <= st1; --AD574采样控制信号初始化,初始态st0向下一状态st1转换
when st1 => cs <= '0'; a0 <= '0'; rc <= '0'; LOCK <= '0';
next_state <= st2; --打开片选,启动12位转换
when st2 => cs <= '0'; a0 <= '0'; rc <= '0'; LOCK <= '0';
if (status = '1') then
next_state <= st2; --转换未结束,继续等待
else
next_state <= st3; --转换结束,进入下一状态
end if;
when st3 => cs <= '0'; a0 <= '0'; rc <= '1'; LOCK <= '0';
next_state <= st4; --令rc为高电平,12位并行输出有效并进入下一状态
when st4 => cs <= '0'; a0 <= '0'; rc <= '1'; LOCK <= '1';
next_state <= st5; --开启数据锁存信号
when st5 => cs <= '1'; a0 <= '1'; rc <= '1'; LOCK <= '0';
next_state <= st0; --关闭AD574,回到初始态
when others => next_state <= st0; --所有闲置状态导入初始态
end case;
end process COM;
REG: process( clk) is
begin
if(clk'EVENT and clk='1') then
current_state <= next_state; --在时钟CLK的上升沿,转换至下一状态
end if;
end process REG; --由current_state将当前状态值带出此进程,进入进程COM
LATCH: process(LOCK)
--此进程中,在LOCK的上升沿,将转换好的数据锁入12位锁存器REGL中,以便得到稳定的显示
begin
if LOCK='1' and LOCK'EVENT then
REGL <= D;
end if;
end process LATCH;
q <= REGL; --REGL的输出端口与目标器件的输出端口q相连接
end architecture behav;
摩尔机与米立机的VHDL设计
标准状态机可以分为摩尔(Moore)机和米立(Mealy)机两种。在摩尔机中,其输出仅仅是当前状态值的函数,并且仅在时钟边沿到来时才发生变化。米立机的输出则是当前状态值、当前输出值和当前输入值的函数。
1. Moore机模型
-- system.vhd
library ieee;
use ieee.std_logic_1164.all;
entity system is
port(clock: in std_logic;
a: in std_logic;
d: out std_logic);
end entity system;
architecture moore of sytstem is
signal b,c: std_logic;
begin
FUNC1: process(a,c) is --第1组组合逻辑进程,为时序逻辑进程提供反馈信号
begin
b <= FUNC1:(a,c); --c是反馈信号
end process FUNC1;
FUNC2: process(c) is
begin
d <= FUNC2(c); --输出信号D所对应的FUNC2,是仅为当前状态的函数
end process FUNC2;
REG: process(clock) is --时序逻辑转换,负责状态的转换
begin
if clock='1' and clock'EVENT then
c <= b: --b是反馈信号
end if;
end process REG;
end architecture moore;
――――――――――――――――――――――――――――――――――――――――――注:此例需要修改方可使用。-------------------------------------------------------------------------
――――――――――――――――――――――――――――――――――――――――――注:此例需要修改方可使用。-------------------------------------------------------------------------
――――――――――――――――――――――――――――――――――――――――――注:此例需要修改方可使用。-------------------------------------------------------------------------
-- SRAM.vhd
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
entity SRAM is
port( --ADC0809接口信号
DIN: in std_logic_vector(7 downto 0); --0809转换数据输入口
CLK,EOC: in std_logic; --CLK:状态机工作时钟;EOC:转换结束状态信号
RST: in std_logic; --系统复位信号
ALE: out std_logic; --0809采样通道选择地址锁存信号
START: out std_logic; --0809采样启动信号,上升沿有效
OE: out std_logic; --转换数据输出使能,接0809的ENABLE(PIN9)
ADDA: out std_logic; --0809采样通道地址最低位
------------------------SRARM 6264接口信号
CS: out std_logic; --6264片选信号,低电平有效
RD,WR: out std_logic; --6264读写控制信号,低电平有效
RAM_DIN: out std_logic_vector(7 downto 0); --6264数据输入端口
ADDRESS: out std_logic_vector(12 downto 0) --地址输出端口
);
end entity SRAM;
architecture behav of SRAM is
type AD_STATES is (ST0,ST1,ST2,ST3,ST4,ST5,ST6,ST7); --A/D转换状态定义
type WRIT_STATES is (START_WRITE,WRITE1,WRITE2,WRITE3,WRITE_END); --SRAM数据写入控制状态定义
signal RAM_CURRENT_STATE,RAM_NEXT_STATE: WRIT_STATES;
signal ADC_CURRENT_STATE,ADC_NEXT_STATE: AD_STATES;
signal ADC_END: std_logic; --0809数据转换结束并锁存标志位,高电平有效
signal LOCK: std_logic; --转换后数据输出锁存信号
signal ENABLE: std_logic; --A/D转换允许信号,高电平有效
signal ADDRES_PLUS: std_logic; --SRAM地址加1时钟信号
signal ADC_DATA: std_logic_vector(7 downto 0); --转换数据读入锁存器
signal ADDRES_CNT: std_logic_vector(12 downto 0); --SRAM地址所存器
begin
ADDA <= '1'; --ADDA=1,ADDB=0,ADDC=0选A/D采样通道为IN-1
RD <= '1'; ---SRAM禁止写
-----------------ADC0809采样控制状态机
ADC: process(ADC_CURRENT_STATE, EOC, ENABLE) --A/D转换转换状态机组合电路进程
begin
if(RST='1') then
ADC_NEXT_STATE <= ST0; --状态机复位
else
case ADC_CURRENT_STATE is
when ST0=>ALE <= '0'; START <='0'; OE<='0'; LOCK<='0';ADC_END <='0'; --AD转换初始化
if(ENABLE='1') then --允许转换,转入下一状态
ADC_NEXT_STATE <= ST1;
else
ADC_NEXT_STATE <= ST0; --禁止转换,仍停留在本状态
end if;
when ST1=> ALE<='1'; START<='0'; OE<='0';LOCK<='0';ADC_END <='0';
ADC_NEXT_STATE <= ST2; --通道选择地址锁存,并转入下一状态
when ST2=>ALE<='1'; START<='1'; OE<='0'; LOCK<='0'; ADC_END <='0';
ADC_NEXT_STATE <= ST3; --启动A/D转换信号START
when ST3=>ALE<='1'; START<='1'; OE<='0'; LOCK<='0'; ADC_END <='0'; --延迟一个脉冲周期
if(EOC='0') then
ADC_NEXT_STATE <= ST4;
else
ADC_NEXT_STATE <= ST3; --转换未结束,继续等待
end if;
when ST4=>ALE<='0'; START<='0'; OE <= '0'; LOCK<='0'; ADC_END<='0';
if (EOC = '0')then
ADC_NEXT_STATE <=ST5; --转换结束,转入下一状态
else
ADC_NEXT_STATE <=ST4; --转换未结束,继续等待
end if;
when ST5=> ALE<='0'; START<='1'; OE<='1'; LOCK<='0'; ADC_END <='0';
ADC_NEXT_STATE <= ST6; --开启数据输出使能信号OE
when ST6=> ALE<='0'; START<='0'; OE<='1'; LOCK<='1'; ADC_END <='1';
ADC_NEXT_STATE <= ST7; --开启数据锁存信号
when ST7=> ALE<='0'; START<='0'; OE<='1'; LOCK<='1'; ADC_END <='1';
ADC_NEXT_STATE <= ST0; --为6264数据写入发出A/D转换周期结束信号
when others=> ADC_NEXT_STATE<= ST0; --所有闲置状态导入初始态
end case;
end if;
end process ADC;
AD_STATE: process(CLK) is
begin
if (CLK'EVENT and clk='1') then
ADC_CURRENT_STATE <= ADC_NEXT_STATE; --在时钟上升沿,转至下一状态
end if;
end process AD_STATE; --由信号current_state将当前状态值带出此进程
DATA_LOCK: process( LOCK) is
begin --此进程中,在LOCK的上升沿,将转换好的数据锁入锁存器ADC_DATA中
if LOCK = '1' and LOCK'EVENT then
ADC_DATA <= DIN;
end if;
end process DATA_LOCK;
--sRAM数据写入控制状态机
WRIT_STATE: process (CLK, RST) is --SRAM写入控制状态机时序电路进程
begin
if RST = '1' then
RAM_CURRENT_STATE <= START_WRITE; --系统复位
elsif (clk'EVENT and CLK='1') then
RAM_CURRENT_STATE <= RAM_NEXT_STATE; --在时钟的上升沿,转入下一状态
end if;
end process WRIT_STATE;
RAM_WRITE: process(RAM_CURRENT_STATE, ADC_END) is --SRAM写入控制时序电路进程
begin
case RAM_CURRENT_STATE is
when START_WRITE =>CS<='1'; WR<='1'; ADDRES_PLUS<='0';
if (ADDRES_CNT = "1111111111111") then --数据写入初始化
ENABLE <= '0'; --SRAM地址计数器已满,禁止A/D转换
RAM_NEXT_STATE <= START_WRITE;
else
ENABLE <='1'; --SRAM地址计数器未满,允许A/D转换
RAM_NEXT_STATE <= WRITE1;
end if;
when WRITE1 => CS<='1'; WR<='1'; ENABLE <='1'; ADDRES_PLUS <='0'; --判断A/D转换周期是否结束
if ( ADC_END ='1') then
RAM_NEXT_STATE <= WRITE2; --已结束
else
RAM_NEXT_STATE <= WRITE1; --转换周期未结束,等待
end if;
when WRITE2=> CS<='0'; WR<='1'; --打开SRAM片选信号
ENABLE <='0'; --禁止A/D转换
ADDRES_PLUS <= '0'; ADDRESS <= ADDRES_CNT; --输出13位地址
RAM_DIN <= ADC_DATA; --8位已转会好的数据输向SRAM数据口
RAM_NEXT_STATE <= WRITE3; --进入下一状态
when WRITE3=> CS<='0'; WR <='0'; --打开允许写信号
ENABLE <= '0'; --仍然禁止A/D转换
ADDRES_PLUS <='1'; --产生地址加1时钟上升沿,使地址计数器加1
RAM_NEXT_STATE <= WRITE_END; --进入结束状态
when WRITE_END => CS<='1'; WR<='1';
ENABLE <='1'; --打开A/D转换允许开关
ADDRES_PLUS <='0'; --地址加1时钟脉冲结束
RAM_NEXT_STATE <= START_WRITE; --返回初始状态
when others=> RAM_NEXT_STATE <= START_WRITE;
end case;
end process RAM_WRITE;
COUNTER: process (ADDRES_PLUS) is --地址计数器加1进程
begin
if (RST ='1') then
ADDRES_CNT <= "0000000000000"; --计数器复位
elsif (ADDRES_PLUS'EVENT and ADDRES_PLUS='1') then
ADDRES_CNT <= ADDRES_CNT +1;
end if;
end process COUNTER;
end architecture behav;
2. 米立机模型
米立机的VHDL结构要求至少有两个进程,或者是一个状态机进程加一个独立的并行赋值语句。
使用VHDL描述状态机时,必须注意避免由于寄存器的引入而创建了不必要的异步反馈路径。根据VHDL综合器的规则,对于所有肯能的输入条件,当进程中的输出信号如果没有被完全地与之对应指定时,即没有为所有可能的输入条件提供明确的赋值时,此信号将自动被指定,即在未列出的条件下保持原值,这就意味着引入了寄存器。在状态机中,如果存在一个或更多的状态没有被明确的指定转换方式,或者对于状态机中的状态值没有规定所有的输出值,寄存器就将在设计者的不知不觉中被引入了。
VHDL的这一重要特点――就是未指定的条件也会生成相应的逻辑电路。为了能及时的发现和纠正此类无意中的失误,在程序的综合过程中,应密切注视VHDL综合器给出的每一各警告信息,并根据警告信息的指示,对程序作必要的修改。
发表评论 评论 (0 个评论)