Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
17 years ago

When to deassert a signal?

I have a problem where I need to check a bit stream to see if it matches a certain pattern. When I find, the pattern, I need to start doing something with the remaining bits until a valid signal is deasserted. Then I need to start everything over again. I'm having trouble figuring out the order in which to do things to make sure it all works right


library ieee;
use ieee.std_logic_1164.all;
entity FrameHolder2 is
	port
	(
		clk,reset: in std_logic;
		input: in std_logic;
		valid: in std_logic;
		output: out std_logic
	);
end FrameHolder2;
architecture structure of FrameHolder2 is
	signal prehold: std_logic_vector(63 downto 0);
	signal start: std_logic;
	
	component rshift8bit is
	PORT
	(
		aclr		: IN STD_LOGIC ;
		clock		: IN STD_LOGIC ;
		enable		: IN STD_LOGIC ;
		shiftin		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (63 DOWNTO 0)
	);
	end component;
	
	stage0: rshift8bit port map(reset,clk,not start,input,prehold);
	--stage1: buffer data in somewhere port map(reset,clk,start and valid,input,something);
	
start <= '1' when prehold = "1101010101010101010101010101010101010101010101010101010101010101" else '0';
--store data somewhere when start = '1' and valid = '0';
end structure;

When valid goes to '0', I need start to go to 0 but I can't just add a "and valid ='0'" to start's when clause because valid might not be '1' right away. I need start to go to 0 when valid goes from 1 to 0. How do I do that?

