Forum Discussion
First in Last out buffer consuming too much resources
Hi all,
I'm trying to implement a first in last out buffer, that has the soul purpose of flipping image data horizontally. The image comes in as a stream of pixels in the order (1,1) , (2,1) , (3,1) ... (765,1) , (1,2) , (2,2) , (3,2) ... (765,2) etc (where the width of the image is 765) Each pixel is put through a threshold and represented by a color label, an x coordinate and a y coordinate. I've implemented a block that instances 3 arrays of length 765 one for the color label (8 bits per label) one for the x coordinate (10 bits per coordinate) one for the y coordinate (10 bits per coordinate) When the arrays are filled (a full line has come in) the direction of the arrays are reversed an the data comes out in effect flipping the row of data and delaying the output of the image by a single row. The block works and I have verified this by modifying the block to flip the RGB values rather than the color label, x and y coordinate and the output image is a horizontally flipped image. However, before this block is used the total logic elements used is around 9% and after it is around 90% (not to mention the compile time is unbearable). I have a feeling this is due to the following info I get during the compilation process Info (276014): Found 3 instances of uninferred RAM logic Info (276007): RAM logic "ImgModelling:inst32|FlipBuffer:inst5|CL_Stack~19" is uninferred due to asynchronous read logic Info (276007): RAM logic "ImgModelling:inst32|FlipBuffer:inst5|X_Stack~21" is uninferred due to asynchronous read logic Info (276007): RAM logic "ImgModelling:inst32|FlipBuffer:inst5|Y_Stack~21" is uninferred due to asynchronous read logic I'm not to sure where I have asynchronous reading occuring (bear in mind I'm very new to VHDL and FPGA's) but the amount of resources being used by this block seems to high and I would like to fix it if possible Can anyone confirm this is why the block is using that many logic elements or help me find out why. Also if anyone has a better idea of how to approach the flipping it would be greatly appreciated. I have provided my code for the block below. Thanks, Mat. CL is the color label FVAL is true when the image frame is valid DVAL is true for a valid pixel so when DVAL = '1' and FVAL = '1' the data is a valid pixel and DVAL = '0' and FVAL = '0' represents the end of a frame.library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity FlipBuffer is
generic(
LABEL_WIDTH : integer := 8;
COORD_WIDTH : integer := 10;
BUFFER_SIZE : integer := 765 -- Screen width
);
port(
-- Clock Signal
CLK : in std_logic;
-- Input Signals
CL_IN : in unsigned(LABEL_WIDTH-1 downto 0);
X_IN : in unsigned(COORD_WIDTH-1 downto 0);
Y_IN : in unsigned(COORD_WIDTH-1 downto 0);
DVAL_IN : in std_logic := '0';
FVAL_IN : in std_logic := '0';
-- Output Signals
CL_OUT : out unsigned(LABEL_WIDTH-1 downto 0) := to_unsigned(0,LABEL_WIDTH);
X_OUT : out unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH);
Y_OUT : out unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH);
DVAL_OUT : out std_logic := '0';
FVAL_OUT : out std_logic := '0'
);
end FlipBuffer;
architecture rt1 of FlipBuffer is
-- output registers
signal cl_reg : unsigned(LABEL_WIDTH-1 downto 0);
signal x_reg : unsigned(COORD_WIDTH-1 downto 0);
signal y_reg : unsigned(COORD_WIDTH-1 downto 0);
signal dval_reg : std_logic := '0';
signal fval_reg : std_logic := '0';
-- Buffer
type FILO_CL_Stack is array(0 to BUFFER_SIZE-1) of unsigned(LABEL_WIDTH-1 downto 0);
type FILO_COORD_Stack is array(0 to BUFFER_SIZE-1) of unsigned(COORD_WIDTH-1 downto 0);
signal CL_Stack : FILO_CL_Stack;
signal X_Stack : FILO_COORD_Stack;
signal Y_Stack : FILO_COORD_Stack;
begin
process (CLK)
variable read : integer;
variable write : integer;
variable reverse : std_logic;
variable read_count : integer;
variable write_count : integer;
begin
if (rising_edge(CLK)) then
if (DVAL_IN = '0' and FVAL_IN = '0') then
-- reset, this will ignore the final line of the frame to ensure
-- initial conditions are set when the frame starts. However, the
-- final line is black and therefore makes no difference.
reverse := '0';
read := BUFFER_SIZE-1;
write := 0;
read_count := 0;
write_count := 0;
cl_reg <= to_unsigned(0,LABEL_WIDTH);
x_reg <= to_unsigned(0,COORD_WIDTH);
y_reg <= to_unsigned(0,COORD_WIDTH);
dval_reg <= '0';
fval_reg <= '0';
elsif (DVAL_IN = '1' and FVAL_IN = '1' and read_count > 0) then
-- Reading and Writing state
-- Read first so data is not overwritten
cl_reg <= CL_Stack(read);
x_reg <= X_Stack(read);
y_reg <= Y_Stack(read);
dval_reg <= '1';
fval_reg <= '1';
-- Write data
CL_Stack(write) <= CL_IN;
X_Stack(write) <= X_IN;
Y_Stack(write) <= Y_IN;
-- Update counts and addresses
if (write_count + 1 = BUFFER_SIZE) then
-- Row writen, reverse buffer and start reading
reverse := not reverse;
write := write;
read := write;
write_count := 0;
read_count := BUFFER_SIZE;
else
-- Still writing row
reverse := reverse;
write_count := write_count + 1;
read_count := read_count + 1;
if (reverse = '0') then
write := write + 1;
read := read + 1;
else
write := write - 1;
read := read - 1;
end if;
end if;
elsif (DVAL_IN = '1' and FVAL_IN = '1' and read_count <= 0) then
-- Writing, NOT Reading state
-- NOT Reading
cl_reg <= to_unsigned(0,LABEL_WIDTH);
x_reg <= to_unsigned(0,COORD_WIDTH);
y_reg <= to_unsigned(0,COORD_WIDTH);
dval_reg <= '0';
fval_reg <= '1';
-- Write data
CL_Stack(write) <= CL_IN;
X_Stack(write) <= X_IN;
Y_Stack(write) <= Y_IN;
-- Update counts and addresses
if (write_count + 1 = BUFFER_SIZE) then
-- Row writen, reverse buffer and start reading
reverse := not reverse;
write := write;
read := write;
write_count := 0;
read_count := BUFFER_SIZE;
else
-- Still writing row
reverse := reverse;
write_count := write_count + 1;
if (reverse = '0') then
write := write + 1;
else
write := write - 1;
end if;
read_count := 0;
read := 0;
end if;
elsif (DVAL_IN = '0' and FVAL_IN = '0' and read_count > 0) then
-- Reading, NOT Writing state
-- NOT Writing
reverse := reverse;
write := write;
write_count := write_count;
-- Read data
cl_reg <= CL_Stack(read);
x_reg <= X_Stack(read);
y_reg <= Y_Stack(read);
dval_reg <= '1';
fval_reg <= '1';
-- Update counts and addresses
read_count := read_count + 1;
if (reverse = '0') then
read := read + 1;
else
read := read - 1;
end if;
else
-- DO NOTHING, maintain state
reverse := reverse;
read_count := read_count;
write_count := write_count;
read := read;
write := write;
cl_reg <= to_unsigned(0,LABEL_WIDTH);
x_reg <= to_unsigned(0,COORD_WIDTH);
y_reg <= to_unsigned(0,COORD_WIDTH);
dval_reg <= '0';
fval_reg <= '1';
end if;
end if;
end process;
CL_OUT <= cl_reg;
X_OUT <= x_reg;
Y_OUT <= y_reg;
DVAL_OUT <= dval_reg;
FVAL_OUT <= fval_reg;
end rt1;22 Replies
- Altera_Forum
Honored Contributor
with Altera RAMs, you have to ensure the read address is registered before it accesses the data in the ram (or in your case, the array). I notice you have a lot of variables, and you say you are very new to VHDL. I would recommend you not use variables for now, and make everything use a signal. You also need to make sure you are following the templates for the rams; I suggest you read the altera coding guidelines:
http://www.altera.com/literature/hb/qts/qts_qii51007.pdf Also - have a written a testbench for this code? have you fully tested it? - Altera_Forum
Honored Contributor
Thanks tricky,
I have written a testbench and fully tested the block, I just left it out of the post so the post was not too long but I've included it below now. With regards to the variables, there's no reason I need them in this design, my previous design was simplified by using variables instead of signals and I just didn't get around to changing them back to signals when I redesigned the block but I will change them back to signals. What is the reason I should stick to variables for now? I will read the design guidelines for altera RAM, but my main question is, is the fact that the arrays are not being inferred to RAM the reason why the block is using so many logic elements? Mat. Testbenchlibrary ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity Flip_test is generic ( LABEL_WIDTH : integer := 8; COORD_WIDTH : integer := 10; BUFFER_SIZE : integer := 5--765 -- Screen width ); end Flip_test; architecture bench of Flip_test is component FlipBuffer port ( -- Clock Signal CLK : in std_logic; -- Input Signals CL_IN : in unsigned(LABEL_WIDTH-1 downto 0); X_IN : in unsigned(COORD_WIDTH-1 downto 0); Y_IN : in unsigned(COORD_WIDTH-1 downto 0); DVAL_IN : in std_logic := '0'; FVAL_IN : in std_logic := '0'; -- Output Signals CL_OUT : out unsigned(LABEL_WIDTH-1 downto 0) := to_unsigned(0,LABEL_WIDTH); X_OUT : out unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH); Y_OUT : out unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH); DVAL_OUT : out std_logic := '0'; FVAL_OUT : out std_logic := '0' ); end component; signal CLK, DVAL_IN, FVAL_IN, DVAL_OUT, FVAL_OUT : std_logic; signal CL_IN, CL_OUT : unsigned(LABEL_WIDTH-1 downto 0); signal X_IN, Y_IN, X_OUT, Y_OUT : unsigned(COORD_WIDTH-1 downto 0); BEGIN clk_process :process begin CLK <= '0'; wait for 100 PS; CLK <= '1'; wait for 100 PS; end process; stim_process :process variable odd : std_logic := '1'; variable run : std_logic := '1'; variable count : unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH); begin DVAL_IN <= '0'; FVAL_IN <= '0'; CL_IN <= to_unsigned(0, LABEL_WIDTH); X_IN <= to_unsigned(0, COORD_WIDTH); Y_IN <= to_unsigned(0, COORD_WIDTH); wait for 150 ps; DVAL_IN <= '0'; FVAL_IN <= '0'; CL_IN <= to_unsigned(4, LABEL_WIDTH); X_IN <= to_unsigned(2, COORD_WIDTH); Y_IN <= to_unsigned(3, COORD_WIDTH); wait for 200 ps; while (run = '1') loop if (count = to_unsigned(10,COORD_WIDTH)) then run := '0'; end if; if (odd = '1') then odd := '0'; DVAL_IN <= '1'; FVAL_IN <= '1'; count := count + 1; CL_IN <= to_unsigned(8, LABEL_WIDTH); X_IN <= count; Y_IN <= count; wait for 200 ps; else odd := '1'; DVAL_IN <= '0'; FVAL_IN <= '1'; --count := count + 1; CL_IN <= to_unsigned(0, LABEL_WIDTH); X_IN <= to_unsigned(333, COORD_WIDTH); Y_IN <= to_unsigned(333, COORD_WIDTH); wait for 200 ps; end if; end loop; DVAL_IN <= '0'; FVAL_IN <= '0'; CL_IN <= to_unsigned(8, LABEL_WIDTH); X_IN <= to_unsigned(222, COORD_WIDTH); Y_IN <= to_unsigned(222, COORD_WIDTH); run := '1'; wait for 200 ps; while (run = '1') loop if (odd = '1') then odd := '0'; DVAL_IN <= '1'; FVAL_IN <= '1'; count := count + 1; CL_IN <= to_unsigned(8, LABEL_WIDTH); X_IN <= count; Y_IN <= count; wait for 200 ps; else odd := '1'; DVAL_IN <= '0'; FVAL_IN <= '1'; --count := count + 1; CL_IN <= to_unsigned(0, LABEL_WIDTH); X_IN <= to_unsigned(333, COORD_WIDTH); Y_IN <= to_unsigned(333, COORD_WIDTH); wait for 200 ps; end if; end loop; --wait; end process; M: FlipBuffer port map (CLK, CL_IN, X_IN, Y_IN, DVAL_IN, FVAL_IN, CL_OUT, X_OUT, Y_OUT, DVAL_OUT, FVAL_OUT); end bench; - Altera_Forum
Honored Contributor
Yes, if the block doesnt infer in ram, it will be LEs. And the reason it wont infer the ram is that it cannot match the behaviour to the templates in the guidelines.
- Altera_Forum
Honored Contributor
Cool, Thanks for the help Tricky,
I'll get to work making sure my design follows the guidelines. :) Mat. - Altera_Forum
Honored Contributor
It doesnt have to be precisly like the guidelines, just make sure the behaviour is correct. But I would suggest signals for the read and write addresses.
- Altera_Forum
Honored Contributor
Ok, so I've converted all my variables to signals.
I've been reading through the guidelines for inferring RAM and from what I can tell, my code is not inferring RAM because I am assigning a new value to the read signal in the same area that I am trying to read from the arrays. Is this correct? Mat. - Altera_Forum
Honored Contributor
it will be nothing to to with the "area", just more the behaviour. You need to make sure it can put the read address register inside the infered ram.
- Altera_Forum
Honored Contributor
So then would it be assignments such as
inferring a counter, stopping the read from acting like a register and being put inside the RAM? Mat.read <= read + 1 - Altera_Forum
Honored Contributor
I suspect the inference issue is elsewhere, because read <= read+1 is actually a bit of logic that does read +1 followed by a register , which should be able to sit in the ram. I suspect the problem is elsewhere. Can you repost the code?
- Altera_Forum
Honored Contributor
Sure, thanks for all the help by the way.
library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity FlipBuffer is generic( LABEL_WIDTH : integer := 8; COORD_WIDTH : integer := 10; BUFFER_SIZE : integer := 765 -- Screen width ); port( -- Clock Signal CLK : in std_logic; -- Input Signals CL_IN : in unsigned(LABEL_WIDTH-1 downto 0); X_IN : in unsigned(COORD_WIDTH-1 downto 0); Y_IN : in unsigned(COORD_WIDTH-1 downto 0); DVAL_IN : in std_logic := '0'; FVAL_IN : in std_logic := '0'; -- Output Signals --VALID : out std_logic; CL_OUT : out unsigned(LABEL_WIDTH-1 downto 0) := to_unsigned(0,LABEL_WIDTH); X_OUT : out unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH); Y_OUT : out unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH); DVAL_OUT : out std_logic := '0'; FVAL_OUT : out std_logic := '0' ); end FlipBuffer; architecture rt1 of FlipBuffer is -- output registers signal cl_reg : unsigned(LABEL_WIDTH-1 downto 0); signal x_reg : unsigned(COORD_WIDTH-1 downto 0); signal y_reg : unsigned(COORD_WIDTH-1 downto 0); signal dval_reg : std_logic := '0'; signal fval_reg : std_logic := '0'; -- Buffer type FILO_CL_Stack is array(0 to BUFFER_SIZE-1) of unsigned(LABEL_WIDTH-1 downto 0); type FILO_COORD_Stack is array(0 to BUFFER_SIZE-1) of unsigned(COORD_WIDTH-1 downto 0); signal CL_Stack : FILO_CL_Stack; signal X_Stack : FILO_COORD_Stack; signal Y_Stack : FILO_COORD_Stack; signal read : integer; signal write : integer; signal reverse : std_logic; signal read_count : integer; signal write_count : integer; begin process (CLK) begin if (rising_edge(CLK)) then if (DVAL_IN = '0' and FVAL_IN = '0') then -- reset, this will ignore the final line of the frame to ensure -- initial conditions are set when the frame starts. However, the -- final line is black and therefore makes no difference. reverse <= '0'; read <= BUFFER_SIZE-1; write <= 0; read_count <= 0; write_count <= 0; cl_reg <= to_unsigned(0,LABEL_WIDTH); x_reg <= to_unsigned(0,COORD_WIDTH); y_reg <= to_unsigned(0,COORD_WIDTH); dval_reg <= '0'; fval_reg <= '0'; elsif (DVAL_IN = '1' and FVAL_IN = '1' and read_count > 0) then -- Reading and Writing state -- Read first so data is not overwritten cl_reg <= CL_Stack(read); x_reg <= X_Stack(read); y_reg <= Y_Stack(read); dval_reg <= '1'; fval_reg <= '1'; -- Write data CL_Stack(write) <= CL_IN; X_Stack(write) <= X_IN; Y_Stack(write) <= Y_IN; -- Update counts and addresses if (write_count + 1 = BUFFER_SIZE) then -- Row writen, reverse buffer and start reading reverse <= not reverse; write <= write; read <= write; write_count <= 0; read_count <= BUFFER_SIZE; else -- Still writing row reverse <= reverse; write_count <= write_count + 1; read_count <= read_count + 1; if (reverse = '0') then write <= write + 1; read <= read + 1; else write <= write - 1; read <= read - 1; end if; end if; elsif (DVAL_IN = '1' and FVAL_IN = '1' and read_count <= 0) then -- Writing, NOT Reading state -- NOT Reading cl_reg <= to_unsigned(0,LABEL_WIDTH); x_reg <= to_unsigned(0,COORD_WIDTH); y_reg <= to_unsigned(0,COORD_WIDTH); dval_reg <= '0'; fval_reg <= '1'; -- Write data CL_Stack(write) <= CL_IN; X_Stack(write) <= X_IN; Y_Stack(write) <= Y_IN; -- Update counts and addresses if (write_count + 1 = BUFFER_SIZE) then -- Row writen, reverse buffer and start reading reverse <= not reverse; write <= write; read <= write; write_count <= 0; read_count <= BUFFER_SIZE; else -- Still writing row reverse <= reverse; write_count <= write_count + 1; if (reverse = '0') then write <= write + 1; else write <= write - 1; end if; read_count <= 0; read <= 0; end if; elsif (DVAL_IN = '0' and FVAL_IN = '0' and read_count > 0) then -- Reading, NOT Writing state -- NOT Writing reverse <= reverse; write <= write; write_count <= write_count; -- Read data cl_reg <= CL_Stack(read); x_reg <= X_Stack(read); y_reg <= Y_Stack(read); dval_reg <= '1'; fval_reg <= '1'; -- Update counts and addresses read_count <= read_count + 1; if (reverse = '0') then read <= read + 1; else read <= read - 1; end if; else -- DO NOTHING, maintain state reverse <= reverse; read_count <= read_count; write_count <= write_count; read <= read; write <= write; cl_reg <= to_unsigned(0,LABEL_WIDTH); x_reg <= to_unsigned(0,COORD_WIDTH); y_reg <= to_unsigned(0,COORD_WIDTH); dval_reg <= '0'; fval_reg <= '1'; end if; end if; end process; CL_OUT <= cl_reg; X_OUT <= x_reg; Y_OUT <= y_reg; DVAL_OUT <= dval_reg; FVAL_OUT <= fval_reg; end rt1; library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity Flip_test is generic ( LABEL_WIDTH : integer := 8; COORD_WIDTH : integer := 10; BUFFER_SIZE : integer := 5--765 -- Screen width ); end Flip_test; architecture bench of Flip_test is component FlipBuffer port ( -- Clock Signal CLK : in std_logic; -- Input Signals CL_IN : in unsigned(LABEL_WIDTH-1 downto 0); X_IN : in unsigned(COORD_WIDTH-1 downto 0); Y_IN : in unsigned(COORD_WIDTH-1 downto 0); DVAL_IN : in std_logic := '0'; FVAL_IN : in std_logic := '0'; -- Output Signals CL_OUT : out unsigned(LABEL_WIDTH-1 downto 0) := to_unsigned(0,LABEL_WIDTH); X_OUT : out unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH); Y_OUT : out unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH); DVAL_OUT : out std_logic := '0'; FVAL_OUT : out std_logic := '0' ); end component; signal CLK, DVAL_IN, FVAL_IN, DVAL_OUT, FVAL_OUT : std_logic; signal CL_IN, CL_OUT : unsigned(LABEL_WIDTH-1 downto 0); signal X_IN, Y_IN, X_OUT, Y_OUT : unsigned(COORD_WIDTH-1 downto 0); BEGIN clk_process :process begin CLK <= '0'; wait for 100 PS; CLK <= '1'; wait for 100 PS; end process; stim_process :process variable odd : std_logic := '1'; variable run : std_logic := '1'; variable count : unsigned(COORD_WIDTH-1 downto 0) := to_unsigned(0,COORD_WIDTH); begin DVAL_IN <= '0'; FVAL_IN <= '0'; CL_IN <= to_unsigned(0, LABEL_WIDTH); X_IN <= to_unsigned(0, COORD_WIDTH); Y_IN <= to_unsigned(0, COORD_WIDTH); wait for 150 ps; DVAL_IN <= '0'; FVAL_IN <= '0'; CL_IN <= to_unsigned(4, LABEL_WIDTH); X_IN <= to_unsigned(2, COORD_WIDTH); Y_IN <= to_unsigned(3, COORD_WIDTH); wait for 200 ps; while (run = '1') loop if (count = to_unsigned(20,COORD_WIDTH)) then run := '0'; end if; if (odd = '1') then odd := '0'; DVAL_IN <= '1'; FVAL_IN <= '1'; count := count + 1; CL_IN <= to_unsigned(8, LABEL_WIDTH); X_IN <= count; Y_IN <= count; wait for 200 ps; else odd := '1'; DVAL_IN <= '0'; FVAL_IN <= '1'; --count := count + 1; CL_IN <= to_unsigned(0, LABEL_WIDTH); X_IN <= to_unsigned(333, COORD_WIDTH); Y_IN <= to_unsigned(333, COORD_WIDTH); wait for 200 ps; end if; end loop; DVAL_IN <= '0'; FVAL_IN <= '0'; CL_IN <= to_unsigned(8, LABEL_WIDTH); X_IN <= to_unsigned(222, COORD_WIDTH); Y_IN <= to_unsigned(222, COORD_WIDTH); run := '1'; wait for 200 ps; while (run = '1') loop if (odd = '1') then odd := '0'; DVAL_IN <= '1'; FVAL_IN <= '1'; count := count + 1; CL_IN <= to_unsigned(8, LABEL_WIDTH); X_IN <= count; Y_IN <= count; wait for 200 ps; else odd := '1'; DVAL_IN <= '0'; FVAL_IN <= '1'; --count := count + 1; CL_IN <= to_unsigned(0, LABEL_WIDTH); X_IN <= to_unsigned(333, COORD_WIDTH); Y_IN <= to_unsigned(333, COORD_WIDTH); wait for 200 ps; end if; end loop; --wait; end process; M: FlipBuffer port map (CLK, CL_IN, X_IN, Y_IN, DVAL_IN, FVAL_IN, CL_OUT, X_OUT, Y_OUT, DVAL_OUT, FVAL_OUT); end bench;