0

シリアル入力に基づいて状態を切り替える有限状態マシンを作成しようとしています。コードの実行方法について説明が必要です。教科書で、「DEFAULT VALUES」とマークしたプロセスのセクションにデフォルト値を配置する必要があることを読みました。ただし、状態を切り替えるたびに、信号はこれらの値をとるようです。たとえば、state_next をデフォルト値の idle に設定します。これを行うと、FSM が理由もなく他の状態からアイドル状態にジャンプし続けます。

もう 1 つの質問は、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;
4

2 に答える 2

2

これは、単一プロセス スタイルの代替バージョンです。

あなたが推測したように、「デフォルト値」はState、明示的に値を設定しなかったときを含めて、物事をリセットしていました。ここでセマンティクスを少し推測しました。文字が InData に複数のサイクルにわたって存在する場合、または別の文字が入ってくる場合はどうなりますか? ただし、ロジックは簡単に変更できる必要があります。

いくつかのメモ:

  1. 何かを書くときはいつでもx <= std_logic_vector(unsigned(y)+250);、おそらく間違った型です。これは、型システムを使用する代わりに、型システムと戦っていることを意味します。d_regの etc 配列を作成Unsignedし、出力への型変換をプログラム フローから除外しました。X <= Y + 250;より明確でシンプルです。
  2. Outこれらのポートはではなくであるべきであり、設計をさらに単純化および明確化するために、InOutそれらを にするように交渉します。Unsigned
  3. スペースはゲートを消費しません。
  4. シングル プロセス スタイルの利点の 1 つは、プロセスを相互接続するために単純に使用され、判断が困難なタイミングで更新されるシグナルが少ないことです。ここで、「更新」は他のすべてと同じクロック エッジで使用されます。
  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;
于 2015-07-22T10:19:42.467 に答える
1

リストされたシグナルの 1 つが変更されるたびに、プロセスが評価されます。したがって、このリストは「感度リスト」と呼ばれます。

プロセスには 2 つのタイプがあり
ます

最初のタイプは感度リストのクロック信号のみを必要とし、後者はすべての右側の信号を必要とします。それ以外の場合、シミュレーションは実際のハードウェア以外の結果を示します。

したがって、入力信号が変化するたびに (<signal>'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 式では使用しないでください。次に、else 条件が真になるのはいつですか。

解決策: レジスターの有効化信号が必要です。

補遺:

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;
于 2015-07-21T20:15:39.147 に答える