登录站点

用户名

密码

状态机的VHDL设计基础知识编辑

已有 1828 次阅读  2009-12-21 16:59
状态机的VHDL设计

一.一般状态机的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”,目的是将转换好的数据锁入12bitsreg中,以便得到正确和稳定的输出。在组合逻辑进程”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: 12A/D转换启动和12w位输出控制信号;

                                                    --rc:A/D转换和数据输出控制信号 ; k12_812位或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;                       --转换数据输出使能,接0809ENABLE(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=0A/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综合器给出的每一各警告信息,并根据警告信息的指示,对程序作必要的修改。

上一篇: VHDL编写的比较器 下一篇: 嵌入式系统的软件延时设计

分享 举报