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
Ok - another question - whats the target device?
Also, looking at your origional code, the problem may lie in the fact that cl/x/y_reg can also be assigned to 0, so its trying to put a mux in the data path to the output register, rather than just the output of ram. - Altera_Forum
Honored Contributor
The target device is a cyclone III.
I've tried removing the setting cl_reg x_reg and y_reg to 0 as that was one of my first ideas, but it still won't infer, also I was under the impression it had more to do with the read address being registered and not the output from the read? Mat. - Altera_Forum
Honored Contributor
Just a note - there is no point assigning a signal (or variable) to itself - the same behaviour can be done by simply doing nothing to the particular signals.
- Altera_Forum
Honored Contributor
Yeah I know, it was more just to help me visualize the logic while writing
the block. It should be affecting anything should it? - Altera_Forum
Honored Contributor
I'd love to be able to get this block to infer the arrays as RAM,
but would it just be better if I used this block to generate read and write signals for an instanced altsyncram block for each (cl, x and y) and then pipe the dval and fval through 2 DFF so that they match the read output of the RAM blocks? Mat. - Altera_Forum
Honored Contributor
That would work - but its annoying me as to why these wont infer ;)
- Altera_Forum
Honored Contributor
Thanks for the help,
It's too late for me right now but I'll try to implement that tomorrow and let you know how it goes. Mat. - Altera_Forum
Honored Contributor
I found the problem - you didnt constrain the read and write addresses, so they were being made as 32 bit values. Then it could not fit these in the memory you infered, so wont create a memory. I constrained them with
read : integer range 0 to BUFFER_SIZE-1; and it infered a ram. It even worked with the origional variables. - Altera_Forum
Honored Contributor
Another note : be warned this may break your testbench as Im guessing the integers will now go over limit at some point. I suggest you catch this in the code.
- Altera_Forum
Honored Contributor
Tricky, your amazing. Thanks heaps mate. I think my design should be alright as the buffer is reversed at the upper address limit and the pointers should never go over but I'll double check.
I do have one question though from reading the ram guidelines. Because it is being inferred as ram should I be expecting a delay in the output by a clock cycle and if so will this delay be imposed on the output of dval and fval as I need the outputs to be in sync. I got the impression from the guidelines that there will be a delay. Mat.