VHDL FSM设置单元输入并使用相同状态的输出

时间:2013-04-27 23:30:07

标签: vhdl fsm

我正在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;

第一条评论启发了更多细节:

内存可以在激活相同周期启用时读取数据,如下所示:Post-Place and Route Simulation 注意“1”(启用时的值被激活)实际上是如何写入内存的。

不幸的是,这段代码是在异步过程中!虽然我非常强烈地想要转向单一过程描述。

与我迄今为止设计的所有电路相比,我很难通过仿真测试它。这是我大学的一个项目,我们将vhdl程序下载到xilinx spartan 3 FPGA。这一次,我们得到了一个在Matlab和FPGA的SRAM之间传输数据的单元(其功能,我不知道)。因此,我必须使用此单元在SRAM和我的内存模块之间传输数据。这意味着,为了模拟,我的testbench文件必须模拟给定的单位!这很难......但是我必须尝试一下,但是......

1 个答案:

答案 0 :(得分:2)

首先,是使用单个进程还是双进程类型的FSM表示法是一个偏好问题(或公司编码样式规则)。我发现单个进程表示法更容易编写/读取/管理。

只有在下一个时钟上升沿之后,启用信号才会对内存代码产生影响。因此,在更新启用后的一个时钟周期内,与实际存储器状态相关的完成信号将可用。我想(并且希望!但是在你发布的代码中看不到它),你的 current_state&lt; = next_state 部分是同步的!因此,更新完成后,状态机将处于SRAM_wait_read状态!

顺便说一下:使用模拟器!它将有助于检查功能!


感谢您添加模拟视图!奇怪的是你的完成信号更新了neg。时钟边缘...在我的模拟中它更新了pos。边缘;顺便说一下! enter image description here

为了使情况更加清晰我建议你在“rising_edge-if”中移动 done&lt; = done_buf; 行(这在使用同步进程时无论如何都应该完成!)。< / p>