UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Visitor jnestorx
Visitor
705 Views
Registered: ‎07-13-2018

Simulation freezing with SystemVerilog interfaces (FSM handshake)

Hello,

 

I am encountering an issue with the Vivado Simulator freezing when trying to implement a valid-ready handshake between two state machines communicating through a systemVerilog interface.

 

Here is the interface:

 

interface vr_i #(parameter WIDTH=16);
  logic             valid;
  logic [WIDTH-1:0] data;
  logic             rdy;
  modport pr_port(output valid, data, input rdy);  // producer port                                                                          
  modport cs_port(input valid, data, output rdy);  // consumer port                                                                          
endinterface: vr_i

Next I created two modules called producer and consumer which use the modports to connect; for the purposes of the example they are just simple state machines - here is the producer, which in state PW asserts valid unconditionally and waits for rdy to be asserted.

module producer( input clk, rst,
                 vr_i.pr_port prp
               );

  logic        count_en;
  logic [7:0]  count;

  assign prp.data = count;

  always_ff @(posedge clk)
    if (rst) count <= '0;
    else if (count_en) count <= count + 1;

enum logic [2:0] { P1, P2, P3, P4, P5, PW } state, next; always_ff @(posedge clk) if (rst) state <= P1; else state <= next; always_comb // When valid=1 and rdy=1, simulation hangs bouncing between begin // this always block and the always block in ther consumer FSM // default values count_en = 0; prp.valid = 0; next = P1; // next state & output logic case (state) P1: begin count_en = 1; next = P2; end P2: next = P3; P3: next = P4; P4: next = P5; P5: next = PW; PW: begin prp.valid = 1; if (prp.rdy) next = P1; else next = PW; $display("producer rdy=%d valid=%d next=%s", prp.rdy, prp.valid, next.name()); end endcase end endmodule: producer

Here is the consumer, which asserts rdy in the CW state and waits for valid.

module consumer( input logic clk, rst,
                 vr_i.cs_port csp,
                 output logic [7:0] data_r
               );

  logic        ld_en;

  always_ff @(posedge clk)
    if (rst) data_r <= 0;
    else if (ld_en) data_r <= csp.data;


  enum logic [2:0] { CW, C1, C2, C3 } state, next;

  always_ff @(posedge clk)
    if (rst) state <= CW;
    else state <= next;

  always_comb  // When valid=1 and rdy=1, simulation hangs bouncing between                                                                  
    begin      // this always block and the always block in ther producer FSM                                                                
      // default values                                                                                                                      
      csp.rdy = 0;
      ld_en = 0;
      next = C1;
      case (state)
        CW: begin
               csp.rdy = 1;
              if (csp.valid)
                begin
                  ld_en = 1;
                  next = C1;
                end
              else next = CW;
              $display("consumer rdy=%d valid=%d next=%s", csp.rdy, csp.valid, next.name());
            end
        C1: next = C2;
        C2: next = C3;
        C3: next = CW;
      endcase
    end
endmodule

I have placed the entire example as I simulated it (including tesbench and top-level module) at the end of this message.

 

The problem I have is that simulation freezes when the two state machines are in the PW and CW states, which is where the handshake is supposed to take place.  Breaking simulation and single-stepping shows that the simulator is bouncing back and forth between the next state/output logic of the two state machines in an infinite loop, as if there were a loop in the combinational logic that was oscillating.  But since the ready and valid signals are both unconditional outputs there is no combinational loop!

I tried running this on another SystemVerilog simulator at EDA playground and it works as expected there.  The problem also goes away if I stick a delay operator into one of the state machine output blocks.  Any idea what is going on?  Am I missing something obvious?

 

Here is the complete code:

