Question

I am implementing a Mealy-type FSM in vhdl. I currently am using double process, although i've just read a single-process might be neater. Consider that a parameter of your answer.

The short version of the question is: May I have a state, inside of which the input of another component is changed, and, aftwerwards, in the same state, use an output of said component? Will that be safe or will it be a rat race, and I should make another state using the component's output?

Long version: I have a memory module. This is a fifo memory, and activating its reset signal takes a variable named queue_pointer to its first element. After writing to the memory, the pointer increases and, should it get out of range, it is (then also) reset to the first element, and an output signal done is activated. By the way, i call this component FIMEM.

My FSM first writes the whole FIMEM, then moves on to other matters. The last write will be done from the state:

            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;

At this state, having enable and write active means data will be written on the FIMEM. If that was the last data space on the memory, FIMEM_done will activate, and the nice chunk of code within the if will take care of the future. But, will there be time enough? If not, and next state goes to SRAM_wait_read, and FIMEM_done gets activated then, there will be problems. The fact that FIMEM is totally synchronous (while this part of my code is in the asynchronous process) messes even more?

here's my memory code, just in case:

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;

More details inspired by the first comment:

The memory can read the data at the same cycle enable is activated, as seen here: Post-Place and Route Simulation Notice how the "1", the value when enable is turned active, is actually written into the memory.

Unfortunately, the piece of code is in the asynchronous process! Although I'm VERY strongly thinking of moving to a single-process description.

In contrast to all the circuits I've designed until now, it is very hard for me to test it via simulation. This is a project in my university, where we download our vhdl programs to a xilinx spartan 3 FPGA. This time, we have been given a unit which transfers data between Matlab and the FPGA's SRAM (the functionality of which, I have no idea). Thus, I have to use this unit to transfer the data between the SRAM and my memory module. This means, in order to simulate, my testbench file will have to simulate the given unit! And this is hard..suppose I must try it, though...

Was it helpful?

Solution

first of all, whether to use a single process or a dual process type of FSM notation is a matter of preference (or company coding style rules). I find single process notation easier to write/read/manage.

your enable signal will have an effect on your memory code only after the next rising clock edge. the done signal related to the actual memory state will therefore be available one clock cycle after updating enable. I guess (and hope! but it's not visible in your posted code), your current_state<=next_state part of the FSM is synchronous! therefore your state machine will be in the SRAM_wait_read state by the time when done is updated!

btw: use a simulator! it will help to check the functionality!


thanks for adding the simulation view! strangely your done signal updates on neg. clock edge... in my simulation it updates on pos. edge; as it should, by the way! enter image description here

to make the situation more clear I suggest, you move the done <= done_buf; line inside the "rising_edge-if" (this should be done anyhow when using synchronous processes!).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top