Search code examples
verilogsystem-verilog

I can't get which two assignment drives are conflicted together


I tried to make the watch that counts the time given that cycle of clk is a minute. But, I had troubles with finding which two assignment are being clashed. (I have been looking for two days but I couldn't find it)

First I tried these codes in the EDA playground.

//code for "design.sv"

module clock(
  input clk, rstn,
  output reg[6:0] minute,      //line 1
  output reg[5:0] hour         //line 2
);

  
  always @ (posedge clk, negedge rstn) begin
    if(!rstn) begin
        minute <= 0; hour = 0;
        end
    else begin
        minute = minute + 1;
        end
  end
  
  always @ (posedge clk) begin
    if((minute%60==0)&&(minute != 0)) begin
        minute <= 0;
        hour = hour + 1;
        end
    
    if((hour%24==0)&&(hour !=0)) hour <= 0;
  end
  
  
endmodule

//code for "testbench.sv"
module test;
  reg clk, rstn;
  reg [6:0] minute;
  reg [5:0] hour;
  
  initial begin
    clk = 0;
    forever #5 clk = ~clk;
  end
  
  initial begin
    rstn = 1; minute = 0; hour = 0;    //line 3
    #30 rstn = 0;
    #1 rstn = 1;
    #600 $finish;
  end
  
  clock clock_inst(clk, rstn, minute, hour);
  
  initial begin
    $dumpfiles("wave.vcd");
    $dumpvars(0, test);
  end
  
endmodule

I simulated these first codes and got the error below.

"Variable ""minute"" cannot be driven by both the procedural and continuous assignment statements. "Variable ""hour"" cannot be driven by both the procedural and continuous assignment statements.

My first conclusion: I concluded that assignments on line 1 and line 2 are making conflict with those of line 3. I thought output reg minute and output reg hour in clock_inst are implicit continuous assignment. Accordingly line 1 and line 2 clashes with assignments on minute and hour(placed in line 3) leading to multidriver issue in one variable.

However, in order to check my conclusion, I revised the code like below.

//revised code for "design.sv"

module clock(
  input clk, rstn,
  output reg[6:0] minute, 
  output reg[5:0] hour
);

  
  initial begin        // newly added block
    minute = 0; hour = 0;
  end
  
  always @ (posedge clk, negedge rstn) begin
    if(!rstn) begin
        minute <= 0; hour = 0;
        end 
    else begin
        minute = minute + 1;
        end
  end
  
  always @ (posedge clk) begin
    if((minute%60==0)&&(minute != 0)) begin
        minute <= 0;
        hour = hour + 1;
        end
    
    if((hour%24==0)&&(hour !=0)) hour <= 0;
  end
  
  
endmodule

//revised code for "testbench.sv"

module test;
  reg clk, rstn;
  reg [6:0] minute;
  reg [5:0] hour;
  
  initial begin
    clk = 0;
    forever #5 clk = ~clk;
  end
  
  initial begin
    rstn = 1;          //revised line
    #30 rstn = 0;
    #1 rstn = 1;
    #600 $finish;
  end
  
  clock clock_inst(clk, rstn, minute, hour);
  
  initial begin
    $dumpfiles("wave.vcd");
    $dumpvars(0, test);
  end
  
endmodule

What I thought is that these codes would give me error because assignment on newly added block would be clashed with output reg[6:0] minute and output reg[5:0] hour assignments.

But it worked really well

VSIM: Simulation has finished. There are no more test vectors to simulate.

VSIM: Simulation has finished.

Now, I cannot find what lines constigate multi-driving error in my first code.


Solution

  • In the original code, variable (reg) minute is driven from more than one always block.

    That is the definition multiple drivers, and will not synthesize.

    The solution is to put all drivers to the variables (regs) in one always block.
    Like this:

      always @ (posedge clk, negedge rstn) begin
        if(!rstn) begin
           minute <= 0;
           hour   <= 0;
        end
        
        else begin
    
            if(minute < 60) 
              minute <= minute + 1;
            else
              minute <= 0;
    
            if(minute < 24) 
              hour   <= hour + 1;
            else
              hour   <= 0;
          
        end
      end  
    

    The modulus operator will not synthesize well except in cases where you are taking a modulus which is a power of 2^N example: 2,4,8,16,32...

    Also take care to always use non-blocking assignments <= in a synchronous always block rather than blocking assignments =. Using blocking assignments in a synchronous always block can cause simulation/ synthesis mismatched behavior.

    What you are seeing in the revised code is an example of the simulator not correctly detecting the multiple drivers associated with the verilog always block in simulation. The SystemVerilog statement always_ff corrects this and will consistently detect a multiple drivers error in simulation and synthesis.

    To demonstrate, I changed the always blocks to always_ff and re-ran on eda playground.
    Like this:

    module clock(
      input clk, rstn,
      output reg[6:0] minute, 
      output reg[5:0] hour
    );
    
      
      initial begin        // newly added block
        minute = 0; hour = 0;
      end
      
      always_ff @ (posedge clk, negedge rstn) begin
        if(!rstn) begin
            minute <= 0; hour = 0;
            end 
        else begin
            minute = minute + 1;
            end
      end
      
      always_ff @ (posedge clk) begin
        if((minute%60==0)&&(minute != 0)) begin
            minute <= 0;
            hour = hour + 1;
            end
        
        if((hour%24==0)&&(hour !=0)) hour <= 0;
      end
      
    endmodule
    

    Produces:

        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable minute detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk, negedge rstn) begin
                  |
        xmelab: *E,MULAXX (./design.sv,13|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable hour detected.
          always_ff @ (posedge clk) begin
                  |
        xmelab: *E,MULAXX (./design.sv,22|10): Multiple drivers to always_ff output variable hour detected.
        xrun: *E,ELBERR: Error during elaboration (status 1), exiting.
    

    Using Cadence and similar using Modelsim/Questa.

    always_ff caught the multiple drivers and always missed it in simulation.