VHDL:有限状态机

时间:2015-07-21 17:02:06

标签: vhdl xilinx-ise

我正在尝试创建一个基于串行输入切换状态的有限状态机。关于我的代码是如何执行的,我需要一些解释。我在教科书中读到了我已经标记过" DEFAULT VALUES"是我应该把我的默认值。但是,每当我切换状态时,我的信号似乎都会采用这些值。例如,我将state_next设置为idle作为默认值。这样做会导致FSM无缘无故地继续从其他状态跳转到空闲状态。

我的另一个问题是如何执行FSM的整个过程。当我从一个状态移动到另一个状态时,是否应该执行case语句(标记为DEFAULT VALUES的部分)之前的部分?或者只有当我从一些后来的状态转移到空闲状态时它才被执行?什么时候应该执行DEFAULT VALUES部分?

我的代码如下所示。请参考"下一状态逻辑"部分。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity delay_incrementor is
     generic ( delay_ports : natural := 3;
               width_ports : natural := 3
                );
    Port ( clk,reset: in STD_LOGIC;
              update : in STD_LOGIC;
              in_data : in  STD_LOGIC_VECTOR (7 downto 0);
              led : out STD_LOGIC_VECTOR (2 downto 0);
              out_data : out  STD_LOGIC_VECTOR (7 downto 0);
              d_big,d_mini,d_opo : inout  STD_LOGIC_VECTOR (25 downto 0);
              w_big,w_mini,w_opo : inout STD_LOGIC_VECTOR (25 downto 0));
end delay_incrementor;

architecture fsm_arch of delay_incrementor is
    type state_type is (idle,channel,d_or_w,delay_channel,delay_channel_inc,width_channel,width_channel_inc);
    type delay_file_type is array (delay_ports-1 downto 0) of std_logic_vector (25 downto 0);
    type width_file_type is array(width_ports-1 downto 0) of std_logic_vector (25 downto 0);
    signal d_reg,d_next,d_succ: delay_file_type;
    signal w_reg,w_next,w_succ: width_file_type;
    signal state_reg,state_next: state_type;
    signal which_channel,which_channel_next: natural;
begin
--------------------------------------
--State Register
--------------------------------------
process(clk,reset)
begin
if reset='1' then
    state_reg <= idle;
    d_reg <= (others => (others => '0'));
    w_reg <= (others => (others => '0'));
    which_channel <= 0;