`timescale 1ns / 1ps

////////////////////////////////////////////////////////////////////////                                                                     
// interface declaration                                                                                                                     
////////////////////////////////////////////////////////////////////////                                                                     

interface vr_i #(parameter WIDTH=16);
  logic             valid;
  logic [WIDTH-1:0] data;
  logic             rdy;
  modport pr_port(output valid, data, input rdy);  // producer port                                                                          
  modport cs_port(input valid, data, output rdy);  // consumer port                                                                          
endinterface: vr_i

////////////////////////////////////////////////////////////////////////                                                                     
// producer FSM                                                                                                                              
////////////////////////////////////////////////////////////////////////                                                                     

module producer( input clk, rst,
                 vr_i.pr_port prp
               );

  logic        count_en;
  logic [7:0]  count;

  assign prp.data = count;

  always_ff @(posedge clk)
    if (rst) count <= '0;
    else if (count_en) count <= count + 1;


  enum logic [2:0] { P1, P2, P3, P4, P5, PW } state, next;

  always_ff @(posedge clk)
    if (rst) state <= P1;
    else state <= next;

  always_comb   // When valid=1 and rdy=1, simulation hangs bouncing between                                                                 

    begin      // this always block and the always block in ther consumer FSM                                                                
      // default values                                                                                                                      
      count_en = 0;
      prp.valid = 0;
      next = P1;
      // next state & output logic                                                                                                           
      case (state)
        P1: begin
              count_en = 1;
              next = P2;
            end
        P2: next = P3;
        P3: next = P4;
        P4: next = P5;
        P5: next = PW;
        PW: begin
              prp.valid = 1;
              if (prp.rdy) next = P1;
              else next = PW;
              $display("producer rdy=%d valid=%d next=%s", prp.rdy, prp.valid, next.name());
            end
      endcase
    end
endmodule: producer

////////////////////////////////////////////////////////////////////////                                                                     
// Consumer FSM                                                                                                                              
////////////////////////////////////////////////////////////////////////  

module consumer( input logic clk, rst,
                 vr_i.cs_port csp,
                 output logic [7:0] data_r
	       );

  logic        ld_en;

  always_ff @(posedge clk)
    if (rst) data_r <= 0;
    else if (ld_en) data_r <= csp.data;


  enum logic [2:0] { CW, C1, C2, C3 } state, next;

  always_ff @(posedge clk)
    if (rst) state <= CW;
    else state <= next;

  always_comb  // When valid=1 and rdy=1, simulation hangs bouncing between                                                                  
    begin      // this always block and the always block in ther producer FSM                                                                
      // default values                                                                                                                      
      csp.rdy = 0;
      ld_en = 0;
      next = C1;
      case (state)
        CW: begin
               csp.rdy = 1;
              if (csp.valid)
                begin
                  ld_en = 1;
                  next = C1;
                end
              else next = CW;
              $display("consumer rdy=%d valid=%d next=%s", csp.rdy, csp.valid, next.name());
            end
        C1: next = C2;
	C2: next = C3;
        C3: next = CW;
      endcase
    end
endmodule

////////////////////////////////////////////////////////////////////////                                                                     
// Top-level instantiates interface, producer, and consumer                                                                                  
////////////////////////////////////////////////////////////////////////                                                                     

module top(input clk, rst);

  logic [7:0] data_c;  // data consumed by consumer                                                                                          

  vr_i #(.WIDTH(8)) VR();  // instantiate interface                                                                                          

  consumer C (.clk, .rst, .csp(VR.cs_port), .data_r(data_c));

  producer P (.clk, .rst, .prp(VR.pr_port));

endmodule: top

////////////////////////////////////////////////////////////////////////                                                                     
//  Testbench                                                                                                                                
////////////////////////////////////////////////////////////////////////                                                                     

module vr_test_tb(

    );

    logic clk, rst;

    top TOP(.clk, .rst);


    always begin
      clk = 0; #5;
      clk = 1; #5;
    end

    initial begin
      rst = 1;
      @(posedge clk) #1;
      rst = 0;
      repeat (20) @(posedge clk);
      $display("All done, jack!");
      $stop;
    end
endmodule

 

 

0 Kudos
6 Replies
Moderator
Moderator
667 Views
Registered: ‎04-24-2013

Re: Simulation freezing with SystemVerilog interfaces (FSM handshake)

Hi @jnestorx,

 

I tried running the simulation in both Vivado and QuestaSim and the output was the same.

 

Capture3.JPG

 

I don't see the simulation freezing, but it is repeating the following

 

producer rdy=1 valid=1 next=P1
consumer rdy=1 valid=1 next=C1
producer rdy=1 valid=1 next=P1
consumer rdy=1 valid=1 next=C1

I believe that the always_comb is the issue. It is automatically executed once at time 0, but doesn't appear to be sensitive to the changes.

 

When I change this to always @(posedge clk)  then the simulation finishes.

consumer rdy=1 valid=0 next=CW
consumer rdy=1 valid=0 next=CW
consumer rdy=1 valid=0 next=CW
consumer rdy=1 valid=0 next=CW
consumer rdy=1 valid=0 next=CW
consumer rdy=1 valid=0 next=CW
consumer rdy=1 valid=0 next=CW
consumer rdy=1 valid=0 next=CW
producer rdy=1 valid=1 next=P1
consumer rdy=1 valid=1 next=C1
producer rdy=1 valid=1 next=P1
consumer rdy=1 valid=1 next=C1
All done, jack!

 

Best Regards
Aidan

 

------------------------------------------------------------------------------------------------------------------
Please mark the Answer as "Accept as solution" if this answered your question
Give Kudos to a post which you think is helpful and may help other users
------------------------------------------------------------------------------------------------------------------
0 Kudos
Visitor jnestorx
Visitor
650 Views
Registered: ‎07-13-2018

Re: Simulation freezing with SystemVerilog interfaces (FSM handshake)

Thank you for your response, amaccre. However, I think I need to clarify what exactly the code is doing.

 

Basically it is two FSMs, each implemented using an always_ff for a state register and an always_comb for the next state/output logic.  As I understand it this is a pretty standard way to code FSMs.  The two state machines are communicating using the valid and ready signals.

 

When I simulate this code the evaluation of the two always_comb blocks results in the infinite loop behavior (this is what I meant by "freezing") that you apparently duplicated on Questa.  However, reading the code I don't see any reason why this should be happening.  Changing the always_comb to an always_ff will resolve the simulation issue but will also result in a circuit that does not have the needed behavior as an FSM.

 

If I replace the interface with discrete signals, the infinite looping issue disappears; therefore I think this is a problem with how the Vivado simulator is handling interfaces.  By the way, the other simulator I ran it on was VCS.

 

Any other suggestions?

 

Thanks!

0 Kudos
Moderator
Moderator
599 Views
Registered: ‎04-24-2013

Re: Simulation freezing with SystemVerilog interfaces (FSM handshake)

Hi @jnestorx,

 

I am not a System Verilog expert so I may be wrong here, but my understanding of what is happening is that the always_comb is not sensitive to the changes in the state machine and that is why it is not moving through the states.

 

When it is changed to always @ it is changing on every clock tick so it is working as expected.

 

I'm happy to see that I'm wrong but from looking at the LRM that's my understanding.

 

Best Regards
Aidan

 

P.S. if you include the @ version of someones name in the reply then they get notified, otherwise it is easy to miss when people reply. 

------------------------------------------------------------------------------------------------------------------
Please mark the Answer as "Accept as solution" if this answered your question
Give Kudos to a post which you think is helpful and may help other users
------------------------------------------------------------------------------------------------------------------
0 Kudos
Visitor jnestorx
Visitor
585 Views
Registered: ‎07-13-2018

Re: Simulation freezing with SystemVerilog interfaces (FSM handshake)

Hello ,@amaccre
Perhaps I am not being clear about the problem, so let me restate it.  

 

When I simulate this example and the two state machines enter the PW and CW states respectively at time 55ns the simulator goes into an infinite loop between the two always_comb blocks. The simulation advances no further past this point in simulation time, and I can only stop it by manually interrupting the simulation.  If after interrupting I single step the simulation I see it bouncing back and forth between the two always_comb blocks that generate the next state and outputs of the two respective state machines.

 

Behavior like this often occurs when there is an unintentional loop between two always_comb blocks, where each changes its output depending on an input from the other.  However, that is *not*  what is occurring here as both state machine outputs depend *only* on the state that they were in.

 

So to restate, the problem is not that the state machine is not advancing, the problem is that the simulation goes into an infinite loop at t=55ns and time advances no further.

 

Thanks,

John

 

 

0 Kudos
Newbie peliasson
Newbie
239 Views
Registered: ‎01-18-2019

Re: Simulation freezing with SystemVerilog interfaces (FSM handshake)

Hi John,

I know it's a late reply, but I stumbled upon this while googling around, since I have the same problem.

I believe to have the answer to your (and mine) problem.

Consider that both always_comb statements are individual processes, consuming and creating events.

Now what happens is, that despite the fact there is no comb loop here, both processes will (at the time of freeze) produce events for each other (in sequence), though nothing is really changing. It is due to the default section in your (and mine) code.

Let's say the consumer process is entered in state CW, with rdy=1, this happens:

rdy->0 (default section)

rdy -> 1 (case section)

Though "rdy" in effect did not change, it does produce an event, which causes your producer process to wake up. Now the producer process is in state PW with valid=1, this happens:

valid -> 0 (default section)

valid -> 1 (case section)

Also in this case, though "valid" did not change in effect (still 1), this also produces an event, which now cause the consumer process to wake up. The story repeats itself...

 

In order to prove my case, I modified my code and removed the default section at the beginning of the FSM decode. Instead setting all outputs in each case statement. This solves the problem for me.

I did not test your code, but assume it would work same way.

Also, I am not suggesting this is the proper solution. I am still looking for that ;-) which is why I googled this..

Hope this helps, and I'd appreciate feedback to get to a long term nicer solution. How should this scenario be handled??

Regards,

Peter

0 Kudos
Newbie peliasson
Newbie
234 Views
Registered: ‎01-18-2019

Re: Simulation freezing with SystemVerilog interfaces (FSM handshake)

I now found another text which describes this, including a switch that some simulator will accept:

https://community.cadence.com/cadence_technology_forums/f/logic-design/15558/problem-with-simvision-hanging-in-an-endless-loop

0 Kudos