Guest
Hello,
I like sharing some ideas to see the different points of view out there!
Assuming that you have a pipelined design that does some calculation that requires 10 (or N) clock cycles of latency.
The module is supposed to be able to perform flow control (pause its input and avoid writing to its output) whenever its output is busy, so the interface would look something similar to the one shown below.
The way I see it, there are two main ways (at least that I know of) to implement correct flow control:
#1- Use a clock enable signal that is controlled by busy_in, connect busy_out to busy_in, and disable your data_out_val whenever busy_out is set.
#2- Don't using a clock enable on your processing, use a FIFO at the end of your processing that is deep enough to accommodate the remaining data flushed from the pipe (at least 10 elements), use an almost full flag, connect busy_out to busy_in, and empty the FIFO when the output is not busy.
I usually use method #1 (roughly shown below)
The way I see it, you save some resources (no FIFO) and the registers and multipliers already have a clock enable port, so no extra logic is required.
- Are there any major pros/cons to using a method over another other?
- Would you guys implement that differently?
C.
entity test is
port (
clk : in std_logic;
reset : out std_logic;
-- input port
data_in : in std_logic_vector(7 downto 0);
data_in_val : in std_logic;
busy_out : out std_logic;
-- output port
data_out : out std_logic_vector(7 downto 0);
data_out_val : in std_logic;
busy_in : in std_logic
);
end test;
architecture my_arc of test is
type type_data_array is array (0 to 9) of std_logic_vector(7 downto 0);
signal my_data_array : type_data_array;
signal my_data_val : std_logic_vector(9 downto 0);
signal my_enable : std_logic;
begin
my_enable <= not busy_in;
busy_out <= busy_in;
data_out <= my_data_array(9);
data_out_val <= my_data_val(9) and (not busy_in);
my_processing : process (clk)
begin
if rising_edge(clk) then
if reset = '1' then
my_data_array <= (others => (others => '0'));
my_data_val <= (others => '0');
elsif my_enable = '1' then
-- shift register (emulates some random processing)
my_data_array(0) <= data_in;
my_data_val(0) <= data_in_val;
for i in 1 to 9 loop
my_data_array(i) <= my_data_array(i-1);
my_data_val(i) <= my_data_val(i-1)
end loop;
end if;
end if;
end process my_processing;
end my_arc;
I like sharing some ideas to see the different points of view out there!
Assuming that you have a pipelined design that does some calculation that requires 10 (or N) clock cycles of latency.
The module is supposed to be able to perform flow control (pause its input and avoid writing to its output) whenever its output is busy, so the interface would look something similar to the one shown below.
The way I see it, there are two main ways (at least that I know of) to implement correct flow control:
#1- Use a clock enable signal that is controlled by busy_in, connect busy_out to busy_in, and disable your data_out_val whenever busy_out is set.
#2- Don't using a clock enable on your processing, use a FIFO at the end of your processing that is deep enough to accommodate the remaining data flushed from the pipe (at least 10 elements), use an almost full flag, connect busy_out to busy_in, and empty the FIFO when the output is not busy.
I usually use method #1 (roughly shown below)
The way I see it, you save some resources (no FIFO) and the registers and multipliers already have a clock enable port, so no extra logic is required.
- Are there any major pros/cons to using a method over another other?
- Would you guys implement that differently?
C.
entity test is
port (
clk : in std_logic;
reset : out std_logic;
-- input port
data_in : in std_logic_vector(7 downto 0);
data_in_val : in std_logic;
busy_out : out std_logic;
-- output port
data_out : out std_logic_vector(7 downto 0);
data_out_val : in std_logic;
busy_in : in std_logic
);
end test;
architecture my_arc of test is
type type_data_array is array (0 to 9) of std_logic_vector(7 downto 0);
signal my_data_array : type_data_array;
signal my_data_val : std_logic_vector(9 downto 0);
signal my_enable : std_logic;
begin
my_enable <= not busy_in;
busy_out <= busy_in;
data_out <= my_data_array(9);
data_out_val <= my_data_val(9) and (not busy_in);
my_processing : process (clk)
begin
if rising_edge(clk) then
if reset = '1' then
my_data_array <= (others => (others => '0'));
my_data_val <= (others => '0');
elsif my_enable = '1' then
-- shift register (emulates some random processing)
my_data_array(0) <= data_in;
my_data_val(0) <= data_in_val;
for i in 1 to 9 loop
my_data_array(i) <= my_data_array(i-1);
my_data_val(i) <= my_data_val(i-1)
end loop;
end if;
end if;
end process my_processing;
end my_arc;