views:

60

answers:

3

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?

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 comments that code improve this simple FSM!

+1  A: 

With inouts its better to split it up right at the top level into two signals data_from_outside and data_to_outside. Then your lower level needs three elements on the entity, one input vector, one output vector and a signal to say when to drive the outside data. Bidirectional signals don't sit well with records either.

The top level then needs to do:

data_pins <= data_to_outside when data_to_outside_enable = '1' else (others => 'Z');
data_from_outside <= data_pins;

From the point of view of style: put everything in one process. There's some debate about this, but many respected posters on comp.arch.fpga and comp.lang.vhdl are of this opinion.

Martin Thompson
A: 

Also, you used a signal assignment symbol <= a few times when you really need a variable assignment :=.

So, you want to write

v.f := a;

for assigning value a to field of variable v, and

s <= a;

to assign a to signal or port s.

Philippe
A: 

Hi Robert

I would side with Martin on this.

Leave the bi-directionality at the top level, and then all the logic below that see two buses, an input bus and an output bus.

The input bus is always the same as the bi-directional data bus.

The bi-directional data bus then gets assigned the output bus when output is valid, and Z when it is not valid.

The Z will be overridden by the actual input state of the bus.

George