Coding an Asynchronous state machine

J

Jamie

I am trying to put together a state machine that is entirely
asynchronous - NO CLK involved at all. But I just cant seem to get it
to synthesize.

I have 2 port inputs, A and B, that I want to trigger the state
transitions and outputs. The structure im trying is something like the
following:


port(OBIT: out std_logic, A: in std_logic, B: in std_logic...)

process(A, B..)
if (A='0') and (B='0') then
OBIT <= '0';
next_state <= S1;
end if;
.....
end process;
 
R

Renaud Pacalet

Jamie a écrit :
I am trying to put together a state machine that is entirely
asynchronous - NO CLK involved at all. But I just cant seem to get it
to synthesize.

Do you have a rough idea of the kind of hardware you expect? If not, then you're
asking too much: a logic synthesizer just can't translate any VHDL description
in hardware.
I have 2 port inputs, A and B, that I want to trigger the state
transitions and outputs. The structure im trying is something like the
following:


port(OBIT: out std_logic, A: in std_logic, B: in std_logic...)

process(A, B..)
if (A='0') and (B='0') then
OBIT <= '0';
next_state <= S1;
end if;
.....
end process;

What is your favourite asynchronous church? DI, QDI, SI, bundle data, dual rail
encoding, two phases, four phases, other? Do you know what a Muller C-element
is? Asynchronous design is something very specific, although some asynchronous
priests pretend that synchronous design is just a sub-case of the much more
general asynchronous design. You can't use the classical synchronous flow (VHDL
+ logic synthesizer) without any modification. Google will give you some
pointers on using synchronous languages and CAD tools for asynchronous design
(one key name: Daniel H. Linder) but you'll need, at least, a specific standard
cells library... You can search for specific tools too (TAST, Marc Renaudin).

Best regards,
--
Renaud Pacalet, GET/ENST/COMELEC/LabSoC
Institut Eurecom BP 193, 2229 route des Cretes
F-06904 Sophia-Antipolis Cedex
Tel : +33 (0) 4 9300 2770
Fax : +33 (0) 4 9300 2627
Fight Spam! Join EuroCAUCE: http://www.euro.cauce.org/
 
M

Mike Treseler

Jamie said:
I am trying to put together a state machine that is entirely
asynchronous - NO CLK involved at all. But I just cant seem to get it
to synthesize.

You would have to fight your synthesis tools
tools to get any asynch feedback.

If this is an intellectual exercise, use schematic entry.
If you want this to work, add a clock.


-- Mike Treseler
 
J

Jamie

Actually I figured it out. Just used StateCAD to create my state
machine with async reset and CLK'ed output. Verified operation then
removed the CLK dependencies of the processes.

viola! It works.
 
R

Renaud Pacalet

Jamie a écrit :
Actually I figured it out. Just used StateCAD to create my state
machine with async reset and CLK'ed output. Verified operation then
removed the CLK dependencies of the processes.

viola! It works.

I'm affraid it doesn't at all. You're using VHDL to model something that has no
hardware equivalent. It simulates the way you want. OK. But you could also do it
in C++. By the way, after removing CLK from the sensivity list of your
synchronous processes, what signals remained?

Regards,
--
Renaud Pacalet, GET/ENST/COMELEC/LabSoC
Institut Eurecom BP 193, 2229 route des Cretes
F-06904 Sophia-Antipolis Cedex
Tel : +33 (0) 4 9300 2770
Fax : +33 (0) 4 9300 2627
Fight Spam! Join EuroCAUCE: http://www.euro.cauce.org/
 
J

Jamie

Renaud Pacalet said:
Jamie a écrit :

I'm affraid it doesn't at all. You're using VHDL to model something that has no
hardware equivalent. It simulates the way you want. OK. But you could also do it
in C++. By the way, after removing CLK from the sensivity list of your
synchronous processes, what signals remained?

Regards,

I believe it does. All the signals remained. It simulates and synthesis completely.
 
R

Renaud Pacalet

Jamie a écrit :
I believe it does. All the signals remained. It simulates and synthesis completely.

