Buffering signals and ungrouping
From Verific Design Automation FAQ
Revision as of 16:07, 19 April 2021 by Hoa (Talk | contribs) (Created page with "During ungrouping (flattening) a hierarchical design, there are nets that need to be merged. The name of the resulting net from the merge will be the name in the highest level...")
During ungrouping (flattening) a hierarchical design, there are nets that need to be merged. The name of the resulting net from the merge will be the name in the highest level of the design hierarchy.
This application example shows how to preserve the net name in the lower hierarchy level by adding a buffer to the net before ungrouping. In particular, it preserves the names of the output flip-flops in lower hierarchy levels.
#include "Map.h" #include "Set.h" #include "Message.h" #include "veri_file.h" #include "DataBase.h" #include "Netlist.h" #include "Array.h" #include "VeriWrite.h" #include "RuntimeFlags.h" #ifdef VERIFIC_NAMESPACE using namespace Verific ; #endif static void Flatten(Netlist *top_netlist) { Set all_netlists(POINTER_HASH) ; top_netlist->Hierarchy(all_netlists,1/*top-to-bottom*/) ; // Iterate over all netlists in which we will do flattening : SetIter si ; Instance *inst ; Netlist *netlist ; FOREACH_SET_ITEM(&all_netlists, si, &netlist) { if (!netlist) continue ; // Collect all instances in this netlist : Array insts(netlist->NumOfInsts()) ; MapIter mi ; FOREACH_INSTANCE_OF_NETLIST(netlist, mi, inst) { insts.InsertLast(inst) ; } // Flatten the instances while (insts.Size()!=0) { inst = (Instance*)insts.RemoveLast() ; if (inst->IsPrimitive()) continue ; (void) inst->Flatten() ; } top_netlist->PropagateConstants() ; } } static void BufferFlipflops(Netlist *netlist) { if (!netlist) return ; // nothing to do. if (netlist->IsBlackBox()) return; // nothing to do. if (netlist->IsEmptyBox()) return; // nothing to do. MapIter mii ; Instance *inst ; FOREACH_INSTANCE_OF_NETLIST(netlist, mii, inst) { if (inst->Type()==PRIM_DFFRS) { // This is the instantiation of a flip-flop, buffer its output Net *onet = inst->GetOutput() ; if (onet) { Net *new_onet = netlist->Buf(onet, onet->Linefile()); // Add a buffer to the DFF output char *new_name = Strings::save("new_", onet->Name()); // Name the output of the buffer new_onet->SetName(new_name); Strings::free(new_name); SetIter si; Port *port; FOREACH_PORT_OF_NET (onet, si, port) { // move ports if (!port) continue; new_onet->Connect(port); onet->Disconnect(port); } } } } } // This function is recursive in nature, and collects all other // netlists that the incoming netlist depends on in a container. void Accumulate(Netlist *netlist, Set &done) { if (!netlist) return ; // Ignore NULL netlists SetItem *item = done.GetItem(netlist) ; if (item) { return ; // We've already been here } Instance *inst ; MapIter mi ; FOREACH_INSTANCE_OF_NETLIST(netlist, mi, inst) { // Now go into the netlist associated with the instance Accumulate(inst->View(), done) ; } // Insert the traversed Netlist done.Insert(netlist) ; } int main(int argc, char **argv) { if (argc < 2) Message::PrintLine("reading default input file: test.v. Specify command line argument to override") ; const char *file_name = 0 ; if (argc>1) { file_name = argv[1] ; // Set the file name as specified by the user } else { file_name = "test.v" ; // Set default file name } // Now read in top-level design. In case of failure return. if (!veri_file::Read(file_name,"work", veri_file::VERILOG_2K)) { // Here, design analysis and elaboration failed return 1 ; } // Get a handle to the top-level netlist Netlist *top = Netlist::PresentDesign() ; if (!top) { Message::PrintLine("cannot find any handle to the top-level netlist") ; return 4 ; } // Print out module that we have handle to Message::Msg(VERIFIC_INFO, 0, top->Linefile(), "top level design is %s(%s)", top->Owner()->Name(), top->Name()) ; // RuntimeFlags::SetVar("db_verilog_writer_write_structural_instance_names", 1); VeriWrite veriWriter; veriWriter.WriteFile ("nl_before.v", top); // Lets accumulate all netlist Set netlists(POINTER_HASH) ; Accumulate(top, netlists) ; // Traverse the design and add buffers to output of flipflops Netlist *netlist ; SetIter si ; FOREACH_SET_ITEM(&netlists, si, &netlist) { BufferFlipflops(netlist) ; } veriWriter.WriteFile ("nl_after.v", top); Flatten(top); veriWriter.WriteFile ("flat_after.v", top); // All done. Wasn't that easy ? return 0 ; }
RTL input:
module top (clk, reset, a, b, s); input clk, reset; input [1:0] a, b; output [1:0] s; wire [1:0] ta, tb, ts; bot ia (clk, reset, a, ta); bot ib (clk, reset, b, tb); assign ts = ta + tb; bot is (clk, reset, ts, s); endmodule module bot (clk, reset, input_d, output_q); input clk, reset; input [1:0] input_d; output [1:0] output_q; reg [1:0] output_q; always @ (posedge clk or posedge reset) begin if (reset) output_q <= 2'b00; else output_q <= input_d; end endmodule
Final flattened netlist:
module top (clk, reset, a, b, s) ; // test.v(1) input clk; // test.v(2) input reset; // test.v(2) input [1:0]a; // test.v(3) input [1:0]b; // test.v(3) output [1:0]s; // test.v(4) wire [1:0]\is/output_q ; // test.v(15) wire [1:0]ta; // test.v(5) wire [1:0]tb; // test.v(5) wire [1:0]ts; // test.v(5) wire [1:0]\ib/output_q ; // test.v(15) wire [1:0]\ia/output_q ; // test.v(15) wire \is/new_output_q[1] , \ib/new_output_q[1] , \add_3/cout , \add_3/n2 , \is/new_output_q[0] , \ib/new_output_q[0] , \ia/new_output_q[1] , \ia/new_output_q[0] ; buf (\is/new_output_q[0] , \is/output_q [0]) ; // test.v(15) buf (\is/new_output_q[1] , \is/output_q [1]) ; // test.v(15) VERIFIC_FADD \add_3/i1 (.cin(1'b0), .a(ta[0]), .b(tb[0]), .o(ts[0]), .cout(\add_3/n2 )); // test.v(8) VERIFIC_DFFRS \is/i6 (.d(ts[0]), .clk(clk), .s(1'b0), .r(reset), .q(\is/output_q [0])); // test.v(21) VERIFIC_DFFRS \is/i5 (.d(ts[1]), .clk(clk), .s(1'b0), .r(reset), .q(\is/output_q [1])); // test.v(21) VERIFIC_FADD \add_3/i2 (.cin(\add_3/n2 ), .a(ta[1]), .b(tb[1]), .o(ts[1]), .cout(\add_3/cout )); // test.v(8) buf (\ib/new_output_q[1] , \ib/output_q [1]) ; // test.v(15) buf (\ib/new_output_q[0] , \ib/output_q [0]) ; // test.v(15) VERIFIC_DFFRS \ib/i6 (.d(b[0]), .clk(clk), .s(1'b0), .r(reset), .q(\ib/output_q [0])); // test.v(21) VERIFIC_DFFRS \ib/i5 (.d(b[1]), .clk(clk), .s(1'b0), .r(reset), .q(\ib/output_q [1])); // test.v(21) buf (\ia/new_output_q[1] , \ia/output_q [1]) ; // test.v(15) buf (\ia/new_output_q[0] , \ia/output_q [0]) ; // test.v(15) VERIFIC_DFFRS \ia/i6 (.d(a[0]), .clk(clk), .s(1'b0), .r(reset), .q(\ia/output_q [0])); // test.v(21) VERIFIC_DFFRS \ia/i5 (.d(a[1]), .clk(clk), .s(1'b0), .r(reset), .q(\ia/output_q [1])); // test.v(21) endmodule