FPGARelated.com
Forums

Xilinx XST and a State Machine - A Mystery

Started by Darol Klawetter ●September 20, 2010
I recently fixed a problem with one of my state machines, and I think
that the cause could be a bug in Xilinx XST. Below is the code that
produced the failure. The state-machine worked most of the time,
though occasionally the 'phaseRamWE' signal would be stuck low, even
though I could see 'phaseRamReadAdr' and 'phaseRamWriteAdr'
incrementing.  I fixed it by explicitly declaring the desired value of
'phaseRamWE' in every state. Notice that all states are defined so it
should recover from any conditions introduced by asynchronous inputs.

Have any of you seen similar behavior? Appears to be an XST bug to me.



parameter [3:0]
    S1 = 4'b0000,
    S2 = 4'b0001,
    S3 = 4'b0010,
    S4 = 4'b0011,
    S5 = 4'b0100,
    S6 = 4'b0101,
    S7 = 4'b0110,
    S8 = 4'b0111,
    S9 = 4'b1000,
    S10 = 4'b1001,
    S11 = 4'b1010,
    S12 = 4'b1011,
    S13 = 4'b1100,
    S14 = 4'b1101,
    S15 = 4'b1110,
    S16 = 4'b1111;

always @(posedge rst or posedge clk)
begin
   if (rst)                                       // 'rst' is asserted
