VHDL 2 进程状态机和输出初始化
VHDL 2 process state machine and output initialization
所以Altera提供了一个2进程状态机的例子a this link.
我有点喜欢这种风格,但我不明白的是,如果 'input' 保持在 '0',则永远不会触发第二个进程,因为状态永远不会改变,并且 'output'因此从未分配或初始化......或者是吗?
我的理解是,敏感度列表信号之一(本例中的 'state')需要进行转换,这在此处永远不会发生。
有人可以澄清一下这是怎么回事吗?
代码如下:
ENTITY state_machine IS
PORT(
clk : IN STD_LOGIC;
input : IN STD_LOGIC;
reset : IN STD_LOGIC;
output : OUT STD_LOGIC_VECTOR(1 downto 0));
END state_machine;
ARCHITECTURE a OF state_machine IS
TYPE STATE_TYPE IS (s0, s1, s2);
SIGNAL state : STATE_TYPE;
BEGIN
PROCESS (clk, reset)
BEGIN
IF reset = '1' THEN
state <= s0;
ELSIF (clk'EVENT AND clk = '1') THEN
CASE state IS
WHEN s0=>
IF input = '1' THEN
state <= s1;
ELSE
state <= s0;
END IF;
WHEN s1=>
IF input = '1' THEN
state <= s2;
ELSE
state <= s1;
END IF;
WHEN s2=>
IF input = '1' THEN
state <= s0;
ELSE
state <= s2;
END IF;
END CASE;
END IF;
END PROCESS;
PROCESS (state)
BEGIN
CASE state IS
WHEN s0 =>
output <= "00";
WHEN s1 =>
output <= "01";
WHEN s2 =>
output <= "10";
END CASE;
END PROCESS;
END a;
编辑:
澄清一下,我的问题是:在我看来 'output' 将处于未定义状态,直到 'input' 转换为“1”。考虑到这是 Altera 的官方示例,这不是不好的做法吗?
顺便说一下,在这里初始化 'output' 的正确方法是什么?使用异步重置 ?
...it looks to me that 'output' will be in a undefined state until
'input' transitions to '1'.
否(见下文)。在模拟开始时,output
将立即取值 "00"
,即使复位未断言并且 input
.
上没有转换也是如此
Isn't that bad practice, considering this is an official example from
Altera ?
不,这段代码没问题。由于重置,状态寄存器 (state
) 可以正确初始化,并且 output
组合取决于 state
。该模型在仿真和硬件中都将按预期运行。
And by the way, what would be the proper way of initializing 'output'
here ? With async reset ?
您不使用重置来初始化组合的输出。复位(异步或同步)用于初始化寄存器(state
,在您的示例中)。
敏感度列表只是语法糖。具有敏感列表的进程等效于相同的进程,没有敏感列表,并且具有 wait on <sensitivity-list>;
作为 last 语句。示例:
PROCESS (state)
BEGIN
CASE state IS
WHEN s0 =>
output <= "00";
WHEN s1 =>
output <= "01";
WHEN s2 =>
output <= "10";
END CASE;
END PROCESS;
相当于:
PROCESS
BEGIN
CASE state IS
WHEN s0 =>
output <= "00";
WHEN s1 =>
output <= "01";
WHEN s2 =>
output <= "10";
END CASE;
WAIT ON state;
END PROCESS;
因此,这个进程(和所有进程一样)在模拟开始时被触发,并为 output
赋值。在您的特定情况下,此值将为 "00"
,因为 state
的初始值是其枚举类型的最左边的值,即 s0
。总而言之,output
被初始化为 "UU"
(U
是枚举类型最左边的值 std_logic
),并且在第一个模拟步骤之后(在 T=0 时) , 它取值 "00"
.
注意:这段代码很好,很好地代表了摩尔状态机的编码(不是 Mealy,正如其他答案所说:输出仅取决于当前状态)。但它有(至少)两个小问题:
- 它对单驱动信号使用
std_logic
解析类型,这不是一个好主意。 std_ulogic
和 std_ulogic_vector
会更好也更安全。
- 它使用名称
input
和 output
,虽然不是语言的保留字,但应避免:它们是 std.textio
中定义的标准输入和输出流。
所以Altera提供了一个2进程状态机的例子a this link.
我有点喜欢这种风格,但我不明白的是,如果 'input' 保持在 '0',则永远不会触发第二个进程,因为状态永远不会改变,并且 'output'因此从未分配或初始化......或者是吗?
我的理解是,敏感度列表信号之一(本例中的 'state')需要进行转换,这在此处永远不会发生。
有人可以澄清一下这是怎么回事吗?
代码如下:
ENTITY state_machine IS
PORT(
clk : IN STD_LOGIC;
input : IN STD_LOGIC;
reset : IN STD_LOGIC;
output : OUT STD_LOGIC_VECTOR(1 downto 0));
END state_machine;
ARCHITECTURE a OF state_machine IS
TYPE STATE_TYPE IS (s0, s1, s2);
SIGNAL state : STATE_TYPE;
BEGIN
PROCESS (clk, reset)
BEGIN
IF reset = '1' THEN
state <= s0;
ELSIF (clk'EVENT AND clk = '1') THEN
CASE state IS
WHEN s0=>
IF input = '1' THEN
state <= s1;
ELSE
state <= s0;
END IF;
WHEN s1=>
IF input = '1' THEN
state <= s2;
ELSE
state <= s1;
END IF;
WHEN s2=>
IF input = '1' THEN
state <= s0;
ELSE
state <= s2;
END IF;
END CASE;
END IF;
END PROCESS;
PROCESS (state)
BEGIN
CASE state IS
WHEN s0 =>
output <= "00";
WHEN s1 =>
output <= "01";
WHEN s2 =>
output <= "10";
END CASE;
END PROCESS;
END a;
编辑: 澄清一下,我的问题是:在我看来 'output' 将处于未定义状态,直到 'input' 转换为“1”。考虑到这是 Altera 的官方示例,这不是不好的做法吗? 顺便说一下,在这里初始化 'output' 的正确方法是什么?使用异步重置 ?
...it looks to me that 'output' will be in a undefined state until 'input' transitions to '1'.
否(见下文)。在模拟开始时,output
将立即取值 "00"
,即使复位未断言并且 input
.
Isn't that bad practice, considering this is an official example from Altera ?
不,这段代码没问题。由于重置,状态寄存器 (state
) 可以正确初始化,并且 output
组合取决于 state
。该模型在仿真和硬件中都将按预期运行。
And by the way, what would be the proper way of initializing 'output' here ? With async reset ?
您不使用重置来初始化组合的输出。复位(异步或同步)用于初始化寄存器(state
,在您的示例中)。
敏感度列表只是语法糖。具有敏感列表的进程等效于相同的进程,没有敏感列表,并且具有 wait on <sensitivity-list>;
作为 last 语句。示例:
PROCESS (state)
BEGIN
CASE state IS
WHEN s0 =>
output <= "00";
WHEN s1 =>
output <= "01";
WHEN s2 =>
output <= "10";
END CASE;
END PROCESS;
相当于:
PROCESS
BEGIN
CASE state IS
WHEN s0 =>
output <= "00";
WHEN s1 =>
output <= "01";
WHEN s2 =>
output <= "10";
END CASE;
WAIT ON state;
END PROCESS;
因此,这个进程(和所有进程一样)在模拟开始时被触发,并为 output
赋值。在您的特定情况下,此值将为 "00"
,因为 state
的初始值是其枚举类型的最左边的值,即 s0
。总而言之,output
被初始化为 "UU"
(U
是枚举类型最左边的值 std_logic
),并且在第一个模拟步骤之后(在 T=0 时) , 它取值 "00"
.
注意:这段代码很好,很好地代表了摩尔状态机的编码(不是 Mealy,正如其他答案所说:输出仅取决于当前状态)。但它有(至少)两个小问题:
- 它对单驱动信号使用
std_logic
解析类型,这不是一个好主意。std_ulogic
和std_ulogic_vector
会更好也更安全。 - 它使用名称
input
和output
,虽然不是语言的保留字,但应避免:它们是std.textio
中定义的标准输入和输出流。