Forum Discussion

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

Takes too long to get address

I'm writing a simple program that reads and writes to RAM. If I want to write, I provide the starting address and a valid signal and I write to memory starting at that address until valid is deasserted. If I want to read, I provide a starting address and a readEn signal and I read from memory starting at that address until readEn is deasserted. The problem is that for some reason, the way I'm incrementing starting addresses takes an extra clock cycle and I can't figure out why.


library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all; 
entity framestore is
	port
	(
		clk,reset : in std_logic;
		input: in std_logic_vector(3 downto 0);
		valid: in std_logic;
		readEN: in std_logic;
		rwaddressstart: in std_logic_vector(14 downto 0);
		output : out std_logic_vector(3 downto 0);
		addressout: out std_logic_vector(14 downto 0);
		holdout: out std_logic_vector(3 downto 0)
	);
end framestore;
architecture structure of framestore is
	signal hold: std_logic_vector(3 downto 0);
	signal address: std_logic_vector(14 downto 0);
	signal tempvalid: std_logic;
	signal tempread: std_logic;
	signal readEn_RE: boolean;
	signal valid_RE: boolean;
	
	component ram4bits is
	PORT
	(
		address		: IN STD_LOGIC_VECTOR (14 DOWNTO 0);
		clock		: IN STD_LOGIC  := '1';
		data		: IN STD_LOGIC_VECTOR (3 DOWNTO 0);
		wren		: IN STD_LOGIC ;
		q		: OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
	);
	end component;