Well, a synchronous state machine is usually made of a synchronous state
register (with next state as data input, current state as data output, clock and
sync or async reset), a combinational circuit computing the next state from the
current state and the inputs and a combinational circuit computing the outputs
from the current state (and the inputs in case of a Meally machine). Usually
this leads to a single synchronous process modelling the state register or the
state register and the first combinational circuit plus one or more
combinational processes modelling the outputs computations. Usually the
sensivity list of the synchronous process contains only the clock and,
optionally, the asynchronous reset. So if you remove the clock you get an empty
list or the asynchronous reset, that is not much. Example with 3 processes:

type TSTATE is (S0, S1, S2);
signal STATE: TSTATE;
....
process(CLK, RSTN)
begin
if RSTN = '0' then
STATE <= S0;
elsif RISING_EDGE(CLK) then
case STATE is
when S0 => if IN0 = '1' then
STATE <= S1;
end if;
when S1 => STATE <= S2;
when S2 => if IN1 = '1' then
STATE <= S0;
end if;
end case;
end if;
end process;

OUT0 <= '1' when STATE = S0 else
'0';

OUT1<= '1' when STATE = S1 else
'0';

In this very simple example if you remove CLK from the sensivity list of the
synchronous process all you get is:

process(RSTN)
begin
if RSTN = '0' then
STATE <= S0;
elsif RISING_EDGE(CLK) then
case STATE is
when S0 => if IN0 = '1' then
STATE <= S1;
end if;
when S1 => STATE <= S2;
when S2 => if IN1 = '1' then
STATE <= S0;
end if;
end case;
end if;
end process;

I beleive most synthesizers will reject this with at least a bunch of warnings.
But if one does not then I can't imagine what it could synthesize. In case
StateCAD that I don't know puts every LHS signals in the sensivity list (some
tools do this, never understood why), after CLK removal you get:

process(RSTN, STATE, IN0, IN1)
begin
if RSTN = '0' then
STATE <= S0;
elsif RISING_EDGE(CLK) then
case STATE is
when S0 => if IN0 = '1' then
STATE <= S1;
end if;
when S1 => STATE <= S2;
when S2 => if IN1 = '1' then
STATE <= S0;
end if;
end case;
end if;
end process;

And I still can't imagine what could be synthesized from this. For my personal
culture could you give us your code before and after clock removal?

Best regards,
--
Renaud Pacalet, GET/ENST/COMELEC/LabSoC
Institut Eurecom BP 193, 2229 route des Cretes
F-06904 Sophia-Antipolis Cedex
Tel : +33 (0) 4 9300 2770
Fax : +33 (0) 4 9300 2627
Fight Spam! Join EuroCAUCE: http://www.euro.cauce.org/
 
F

fe

I beleive most synthesizers will reject this with at least a bunch of warnings.
But if one does not then I can't imagine what it could synthesize. In case
StateCAD that I don't know puts every LHS signals in the sensivity list (some
tools do this, never understood why), after CLK removal you get:

process(RSTN, STATE, IN0, IN1)
begin
if RSTN = '0' then
STATE <= S0;
elsif RISING_EDGE(CLK) then
case STATE is
when S0 => if IN0 = '1' then
STATE <= S1;
end if;
when S1 => STATE <= S2;
when S2 => if IN1 = '1' then
STATE <= S0;
end if;
end case;
end if;
end process;

And I still can't imagine what could be synthesized from this. For my personal
culture could you give us your code before and after clock removal?

Renaud,
Synthesizers don't need sensitivity list. The warning is only to tell you
that you will obtain different simulation result before and after synthesis.

process(rst_an)
begin
if rst_an = '0' then
....
elsif rising_edge(clk) then
...
end if;
end process;

is equivalent for the synthesizer to

process(rst_an, clk)
begin
if rst_an = '0' then
....
elsif rising_edge(clk) then
...
end if;
end process;

but not for the simulator. The warning is for that.

Jamie,
I don't know what you did but you can't simulate something and after that
modify it to synthesis. Circuit must have the same behaviour before and
after synthesis otherwise functional simulation is useless.

