Intel® Quartus® Prime Software
Intel® Quartus® Prime Design Software, Design Entry, Synthesis, Simulation, Verification, Timing Analysis, System Design (Platform Designer, formerly Qsys)
16636 Discussions

Takes too long to get address

Altera_Forum
Honored Contributor II
1,488 Views

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;
0 Kudos
18 Replies
Altera_Forum
Honored Contributor II
743 Views

write enable should be applied at the same clock cycle as the write address. In your code, write enable is supplied from the port directly, but address registered and thus one cycle delayed. If address is a registered signal, write enable should be as well. But the address is already registered in the RAM block, so it can be assigned outside the clocked process code.

0 Kudos
Altera_Forum
Honored Contributor II
743 Views

I don't really follow 100%. You're saying that the lines 

if(valid_RE or readEn_RE) then address <= rwaddressstart; elsif(valid = '1' or readEn = '1') then address <= address + '1';  

shouldn't be in the process block because they're already being stored in registers, and should be taken outside of the process block?
0 Kudos
Altera_Forum
Honored Contributor II
743 Views

You need to register the valid input to align it with the address signal you are creating and connect the registered version of it to the write-enable port of the ram.

0 Kudos
Altera_Forum
Honored Contributor II
743 Views

Register both or none of the RAM block input signals.

0 Kudos
Altera_Forum
Honored Contributor II
743 Views

When you say register valid, does that mean, just assign it to a signal?

0 Kudos
Altera_Forum
Honored Contributor II
743 Views

I mean register the incoming valid signal and change the port map of the store like this 

 

signal valid_r : std_logic; begin process(clk, reset) begin if reset = '1' then valid_r <= '0'; elsif rising_edge(clk) then valid_r <= valid; end if; end process; store: ram4bits port map ( address => address, clock => clk, data => input, wren => valid_r, q => hold );
0 Kudos
Altera_Forum
Honored Contributor II
743 Views

What does it mean to change the portmap to be what you specified? I'm not famililar with the => notation. I changed it to exactly how you specified but I'm still missing the first value that I try to write. To me it looks like the first value is just never written to memory. To test it out I made a simple wave form with a valid signal that's high for a cycle (starting when clock is low, ending when clock is high) and I also have an input in that same cycle. At the falling edge, I see my output for the rising edge, and thats when the address appears but that first value isn't written.  

 

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); validreout: out std_logic; readreout: out std_logic ); 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; 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; if(valid_RE or readEn_RE) then address <= rwaddressstart; elsif(valid = '1' or readEn = '1') then address <= address + '1'; end if; elsif(clk'event and clk = '0') then tempread <= readEn; tempvalid <= valid; end if; end process; store: ram4bits port map(address => address,clock => clk,data => input,wren => reg,q=>hold); readEn_RE <= tempread = '0' and readEn = '1'; valid_RE <= tempvalid = '0' and valid = '1'; output <= hold when readEn = '1' else "0000"; validreout <= '1' when valid_RE else '0'; readreout <= '1' when readEn_RE else '0'; addressout <= address; holdout <= hold; end structure;
0 Kudos
Altera_Forum
Honored Contributor II
743 Views

Can you post an image of the output waveform? it sounds like your input and valid signal may be missaligned.

0 Kudos
Altera_Forum
Honored Contributor II
743 Views
0 Kudos
Altera_Forum
Honored Contributor II
743 Views

My input and valid appear to arrive at exactly the same time, which is how I set it in my wavefunction.

0 Kudos
Altera_Forum
Honored Contributor II
743 Views

 

--- 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
0 Kudos
Altera_Forum
Honored Contributor II
743 Views

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.

0 Kudos
Altera_Forum
Honored Contributor II
743 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
743 Views

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?
0 Kudos
Altera_Forum
Honored Contributor II
743 Views

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
0 Kudos
Altera_Forum
Honored Contributor II
743 Views

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?

0 Kudos
Altera_Forum
Honored Contributor II
743 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
743 Views

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
0 Kudos
Reply