VHDL语法入门 (六) 状态机

状态机

如果状态机的输出信号不仅与电路当前状态有关,还与当前输入有关,则这种状态机称为米勒(Mealy)型状态机。

如果状态机的输出信号仅仅与电路当前状态有关,则称为摩尔(Moore)型状态机。

下图是一种相对通用的状态机原理图,主要由组合逻辑电路和时序逻辑电路两部分组成,

状态机的设计比较灵活多样,下面介绍两种相对常见的结构清晰,易于理解的状态机设计风格

设计风格1

该风格设计状态机时,将时序逻辑电路和组合逻辑电路进行分开设计,需要先定义一个枚举类型,包含状态机需要的所有状态。

首先时时序逻辑部分的设计

process (reset, clock)
begin
    if(reset = '1') then
        pr_state <= state0;
    elsif (clock'event and clock = '1') then
        pr_state <= nx_state;
    end if;
end process;

这种设计风格的优点是时序电路的设计方法基本上是标准的。此外,这种风格占用的寄存器数量最少。这段代码综合得到的寄存器的数量等于对状态机所有状态进行编码所需要的位数。

状态机中时序逻辑电路的设计

process(input, pr_state)
begin
    case pr_state is
        when state0 =>
            if(input=...)then
                output <= <value>;
                nx_state <= state1;
            else...
            end if;
        when state1 =>
            if(input=...)then
                output <= <value>;
                nx_state <= state2;
            else...
            end if;
        when state2 =>
            if(input=...)then
                output <= <value>;
                nx_state <= state3;
            else...
            end if;
        ...
    end case;
end process;

整个代码中,由于没有任何信号的赋值是通过其他某个信号的跳变来触发的,所以不会生成寄存器

下面给出完整的模板

library ieee;
use ieee.std_logic_1164.all;

entity <entity_name> is
    port(
        input: in <data_type>;    
        reset, clock: in std_logic;
        output: out <data_type>;
    );
end <entity_name>;

architecutre <arc_name> of <entity_name> is
    type state is (state0,state1,state2,state3...);
    signal pr_state,nx_state: state;
begin
    process(reset,clock)
    begin
        if(reset = '1') then
            pr_state <= state0;
        elsif (clock'event and clock = '1') then
            pr_state <= nx_state;
        end if;
    end process;
    process(input, pr_state)
    begin
        case pr_state is
            when state0 =>
                if(input=...)then
                    output <= <value>;
                    nx_state <= state1;
                else...
                end if;
            when state1 =>
                if(input=...)then
                    output <= <value>;
                    nx_state <= state2;
                else...
                end if;
            when state2 =>
                if(input=...)then
                    output <= <value>;
                    nx_state <= state3;
                else...
                end if;
            ...
        end case;
    end process;
end <arc_name>;

设计风格2

前面我们介绍的设计风格,在进行综合后,会产生如下的电路结构

 此时,如果是米勒型状态机,那么输出随输入的变化而改变,但是在很多应用中,需要同步的寄存器输出,输出信号只有在时钟边沿出现时才能更新,此时输出必须先用寄存器存储起来。使用风格2设计的状态机会产生如下电路结构

 风格2与1相比,只有一个差别,就是引入了内部信号temp。这个信号将输出结果存储起来,只有当所需的时钟边沿到来时才将它赋给输出端口

library ieee;
use ieee.std_logic_1164.all;

entity <entity_name> is
    port(
        input: in <data_type>;    
        reset, clock: in std_logic;
        output: out <data_type>;
    );
end <entity_name>;

architecutre <arc_name> of <entity_name> is
    type state is (state0,state1,state2,state3...);
    signal pr_state,nx_state: state;
    signal temp: <data_type>;
begin
    process(reset,clock)
    begin
        if(reset = '1') then
            pr_state <= state0;
        elsif (clock'event and clock = '1') then
            output <= temp;
            pr_state <= nx_state;
        end if;
    end process;
    process(pr_state)
    begin
        case pr_state is
            when state0 =>
                temp <=<value>;
                if(condition)then
                    nx_state <= state1;
                else...
                end if;
            when state1 =>
                temp <=<value>;
                if(condition)then
                    nx_state <= state2;
                else...
                end if;
            when state2 =>
                temp <=<value>;
                if(condition)then
                    nx_state <= state3;
                else...
                end if;
            ...
        end case;
    end process;
end <arc_name>;

二进制编码与独热码

对状态机的状态进行编码时有多种选择,默认的方式是以二进制编码。它的优点是需要的寄存器数量最少,有n个寄存器就可以对2^n个状态进行编码。但是这种编码方式需要更多的外部辅助逻辑,并且速度较慢。

另一种极端的编码方式是独热(OneHot)编码。此时,每个状态都需要一个寄存器。因此,它需要的寄存器最多,n个状态就需要n个寄存器。但是这种方法需要最少的辅助逻辑并且最有最快的速度。

一种介于两者之间的编码方式就是双热编码方式。在这种编码方式下,每一次状态变化会带来两个位的跳变,因此n个寄存器可以实现对n(n-1)/2个状态进行编码

状态

编码风格

二进制

双热

独热

state0

000

00011

00000001

state1

001

00101

00000010

state2

010

01001

00000100

state3

011

10001

00001000

state4

100

00110

00010000

state5

101

01010

00100000

state6

110

10010

01000000

state7

111

01100

10000000

实例

风格1

  一个使用摩尔状态机实现的简易的0-9环形计数器的状态转移图,流程图如下

library ieee;
use ieee.std_logic_1164.all;

entity counter is 
    port(clk,rst: in std_logic;
         cout: out std_logic_vector(3 downto 0));
 end counter;
 
 architecture state_machine of counter is
     type state is(zero,one,two,three,four,five,six,seven,eight,nine);
     signal pr_state,nx_state: state;
 begin
     process(rst,clk)
     begin
         if(rst = '1')then
             pr_state <= zero;
         elsif (clk'event and clk = '1') then
             pr_state <= nx_state;
         end if;
     end process;
     process (pr_state)
     begin
         case pr_state is
             when zero =>
                 count <= "0000";
                 nx_state <= one;
             when one =>
                 count <= "0001";
                 nx_state <= two;
             when two =>
                 count <= "0010";
                 nx_state <= three;
             when three =>
                 count <= "0011";
                 nx_state <= four;
             when four =>
                 count <= "0100";
                 nx_state <= five;
             when five =>
                 count <= "0101";
                 nx_state <= six;
             when six =>
                 count <= "0110";
                 nx_state <= seven;
             when seven =>
                 count <= "0111";
                 nx_state <= eight;
             when eight =>
                 count <= "1000";
                 nx_state <= nine;
             when nine =>
                 count <= "1001";
                 nx_state <= zero;
     end process;
 end state_machine;

风格2

下面的代码实现了一个序列检测器电路,状态机输入是一个串行位流,当检测到序列“111”时,输出1。此外,如果出现连续的‘1’,如“···011111···”,此时需要连续输出3个1。流程图如下:

library ieee;
use ieee.std_logic_1164.all;

entity string_detector is
    port(d,clk,rst: in bit;
         q: out bit);
 end string_detector;
 
 architecture my_arch of string_detector is
     type state is (zero,one,two,three);
     signal pr_state,nx_state: state;
 begin
     process(rst,clk)
     begin
         if (rst = '1') then
             pr_state <= zero;
         elsif (clk'event and clk = '1') then
             pr_state <= nx_state;
         end if;
     end process;
     process (d,pr_state)
     begin
         case pr_state is
             when zero =>
                 q <= '0';
                 if (d = '1') then 
                     nx_state <= one;
                 else 
                     nx_state <= state;
                 end if;
             when one =>
                 q <= '0';
                 if (d = '1') then 
                     nx_state <= two;
                 else
                     nx_state <= zero;
                 end if;
             when two =>
                 q <= '0';
                 if (d = '1') then
                     nx_state <= three;
                 else
                     nx_state <= zero;
                 end if;
             when three =>
                 q <= '1';
                 if(d = '1') then
                     nx_state <= three;
                 else
                     nx_state <= zero;
                 end if;
         end case;
     end process;
 end my_arch;

 

  • 6
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值