分享

关于xilinx ise:VHDL:有限状态机中的默认值 | 码农家园

 qingxiangwang 2024-01-21 发布于江西

我正在尝试制造一个基于串行输入来切换状态的有限状态机。 我需要一些有关如何执行代码的解释。 我从一本教科书中看到,我在过程中标记为"默认值"的部分是放置默认值的地方。 但是,无论何时切换状态,我的信号似乎都采用这些值。 例如,我将state_next设置为idle为默认值。 这样做导致FSM无缘无故地继续从其他状态跳入空闲状态。

我的另一个问题是澄清如何执行FSM的整个过程。 当我从一种状态转移到另一种状态时,是否应该执行case语句之前的部分(标记为DEFAULT VALUES的部分)? 还是仅当我从稍后的状态返回到空闲状态时才执行? 应何时执行"默认值"部分?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
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;
  • 没有声明,您的代码示例是不完整的。

这是单处理样式的替代版本。

如您所料,只要您没有显式设置值,"默认值"就会重置包括State在内的所有内容:这可能是不希望的,而我已经进行了一些到显式空闲状态的转换(在* _channel_inc中)。我对这里的语义有些猜测:如果一个字符在InData上存在一个以上的周期,或者输入了另一个字符,会发生什么?但逻辑应该易于更改。

一些注意事项:

  • 任何时候编写x <= std_logic_vector(unsigned(y)+250);都可能是错误的类型。这意味着您正在使用类型系统而不是使用它。我制作了Unsignedd_reg etc数组,并从程序流中排除了将类型转换转换为输出的情况。 X <= Y + 250;更清晰,更简单。
  • 这些端口应该是Out,而不是InOut-我会协商将它们设置为Unsigned,从而进一步简化和阐明设计。
  • 空间不消耗门。
  • 单一过程样式的优点之一是,用于互连过程的信号更少,并且在难以确定的时间进行更新。此处,"更新"与其他所有时钟都在同一时钟沿使用。
  • 幻数... if in_data ="01101001" then --"i"if in_data = to_slv('i') then后者更易于阅读,更容易编写(并正确)。如果您不喜欢to_slv辅助函数(可综合),请至少使用命名常量(其名称反映字符)。这也可以很容易地看出该代码正在处理ASCII(对不起,Latin-1)。
  • 编辑:为了使SM不太混乱,我在本地重载了=以允许在slv和字符之间进行直接比较:将这种技巧本地化到需要的地方是一个好主意。这些功能甚至可以在流程本身中声明。
  • 首选rising_edge(clk)而不是过时的(clk='1' and clk'event)样式。
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    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;
    • 在一个时钟上升沿尝试执行过多操作是否有问题?如果我要在该过程中再添加20个状态怎么办?
    • (1)视情况而定。在某些时候,做太多会消耗比您更多的FPGA资源(门等)。但是请注意,状态机一次只能处于一种状态,因此它在任何时钟沿只能做的事情受到限制。 (2)该过程将起作用;但是,可能很难理解,维护和调试。我建议不要让状态机发展到无法理解的程度。我已经看到一些具有许多状态的SM,它们具有简单的结构(几个简单状态链),并且易于维护和理解-因此不会建议任何严格的规则。

    每当列出的信号之一发生更改时,都会对过程进行评估。因此,此列表称为"敏感性列表"。

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

    第一种只需要灵敏度列表中的时钟信号,后一种则需要右手边的信号,否则仿真将显示除实际硬件以外的其他结果。

    因此,每次输入信号发生变化('event = true)时,都会根据begin ... end process评估过程。

    因此,对于DEFAULT部分,每个信号都会获得默认值,并且不可能以这种编码方式生成锁存器。通常,state_next不会设置为空闲。设置为state_reg

    免费翻译:保持当前状态,除非另行通知

    您的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    ...
    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;

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

    解决方案:您的寄存器需要一个使能信号。

    附录:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    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;
    • 谢谢,这样可以解决问题。关于我的代码段,我试图使用update作为启用信号。从到目前为止的测试来看,似乎有些奏效,并且只要更新信号不发生变化,else条件就成立。没有这样的更新信号,如何更新d_nextw_next
    • @eugenewu将使能信号嵌入到edge_edge条件的then分支中。您可以删除最后一个过程。

      本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
      转藏 分享 献花(0

      0条评论

      发表

      请遵守用户 评论公约

      类似文章 更多