Guest
Hi All,
I'm working on a pipeline design (for Xilinx Virtex) and I'd like to
get some opinions on whether it's ok to use a latch inside a
combinatoral process squeezed between two sequential processes that
hold the pipeline registers.
As the input to the latch is registered, and the output from the logic
containing the latch isn't used until it's been registered, is this a
'good'
latch design? What other issues should be considered?
The same pipeline design without inferring a latch is over 50Mhz slower
so I'm keen to hitch my trailer to the 'latches can be great when they
are not inferred by mistake' wagon train
A simplified example is shown below, COMB_B process contains the latch
and does some trivial calculation. Whereas COMB_A does the same
calculation, but without a latch, and a lot slower.
Or is there is a way to make XST avoid inferring two lots of (a_reg -
b_reg) logic in COMB_A? It's this logic that causes the 50Mhz hit and
why I used a latch COMB_B.
Thanks,
Andy.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity test_latch is
port (clk : in std_logic;
rst : in std_logic;
d_in : in std_logic;
a_in : in std_logic_vector(31 downto 0);
b_in : in std_logic_vector(31 downto 0);
x_in : in std_logic_vector(31 downto 0);
r_out : out std_logic_vector(31 downto 0)
);
end test_latch;
architecture Behavioral of test_latch is
signal a_reg,b_reg,x_reg : std_logic_vector(31 downto 0);
signal d_reg : std_logic;
signal latch : std_logic_vector(31 downto 0);
signal r : std_logic_vector(31 downto 0);
begin
SEQ1 : process (clk,rst) is
begin
if (rst ='1') then
a_reg <= (others => '0');
b_reg <= (others => '0');
x_reg <= (others => '0');
d_reg <= '0';
elsif (rising_edge(clk)) then
if (d_reg = '1') then
a_reg <= a_in;
b_reg <= b_in;
x_reg <= x_in;
d_reg <= d_in;
end if;
end if;
end process;
-- COMB_A : process (d_reg,x_reg,a_reg,b_reg) is
-- begin
-- if (d_reg = '1') then
-- if (signed(x_reg) > (signed(a_reg) - signed(b_reg))) then
-- r <= x_reg;
-- else
-- r <= std_logic_vector(signed(a_reg) - signed(b_reg));
-- end if;
-- else
-- r <= (others => '0');
-- end if;
-- end process;
COMB_B : process (x_reg,a_reg,b_reg,d_reg) is
begin
if (d_reg = '1') then
latch <= std_logic_vector(signed(a_reg) - signed(b_reg));
if (signed(x_reg) > signed(latch)) then
r <= x_reg;
else
r <= latch;
end if;
else
r <= (others => '0');
-- dont specify value for 'latch' as that's what
-- we want to infer
end if;
end process;
SEQ2 : process (clk,rst) is
begin
if (rst ='1') then
elsif (rising_edge(clk)) then
r_out <= r;
end if;
end process;
end Behavioral;
I'm working on a pipeline design (for Xilinx Virtex) and I'd like to
get some opinions on whether it's ok to use a latch inside a
combinatoral process squeezed between two sequential processes that
hold the pipeline registers.
As the input to the latch is registered, and the output from the logic
containing the latch isn't used until it's been registered, is this a
'good'
latch design? What other issues should be considered?
The same pipeline design without inferring a latch is over 50Mhz slower
so I'm keen to hitch my trailer to the 'latches can be great when they
are not inferred by mistake' wagon train
A simplified example is shown below, COMB_B process contains the latch
and does some trivial calculation. Whereas COMB_A does the same
calculation, but without a latch, and a lot slower.
Or is there is a way to make XST avoid inferring two lots of (a_reg -
b_reg) logic in COMB_A? It's this logic that causes the 50Mhz hit and
why I used a latch COMB_B.
Thanks,
Andy.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity test_latch is
port (clk : in std_logic;
rst : in std_logic;
d_in : in std_logic;
a_in : in std_logic_vector(31 downto 0);
b_in : in std_logic_vector(31 downto 0);
x_in : in std_logic_vector(31 downto 0);
r_out : out std_logic_vector(31 downto 0)
);
end test_latch;
architecture Behavioral of test_latch is
signal a_reg,b_reg,x_reg : std_logic_vector(31 downto 0);
signal d_reg : std_logic;
signal latch : std_logic_vector(31 downto 0);
signal r : std_logic_vector(31 downto 0);
begin
SEQ1 : process (clk,rst) is
begin
if (rst ='1') then
a_reg <= (others => '0');
b_reg <= (others => '0');
x_reg <= (others => '0');
d_reg <= '0';
elsif (rising_edge(clk)) then
if (d_reg = '1') then
a_reg <= a_in;
b_reg <= b_in;
x_reg <= x_in;
d_reg <= d_in;
end if;
end if;
end process;
-- COMB_A : process (d_reg,x_reg,a_reg,b_reg) is
-- begin
-- if (d_reg = '1') then
-- if (signed(x_reg) > (signed(a_reg) - signed(b_reg))) then
-- r <= x_reg;
-- else
-- r <= std_logic_vector(signed(a_reg) - signed(b_reg));
-- end if;
-- else
-- r <= (others => '0');
-- end if;
-- end process;
COMB_B : process (x_reg,a_reg,b_reg,d_reg) is
begin
if (d_reg = '1') then
latch <= std_logic_vector(signed(a_reg) - signed(b_reg));
if (signed(x_reg) > signed(latch)) then
r <= x_reg;
else
r <= latch;
end if;
else
r <= (others => '0');
-- dont specify value for 'latch' as that's what
-- we want to infer
end if;
end process;
SEQ2 : process (clk,rst) is
begin
if (rst ='1') then
elsif (rising_edge(clk)) then
r_out <= r;
end if;
end process;
end Behavioral;