2015-07-21 95 views
0

我正在尝试使一个有限状态机根据串行输入切换状态。我需要一些关于我的代码如何执行的解释。我在一本教科书中读到,在过程中标记为“默认值”的部分是我应该放置默认值的地方。但是,每当我切换状态时,我的信号似乎都会采用这些值。例如,我将state_next设置为空闲作为默认值。这样做导致密克罗尼西亚联邦继续从其他国家无缘无故地跳到闲置状态。VHDL:有限状态机中的默认值

我的另一个问题是澄清如何执行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; 
+0

你的代码示例没有声明不完整的。 – user1155120

回答

2

下面是一个过程式的另一种版本。如你所猜测的那样,“默认值”在你没有明确设置值时重新设置包括State在内的东西:这可能是不需要的,我已经做了一些明显的空闲转换(在* _channel_inc中)。我在这里猜到了一些语义:如果一个角色出现在InData上多于一个周期,或者如果有不同的角色出现,会发生什么?但逻辑应该很容易改变。

的几个注意事项:

  1. 任何时候,你写的东西x <= std_logic_vector(unsigned(y)+250);可能是错误的类型。这意味着你正在打击类型系统而不是使用它。我制作了d_reg等数组Unsigned,并将类型转换放到了程序流程之外的输出中。 X <= Y + 250;更清晰,更简单。
  2. 这些港口应该是Out,而不是InOut - 我会谈判,使他们Unsigned,进一步简化和澄清设计。
  3. 空间不消耗大门。
  4. 单一过程风格的一个优点是,简单地用于互连过程的信号较少,在难以确定的时间更新。在这里,“更新”在其他所有的时钟边沿上使用。
  5. 幻数...... if in_data = "01101001" then --"i"if in_data = to_slv('i') then。后者更容易阅读,而且写起来更容易(并且正确)。如果您不喜欢to_slv辅助函数(可合成),则至少应使用名称反映字符的命名常量。这也很容易说明这段代码正在处理ASCII(对不起,Latin-1)。
  6. 编辑:为了使SM更少混乱,我已经在本地重载=允许直接比较一个SLV和一个角色:这是一个好主意,保持这种技巧本地化到需要的地方。这些功能甚至可以在流程本身中声明。
  7. 优选rising_edge(clk)以过时的(clk='1' and clk'event)风格。

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; 
+0

在一个上升时钟边缘尝试做太多问题有问题吗?如果我要在这个过程中增加20个国家呢? –

+0

(1)取决于。在某些时候,做太多会占用更多的FPGA资源(门等)。但是请注意,状态机一次只能处于一种状态,因此它在任何时钟边缘上的功能都是有限的。 (2)该过程将起作用;但是它可能太难理解,维护和调试。我建议不要让状态机发展到你无法理解的地步。我见过一些有很多国家的SM有一个简单的结构(几个简单的国家链),很容易维护和理解 - 所以不会提出任何坚定的规则。 –

1

的方法时所列出的信号中的一个发生了变化进行评估每次。因此这个列表被称为“敏感列表”。

有2种类型的处理:
- 按顺序的(与时钟信号),并
- combinatorical(只是普通逻辑)。

第一种类型只需要灵敏度列表中的时钟信号,后者需要每个右手边的信号,否则仿真将显示比真实硬件其他结果。

因此,每当输入信号发生变化(<信号>'事件=真)时,过程从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; 
+0

谢谢,这清除了事情。关于我的代码段,我试图使用'update'作为启用信号。从我迄今为止测试过的数据来看,它似乎有些作用,并且只要更新信号没有改变,其他条件就成立。 如何在没有这种更新信号的情况下更新'd_next'和'w_next'? –

+0

@eugenewu使能信号被嵌入到rising_edge条件的then分支中。你可以删除你的最后一道工序。 – Paebbels