and deasserted synchronously to 'clk'
   begin
      rfd <= 1'b0;
      phaseRamWE <= 1'b0;
      phaseRamWriteAdr <= 0;
      phaseRamReadAdr <= 0;
      phaseAccum <= 0;
      state <= S1;
   end
   else
   begin
      case (state)
         S1:
         begin
            if (pipeFill == 1'b1)                     // 'pipeFill' is
asynchronous to 'clk'
            begin
               phaseRamWE <= 1'b1;
               state <= S2;
            end
         end

         S2:
         begin
            phaseRamReadAdr <= phaseRamReadAdr + 1;
            state <= S3;
         end


         S3:
         begin
            phaseRamReadAdr <= phaseRamReadAdr + 1;
            state <= S4;
         end

         S4:
         begin
            phaseRamWriteAdr <= phaseRamWriteAdr + 1;
            phaseRamReadAdr <= phaseRamReadAdr + 1;
            state <= S5;
         end

         S5:
         begin
            phaseRamWriteAdr <= phaseRamWriteAdr + 1;
            phaseRamReadAdr <= phaseRamReadAdr + 1;
            state <= S6;
         end

         S6:
         begin
            rfd <= 1'b1;
            phaseRamReadAdr <= phaseRamReadAdr + 1;
            phaseRamWriteAdr <= phaseRamWriteAdr + 1;
            if (start == 1'b0)                        // 'start' is
synchronous
            begin
               state <= S7;
            end
            else
            begin
               state <= S8;
            end
         end


         S7:
         begin
            if (start == 1'b0)                   // 'start' is
synchronous
            begin
               state <= S7;
            end
            else
            begin
               state <= S8;
               phaseRamReadAdr <= phaseRamReadAdr + 1;
               phaseRamWriteAdr <= phaseRamWriteAdr + 1;
            end
         end


         S8:
         begin
            if (start == 1'b0)                      // 'start' is
synchronous
            begin
               state <= S9;
               phaseRamWE <= 1'b0;
               phaseAccum <= 0;
               rfd <= 1'b0;
               phaseRamReadAdr <= 0;
               phaseRamWriteAdr <= 0;
            end
            else
            begin
               state <= S8;
               phaseRamReadAdr <= phaseRamReadAdr + 1;
               phaseRamWriteAdr <= phaseRamWriteAdr + 1;
            end
         end

         S9: state <= S10;
         S10: state <= S11;
         S11: state <= S12;
         S12: state <= S13;
         S13: state <= S14;
         S14: state <= S15;
         S15: state <= S16;
         S16: state <= S1;

      endcase

   end
end
Darol Klawetter wrote:

> I recently fixed a problem with one of my state machines, and I think > that the cause could be a bug in Xilinx XST. Below is the code that > produced the failure. The state-machine worked most of the time, > though occasionally the 'phaseRamWE' signal would be stuck low, even > though I could see 'phaseRamReadAdr' and 'phaseRamWriteAdr' > incrementing. I fixed it by explicitly declaring the desired value of > 'phaseRamWE' in every state. Notice that all states are defined so it > should recover from any conditions introduced by asynchronous inputs. > > Have any of you seen similar behavior? Appears to be an XST bug to me.
I have seen similar behaviour with Altera Quartus. It was the same problem: asynchronous inputs changed the state machine and sometimes it hangs. I think it is possible that the state machine is internally implemented with some more bits and it is possible that it hangs, if there are some timing violations or meta stability conditions, because then there is an invalid state encoded and everything can happen with optimized gates. The fix was easy: Creating an input latch (or even two, if you are paranoid) for each asynchronous signal to make it synchronous. -- Frank Buss, http://www.frank-buss.de piano and more: http://www.youtube.com/user/frankbuss
On Sep 20, 10:52=A0am, Darol Klawetter <darol.klawet...@l-3com.com>
wrote:
> I recently fixed a problem with one of my state machines, and I think > that the cause could be a bug in Xilinx XST. Below is the code that > produced the failure. The state-machine worked most of the time, > though occasionally the 'phaseRamWE' signal would be stuck low, even > though I could see 'phaseRamReadAdr' and 'phaseRamWriteAdr' > incrementing. =A0I fixed it by explicitly declaring the desired value of > 'phaseRamWE' in every state. Notice that all states are defined so it > should recover from any conditions introduced by asynchronous inputs. > > Have any of you seen similar behavior? Appears to be an XST bug to me. >
<snip> I only skimmed the code, but this bit jumped out at me: if (pipeFill =3D=3D 1'b1) // 'pipeFill' is asynchronous to 'clk' If pipeFill is really asynchronous to the clock that is running your state machine, using it without synchronizing it first is going to cause you problems. Probably not because of metastability, but because of coherency problems. If pipeFill is changing near the clock edge, some FFs will see the new value, and some the old. This can cause weird and flaky behaviour. Regards, John McCaskill www.FasterTechnology.com
On Sep 20, 11:00=A0am, Frank Buss <f...@frank-buss.de> wrote:
> Darol Klawetter wrote: > > I recently fixed a problem with one of my state machines, and I think > > that the cause could be a bug in Xilinx XST. Below is the code that > > produced the failure. The state-machine worked most of the time, > > though occasionally the 'phaseRamWE' signal would be stuck low, even > > though I could see 'phaseRamReadAdr' and 'phaseRamWriteAdr' > > incrementing. =A0I fixed it by explicitly declaring the desired value o=
f
> > 'phaseRamWE' in every state. Notice that all states are defined so it > > should recover from any conditions introduced by asynchronous inputs. > > > Have any of you seen similar behavior? Appears to be an XST bug to me. > > I have seen similar behaviour with Altera Quartus. It was the same proble=
m:
> asynchronous inputs changed the state machine and sometimes it hangs. I > think it is possible that the state machine is internally implemented wit=
h
> some more bits and it is possible that it hangs, if there are some timing > violations or meta stability conditions, because then there is an invalid > state encoded and everything can happen with optimized gates. The fix was > easy: Creating an input latch (or even two, if you are paranoid) for each > asynchronous signal to make it synchronous. > > -- > Frank Buss,http://www.frank-buss.de > piano and more:http://www.youtube.com/user/frankbuss
I thought the same thing, especially because XST often uses one-hot encoding internally, and that introduces more state bits. Even though I exhaustively defined all states, this may not be the case in the post-synthesis result.
On Sep 20, 11:05=A0am, John McCaskill <jhmccask...@gmail.com> wrote:
> On Sep 20, 10:52=A0am, Darol Klawetter <darol.klawet...@l-3com.com> > wrote: > > > I recently fixed a problem with one of my state machines, and I think > > that the cause could be a bug in Xilinx XST. Below is the code that > > produced the failure. The state-machine worked most of the time, > > though occasionally the 'phaseRamWE' signal would be stuck low, even > > though I could see 'phaseRamReadAdr' and 'phaseRamWriteAdr' > > incrementing. =A0I fixed it by explicitly declaring the desired value o=
f
> > 'phaseRamWE' in every state. Notice that all states are defined so it > > should recover from any conditions introduced by asynchronous inputs. > > > Have any of you seen similar behavior? Appears to be an XST bug to me. > > <snip> > > I only skimmed the code, but this bit jumped out at me: > > =A0 =A0 =A0 =A0 =A0 =A0 if (pipeFill =3D=3D 1'b1) =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 // 'pipeFill' is
> asynchronous to 'clk' > > If pipeFill is really asynchronous to the clock that is running your > state machine, =A0using it without synchronizing it first is going to > cause you problems. =A0Probably not because of metastability, but > because of coherency problems. If pipeFill is changing near the clock > edge, some FFs will see the new value, and some the old. =A0This can > cause weird and flaky behaviour. > > Regards, > > John McCaskillwww.FasterTechnology.com
Agreed, but the state machine should recover, right? All states are defined.
On Mon, 20 Sep 2010 08:52:16 -0700 (PDT), Darol Klawetter
<darol.klawetter@l-3com.com> wrote:

>I recently fixed a problem with one of my state machines, and I think >that the cause could be a bug in Xilinx XST. Below is the code that >produced the failure. The state-machine worked most of the time, >though occasionally the 'phaseRamWE' signal would be stuck low, even >though I could see 'phaseRamReadAdr' and 'phaseRamWriteAdr' >incrementing. I fixed it by explicitly declaring the desired value of >'phaseRamWE' in every state. Notice that all states are defined so it >should recover from any conditions introduced by asynchronous inputs. > >Have any of you seen similar behavior? Appears to be an XST bug to me.
Try adding a (* safe_implementation = "yes" *) to your state register and see if that gets rid of the problem. -- Muzaffer Kal DSPIA INC. ASIC/FPGA Design Services http://www.dspia.com
On Sep 20, 11:05=A0am, John McCaskill <jhmccask...@gmail.com> wrote:
> On Sep 20, 10:52=A0am, Darol Klawetter <darol.klawet...@l-3com.com> > wrote: > > > I recently fixed a problem with one of my state machines, and I think > > that the cause could be a bug in Xilinx XST. Below is the code that > > produced the failure. The state-machine worked most of the time, > > though occasionally the 'phaseRamWE' signal would be stuck low, even > > though I could see 'phaseRamReadAdr' and 'phaseRamWriteAdr' > > incrementing. =A0I fixed it by explicitly declaring the desired value o=
f
> > 'phaseRamWE' in every state. Notice that all states are defined so it > > should recover from any conditions introduced by asynchronous inputs. > > > Have any of you seen similar behavior? Appears to be an XST bug to me. > > <snip> > > I only skimmed the code, but this bit jumped out at me: > > =A0 =A0 =A0 =A0 =A0 =A0 if (pipeFill =3D=3D 1'b1) =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 // 'pipeFill' is
> asynchronous to 'clk' > > If pipeFill is really asynchronous to the clock that is running your > state machine, =A0using it without synchronizing it first is going to > cause you problems. =A0Probably not because of metastability, but > because of coherency problems. If pipeFill is changing near the clock > edge, some FFs will see the new value, and some the old. =A0This can > cause weird and flaky behaviour. > > Regards, > > John McCaskillwww.FasterTechnology.com
I think I just found the source of the problem, and it's not a bug in XST. In state S1, if 'state' is updated while 'phaseRamWE' is not, then it would produce the symptoms I saw. Early on, I had considered synchronizing pipeFill to the 'clk" domain, but I thought I would just handle it in the robustness of the state machine - my mistake.
On Sep 20, 11:12=A0am, Darol Klawetter <darol.klawet...@l-3com.com>
wrote:
> On Sep 20, 11:05=A0am, John McCaskill <jhmccask...@gmail.com> wrote: > > > > > On Sep 20, 10:52=A0am, Darol Klawetter <darol.klawet...@l-3com.com> > > wrote: > > > > I recently fixed a problem with one of my state machines, and I think > > > that the cause could be a bug in Xilinx XST. Below is the code that > > > produced the failure. The state-machine worked most of the time, > > > though occasionally the 'phaseRamWE' signal would be stuck low, even > > > though I could see 'phaseRamReadAdr' and 'phaseRamWriteAdr' > > > incrementing. =A0I fixed it by explicitly declaring the desired value=
of
> > > 'phaseRamWE' in every state. Notice that all states are defined so it > > > should recover from any conditions introduced by asynchronous inputs. > > > > Have any of you seen similar behavior? Appears to be an XST bug to me=
.
> > > <snip> > > > I only skimmed the code, but this bit jumped out at me: > > > =A0 =A0 =A0 =A0 =A0 =A0 if (pipeFill =3D=3D 1'b1) =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 // 'pipeFill' is
> > asynchronous to 'clk' > > > If pipeFill is really asynchronous to the clock that is running your > > state machine, =A0using it without synchronizing it first is going to > > cause you problems. =A0Probably not because of metastability, but > > because of coherency problems. If pipeFill is changing near the clock > > edge, some FFs will see the new value, and some the old. =A0This can > > cause weird and flaky behaviour. > > > Regards, > > > John McCaskillwww.FasterTechnology.com > > Agreed, but the state machine should recover, right? All states are > defined.
Hello Darol, While you may have specified all the possible states for the width of state variable that you used, unless you tell XST otherwise, it will choose which ever encoding style that it feels is optimal. That is usually a one hot encoding for a state machine the size of yours. By default, XST will assume that states that you do not explicitly have a transition to are truly unreachable and will not worry about them, and will ignore default or when others cases of your case statement. You can change the default behavior. You can force the tools to use an encoding of your choice, and you can use the safe state machine constraint to cause the tools to be more conservative in their assumptions about unreachable states. Doing that will come at a cost that the tools will choose a different encoding that will probably be slower and bigger. I think that you are much better off to always synchronize an asynchronous signal at the boundary of your design. Regards, John McCaskill www.FasterTechnology.com
On Sep 20, 11:55=A0am, John McCaskill <jhmccask...@gmail.com> wrote:
> On Sep 20, 11:12=A0am, Darol Klawetter <darol.klawet...@l-3com.com> > wrote: > > > > > On Sep 20, 11:05=A0am, John McCaskill <jhmccask...@gmail.com> wrote: > > > > On Sep 20, 10:52=A0am, Darol Klawetter <darol.klawet...@l-3com.com> > > > wrote: > > > > > I recently fixed a problem with one of my state machines, and I thi=
nk
> > > > that the cause could be a bug in Xilinx XST. Below is the code that > > > > produced the failure. The state-machine worked most of the time, > > > > though occasionally the 'phaseRamWE' signal would be stuck low, eve=
n
> > > > though I could see 'phaseRamReadAdr' and 'phaseRamWriteAdr' > > > > incrementing. =A0I fixed it by explicitly declaring the desired val=
ue of
> > > > 'phaseRamWE' in every state. Notice that all states are defined so =
it
> > > > should recover from any conditions introduced by asynchronous input=
s.
> > > > > Have any of you seen similar behavior? Appears to be an XST bug to =
me.
> > > > <snip> > > > > I only skimmed the code, but this bit jumped out at me: > > > > =A0 =A0 =A0 =A0 =A0 =A0 if (pipeFill =3D=3D 1'b1) =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 // 'pipeFill' is
> > > asynchronous to 'clk' > > > > If pipeFill is really asynchronous to the clock that is running your > > > state machine, =A0using it without synchronizing it first is going to > > > cause you problems. =A0Probably not because of metastability, but > > > because of coherency problems. If pipeFill is changing near the clock > > > edge, some FFs will see the new value, and some the old. =A0This can > > > cause weird and flaky behaviour. > > > > Regards, > > > > John McCaskillwww.FasterTechnology.com > > > Agreed, but the state machine should recover, right? All states are > > defined. > > Hello Darol, > > While you may have specified all the possible states for the width of > state variable that you used, unless you tell XST otherwise, it will > choose which ever encoding style that it feels is optimal. That is > usually a one hot encoding for a state machine the size of yours. =A0By > default, XST will assume that states that you do not explicitly have a > transition to are truly unreachable and will not worry about them, and > will ignore default or when others cases of your case statement. > > You can change the default behavior. You can force the tools to use an > encoding of your choice, and you can use the safe state machine > constraint to cause the tools to be more conservative in their > assumptions about unreachable states. Doing that will come at a cost > that the tools will choose a different encoding that will probably be > slower and bigger. > > I think that you are much better off to always synchronize an > asynchronous signal at the boundary of your design. > > Regards, > > John McCaskillwww.FasterTechnology.com
Thanks for the response, John. Yes, I realized that the Xilinx tools could use different state encoding than that specified by the user, but it seemed reasonable to assume that functionality would be matched (wrong assumption). Anyway, you may have noticed, from a previous post to this thread, that my problem was caused by my own error and was not tool related. I agree with your last paragraph. It's typically better to use a couple of flops on an asynchronous control signal than trying to handle it within the state machine (especially if the tool is going to take encoding liberties).
On Sep 20, 2:02=A0pm, Darol Klawetter <darol.klawet...@l-3com.com>
wrote:

> > I agree with your last paragraph. It's typically better to use a > couple of flops on an asynchronous control signal than trying to > handle it within the state machine (especially if the tool is going to > take encoding liberties).- Hide quoted text - >
The rule is that any time there is a logic path from an asynchronous input to more than one device that samples the signal(s), you must first synchronize the signal before feeding it into any logic path. This condition occurs for any state machine with more than one state. KJ