regards
fe
Sr ASIC Designer
 
R

Renaud Pacalet

fe a écrit :
Renaud,
Synthesizers don't need sensitivity list. The warning is only to tell you
that you will obtain different simulation result before and after synthesis.

I don't agree with that:

process(A, B)
begin
if A then
S <= B;
end if;
end process;

simulates and synthesizes as a latch while:

process(A)
begin
if A then
S <= B;
end if;
end process;

simulates and synthesizes as a DFF. This is an example where the sensivity list
is needed. I don't know if we could find another example... Any idea?

Regards,
--
Renaud Pacalet, GET/ENST/COMELEC/LabSoC
Institut Eurecom BP 193, 2229 route des Cretes
F-06904 Sophia-Antipolis Cedex
Tel : +33 (0) 4 9300 2770
Fax : +33 (0) 4 9300 2627
Fight Spam! Join EuroCAUCE: http://www.euro.cauce.org/
 
J

Jamie

Renaud Pacalet said:
Jamie a écrit :

Well, a synchronous state machine is usually made of a synchronous state
register (with next state as data input, current state as data output, clock and
sync or async reset), a combinational circuit computing the next state from the
current state and the inputs and a combinational circuit computing the outputs
from the current state (and the inputs in case of a Meally machine). Usually
this leads to a single synchronous process modelling the state register or the
state register and the first combinational circuit plus one or more
combinational processes modelling the outputs computations. Usually the
sensivity list of the synchronous process contains only the clock and,
optionally, the asynchronous reset. So if you remove the clock you get an empty
list or the asynchronous reset, that is not much. Example with 3 processes:

type TSTATE is (S0, S1, S2);
signal STATE: TSTATE;
...
process(CLK, RSTN)
begin
if RSTN = '0' then
STATE <= S0;
elsif RISING_EDGE(CLK) then
case STATE is
when S0 => if IN0 = '1' then
STATE <= S1;
end if;
when S1 => STATE <= S2;
when S2 => if IN1 = '1' then
STATE <= S0;
end if;
end case;
end if;
end process;

OUT0 <= '1' when STATE = S0 else
'0';

OUT1<= '1' when STATE = S1 else
'0';

In this very simple example if you remove CLK from the sensivity list of the
synchronous process all you get is:

process(RSTN)
begin
if RSTN = '0' then
STATE <= S0;
elsif RISING_EDGE(CLK) then
case STATE is
when S0 => if IN0 = '1' then
STATE <= S1;
end if;
when S1 => STATE <= S2;
when S2 => if IN1 = '1' then
STATE <= S0;
end if;
end case;
end if;
end process;

I beleive most synthesizers will reject this with at least a bunch of warnings.
But if one does not then I can't imagine what it could synthesize. In case
StateCAD that I don't know puts every LHS signals in the sensivity list (some
tools do this, never understood why), after CLK removal you get:

process(RSTN, STATE, IN0, IN1)
begin
if RSTN = '0' then
STATE <= S0;
elsif RISING_EDGE(CLK) then
case STATE is
when S0 => if IN0 = '1' then
STATE <= S1;
end if;
when S1 => STATE <= S2;
when S2 => if IN1 = '1' then
STATE <= S0;
end if;
end case;
end if;
end process;

And I still can't imagine what could be synthesized from this. For my personal
culture could you give us your code before and after clock removal?

Best regards,

My code follows. The commented out lines of code are what I removed to
be free of the clock.

-- VHDL code created by Xilinx's StateCAD 6.1i
-- Mon Oct 20 13:05:15 2003

-- This VHDL code (for use with Xilinx XST) was generated using:
-- enumerated state assignment with structured code format.
-- Minimization is enabled, implied else is disabled,
-- and outputs are speed optimized.

LIBRARY ieee;
USE ieee.std_logic_1164.all;