begin	
	process(clk,reset,valid,readEn)
	begin
		if(reset = '1') then
			address <= "000000000000000";
		elsif(clk'event and clk = '1') then
			tempread <= readEn;
			tempvalid <= valid;
			if(valid_RE or readEn_RE) then
				address <= rwaddressstart;
			elsif(valid = '1' or readEn = '1') then
				address <= address + '1';
			end if;
		end if;
	end process;
	
	store: ram4bits port map(address,clk,input,valid,hold);
	
	readEn_RE <= tempread <= '0' and readEn = '1';
	valid_RE <= tempvalid <= '0' and valid = '1';
	output <= hold when readEn = '1' else "0000";
	
	addressout <= address;
	holdout <= hold;
	
end structure;

The problem is that this code I think happens a cycle too late:


			if(valid_RE or readEn_RE) then
				address <= rwaddressstart;

18 Replies

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

    --- Quote Start ---

    My input and valid appear to arrive at exactly the same time

    --- Quote End ---

    Yes. Now input is one clock cycle too early.

    In my opinion, you have added more confusion with the edge detection working on both clock edges. It doesn't seem correct the way you're doing it.

    Personally, I would proceed like this:

    - determine if all input signals are clock synchronous, otherwise provide synchronisation registers

    - sketch a timing diagram of existing input signals and expected/intended design reactions

    - check if it's feasible considering the used IP, in this case the RAM block

    - use a synchronous, single clock edge process as design basic
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    The valid signal and the input are synchronous. When the valid signal arrives, that's when I want to start writing to memory. I can't just make my input one cycle delayed because my input shows up with the valid signal. I'll go back to one edge sensitivity. I just would like to figure out how I can have valid and input line up as they are, and have it still work.

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

    I've simplified the code a little bit to hopefully make some things happen faster/cleaner but it still misses that first value.

    
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_arith.all;
    use ieee.std_logic_unsigned.all; 
    entity framestore is
    	port
    	(
    		clk,reset : in std_logic;
    		input: in std_logic_vector(3 downto 0); -- the input ethernet frame
    		valid: in std_logic; --valid signal that comes with input
    		readEN: in std_logic; --high when we want to read from memory
    		rwaddressstart: in std_logic_vector(14 downto 0); --address where we want to START reading or writing
    		output : out std_logic_vector(3 downto 0); --output, has value if we're reading
    		addressout: out std_logic_vector(14 downto 0); --test signal to tell us the address
    		holdout: out std_logic_vector(3 downto 0) --test signal to tell us what's being read out of memory
    	);
    end framestore;
    architecture structure of framestore is
    	signal hold: std_logic_vector(3 downto 0);
    	signal address: std_logic_vector(14 downto 0);
    	signal reg: std_logic;
    	
    	component ram4bits is
    	PORT
    	(
    		address		: IN STD_LOGIC_VECTOR (14 DOWNTO 0);
    		clock		: IN STD_LOGIC  := '1';
    		data		: IN STD_LOGIC_VECTOR (3 DOWNTO 0);
    		wren		: IN STD_LOGIC ;
    		q		: OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
    	);
    	end component;
    begin	
    	process(clk,reset,valid,readEn)
    	begin
    		if(reset = '1') then
    			address <= "000000000000000";
    			reg <= '0';
    		elsif(clk'event and clk = '1') then
    			reg <= valid; --register the valid signal, don't know if this is necessary, we could just use the valid signal probably
    			if(valid = '0' and readEn ='0') then
    				address <= rwaddressstart;
    			elsif(valid = '1' or readEn = '1') then -- if it's not a rising edge, just start adding 1 to the address
    				address <= address + '1';
    			end if;
    		end if;
    	end process;
    	
    	store: ram4bits port map(address => address,clock => clk,data => input,wren => reg,q=>hold);
    	
    	output <= hold when readEn = '1' else "0000"; --self explanatory
    	
    	--test signals
    	addressout <= address;
    	holdout <= hold;
    	
    end structure;
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    dont register valid anymore.

    On a side note - the waveform you have provided just doesnt look right. Addressout is very glitchy, but it should be the same as address, which is clearly isnt, or is the addressout in the diagram another address out?
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    addressout is the only address in the system, not sure why its glitchy. Taking out the register for valid resulted in my finally being able to see the first 4 bits of my input signal! Now the weird part is, it produces the first 4bits on the output for 2 clock cycles and all of the other following ones are only on it for 1! Sorry if I've been saying byte before, I forgot that everything is 4 bits wide.

    Here's a trace:

    http://img143.imageshack.us/img143/2103/37447525.png

    Thanks guys, I think I'm close
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Do you think the reason it holds the first value for 2 cycles has to do with how address is assigned and incremented? Maybe I need to assign and increment address in the first step?

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

    I previously mentioned, that you have also the option to register none of the RAM block input signals, because they are already registered in the RAM. This would be my preferred method to achieve a fast design reaction.

      process(clk,reset)
      begin
        if(reset = '1') then
          next_addr <= (others => '0'); -- not actually required
          cont <= '0';
        elsif(clk'event and clk = '1') then
          cont <= valid OR readEn;
          next_addr <= address + '1';
        end if;
      end process;
      
      store: ram4bits port map(address => address,clock => clk,data => input,wren => valid,q=>hold);
      address <= next_addr WHEN cont = '1' ELSE
        rwaddressstart;
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    I implemented the code you gave me:

    
    architecture structure of framestore is
    	signal hold: std_logic_vector(3 downto 0);
    	signal address: std_logic_vector(14 downto 0);
    	signal next_address: std_logic_vector(14 downto 0);
    	signal cont: std_logic;
    	
    	component ram4bits is
    	PORT
    	(
    		address		: IN STD_LOGIC_VECTOR (14 DOWNTO 0);
    		clock		: IN STD_LOGIC  := '1';
    		data		: IN STD_LOGIC_VECTOR (3 DOWNTO 0);
    		wren		: IN STD_LOGIC ;
    		q		: OUT STD_LOGIC_VECTOR (3 DOWNTO 0)
    	);
    	end component;
    begin	
    	process(clk,reset,valid,readEn)
    	begin
    		if(reset = '1') then
    			next_address <= "000000000000000";
    			cont <= '0';
    		elsif(clk'event and clk = '1') then
    			cont <= valid OR readEN;
    			next_address <= address + '1';
    		end if;
    	end process;
    	
    	store: ram4bits port map(address,clk,input,valid,hold);
    	
    	output <= hold when readEn = '1' else "0000"; --self explanatory
    	address <= next_address when cont = '1' else rwaddressstart;
    	
    	addressout <= address;
    	
    end structure;
    

    and it actually gave me the same result as what I had before (the first piece of data that gets read from memory gets read for two clock cycles).

    From a hardware level, I'm not sure I understand what this does differently. What do you mean when you say something is registered? Does that mean it's stored in a register? Does that make things slower? Why is something here not stored in a register and something in my code was? Why do I need cont for example? Why can't I just directly say address <= next_address when readEn ='1' or valid = '1'? Why do I even need the process at all? Why can't I say address <= address + '1' when etc.?

    Thanks