J
Jonathan Bromley
Guest
OK, so I tried the following synthesis example -
various declarations omitted to save space.
I have been able to try this on five different
synthesis tools, spanning the whole range of
cost and FPGA-vs-ASIC. The results surprised
me a little - it's a long time since I did such
a complete survey.
~~~~~~~
Form 1: Clocked process, with combinational output logic
outside the usual clocked if..else...endif block.
~~~~~~~
process(clock, reset)
variable count: unsigned(7 downto 0);
begin
-- 8-bit counter, clocked with async reset
if reset = '1' then
count := (others => '0');
elsif rising_edge(clock) then
count := count + 1;
end if;
-- Combinational logic
q <= std_logic_vector(count);
msb <= count(7);
if count = (count'range => '1') then
tc <= '1';
else
tc <= '0';
end if;
end process;
This is the form I was objecting to in an earlier post,
on the grounds that the signal assignments don't match
standard synthesis templates. EVERY ONE of the five
synthesis tools I tried gave exactly the results you
might hope for: "msb" is directly connected to count[7],
"q" is directly connected to count[7:0], "tc" is the
output of an AND gate looking at all eight bits of count.
~~~~~~~
Form 2: Clocked process, with outputs assigned based on
next-state value of counter variable.
~~~~~~~
process(clock, reset)
variable count: unsigned(7 downto 0);
begin
if reset = '1' then
count := (others => '0');
q <= std_logic_vector(count);
msb <= count(7);
if count = (count'range => '1') then
tc <= '1';
else
tc <= '0';
end if;
elsif rising_edge(clock) then
count := count + 1;
q <= std_logic_vector(count);
msb <= count(7);
if count = (count'range => '1') then
tc <= '1';
else
tc <= '0';
end if;
end if;
end process;
You'll note that this is quite a bit nastier because
it's necessary to assign to the outputs both in the
reset and in the clocked branch, otherwise the
"q" and "count" registers will have subtly different
behaviour and could not be merged.
All five tools gave correct results, but two tools
failed to merge the duplicate registers they had
created for count and q. Of course, it is entirely
possible that those duplicate registers might be
merged later, during place-and-route, as they were
indeed exact duplicates.
I'm not quite sure what to think now. Form 1 still
does not really appeal. In particular, it cannot be
reproduced in Verilog. Form 2 gives registered outputs
for everything - not even the very simplest combinational
logic between flops and outputs - and maps well to Verilog,
but it's disappointing that some tools didn't merge the
duplicate registers and there is no doubt that it's
clumsier to code, especially if there's an asynchronous
reset in the process.
One final data point: The style of asynch reset
that has been suggested here on several occasions,
allowing you to reset some but not all of a process's
registers without implying unwanted enable logic,
worked as expected in all five tools I tried:
process (clock, reset)
variable count: unsigned(7 downto 0);
begin
if rising_edge(clock) then
count_pipe <= count; -- count_pipe isn't reset
count := count + 1;
end if;
if reset = '1' then
count := (others => '0');
end if;
end process;
This form also maps happily to Verilog.
Comments welcomed.
--
Jonathan Bromley, Consultant
DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services
Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com
The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.
various declarations omitted to save space.
I have been able to try this on five different
synthesis tools, spanning the whole range of
cost and FPGA-vs-ASIC. The results surprised
me a little - it's a long time since I did such
a complete survey.
~~~~~~~
Form 1: Clocked process, with combinational output logic
outside the usual clocked if..else...endif block.
~~~~~~~
process(clock, reset)
variable count: unsigned(7 downto 0);
begin
-- 8-bit counter, clocked with async reset
if reset = '1' then
count := (others => '0');
elsif rising_edge(clock) then
count := count + 1;
end if;
-- Combinational logic
q <= std_logic_vector(count);
msb <= count(7);
if count = (count'range => '1') then
tc <= '1';
else
tc <= '0';
end if;
end process;
This is the form I was objecting to in an earlier post,
on the grounds that the signal assignments don't match
standard synthesis templates. EVERY ONE of the five
synthesis tools I tried gave exactly the results you
might hope for: "msb" is directly connected to count[7],
"q" is directly connected to count[7:0], "tc" is the
output of an AND gate looking at all eight bits of count.
~~~~~~~
Form 2: Clocked process, with outputs assigned based on
next-state value of counter variable.
~~~~~~~
process(clock, reset)
variable count: unsigned(7 downto 0);
begin
if reset = '1' then
count := (others => '0');
q <= std_logic_vector(count);
msb <= count(7);
if count = (count'range => '1') then
tc <= '1';
else
tc <= '0';
end if;
elsif rising_edge(clock) then
count := count + 1;
q <= std_logic_vector(count);
msb <= count(7);
if count = (count'range => '1') then
tc <= '1';
else
tc <= '0';
end if;
end if;
end process;
You'll note that this is quite a bit nastier because
it's necessary to assign to the outputs both in the
reset and in the clocked branch, otherwise the
"q" and "count" registers will have subtly different
behaviour and could not be merged.
All five tools gave correct results, but two tools
failed to merge the duplicate registers they had
created for count and q. Of course, it is entirely
possible that those duplicate registers might be
merged later, during place-and-route, as they were
indeed exact duplicates.
I'm not quite sure what to think now. Form 1 still
does not really appeal. In particular, it cannot be
reproduced in Verilog. Form 2 gives registered outputs
for everything - not even the very simplest combinational
logic between flops and outputs - and maps well to Verilog,
but it's disappointing that some tools didn't merge the
duplicate registers and there is no doubt that it's
clumsier to code, especially if there's an asynchronous
reset in the process.
One final data point: The style of asynch reset
that has been suggested here on several occasions,
allowing you to reset some but not all of a process's
registers without implying unwanted enable logic,
worked as expected in all five tools I tried:
process (clock, reset)
variable count: unsigned(7 downto 0);
begin
if rising_edge(clock) then
count_pipe <= count; -- count_pipe isn't reset
count := count + 1;
end if;
if reset = '1' then
count := (others => '0');
end if;
end process;
This form also maps happily to Verilog.
Comments welcomed.
--
Jonathan Bromley, Consultant
DOULOS - Developing Design Know-how
VHDL * Verilog * SystemC * e * Perl * Tcl/Tk * Project Services
Doulos Ltd., 22 Market Place, Ringwood, BH24 1AW, UK
jonathan.bromley@MYCOMPANY.com
http://www.MYCOMPANY.com
The contents of this message may contain personal views which
are not the views of Doulos Ltd., unless specifically stated.