FSM Problem with inout signal

R

Rob Tercher

Guest
Hi all,

I have a very simple FSM which should drive some output signals of an
external RAM. The problem that I have comes with handling the data bus
which can be input as well as output... I am not too sure how I can handle
best this case in my FSM. The problem comes from the following line:

v.sram_data <= io_sram_data;

Obviously, the left hand side is a variable while the right hand side is
a signal. Is there a "nice" way how to handle inout signals in a FSM as
the one I have?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity sram_fsm is
port (
clk : in std_logic;
reset : in std_logic;
out_sram_rd : out std_logic;
out_sram_wr : out std_logic;
out_sram_addr : out std_logic_vector(3 downto 0);
io_sram_data : inout std_logic_vector(7 downto 0)

);
end;

architecture Behavioral of sram_fsm is

type state_type is (wr_init, wr_data, rd_init, rd_data);

type reg_type is record
state : state_type;
sram_data : std_logic_vector(7 downto 0);
sram_addr : std_logic_vector(3 downto 0);
sram_rd : std_logic;
sram_wr : std_logic;
end record;

signal r, rin : reg_type;

begin

comb : process (r)
variable v : reg_type;
begin
v := r;

case r.state is
when wr_init =>
v.sram_data := "00000000";
v.sram_addr := "0000";
v.sram_rd := '0';
v.sram_wr := '0';
v.state := wr_data;
when wr_data =>
io_sram_data <= "00001000";
v.sram_wr := '1';
v.state := rd_init;
when rd_init =>
v.sram_addr := "0000";
v.sram_rd := '1';
v.sram_wr := '0';
v.state := wr_data;
when rd_data =>
v.sram_data <= io_sram_data;
v.state := wr_init;
end case;

out_sram_addr <= v.sram_addr;
out_sram_rd <= v.sram_rd;
out_sram_wr <= v.sram_wr;

rin <= v;

end process;

regs : process (reset, clk)
begin
if reset = '0' then
r.state <= wr_init;
elsif rising_edge(clk) then
r <= rin;
end if;
end process;

end Behavioral;

Many thanks for your inputs!
 
On Oct 13, 8:33 pm, Rob Tercher <R...@yahoo.com> wrote:
Hi all,

I have a very simple FSM which should drive some output signals of an
external RAM. The problem that I have comes with handling the data bus
which can be input as well as output... I am not too sure how I can handle
best this case in my FSM. The problem comes from the following line:

v.sram_data <= io_sram_data;

Obviously, the left hand side is a variable while the right hand side is
a signal. Is there a "nice" way how to handle inout signals in a FSM as
the one I have?

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

entity sram_fsm is
   port (
     clk                       : in std_logic;
     reset                     : in std_logic;
      out_sram_rd           : out std_logic;
      out_sram_wr           : out std_logic;
     out_sram_addr       : out std_logic_vector(3 downto 0);
     io_sram_data        : inout std_logic_vector(7 downto 0)

   );
end;

architecture Behavioral of sram_fsm is

    type state_type is (wr_init, wr_data, rd_init, rd_data);

    type reg_type is record
      state       : state_type;
       sram_data   : std_logic_vector(7 downto 0);
      sram_addr   : std_logic_vector(3 downto 0);
      sram_rd     : std_logic;
       sram_wr     : std_logic;
    end record;

     signal r, rin : reg_type;

begin

    comb : process (r)
    variable v : reg_type;
     begin
       v := r;

       case r.state is
         when wr_init =
            v.sram_data    := "00000000";
             v.sram_addr    := "0000";
             v.sram_rd      := '0';
             v.sram_wr      := '0';
             v.state        := wr_data;
            when wr_data =
              io_sram_data <= "00001000";
          v.sram_wr      := '1';
             v.state        := rd_init;
         when rd_init =
              v.sram_addr   := "0000";
              v.sram_rd     := '1';
              v.sram_wr     := '0';
              v.state       := wr_data;
         when rd_data =
             v.sram_data <= io_sram_data;
           v.state       := wr_init;
        end case;

     out_sram_addr <= v.sram_addr;
     out_sram_rd <= v.sram_rd;
     out_sram_wr <= v.sram_wr;

      rin <= v;

    end process;

     regs : process (reset, clk)
     begin
       if reset = '0' then
           r.state <= wr_init;
       elsif rising_edge(clk) then
          r <= rin;
       end if;
    end process;

end Behavioral;

Many thanks for your inputs!
One way...
Add the statement io_sram_data <= (others => 'Z')' as a default
statement at the begining of your process.

Another way...
1. Define some internal signals
signal io_sram_data_int: std_logic_vector(io_sram_data'range);
signal Output_Enable: std_ulogic;

2. Within your state machine, drive the signal io_sram_data_int rather
than io_sram_data;
3. Add the following
io_sram_data <= io_sram_data_int when (Output_Enable = '1') else
(others => 'Z');
where you then have to define the logic for when Output_Enable where
it is active when you want to drive it

I'd also suggest not using combinatorial processes, use a synchronous
process and concurrent statements.

Kevin Jennings
 
While I greatly prefer single, clocked processes over separate clocked
and combinatorial ones, here is how you can fix what you have:

Add io_sram_data to the sensitivity list for your comb process.

After the "v := r;" statement, before anything else, insert;

io_sram_data <= (others => 'Z');

This does two things.

First, it avoids a latch because you had many states where you did not
assign io_sram_data, and in your combinatorial process, failing to
assign a value to a signal will get you a latch. By making sure you
always drive it with something, it will eliminate any chance of a
latch. This is just one of the reasons I don't like split combo/
clocked processes.

Second, it defaults to driving the output to high-Z, unless you drive
it with data when in a specific state(s). Driving the output to Z
allows whatever is on the outside of the device to drive it's value,
and for your statemachine to see that value on the signal. The
synthesis tool will create the tri-state drivers and enables for them.

Other reasons I prefer single, clocked process descriptions:

It allows you to use local variables and actually "hide" data to keep
it local and free from external interference. By keeping local things
local, it isolates changes to that local data (state definitions,
etc.) from other processes that may depend on it being a certain way
you once defined it. I'm not really sure why you used a variable,
since you still have to transfer the data to/from external signals to
interact with the clocked process.

It avoids latches.

It avoids splitting reset or clock enable functionality into a
separate process from the rest of the logic.

It avoids duplicate signal declarations and assignments.

It avoids issues with incomplete sensitivity lists.

Hope this helps,

Andy
 

Welcome to EDABoard.com

Sponsor

Back
Top