10 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    When valid goes to '0', I need start to go to 0 but I can't just add a "and valid ='0'" to start's when clause because valid might not be '1' right away. I need start to go to 0 when valid goes from 1 to 0. How do I do that?

    --- Quote End ---

    You need to create a falling edge detector for the valid signal.

    process (clk, reset) begin
    if (reset ='1') then
       reg <= '0';
    elsif (clk'event and clk='1') then
       reg <= valid;   
    end if;
    --falling edge detect. This produces a one clk wide pulse when valid goes from '1' to '0'
    valid_fe <= reg and not valid;
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I'm not sure I understand how this works. To me it looks like you're checking for valid and not valid at the same time

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Ok, I think I understand how it should work, but I don't understand why it still doesn't work. The process statement makes it so that the reg stores the value of valid, and then you're comparing the old value of valid with the new value of valid so you detect the falling edge. Here's how I tried to implement it, but it doesn't work:

    
    library ieee;
    use ieee.std_logic_1164.all;
    --This file is responsible for reading in frames and storing them
    entity FrameHolder2 is
    	port
    	(
    		clk,reset: in std_logic;--clock and reset inputs
    		input: in std_logic;--the serial input on which the ethernet frames arrive
    		valid: in std_logic;--the valid signal which lets us know when an ethernet frame is valid
    		startout: out std_logic;--a test output to let us trace when we are storing ethernet information
    		storeout: out std_logic;--a test output to let us know when we would commit the stored data
    		output: out std_logic--the output ethernet stream
    	);
    end FrameHolder2;
    architecture structure of FrameHolder2 is
    	signal prehold: std_logic_vector(63 downto 0);--holds the preamble
    	signal start: std_logic;--lets us know if we're ready to start storing the ethernet frame
    	signal reg: std_logic;--temporary register to help detect when valid goes to '0'
    	signal valid_fe: std_logic;--valid falling edge, lets us know when valid goes to '0' from '1'
    	
    	component rshift8byte is --8 byte right shift register for holding onto the preamble
    	PORT
    	(
    		aclr		: IN STD_LOGIC ;
    		clock		: IN STD_LOGIC ;
    		enable		: IN STD_LOGIC ;
    		shiftin		: IN STD_LOGIC ;
    		q		: OUT STD_LOGIC_VECTOR (63 DOWNTO 0)
    	);
    	end component;
    begin	
    	process (clk, reset) 
    	begin
    	if (reset ='1') then
    		reg <= '0';
    	elsif (clk'event and clk='1') then
    		reg <= valid;   --this detects when valid goes from '1' to '0'
    	end if;
    	end process;
    	stage0: rshift8byte port map(reset,clk,not start,input,prehold);
    	
    valid_fe <= '1' when reg = '1' and valid = '0'; --detects when valid goes from '1' to '0', we need to do this 
    --because valid goes high at some point during the preamble, and goes low when the frame is received.
    --We need to know when we are done receiving a frame and this occurs on the falling edge of valid.
    start <= '1' when prehold = "1101010101010101010101010101010101010101010101010101010101010101" and valid_fe = '0' else '0';--start storing the ethernet frame until we get a falling edge of valid
    storeout <= '1' when valid_fe = '1';
    startout <= start;
    end structure;
    

    Thanks for the help
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    valid_fe <= '1' when reg = '1' and valid = '0'; --detects when valid goes from '1' to '0'

    --- Quote End ---

    You cannot do this. This creates a latch which is very bad.

    valid_fe <= '1' when (reg = '1' and valid = '0') else '0';

    You must have and else in a 'when' statement or else you end up with a latch. The compiler/synthesizer doesn't know how to assign "valid_fe" when the statement is false.

    There is another part of your code which does the same thing. This needs to be fixed as well.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I'm also assuming the VALID signal is synchronous to the CLK clock domain. If not you need to synchronize it first.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    --- Quote Start ---

    I'm also assuming the VALID signal is synchronous to the CLK clock domain. If not you need to synchronize it first.

    --- Quote End ---

    Valid is an input. I'm not sure what you mean by, is it synchronous. I assume it is.

    Here's what ended up working:

    
    library ieee;
    use ieee.std_logic_1164.all;
    --This file is responsible for reading in frames and storing them
    entity FrameHolder2 is
    	port
    	(
    		clk,reset: in std_logic;--clock and reset inputs
    		input: in std_logic;--the serial input on which the ethernet frames arrive
    		valid: in std_logic;--the valid signal which lets us know when an ethernet frame is valid
    		startout: out std_logic;--a test output to let us trace when we are storing ethernet information
    		storeout: out std_logic;--a test output to let us know when we would commit the stored data
    		output: out std_logic--the output ethernet stream
    	);
    end FrameHolder2;
    architecture structure of FrameHolder2 is
    	signal prehold: std_logic_vector(63 downto 0);--holds the preamble
    	signal start: std_logic;--lets us know if we're ready to start storing the ethernet frame
    	signal reg: std_logic;--temporary register to help detect when valid goes to '0'
    	signal valid_fe: boolean;--valid falling edge, lets us know when valid goes to '0' from '1'
    	
    	component rshift8byte is --8 byte right shift register for holding onto the preamble
    	PORT
    	(
    		aclr		: IN STD_LOGIC ;
    		clock		: IN STD_LOGIC ;
    		enable		: IN STD_LOGIC ;
    		shiftin		: IN STD_LOGIC ;
    		q		: OUT STD_LOGIC_VECTOR (63 DOWNTO 0)
    	);
    	end component;
    begin	
    	process (clk, reset) 
    	begin
    	if (reset ='1') then
    		reg <= '0';
    	elsif (clk'event and clk='1') then
    		reg <= valid;   --this detects when valid goes from '1' to '0'
    	end if;
    	end process;
    	stage0: rshift8bit port map(reset,clk,not start,input,prehold);
    	--stage1: something port map(reset,clk,start and valid,input,something);
    	
    valid_fe <= reg='1' and valid='0'; --detects when valid goes from '1' to '0', we need to do this 
    --because valid goes high at some point during the preamble, and goes low when the frame is received.
    --We need to know when we are done receiving a frame and this occurs on the falling edge of valid.
    start <= '1' when prehold = "1101010101010101010101010101010101010101010101010101010101010101" and not valid_fe else '0';--start storing the ethernet frame until we get a falling edge of valid
    storeout <= '1' when valid_fe else '0';
    startout <= start;
    end structure;
    

    I'm using valid_fe as a boolean in this case
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Im not sure I like this statement:

    
    start <= '1' when prehold = "1101010101010101010101010101010101010101010101010101010101010101" and not valid_fe else '0';--start storing the ethernet frame until we get a falling edge of valid
    
    You have 64 elements in a single gate. This would be very slow when it's put into real hardware, and likely prone to setup time violations.

    Instead of using a shift register, it might be better (and probably cheaper logic wise) to use a state machine to watch the incoming bit-stream, and when the correct stream appears, put it into a "start" state, or fire off a start signal.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    no you shouldnt.

    You could hold the sequence in a small rom and use a counter to address it so you do something like this and be able to run alot faster (ie faster clock):

    
    .......
      constant WORD_TO_LOOK_FOR : std_logic_vector := "1101010101010101010101010101010101010101010101010101010101010101";
      signal rom_addr : integer range 0 to WORD_TO_LOOK_FOR'length-1;
      type state_t is (wait_for_start, collecting_word);
      signal state : state_t;
    begin
    ...
    process(clk, reset)
    begin
      if reset = '1' then
        state <= wait_for_start;
        rom_addr <= 0;
        start <= '0';
        
      elsif rising_edge(clk) then
        
        start <= '0';
        case state is
          when wait_for_start => 
            
            if valid = '1' then
              if input = WORD_TO_LOOK_FOR(0) then
                rom_addr <= rom_addr + 1;
                state <= collecting_word
                
              else
                state <= wait_for_start;
              end if;
            else
              state <= wait_for_start;
            end if;
              
          when collecting_word =>
            
            if valid = '1' then
              if input = WORD_TO_LOOK_FOR(rom_addr) then
              
                if rom_addr = WORD_TO_LOOK_FOR'length-1 then
                  --got entire word, start something off
                  start <= '1';
                  state <= wait_for_start;
                else
                  
                  --waiting for entire word
                  state <= collecting_word;
                  
                  --address increment - looking for the next bit in sequence
                  rom_addr <= rom_addr + 1;
                end if;
              
              else
                --sequence broken, go back to start
                state <= wait_for_start;
                rom_addr <= 0;
              end if;
            
            else
              
              --hold in this state
              state <= collecting_word;
            end if;
        end case;
      end if;
        
    end process;
              
    

    edit : fixed the addressing.

    edit : also - I may have got the understanding of valid wrong - but I hope you get the gist of what Im trying to do.