elsif (clk='1' and clk'event) then
    state_reg <= state_next;
    d_reg <= d_next;
    w_reg <= w_next;
    which_channel <= which_channel_next;
end if;
end process;
--------------------------------------
--Next-State Logic/Output Logic
--------------------------------------
process(state_reg,in_data,d_reg,w_reg,which_channel)
begin
    state_next <= idle; --DEFAULT VALUES
    d_succ <= d_reg;
    w_succ <= w_reg;
    which_channel_next <= 0;
    case state_reg is
        when idle =>
            if in_data = "01100011" then --"c"
                state_next <= channel;
                which_channel_next <= 0;
            end if;
        when channel =>
            if (48 <= unsigned(in_data)) and (unsigned(in_data)<= 57) then
                which_channel_next <= (to_integer(unsigned(in_data))-48);
                state_next <= d_or_w;
            elsif in_data = "00100011" then --"#"
                state_next <= idle;
                which_channel_next <= which_channel;
            end if;
        when d_or_w =>
            if in_data = "01100100" then --"d"
                state_next <= delay_channel;
            elsif in_data = "01110111" then --"w"
                state_next <= width_channel;
            elsif in_data = "00100011" then --"#"
                state_next <= idle;
            end if;
        when delay_channel =>
            if in_data = "01101001" then --"i"
                state_next <= delay_channel_inc;
            elsif in_data = "00100011" then --"#"
                state_next <= idle;
            end if;
        when delay_channel_inc =>
            if in_data = "01110101" then --"u"
                d_succ(which_channel) <= std_logic_vector(unsigned(d_reg(which_channel))+250);
            elsif in_data = "01100100" then --"d"
                d_succ(which_channel) <= std_logic_vector(unsigned(d_reg(which_channel))-250);
            else
                d_succ(which_channel) <= d_reg(which_channel);
            end if;
            if in_data = "00100011" then --"#"
                state_next <= idle;
            end if;
        when width_channel =>
            if in_data = "01101001" then --"i"
                state_next <= width_channel_inc;
            elsif in_data = "00100011" then --"#"
                state_next <= idle;
            end if;
        when width_channel_inc =>
            if in_data = "01110101" then --"u"
                w_succ(which_channel) <= std_logic_vector(unsigned(w_reg(which_channel))+250);
            elsif in_data = "01100100" then --"d"
                w_succ(which_channel) <= std_logic_vector(unsigned(w_reg(which_channel))-250);
            else
                w_succ(which_channel) <= w_reg(which_channel);
            end if;
            if in_data = "00100011" then --"#"
                state_next <= idle;
            end if;
    end case;
end process;
process(update,d_reg,w_reg,reset)
begin
if reset='1' then
    d_next <= (others => (others =>'0'));
    w_next <= (others => (others =>'0'));
elsif (update'event and update='1') then
    d_next <= d_succ;
    w_next <= w_succ;
else
    d_next <= d_reg;
    w_next <= w_reg;
end if;
end process;
--------------------------------------
--Output Logic
--------------------------------------
d_big <= d_reg(0);
d_mini <= d_reg(1);
d_opo <= d_reg(2);
w_big <= w_reg(0);
w_mini <= w_reg(1);
w_opo <= w_reg(2);
end fsm_arch;

2 个答案:

答案 0 :(得分:2)

这是单一流程风格的替代版本。

正如你推测的那样,&#34;默认值&#34;你没有明确设置值时重置包括State在内的东西:这可能是不需要的,我已经做了一些过渡到空闲显式(在* _channel_inc中)。我在这里的语义上已经猜到了一点:如果一个字符出现在InData上超过一个周期,或者是否有不同的字符,会发生什么?但逻辑应该很容易改变。

一些注意事项:

  1. 任何时候你写x <= std_logic_vector(unsigned(y)+250);的东西可能是错误的类型。这意味着你要打击类型系统而不是使用它。我创建了d_regUnsigned的数组,并将类型转换排除在程序流之外的输出中。 X <= Y + 250;更清晰,更简单。
  2. 这些端口应该是Out,而不是InOut - 我会协商制作Unsigned,进一步简化和澄清设计。
  3. 空间不消耗门。
  4. 单一过程风格的一个优点是,用于互连过程的信号较少,在难以确定的时间更新。在这里,&#34;更新&#34;用于与其他所有内容相同的时钟边缘。
  5. 幻数...... if in_data = "01101001" then --"i"if in_data = to_slv('i') then。后者更容易阅读,更容易编写(并得到正确)。如果您不喜欢to_slv辅助函数(可以合成),请至少使用名称常量来反映字符。这也很容易说明这段代码正在处理ASCII(对不起,拉丁语-1)。
  6. 编辑:为了减少SM的混乱,我在本地重载=以允许直接比较slv和角色:这是一个好主意将这种技巧本地化到需要的地方。甚至可以在流程本身中声明这些功能。
  7. 首选rising_edge(clk)为过时的(clk='1' and clk'event)样式。
  8. library IEEE;
    use IEEE.STD_LOGIC_1164.ALL;
    use IEEE.NUMERIC_STD.ALL;
    
    entity delay_increment is
        generic ( delay_ports : natural := 3;
                  width_ports : natural := 3
                    );
        Port ( clk,reset: in STD_LOGIC;
                  update : in STD_LOGIC;
                  in_data : in  STD_LOGIC_VECTOR (7 downto 0);
                  led : out STD_LOGIC_VECTOR (2 downto 0);
                  out_data : out  STD_LOGIC_VECTOR (7 downto 0);
                  d_big,d_mini,d_opo : out STD_LOGIC_VECTOR (25 downto 0);
                  w_big,w_mini,w_opo : out STD_LOGIC_VECTOR (25 downto 0));
    end delay_increment;
    
    architecture fsm_arch of delay_increment is
        type state_type is (idle,channel,d_or_w,delay_channel,delay_channel_inc,width_channel,width_channel_inc);
        type delay_file_type is array (delay_ports-1 downto 0) of unsigned (25 downto 0);
        type width_file_type is array(width_ports-1 downto 0) of unsigned (25 downto 0);
        signal d_reg, d_succ: delay_file_type;
        signal w_reg, w_succ: width_file_type;
        signal state_reg : state_type;
        signal which_channel : natural;
        function to_slv(C : Character) return STD_LOGIC_VECTOR is
        begin
           return STD_LOGIC_VECTOR(to_unsigned(Character'pos(c),8));
        end to_slv;
        function "=" (A : STD_LOGIC_VECTOR(7 downto 0); B : Character) 
           return boolean is
        begin
           return (A = to_slv(B));
        end function "+";
    
    begin
    --------------------------------------
    --State Machine
    --------------------------------------
    process(clk,reset)
    begin
    if reset='1' then
        state_reg <= idle;
        d_reg <= (others => (others => '0'));
        w_reg <= (others => (others => '0'));
        which_channel <= 0;
    elsif rising_edge(clk) then
        -- default actions ... update if asked
        if update ='1' then
           d_reg <= d_succ;
           w_reg <= w_succ;
        end if;
        case state_reg is
            when idle =>
                if in_data = 'c' then 
                    state_reg <= channel;
                    which_channel <= 0;
                end if;
            when channel =>
                if (Character'pos('0') <= unsigned(in_data)) and (unsigned(in_data)<= Character'pos('9')) then
                    which_channel <= (to_integer(unsigned(in_data)) - Character'pos('0'));
                    state_reg <= d_or_w;
                elsif in_data = '#' then 
                    state_reg <= idle;
                    which_channel <= which_channel;
                end if;
            when d_or_w =>
                if in_data = 'd' then 
                    state_reg <= delay_channel;
                elsif in_data = 'w' then 
                    state_reg <= width_channel;
                elsif in_data = '#' then 
                    state_reg <= idle;
                end if;
            when delay_channel =>
                if in_data = 'i' then 
                    state_reg <= delay_channel_inc;
                elsif in_data = '#' then 
                    state_reg <= idle;
                end if;
            when delay_channel_inc =>
                if in_data = 'u' then 
                    d_succ(which_channel) <= d_reg(which_channel) + 250;
                    state_reg <= idle;
                elsif in_data = 'd' then 
                    d_succ(which_channel) <= d_reg(which_channel) - 250;
                    state_reg <= idle;
                else
                    d_succ(which_channel) <= d_reg(which_channel); -- wait for any of 'u', 'd', '#'
                end if;
                if in_data = '#' then 
                    state_reg <= idle;
                end if;
            when width_channel =>
                if in_data = 'i' then 
                    state_reg <= width_channel_inc;
                elsif in_data = '#' then 
                    state_reg <= idle;
                end if;
            when width_channel_inc =>
                if in_data = 'u' then 
                    w_succ(which_channel) <= w_reg(which_channel) + 250;
                    state_reg <= idle;
                elsif in_data = 'd' then 
                    w_succ(which_channel) <= w_reg(which_channel) - 250;
                    state_reg <= idle;
                else
                    w_succ(which_channel) <= w_reg(which_channel); -- wait for any of 'u', 'd', '#'
                end if;
                if in_data = '#' then 
                    state_reg <= idle;
                end if;
        end case;
    end if;
    end process;
    
    --------------------------------------
    --Output Logic
    --------------------------------------
    d_big  <= std_logic_vector(d_reg(0));
    d_mini <= std_logic_vector(d_reg(1));
    d_opo  <= std_logic_vector(d_reg(2));
    w_big  <= std_logic_vector(w_reg(0));
    w_mini <= std_logic_vector(w_reg(1));
    w_opo  <= std_logic_vector(w_reg(2));
    end fsm_arch;
    

答案 1 :(得分:1)

每当列出的一个信号发生变化时,就会评估一个过程。因此,此列表称为“敏感列表”。

有两种类型的过程:
  - 顺序(带时钟信号)和
  - 组合(只是简单的逻辑)。

第一种类型只需要灵敏度列表中的时钟信号,后者需要每个右侧的手持信号,否则模拟将显示除实际硬件之外的其他结果。

因此,每当输入信号发生变化(&lt; signal&gt;'event = true)时,就会从begin ... end process评估该过程。

因此,关于你的DEFAULT部分,每个信号都有一个默认值,并且不可能生成具有这种编码风格的锁存器。通常,state_next未设置为空闲。它设置为state_reg

免费翻译:保持当前状态,直到另有说明

您的代码:

...
elsif (update'event and update='1') then
  d_next <= d_succ;
  w_next <= w_succ;
else
  d_next <= d_reg;
  w_next <= w_reg;
end if;

无法合成。我假设更新不是真正的时钟信号,因此不应该在rising_edge表达式中使用它。其次,其他条件何时为真?

解决方案:您需要为您的注册启用信号。

<强>附录:

process(clk,reset)
begin
  if reset='1' then
    state_reg <= idle;
    d_reg <= (others => (others => '0'));
    w_reg <= (others => (others => '0'));
    which_channel <= 0;
  elsif (clk='1' and clk'event) then
    state_reg <= state_next;
    which_channel <= which_channel_next;
    if update = '1' then
      d_reg <= d_next;
      w_reg <= w_next;
     end if;
  end if;
end process;