Replacing Verific built-in primitives/operators with user implementations

From Verific Design Automation FAQ
Jump to: navigation, search

Below is a C++ application illustrating how to replace Verific's built-in primitives/operators with user implementations.

#include <iostream>

#include "veri_file.h"
#include "DataBase.h"
#include "VeriWrite.h"

#include "Strings.h"

using namespace std ;

#ifdef VERIFIC_NAMESPACE
using namespace Verific ;
#endif

int main(int argc, const char **argv)
{
    // Analyze & elaborate my design:
    if (!veri_file::Analyze("test.v")) return 1 ;
    if (!veri_file::Elaborate("test")) return 1 ;

    // Get the FADD primitive. It is in "Primitives" library"
    Library *prims = Library::Primitives() ;
    if (!prims) return 2 ;

    // Name of the cell is "VERIFIC_FADD":
    Cell *cell_fadd = prims->GetCell("VERIFIC_FADD") ;
    if (!cell_fadd) return 3 ;

    // And name of the netlist is "INTERFACE":
    Netlist *prim_fadd = cell_fadd->GetNetlist("INTERFACE") ;
    if (!prim_fadd) return 4 ;

    // Get my top level design:
    Netlist *top = Netlist::PresentDesign() ;
    if (!top) return 5 ;

    // Write out the original synthesized design:
    VeriWrite vw ;
    vw.WriteFile("test.v.golden.new", top) ;

    // Now read my own version of "fadd" having internal logic:
    if (!veri_file::Analyze("fadd.v")) return 6 ;
    if (!veri_file::Elaborate("fadd")) return 6 ;

    // Get the netlist for my "fadd"`
    // Current top-level design is the one elaborated last.
    Netlist *fadd = Netlist::PresentDesign() ;
    if (!fadd) return 6 ;

    // Make previous top-level design as top:
    top->SetPresentDesign() ;

    SetIter si ;
    Instance *inst ;

    // Now replace ALL references of Primitives.VERIFIC_FADD with my version of "fadd"
    prim_fadd->ReplaceReferences(fadd) ;
    // If one wants to selectively replace, (s)he can use the following instead:
#ifdef SELECTIVE
    FOREACH_REFERENCE_OF_NETLIST(prim_fadd, si, inst) {
        // Here one can skip some instances depending on whatever condition:
        inst->ReplaceView(fadd) ;
    }
#endif

    // Write out the design with Verific's primitive FADD replaced with my own "fadd":
    vw.WriteFile("replaced.v.golden.new", top) ;

    // Now, flatten the instantiations of my "fadd".
    // This will inline the logic added into its container:
    FOREACH_REFERENCE_OF_NETLIST(fadd, si, inst) {
        // One can choose to selectively flatten some instances as well:
        inst->Flatten(0, "_" /* path seprator */) ;
    }

    // Now this is VERIFIC_FADD replaced with my "fadd" logic:
    vw.WriteFile("flattened.v.golden.new", top) ;

    return 0 ;
}
 

Input testcase (test.v):

module test (input a, b, output s) ;
    assign s = a + b;
endmodule
 

User's implementation of fadd (fadd.v):

// Important: This module must have the same ports (name and size)
// as the primitive it is to replace.
module fadd (input cin, a, b, output o, cout) ;
    assign o = (a ^ b) ^ cin ;
    assign cout = ((a ^ b) & cin) | (a & b) ;
endmodule
 

Final netlist (flattened.v.golden.new):

//
// Verific Verilog Description of module test
//

module test (a, b, s);   // test.v(1)
    input a;   // test.v(1)
    input b;   // test.v(1)
    output s;   // test.v(1)


    add_1u_1u add_3 (.cin(1'b0), .a({a}), .b({b}), .o({s}));   // test.v(2)

endmodule

//
// Verific Verilog Description of OPERATOR add_1u_1u
//

module add_1u_1u (cin, a, b, o, cout);
    input cin;
    input [0:0]a;
    input [0:0]b;
    output [0:0]o;
    output cout;


    wire i1_n4, i1_n7, i1_n8;

    xor (i1_n4, a[0], b[0]) ;   // fadd.v(2)
    xor (o[0], i1_n4, cin) ;   // fadd.v(2)
    and (i1_n7, i1_n4, cin) ;   // fadd.v(3)
    and (i1_n8, a[0], b[0]) ;   // fadd.v(3)
    or (cout, i1_n7, i1_n8) ;   // fadd.v(3)

endmodule