我正在vhdl中实现Mealy类型的FSM。我目前正在使用双重过程,虽然我刚读过单个过程可能更整洁。考虑一下你答案的参数。
问题的简短版本是:我可以有一个状态,其中另一个组件的输入被更改,并且,在相同的状态下,使用所述组件的输出?这是安全还是竞争激烈?我应该使用组件的输出创建另一个状态?
长版:我有一个内存模块。这是一个fifo内存,激活其复位信号会将名为queue_pointer的变量带到其第一个元素。写入存储器后,指针会增加,如果超出范围,它(然后也)复位到第一个元素,并且输出信号 done 被激活。顺便说一下,我将这个组件称为FIMEM。
我的FSM首先编写整个FIMEM,然后转向其他事项。最后一次写作将从州完成:
when SRAM_read =>
READ_ACK <= '1';
FIMEM_enable <= '1';
FIMEM_write_readNEG <= '0';
if(FIMEM_done = '1') then --is that too fast? if so, we're gonna have to add another state
FIMEM_reset <= '1'; --this is even faster, will need check
data_pipe_to_FOMEM := DELAYS_FIMEM_TO_FOMEM;
next_state <= processing_phase1;
else
SRAM_address := SRAM_address + 1;
next_state <= SRAM_wait_read;
end if;
在此状态下,启用和写入活动意味着数据将写入FIMEM。如果这是内存中的最后一个数据空间,FIMEM_done将激活,if中的大块代码将处理未来。但是,还有足够的时间吗?如果没有,并且下一个状态进入SRAM_wait_read,然后FIMEM_done被激活,则会出现问题。事实上FIMEM是完全同步的(虽然我的代码的这部分是在异步过程中)会更加混乱吗?
这是我的记忆代码,以防万一:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity memory is
generic (size: positive := 20);
Port ( clk,
reset,
enable,
write_readNEG: in std_logic;
done: out std_logic;
data_in: in STD_LOGIC_VECTOR(7 downto 0);
data_out: out STD_LOGIC_VECTOR(7 downto 0) );
end memory;
architecture Behavioral of memory is
subtype word is STD_LOGIC_VECTOR(7 downto 0);
type fifo_memory_t is array (0 to size-1) of word;
signal fifo_memory : fifo_memory_t :=((others=> (others=>'0')));
--Functionality instructions:
--Resetting sets the queue pointer to the first element, and done to 0
--Each cycle with enable active, a datum from the pointer position is
--written/read according to write_readNEG, and the pointer is incremented.
--If the operation was at the last element, the pointer returns to the first place
--and done is set to 1. When done is 1, enable is ignored.
Begin
process(clk,reset)
variable done_buf : std_logic;
variable queue_pointer: natural range 0 to size-1;
begin
if(reset = '1') then
queue_pointer := 0;
done_buf := '0';
elsif(rising_edge(clk)) then
if(done_buf = '0' and enable = '1') then
case write_readNEG is
when '0' =>
data_out <= fifo_memory(queue_pointer);
when '1' =>
fifo_memory(queue_pointer) <= data_in;
when others => null;
end case;
if(queue_pointer = size-1) then
done_buf := '1';
queue_pointer := 0;--check
else
queue_pointer := queue_pointer + 1;
end if;
end if; --enable x not done if
end if; --reset/rising edge end if
done <= done_buf;
end process;
End Behavioral;
第一条评论启发了更多细节:
内存可以在激活相同周期启用时读取数据,如下所示: 注意“1”(启用时的值被激活)实际上是如何写入内存的。
不幸的是,这段代码是在异步过程中!虽然我非常强烈地想要转向单一过程描述。
与我迄今为止设计的所有电路相比,我很难通过仿真测试它。这是我大学的一个项目,我们将vhdl程序下载到xilinx spartan 3 FPGA。这一次,我们得到了一个在Matlab和FPGA的SRAM之间传输数据的单元(其功能,我不知道)。因此,我必须使用此单元在SRAM和我的内存模块之间传输数据。这意味着,为了模拟,我的testbench文件必须模拟给定的单位!这很难......但是我必须尝试一下,但是......
答案 0 :(得分:2)
首先,是使用单个进程还是双进程类型的FSM表示法是一个偏好问题(或公司编码样式规则)。我发现单个进程表示法更容易编写/读取/管理。
只有在下一个时钟上升沿之后,启用信号才会对内存代码产生影响。因此,在更新启用后的一个时钟周期内,与实际存储器状态相关的完成信号将可用。我想(并且希望!但是在你发布的代码中看不到它),你的 current_state&lt; = next_state 部分是同步的!因此,更新完成后,状态机将处于SRAM_wait_read状态! 顺便说一下:使用模拟器!它将有助于检查功能!感谢您添加模拟视图!奇怪的是你的完成信号更新了neg。时钟边缘...在我的模拟中它更新了pos。边缘;顺便说一下!
为了使情况更加清晰我建议你在“rising_edge-if”中移动 done&lt; = done_buf; 行(这在使用同步进程时无论如何都应该完成!)。< / p>