newby: eliminating excess flipflops from simple state machin

P

Paul Guy

Guest
I have been puzzled by the fact that two implementations have such
drastic differences in synthesized circuits. I know that I have failed
to cover all the if-then-else possibilities (that's required to
generate SOME of the flipflops). I am really at my wit's end trying to
get my head around the "why" and the "howto get around it" of the
following situation:

first program, it is compiled under Lattice & Synplify, and it
works just fine, it's a 4 bit counter, described as a finite state
machine, using an asynch reset and synchronous preset (the chips we're
using do not allow asynch preset). This one synthesizes nicely to 4
flipflops.
The 2nd program is the same as the first, except the lines with
##### in them are removed.
........................................................................
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity counter is
PORT(clock :IN STD_LOGIC;
barreset :IN STD_LOGIC;
barpreset :IN STD_LOGIC;
q :OUT STD_LOGIC_VECTOR (3 downto 0));

attribute LOC : string;
ATTRIBUTE LOC of clock: signal is "P2";
ATTRIBUTE LOC of barreset: signal is "P3";
ATTRIBUTE LOC of barpreset: signal is "P4";
ATTRIBUTE LOC of q: signal is "P27 P26 P25 P24";
end;


--this one works


architecture howitcounts of counter is
TYPE statemachine IS (s0,s1,s2,s3,s4,s5,s6,s7,s8,s9);
begin
PROCESS (clock,barreset)
VARIABLE state: statemachine;
begin
if (barreset = '0') then
state := s0;
elsif rising_edge(clock) then
if (barpreset = '0') then --########
state := s8; --########
end if; --########
CASE state IS
WHEN s0 => state := s1;
WHEN s1 => state := s2;
WHEN s2 => state := s3;
WHEN s3 => state := s4;
WHEN s4 => state := s5;
WHEN s5 => state := s6;
WHEN s6 => state := s7;
WHEN s7 => state := s8;
WHEN s8 => state := s9;
WHEN s9 => state := s0;
WHEN OTHERS => state := s0;
END CASE;
end if;

CASE state is
WHEN s0 => q <= "0000";
WHEN s1 => q <= "0001";
WHEN s2 => q <= "0010";
WHEN s3 => q <= "0011";
WHEN s4 => q <= "0100";
WHEN s5 => q <= "0101";
WHEN s6 => q <= "0110";
WHEN s7 => q <= "0111";
WHEN s8 => q <= "1000";
WHEN s9 => q <= "1001";
WHEN OTHERS => q <= "0000";
END CASE;
END PROCESS;

end howitcounts;
............................................................

this next program DOES NOT work nicely. It requires about 13 flipflops
and thus fails miserably when using a GAL22V10C (10 flipflops). The
ONLY diference between the two, is 3 lines removed that control the
synchronous preset (I have shown #####'s on the 1st program where that
code is).
Hopefully your newsreader will preserve tabs.... otherwise this code
will be a mess to read.
The implementation is rather clunky for a 4 bit counter, because I
will use this program as a template for much more complicated state
machines.
I suspect that the compiler thinks that the circuit will remember
the states in one case, and won't remember then in the other case,
hence it needs a flipflop for every state. The "prefit equations"
suggest that there is a shift register synthesized for the "bad
circuit". I am not very comfortable with FSM details, but it would
appear that it might be trying to create a "one-hot" implementation.
Am I totally misled? Why should there be such a difference in
implementation? Would I be better off to break this program up into
more processes? Did I screw up in the if-else blocks?
Thanks for any help......

-Paul
 
A few comments:
The two USE statements,
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;
are not needed.

The WHEN OTHERS clauses of the two CASE statements are not needed since
all possible values of "state" are already covered by the other WHEN
clauses.

Also, are you trying to preset the state machine to s8 or s9?
 
Paul,
It is surprising that you have different synthesis results.
Since your "CASE state is" fully covers all possibilities,
the lines marked with "--########" have no synthesis semantic.

I agree that the second implementation seems to be implemented as
one-hot. The synthesis tool probably will not do this by
default. I suspect that some how when you were synthesizing
the second design that you accidentally selected one-hot.
You might check your constraints and try again. If that does
not work, try selecting binary/sequentical encoding (not gray)
to try to get it closer to what you want.

If that does not work, you might try using Synplicity's
"syn_encoding" to force the coding to something exactly the
values you expect for Q.


Alternately, if you want to stop fooling around with synthesis
tool switches, use use a counter. I do this for ring
counters like you show:

architecture howitcounts of counter is
signal StateReg : unsigned(3 downto 0) ;
begin
StateProc : PROCESS (clock,barreset)
begin
if (barreset = '0') then
StateReg <= "0000" ;
elsif rising_edge(clock) then
If StateReg = 9 then
StateReg <= "0000" ;
else
StateReg <= StateReg + 1 ;
end if ;
end if ;
end process ;

Q <= std_logic_vector(StateReg) ;


Cheers,
Jim
P.S.
I recommend the use of the package numeric_std rather
than std_logic_arith for all new designs.
--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis
Director of Training mailto:Jim@SynthWorks.com
SynthWorks Design Inc. http://www.SynthWorks.com
1-503-590-4787

Expert VHDL Training for Hardware Design and Verification
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Paul Guy wrote:
I have been puzzled by the fact that two implementations have such
drastic differences in synthesized circuits. I know that I have failed
to cover all the if-then-else possibilities (that's required to
generate SOME of the flipflops). I am really at my wit's end trying to
get my head around the "why" and the "howto get around it" of the
following situation:

