System Verilog Assertion Binding (SVA Bind)

Nowadays we use to deal with modules of Verilog or VHDL or a combination of both. Mostly verification engineers are not allowed to modify these modules. But still, SVA addition to these modules is required, and easy to verify a lot of RTL functionality. How can you add SVA to these modules?  Let’s find out !!

Here is where System Verilog ‘bind’ comes into the picture. Generally, you create an SVA bind file and instantiate sva module with the RTL module.SVA bind file requires assertions to be wrapped in a module that includes the port declaration, So now let’s understand this with a small example to understand basic things on  how to use SVA bind

module DUT_dummy (output logic [7:0] out,
                  output logic x,
                  input logic wr, rd, clk, rst,
                  input logic [7:0] in);
  
  //DUT Logic
  ...
  ...
  ...
  
endmodule : DUT_dummy
 
module SVA_dummy (input [7:0] out, in,
                  input x,
                  input wr, rd, clk, rst_n);
  
  ASSERTION1_NAME:
  `assert_async_rst(!rst_n |-> ...
                    
  ASSERTION2_NAME:
  `assert_clk (x > 1 |-> out);
  ...
 
endmodule : SVA_dummy
                    
module TB();
  logic [7:0] out;
  logic x;
  logic wr, rd, clk, rst;
  logic [7:0] in;
  
  //Instantiation
  
  DUT_dummy DUT_U1 (.*);
  
  //Binding with SVA using implicit port connection
  bind DUT_dummy : DUT_U1 SVA_dummy sva (.*);
  ...
  ...
endmodule : TB

Here, you can see that there is a DUT instantiation created DUT_u1 instance of DUT_dummy. Now the point of interest for us would be, how to bind the DUT instance to the SVA module.

To understand this take a look at an example where you could see the ‘bind’ keyword used with the DUT_dummy module and SVA_dummy. This is the place where we are binding the DUT module with the SVA module. Thus passing DUT signal information to the SVA module. With this, we could play around with the DUT signal and can check assertion properties using DUT signals available through this instantiation. If the assertion module uses the same signal names as the target module, the bind file port declarations are still required but the bind-instantiation can be done using the SystemVerilog (.*) implicit port connections that you can see in the example. If signal names are not exactly matching between target and bind file module then we need to expand the instantiation with respected port names.

Binding assertions to both modules and interfaces: Let’s say you have an interface called Initiator and a module called Target. You want to write an assertion that ensures that the Initiator interface always sends a request before sending a response. You can write this assertion in a separate file called assertions.sv. Then, you can bind the assertion to both the Initiator interface and the Target module using the following code:

module Initiator;
  ...
  bind assertions.sv Initiator;
  ...
endmodule

module Target;
  ...
  bind assertions.sv Target;
  ...
endmodule

This way, the assertion will be checked for both the Initiator interface and the Target module.

Binding assertions to specific instances of modules and interfaces: Let’s say you have a design that has two instances of the Target module. You want to write an assertion that ensures that the first instance of the Target module always sends a request before sending a response, but the second instance of the Target module does not need to follow this rule. You can write this assertion in a separate file called assertions.sv. Then, you can bind the assertion to the first instance of the Target module using the following code:

module Target1;
  ...
  bind assertions.sv Target1;
  ...
endmodule

module Target2;
  ...
  // No binding needed for Target2
  ...
endmodule

This way, the assertion will only be checked for the first instance of the Target module.

Binding assertions to multiple signals in a module or interface: Let’s say you have a module called Counter that has two signals called count and reset. You want to write an assertion that ensures that the count signal is always incremented by 1 when the reset signal is low. You can write this assertion in a separate file called assertions.sv. Then, you can bind the assertion to the count and reset signals using the following code:

module Counter;
  ...
  bind assertions.sv count, reset;
  ...
endmodule

This way, the assertion will be checked for the count and reset signals whenever they are accessed in the Counter module.

Binding assertions to variables in a module or interface: Let’s say you have a module called StateMachine that has a variable called state. You want to write an assertion that ensures that the state variable always changes to a specific value when a certain event occurs. You can write this assertion in a separate file called assertions.sv. Then, you can bind the assertion to the state variable using the following code:

module StateMachine;
  ...
  bind assertions.sv state;
  ...
endmodule

This way, the assertion will be checked for the state variable whenever it is changed in the StateMachine module.

I hope these examples help to clarify how SVA Bind can be used to achieve the benefits mentioned above.