- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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;
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Register both or none of the RAM block input signals.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
When you say register valid, does that mean, just assign it to a signal?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
);
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Can you post an image of the output waveform? it sounds like your input and valid signal may be missaligned.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
My input and valid appear to arrive at exactly the same time, which is how I set it in my wavefunction.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
--- 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
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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;
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
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
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page