#933 Simulation hangs with no reason

devel
closed-invalid
nobody
None
1
2013-06-18
2013-06-12
Diego Martín
No

I have to FSM that interacts with each other. One of them sets a start signal and after doing something, the other FSM sets a done signal.
It is happening that at the moment the done signal should be asserted, the simulation hangs (no more clock ticks & it doesn't advance in time)
Specificaly, the problem is caused by the signal cam_poweron_done inside camera_ctrl module.
I'm attaching the original code which generates the error (I've removed the uncessesary lines so the code doesn't have any functional sense, but it still reproduce the error)

1 Attachments

Discussion

  • Diego Martín
    Diego Martín
    2013-06-12

    This is the command line used to run the example attached:
    > iverilog tb_puntero_top.v -y . -o tb_puntero_top

     
    Last edit: Diego Martín 2013-06-12
  • Your problem is that you have a combinatorial loop between the two "always @*" blocks that calculate the next states for the two state machines. Moving the assignments to cam_poweron and cam_poweron_done into separate "always @*" blocks fixes the problem.

    I'll close this bug as invalid once you have had a chance to respond.

     
    Last edit: Martin Whitaker 2013-06-12
  • Diego Martín
    Diego Martín
    2013-06-14

    Hi Martin, thanks for your quick response.

    I don't see the combinational loops you are mentioning.
    The master controller fsm sets the cam_poweron signal.
    The camera controller fsm do whatever it is supposed to do and when it finishes it sets the cam_poweron_done which makes the master controller fsm go to the next state.
    The way I wrote both fsm is very typical of Moore codification.

    One thing I've tested is that if I assign the value of cam_poweron_done in each state, instead of assiging a default value outside the case statement and only seting it in the state it change its value, the simulation runs correctly.

    But I know this code works on other simulations, like Xilinx ISE, and it is also synthesizable so I think there aren't combinational loops.

    Is there something I'm not seeing?
    Thanks!
    Diego

     
  • Cary R.
    Cary R.
    2013-06-14

    Hi Diego,

    Martin is correct there is a loop. Here is a significantly simplified version of your code for just the state that causes the loop.

    module top;
    reg cam_poweron_done;
    reg cam_poweron;
    reg state;

    initial state = 1'b0;

    always @(*) begin
    cam_poweron_done = 1'b0;
    cam_poweron_done = 1'b1;
    if (state && cam_poweron) $display("A different state");
    end

    always @(*) begin
    cam_poweron = 1'b0;
    cam_poweron = 1'b1;
    if (state && cam_poweron_done) $display("A different state");
    end
    endmodule

    The state variable is only used to start the loop and to add the sensitivities to the appropriate @(*) without generating any output. So what you have is two always blocks that depend on each other and each changes the state of the variable the other depends on every time it runs. This likely synthesizes correctly since the final values are deterministic, but there is a zero time glitch that is causing Icarus to loop indefinitely. I'm not sure why the other simulator is not also looping. It may filter these zero time glitches, but I believe that is incorrect behavior.

    Note that using the -pfileline=1 flag in development when running the compiler produces diagnostic output during the run which makes it trivial to find the statements in the loop.

     
  • The likely reason that the other simulator is not looping is that in Diego's example the two state machines are in different modules, and cam_poweron and cam_poweron_done are connected via module ports. We can modify Cary's example to emulate this by adding a couple of intermediate wires, as follows:

    module top;
    reg cam_poweron_done;
    reg cam_poweron;
    reg state;
    
    wire w_cam_poweron_done = cam_poweron_done;
    wire w_cam_poweron = cam_poweron;
    
    initial state = 1'b0;
    
    always @(*) begin
    cam_poweron_done = 1'b0;
    cam_poweron_done = 1'b1;
    if (state && w_cam_poweron) $display("A different state");
    end
    
    always @(*) begin
    cam_poweron = 1'b0;
    cam_poweron = 1'b1;
    if (state && w_cam_poweron_done) $display("A different state");
    end
    endmodule
    

    With this example, the simulator has two options:

    1. Execute both procedural assignments in the always block, then update the wire assignment.
    2. Update the wire assignment after each procedural assignment.

    The first option will effectively filter out the glitches. Icarus does option 2, so is sensitive to the glitches. I believe both options are allowed by the IEEE-1394 standard.

    I've tested this on another simulator. Cary's original example loops indefinitely. Adding the wires prevents the loop

     
    • Priority: 7 --> 1
     
  • Cary R.
    Cary R.
    2013-06-14

    Yes, the wires/port which can act like a continuous assignment change the glitch dynamic.

     
  • Diego Martín
    Diego Martín
    2013-06-18

    Thanks! Finally I've understood the combinational loop. I also googled "zero time glitches" and found that's a typical problem and the behavior depends on each simulator.
    I'll fix my code assigning the value of the output in each state and not using the "default value" syntax.

     
  • Cary R.
    Cary R.
    2013-06-18

    • status: open --> closed-invalid
     
  • Cary R.
    Cary R.
    2013-06-18

    I am now closing this report as invalid.

    Don't forget the -pfileline=1 flag if you find yourself in a similar situation in the future. It can generate a huge amount of information but with this information it is mush easier to find the constructs that are caught in a loop.