first program, it is compiled under Lattice & Synplify, and it
works just fine, it's a 4 bit counter, described as a finite state
machine, using an asynch reset and synchronous preset (the chips we're
using do not allow asynch preset). This one synthesizes nicely to 4
flipflops.
The 2nd program is the same as the first, except the lines with
##### in them are removed.
.......................................................................
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.std_logic_arith.all;

entity counter is
PORT(clock :IN STD_LOGIC;
barreset :IN STD_LOGIC;
barpreset :IN STD_LOGIC;
q :OUT STD_LOGIC_VECTOR (3 downto 0));

attribute LOC : string;
ATTRIBUTE LOC of clock: signal is "P2";
ATTRIBUTE LOC of barreset: signal is "P3";
ATTRIBUTE LOC of barpreset: signal is "P4";
ATTRIBUTE LOC of q: signal is "P27 P26 P25 P24";
end;


--this one works


architecture howitcounts of counter is
TYPE statemachine IS (s0,s1,s2,s3,s4,s5,s6,s7,s8,s9);
begin
PROCESS (clock,barreset)
VARIABLE state: statemachine;
begin
if (barreset = '0') then
state := s0;
elsif rising_edge(clock) then
if (barpreset = '0') then --########
state := s8; --########
end if; --########
CASE state IS
WHEN s0 => state := s1;
WHEN s1 => state := s2;
WHEN s2 => state := s3;
WHEN s3 => state := s4;
WHEN s4 => state := s5;
WHEN s5 => state := s6;
WHEN s6 => state := s7;
WHEN s7 => state := s8;
WHEN s8 => state := s9;
WHEN s9 => state := s0;
WHEN OTHERS => state := s0;
END CASE;
end if;

CASE state is
WHEN s0 => q <= "0000";
WHEN s1 => q <= "0001";
WHEN s2 => q <= "0010";
WHEN s3 => q <= "0011";
WHEN s4 => q <= "0100";
WHEN s5 => q <= "0101";
WHEN s6 => q <= "0110";
WHEN s7 => q <= "0111";
WHEN s8 => q <= "1000";
WHEN s9 => q <= "1001";
WHEN OTHERS => q <= "0000";
END CASE;
END PROCESS;

end howitcounts;
...........................................................

this next program DOES NOT work nicely. It requires about 13 flipflops
and thus fails miserably when using a GAL22V10C (10 flipflops). The
ONLY diference between the two, is 3 lines removed that control the
synchronous preset (I have shown #####'s on the 1st program where that
code is).
Hopefully your newsreader will preserve tabs.... otherwise this code
will be a mess to read.
The implementation is rather clunky for a 4 bit counter, because I
will use this program as a template for much more complicated state
machines.
I suspect that the compiler thinks that the circuit will remember
the states in one case, and won't remember then in the other case,
hence it needs a flipflop for every state. The "prefit equations"
suggest that there is a shift register synthesized for the "bad
circuit". I am not very comfortable with FSM details, but it would
appear that it might be trying to create a "one-hot" implementation.
Am I totally misled? Why should there be such a difference in
implementation? Would I be better off to break this program up into
more processes? Did I screw up in the if-else blocks?
Thanks for any help......

-Paul
 
On Tue, 25 May 2004 10:08:44 -0700, Jim Lewis <Jim@SynthWorks.com>
wrote:

Paul,
It is surprising that you have different synthesis results.
Since your "CASE state is" fully covers all possibilities,
the lines marked with "--########" have no synthesis semantic.

I agree that the second implementation seems to be implemented as
one-hot. The synthesis tool probably will not do this by
default. I suspect that some how when you were synthesizing
the second design that you accidentally selected one-hot.
You might check your constraints and try again. If that does
not work, try selecting binary/sequentical encoding (not gray)
to try to get it closer to what you want.

If that does not work, you might try using Synplicity's
"syn_encoding" to force the coding to something exactly the
values you expect for Q.


Alternately, if you want to stop fooling around with synthesis
tool switches, use use a counter. I do this for ring
counters like you show:

architecture howitcounts of counter is
signal StateReg : unsigned(3 downto 0) ;
begin
StateProc : PROCESS (clock,barreset)
begin
if (barreset = '0') then
StateReg <= "0000" ;
elsif rising_edge(clock) then
If StateReg = 9 then
StateReg <= "0000" ;
else
StateReg <= StateReg + 1 ;
end if ;
end if ;
end process ;

Q <= std_logic_vector(StateReg) ;


Cheers,
Jim
P.S.
I recommend the use of the package numeric_std rather
than std_logic_arith for all new designs.



I later tried setting a constraint ("syn_encoding") and it yielded
more consistent results, but in this case both versions ended up as a
one-hot. My guess is that when I use an asynchronous reset, because
the state machine definition is bypassed in the "if" statement, the
states must be memorized, and that requires all 10 states to require
their own registers.
You are correct about modelling it as a counter..... it boils down
to the minimum 4 registers. The synthesis part of the package must
somehow realize that a counter is best done sequentially, and a state
machine is best done by one-hot, despite the constraints. The code I
finally chose looks remarkably like that you have shown above.
Originally this whole query came about as a result of trying to put
a 2 decade counter with reset, preset and carryout onto a 10 register
GALV2210. I was demonstrating the similiarities between a behavioural
representation as a counter (adding the counts), and a state machine.
The statemachine failed miserably - it required far too many
flipflops. Students are always quite interested in seeing how an
instructor "gets off the hook" in such a case. Both them and I did
learn something about the trade-offs between sequential and one-hot
implementations of state machines. Next year for this course I must
invest in chips with higher complexity - more gates and registers!
-Thanks for your help......

-Paul
 

Welcome to EDABoard.com

Sponsor

Back
Top