Search code examples
verilogsystem-verilogverificationhdlsystem-verilog-assertions

illegal combination of always and assignment


I have planned to write verification for dual port ram with assertions but when I try to bind the property below. I have not used any rd pins or rst pins I have take my dut from

https://www.intel.com/content/www/us/en/programmable/support/support-resources/design-examples/design-software/verilog/ver-true-dual-port-ram-sclk.html

module dpram_property(
    input [7:0] data_a, data_b,
    input [5:0] addr_a, addr_b,
    input we_a, we_b, clk,
    output [7:0] q_a,
    output [7:0] q_b
);


property dp_ram_PORT_A_write;
  @(posedge clk) if(!we_a) (q_a-8'b1)==$past(q_a);
   endproperty

property dp_ram_PORT_B_write;
  @(posedge clk) if(!we_b) (q_b-8'b1)==$past(q_b);
   endproperty

initial
    begin          
      #20;
       assert property(dp_ram_PORT_A_write)
         $display($stime,,,"\n\t\t DP_RAM PORT-A WRITE CHECK PASS USING $past q_a=%d q_a_past=%d\n",q_a,$past(q_a));
       else
        $display($stime,,,"\n\t\t DP_RAM PORT-A WRITE CHECK FAIL USING $past q_a=%d q_a_past=%d\n",q_a,$past(q_a));
      #20;
       assert property(dp_ram_PORT_A_write)
        $display($stime,,,"\n\t\t DP_RAM PORT-A WRITE CHECK PASS USING $past q_a=%d q_a_past=%d\n",q_a,$past(q_a));
       else
        $display($stime,,,"\n\t\t DP_RAM PORT-A WRITE CHECK FAIL USING $past q_a=%d q_a_past=%d\n",q_a,$past(q_a));
        #5120;
         assert property(dp_ram_PORT_B_write)
           $display($stime,,,"\n\t\t DP_RAM PORT-B WRITE CHECK PASS USING $past q_b=%d q_b_past=%d\n",q_b,$past(q_b));
       else
         $display($stime,,,"\n\t\t DP_RAM PORT-B WRITE CHECK FAIL USING $past q_b=%d q_b_past=%d\n",q_b,$past(q_b));
        #20;
           assert property(dp_ram_PORT_B_write)
             $display($stime,,,"\n\t\t DP_RAM PORT-B WRITE CHECK PASS USING $past q_b=%d q_b_past=%d\n",q_b,$past(q_b));
       else
         $display($stime,,,"\n\t\t DP_RAM PORT-B WRITE CHECK FAIL USING $past q_b=%d q_b_past=%d\n",q_b,$past(q_b));
         end 
endmodule  

verification Testbench:

`include "dpram_property.sv"
`include "dpram.sv"
module testbench();
logic clk,we_a, we_b ;
logic [5:0] addr_a;
logic [7:0] data_a;
logic [5:0] addr_b;
logic [7:0] data_b;
wire [7:0] q_a;
wire [7:0] q_b;
dpram u1(.clk(clk),.we_a(we_a),.we_b(we_b),.addr_a(addr_a),.addr_b(addr_b),.data_a(data_a),.data_b(data_b),.q_a(q_a),.q_b(q_b));

bind dpram dpram_property inst(.clk(clk),.we_a(we_a),.we_b(we_b),.addr_a(addr_a),.addr_b(addr_b),.data_a(data_a),.data_b(data_b),.q_a(q_a),.q_b(q_b));

covergroup cg;
    option.per_instance=1;
    type_option.merge_instances=1; 
  coverpoint q_a
  {
    bins range[256]={[0:255]};  
    bins b1=(0=>1);
    bins b2=(1=>2);
  }
  coverpoint q_b
  {
    bins range[256]={[0:255]};

    // Transaction bins

    bins b1=(0=>1);
    bins b2=(2=>3);
  }
  coverpoint addr_a
  {
    bins range[64]={[0:63]};
  }
  coverpoint addr_b
  {
    bins range[64]={[0:63]};
  }
  coverpoint we_a;
  coverpoint we_b;

endgroup
cg cg_inst=new();
  always@(posedge clk)
    begin
      cg_inst.sample();
    end


initial
      begin
          clk=1'b1;
          forever #5 clk=~clk;
      end

initial
    begin
       we_a=1'b0;we_b=1'b0;;
      for(int i=1; i<=64;i++)
      begin
            we_a=1'b1;
            data_a<=i;
            addr_a=i-1;
            #10;we_a=1'b0;
            addr_a=i-1;
            #10;
        end

      for(int i=1; i<=64;i++)
      begin
            we_a=1'b1;
            data_a<=i+64;
            addr_a=i-1;
            #10;we_a=1'b0;
            addr_a=i-1;
            #10;
      end
      for(int i=1; i<=64;i++)
      begin
            we_a=1'b1;
            data_a<=i+127;
            addr_a=i-1;
            #10;we_a=1'b0;
            addr_a=i-1;
            #10;
      end
      for(int i=1; i<=64;i++)
      begin
            we_a=1'b1;
            data_a<=i+191;
            addr_a=i-1;
            #10;we_a=1'b0;
            addr_a=i-1;
            #10;
      end

      #20;we_a=1'b0;

      //port b writing and reading

        for(int i=1; i<=64;i++)
        begin
            we_b=1'b1;
            data_b=i;
            addr_b=i-1;
            #10;we_b=1'b0;
            addr_b=i-1;
            #10;
         end

      for(int i=1; i<=64;i++)
        begin
            we_b=1'b1;
            data_b=i+63;
            addr_b=i-1;
            #10;we_b=1'b0;
            addr_b=i-1;
            #10;
         end
      for(int i=1; i<=64;i++)
        begin
            we_b=1'b1;
            data_b=i+127;
            addr_b=i-1;
            #10;we_b=1'b0;
            addr_b=i-1;
            #10;
         end

      for(int i=1; i<=64;i++)
        begin
            we_b=1'b1;
            data_b=i+191;
            addr_b=i-1;
            #10;we_b=1'b0;
            addr_b=i-1;
            #10;
         end
      #20;we_b=1'b0;
       $finish;
    end
    always @(posedge clk)
            begin
              $display($stime,,,"clk=%b we_a=%b we_b=%b addr_a=%b data_a=%b addr_b=%b data_b=%b q_a=%d q_b=%d",clk,we_a, we_b,addr_a,data_a,addr_b,data_b,q_a, q_b);
            end
endmodule

I got the following error:

dpram_property inst (.clk(clk), .we_a(we_a), .we_b(we_b), .addr_a(addr_a), .addr_b(addr_b), .data_a(data_a), .data_b(data_b), .q_a(q_a), .q_b(q_b));
                                                                                                                                 |
ncelab: *E,ICDPAV (./INCA_libs/irun.lnx86.15.20.nc/.cdssvbind/cds_tmp_svbind_single_00000011_11ac6e15_1.sva,4|129): Illegal combination of driver and procedural assignment to variable q_a detected (procedural assignment found in always block at line 12 in file ./dpram.sv).
`line directed : file : ./testbench.sv, line : 14
dpram_property inst (.clk(clk), .we_a(we_a), .we_b(we_b), .addr_a(addr_a), .addr_b(addr_b), .data_a(data_a), .data_b(data_b), .q_a(q_a), .q_b(q_b));
                                                                                                                                            |
ncelab: *E,ICDPAV 

(./INCA_libs/irun.lnx86.15.20.nc/.cdssvbind/cds_tmp_svbind_single_00000011_11ac6e15_1.sva,4|140): Illegal combination of driver and procedural assignment to variable q_b detected (procedural assignment found in always block at line 26 in file ./dpram.sv).
    `line directed : file : ./testbench.sv, line : 14
    irun: *E,ELBERR: Error during elaboration (status 1), exiting.

I have also shared my code below what modifications should I do?

module dpram
  (
    input [7:0] data_a, data_b,
    input [5:0] addr_a, addr_b,
    input we_a, we_b, clk,
    output reg [7:0] q_a, q_b
);
    // Declare the RAM variable
    reg [7:0] ram[63:0];

    // Port A
    always @ (posedge clk)
    begin
        if (we_a) 
        begin
            ram[addr_a] <= data_a;
            q_a <= data_a;
        end
        else 
        begin
            q_a <= ram[addr_a];
        end
    end

    // Port B
    always @ (posedge clk)
    begin
        if (we_b)
        begin
            ram[addr_b] <= data_b;
            q_b <= data_b;
        end
        else
        begin
            q_b <= ram[addr_b];
        end
    end

endmodule

Solution

  • You declare q_a and q_b as output in the dpram_property module. Change them to input in that module:

    module dpram_property (
        input [7:0] data_a, data_b,
        input [5:0] addr_a, addr_b,
        input we_a, we_b, clk,
        input[7:0] q_a, q_b
    

    Inside your bound module (dpram_property), you don't want to drive signals which are driven in the target module (dpram) to avoid contention.

    I posted your code on edaplayground, and there are no more compile errors on Cadence Incisive.

    Cliff Cummings has a nice discussion on bind in this paper: SystemVerilog Assertions Design Tricks and SVA Bind Files