-- Finite State Machine to decode direction
-- of the HEDR-8000 OPTICAL SM ENCODER
-- ...00<->01<->11<->10...
ENTITY KDECODE IS
port (A,B: in std_logic;
--PORT (CLK,A,B,RESET: IN std_logic;
DBIT,UBIT : OUT std_logic);
attribute NOREDUCE: string;
END;

ARCHITECTURE BEHAVIOR OF KDECODE IS
TYPE type_sreg IS (S0,S1,S2,S3,S4,S5,S6,S7);
SIGNAL sreg, next_sreg : type_sreg;
SIGNAL next_DBIT,next_UBIT : std_logic;
attribute NOREDUCE of next_sreg: signal is "true";
BEGIN
process(next_sreg, next_DBIT, next_UBIT)
--PROCESS (CLK, RESET, next_sreg, next_DBIT, next_UBIT)
BEGIN
sreg <= next_sreg;
DBIT <= next_DBIT;
UBIT <= next_UBIT;
--IF ( RESET='1' ) THEN
-- sreg <= S0;
-- DBIT <= '0';
-- UBIT <= '0';
--ELSIF CLK='1' AND CLK'event THEN
-- sreg <= next_sreg;
-- DBIT <= next_DBIT;
-- UBIT <= next_UBIT;
--END IF;
END PROCESS;


PROCESS (sreg,A,B)
BEGIN
next_DBIT <= '0'; next_UBIT <= '0';

next_sreg<=S0;

CASE sreg IS
WHEN S0 =>
IF ( A='1' AND B='0' ) THEN
next_sreg<=S7;
next_UBIT<='0';
next_DBIT<='1';
END IF;
IF ( A='0' AND B='1' ) THEN
next_sreg<=S1;
next_DBIT<='0';
next_UBIT<='1';
END IF;
IF ( A='0' AND B='0' ) THEN
next_sreg<=S0;
next_DBIT<='0';
next_UBIT<='0';
END IF;
IF ( A='1' AND B='1' ) THEN
next_sreg<=S2;
next_DBIT<='0';
next_UBIT<='0';
END IF;
WHEN S1 =>
IF ( A='0' AND B='0' ) THEN
next_sreg<=S4;
next_DBIT<='1';
next_UBIT<='1';
END IF;
IF ( A='1' AND B='1' ) THEN
next_sreg<=S2;
next_DBIT<='0';
next_UBIT<='0';
END IF;
IF ( B='1' AND A='0' ) THEN
next_sreg<=S1;
next_DBIT<='0';
next_UBIT<='1';
END IF;
IF ( A='1' AND B='0' ) THEN
next_sreg<=S3;
next_DBIT<='0';
next_UBIT<='1';
END IF;
WHEN S2 =>
IF ( A='0' AND B='1' ) THEN
next_sreg<=S5;
next_UBIT<='0';
next_DBIT<='1';
END IF;
IF ( A='1' AND B='0' ) THEN
next_sreg<=S3;
next_DBIT<='0';
next_UBIT<='1';
END IF;
IF ( A='1' AND B='1' ) THEN
next_sreg<=S2;
next_DBIT<='0';
next_UBIT<='0';
END IF;
IF ( A='0' AND B='0' ) THEN
next_sreg<=S0;
next_DBIT<='0';
next_UBIT<='0';
END IF;
WHEN S3 =>
IF ( A='1' AND B='1' ) THEN
next_sreg<=S6;
next_DBIT<='1';
next_UBIT<='1';
END IF;
IF ( A='0' AND B='0' ) THEN
next_sreg<=S0;
next_DBIT<='0';
next_UBIT<='0';
END IF;
IF ( B='0' AND A='1' ) THEN
next_sreg<=S3;
next_DBIT<='0';
next_UBIT<='1';
END IF;
IF ( A='0' AND B='1' ) THEN
next_sreg<=S1;
next_DBIT<='0';
next_UBIT<='1';
END IF;
WHEN S4 =>
IF ( A='1' AND B='0' ) THEN
next_sreg<=S3;
next_DBIT<='0';
next_UBIT<='1';
END IF;
IF ( A='0' AND B='1' ) THEN
next_sreg<=S5;
next_UBIT<='0';
next_DBIT<='1';
END IF;
IF ( A='0' AND B='0' ) THEN
next_sreg<=S4;
next_DBIT<='1';
next_UBIT<='1';
END IF;
IF ( A='1' AND B='1' ) THEN
next_sreg<=S6;
next_DBIT<='1';
next_UBIT<='1';
END IF;
WHEN S5 =>
IF ( A='0' AND B='0' ) THEN
next_sreg<=S0;
next_DBIT<='0';
next_UBIT<='0';
END IF;
IF ( A='1' AND B='1' ) THEN
next_sreg<=S6;
next_DBIT<='1';
next_UBIT<='1';
END IF;
IF ( B='1' AND A='0' ) THEN
next_sreg<=S5;
next_UBIT<='0';
next_DBIT<='1';
END IF;
IF ( A='1' AND B='0' ) THEN
next_sreg<=S7;
next_UBIT<='0';
next_DBIT<='1';
END IF;
WHEN S6 =>
IF ( A='0' AND B='0' ) THEN
next_sreg<=S4;
next_DBIT<='1';
next_UBIT<='1';
END IF;
IF ( A='0' AND B='1' ) THEN
next_sreg<=S1;
next_DBIT<='0';
next_UBIT<='1';
END IF;
IF ( A='1' AND B='0' ) THEN
next_sreg<=S7;
next_UBIT<='0';
next_DBIT<='1';
END IF;
IF ( A='1' AND B='1' ) THEN
next_sreg<=S6;
next_DBIT<='1';
next_UBIT<='1';
END IF;
WHEN S7 =>
IF ( A='0' AND B='1' ) THEN
next_sreg<=S5;
next_UBIT<='0';
next_DBIT<='1';
END IF;
IF ( A='1' AND B='1' ) THEN
next_sreg<=S2;
next_DBIT<='0';
next_UBIT<='0';
END IF;
IF ( A='0' AND B='0' ) THEN
next_sreg<=S4;
next_DBIT<='1';
next_UBIT<='1';
END IF;
IF ( B='0' AND A='1' ) THEN
next_sreg<=S7;
next_UBIT<='0';
next_DBIT<='1';
END IF;
WHEN OTHERS =>
END CASE;
END PROCESS;
END BEHAVIOR;
 
J

Jim Lewis

I would not count on the DFF synthesizing to a DFF
in all synthesis tools (some make it a latch):
process(A)
begin
if A then
S <= B;
end if;
end process;

simulates and synthesizes as a DFF.

--
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Jim Lewis
Director of Training mailto:[email protected]
SynthWorks Design Inc. http://www.SynthWorks.com
1-503-590-4787

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

fe

Sorry, you are correct, latch is an exception to the rule.
Any latch construct without the appropriate sensitivity list will produce a
dff (I don't know why, probably because latch is normally unwanted that
syntesizer produce a dff).

This latch will provide a dff too in synthesis but not in simulation (no
latch, no dff)
process(B)
begin
if A then
S <= B;
end if;
end process;

Try these mux21.
process(A)
begin
if A then
S <= B;
else
S <= C;
end if;
end process;

process(B)
begin
if A then
S <= B;
else
S <= C;
end if;
end process;

process(C)
begin
if A then
S <= B;
else
S <= C;
end if;
end process;

Except latch, any combinatorial stuff with incomplete sensitivity list or
any clocked process without the clk in the sensitivity list will produce the
correct hardware (synthesis) but not the simulation.

regards
fe
 
F

fe

Sorry, you are correct, latch is an exception to the rule.
Any latch construct without the appropriate sensitivity list will produce a
dff (I don't know why, probably because latch is normally unwanted that
syntesizer produce a dff).

with my synthesizer. Like Jim Lewis said, some tools will make the correct
latch.

fe
 
R

Renaud Pacalet

Jamie a écrit :
My code follows. The commented out lines of code are what I removed to
be free of the clock.
LIBRARY ieee;
USE ieee.std_logic_1164.all;


-- Finite State Machine to decode direction
-- of the HEDR-8000 OPTICAL SM ENCODER
-- ...00<->01<->11<->10...
ENTITY KDECODE IS
port (A,B: in std_logic;
--PORT (CLK,A,B,RESET: IN std_logic;
DBIT,UBIT : OUT std_logic);
attribute NOREDUCE: string;
END;

ARCHITECTURE BEHAVIOR OF KDECODE IS
TYPE type_sreg IS (S0,S1,S2,S3,S4,S5,S6,S7);
SIGNAL sreg, next_sreg : type_sreg;
SIGNAL next_DBIT,next_UBIT : std_logic;
attribute NOREDUCE of next_sreg: signal is "true";
BEGIN
process(next_sreg, next_DBIT, next_UBIT)
--PROCESS (CLK, RESET, next_sreg, next_DBIT, next_UBIT)
BEGIN
sreg <= next_sreg;
DBIT <= next_DBIT;
UBIT <= next_UBIT;
--IF ( RESET='1' ) THEN
-- sreg <= S0;
-- DBIT <= '0';
-- UBIT <= '0';
--ELSIF CLK='1' AND CLK'event THEN
-- sreg <= next_sreg;
-- DBIT <= next_DBIT;
-- UBIT <= next_UBIT;
--END IF;
END PROCESS;

Thanks Jamie for posting this code. It helps a lot understanding your design.
So, you started from a 2 processes style description, one synchronous (state
register plus outputs registers) and the other combinational (outputs and next
state computation). My first remark will be that the original sensivity list of
the synchronous process should be (CLK, RESET) and not what it was. The tool
you're using generates uselessly long sensivity lists for synchronous processes.
Harmless but it seriously slows down the simulation. My second remark is that by
removing the synchronous related stuff you turned DFFs into wires:

process(next_sreg, next_DBIT, next_UBIT)
begin
sreg <= next_sreg;
DBIT <= next_DBIT;
UBIT <= next_UBIT;
end process;

just says that any change on next_sreg, next_DBIT or next_UBIT will propagate to
the corresponding sreg, DBIT or UBIT. Due to the simulation algorithm this
propagation will take exactly one simulation step (one delta cycle). A
synthesizer will simply consider that next_sreg and sreg are two names for the
same net, same for DBIT and next_DBIT, UBIT and next_UBIT. Your second process
is a combinational one. At least it intends to be combinational. That is, any
change on the inputs (sreg, A, B), resumes the process that recomputes every
output (next_DBIT, next_UBIT, next_sreg). The way this process is written is not
as clean as one could expect. sreg beeing of enumerated type and the case
statement beeing complete on this type, everything is perfect on that side. But
A and B are of type std_logic (they probably should be of type std_ulogic but
it's another story, forget it) and they can take any value from the 9 possible
values of this type, not only '0' and '1'. When simulating your design, if A,
for instance, changes and get 'Z' as its new value then the process will resume
and schedule '0', '0', S0 for next_DBIT, next_UBIT, next_sreg. Something that
you can't achieve in hardware and could lead in before and after synthesis
simulation mismatches. But let's ignore it. The most important thing is that
next_DBIT, next_UBIT and next_sreg depend on sreg while from your modified first
process sreg is just another name for next_sreg (one delta cycle delayed in
simulation). So next_sreg depends on next_sreg. Nice combinational loop. I am
surprised that your synthesizer didn't warn you because the behaviour of such
loops is quite difficult to predict without, at least, an electrical simulation
(Spice, Eldo, etc.)

In a previous post you wrote that it works. What do you mean by "works"?
Simulate as you wanted before and after synthesis? or behaves as you wanted in
the FPGA?

Best regards,
--
Renaud Pacalet, GET/ENST/COMELEC/LabSoC
Institut Eurecom BP 193, 2229 route des Cretes
F-06904 Sophia-Antipolis Cedex
Tel : +33 (0) 4 9300 2770
Fax : +33 (0) 4 9300 2627
Fight Spam! Join EuroCAUCE: http://www.euro.cauce.org/
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top