############################################################################# # This script was written and developed by ABKGroup students at UCSD. # However, the underlying commands and reports are copyrighted by Cadence. # We thank Cadence for granting permission to share our research to help # promote and foster the next generation of innovators. # Author: Sayak Kundu, ABKGroup, UCSD # # Usage: First source the script in Innovus shell. then use gen_pb_netlist # command to write out the netlist. The protobuf netlist will be available # as <design name>.pb.txt. ############################################################################# #### Print the design header #### proc print_header { fp } { set design [dbget top.name] set user [exec whoami] set date [exec date] set run_dir [exec pwd] set canvas_width [dbget top.fplan.coreBox_sizex] set canvas_height [dbget top.fplan.coreBox_sizey] puts $fp "# User: $user" puts $fp "# Date: $date" puts $fp "# Run area: $run_dir" puts $fp "# Block : $design" puts $fp "# FP bbox: {0.0 0.0} {$canvas_width $canvas_height}" ## Add dummy Column and Row info ## puts $fp "# Columns : 10 Rows : 10" } #### Print helper #### proc print_placeholder { fp key value } { puts $fp " attr {" puts $fp " key: \"$key\"" puts $fp " value {" puts $fp " placeholder: \"$value\"" puts $fp " }" puts $fp " }" } proc print_float { fp key value } { puts $fp " attr {" puts $fp " key: \"$key\"" puts $fp " value {" puts $fp " f: $value" puts $fp " }" puts $fp " }" } ### Helper to convert Orientation format ### proc get_orient { tmp_orient } { set orient "N" if { $tmp_orient == "R0"} { set orient "N" } elseif { $tmp_orient == "R180" } { set orient "S" } elseif { $tmp_orient == "R90" } { set orient "W" } elseif { $tmp_orient == "R270" } { set orient "E" } elseif { $tmp_orient == "MY" } { set oreint "FN" } elseif { $tmp_orient == "MX" } { set oreint "FS" } elseif { $tmp_orient == "MX90" } { set orient "FW" } elseif { $tmp_orient == "MY90" } { set orient "FE" } return $orient } #### Procedure to print the sinks #### proc print_net { net_ptr fp } { ### Print Terms ### foreach term [dbget [dbget ${net_ptr}.terms.isOutput 1 -p ].name -e] { puts $fp " input: \"${term}\"" } ### Print Macro Pins ### foreach macro_pin [dbget [dbget [dbget ${net_ptr}.instTerms.isInput 1 -p \ ].inst.cell.subClass block -p3 ].name -e] { puts $fp " input: \"${macro_pin}\"" } ### Print Stdcells ### foreach inst [dbget [dbget [dbget ${net_ptr}.instTerms.isInput 1 -p \ ].inst.cell.subClass core -p2 ].name -e] { puts $fp " input: \"${inst}\"" } } #### Procedure to write Ports #### proc write_node_port { port_ptr fp {origin_x 0} {origin_y 0} } { puts $fp "node {" set name [lindex [dbget ${port_ptr}.name] 0] puts $fp " name: \"${name}\"" if { [dbget ${port_ptr}.isInput] == 1 } { set net_ptr [dbget ${port_ptr}.net] print_net $net_ptr $fp } ### Attribute: type ### print_placeholder $fp "type" "port" ### Attribute: Side ### set tmp_side [dbget ${port_ptr}.side] set side "" if {$tmp_side == "West"} { set side "left" } elseif {$tmp_side == "East"} { set side "right" } elseif {$tmp_side == "North"} { set side "top" } elseif {$tmp_side == "South"} { set side "bottom" } else { puts "Error: Wrong Direction. Port Name: $name" } print_placeholder $fp "side" $side ### Attribute: X ### set X1 [lindex [dbget ${port_ptr}.pinShapes.rect] 0 0] set X2 [lindex [dbget ${port_ptr}.pinShapes.rect] 0 2] set X [expr ($X1 + $X2)/2] if {$side == "top" || $side == "bottom"} { set X [expr $X - $origin_x] } elseif { $side == "right" } { set X [expr $X - 2*$origin_x] } print_float $fp "x" $X ### Attribute: Y ### set Y1 [lindex [dbget ${port_ptr}.pinShapes.rect] 0 1] set Y2 [lindex [dbget ${port_ptr}.pinShapes.rect] 0 3] set Y [expr ($Y1 + $Y2)/2] if {$side == "left" || $side == "right"} { set Y [expr $Y - $origin_y] } elseif { $side == "top" } { set Y [expr $Y - 2*$origin_y] } print_float $fp "y" $Y puts $fp "}" } #### Procedure to write Macros #### proc write_node_macro { macro_ptr fp {origin_x 0} {origin_y 0}} { puts $fp "node {" set name [lindex [dbget ${macro_ptr}.name] 0] puts $fp " name: \"${name}\"" ### Attribute: ref_name ### set ref_name [dbget ${macro_ptr}.cell.name] print_placeholder $fp "ref_name" ${ref_name} ### Attribute: Width ### set width [dbget ${macro_ptr}.box_sizex] print_float $fp "width" $width ### Attribute: Height ### set height [dbget ${macro_ptr}.box_sizey] print_float $fp "height" $height ### Attribute: type ### print_placeholder $fp "type" "macro" ### Attribute: X ### set X1 [lindex [dbget ${macro_ptr}.box] 0 0] set X2 [lindex [dbget ${macro_ptr}.box] 0 2] set X [expr ($X1 + $X2)/2 - $origin_x] print_float $fp "x" $X ### Attribute: Y ### set Y1 [lindex [dbget ${macro_ptr}.box] 0 1] set Y2 [lindex [dbget ${macro_ptr}.box] 0 3] set Y [expr ($Y1 + $Y2)/2 - $origin_y] print_float $fp "y" $Y ### Attribute: Y ### set tmp_orient [dbget ${macro_ptr}.orient] set orient [get_orient $tmp_orient] print_placeholder $fp "orientation" $orient puts $fp "}" } #### Procedure to Write Macro Pins #### proc write_node_macro_pin { macro_pin_ptr fp {origin_x 0} {origin_y 0}} { puts $fp "node {" set name [lindex [dbget ${macro_pin_ptr}.name] 0] puts $fp " name: \"${name}\"" ### Print all the sinks ### if { [dbget ${macro_pin_ptr}.isOutput] == 1} { set net_ptr [dbget ${macro_pin_ptr}.net] print_net $net_ptr $fp } ### Attribute: Macro Name ### set macro_name [lindex [dbget ${macro_pin_ptr}.inst.name] 0] print_placeholder $fp "macro_name" $macro_name ### Attribute: type ### print_placeholder $fp "type" "macro_pin" set X [expr [dbget ${macro_pin_ptr}.pt_x] - $origin_x] set Y [expr [dbget ${macro_pin_ptr}.pt_y] - $origin_y] set cell_height [dbget ${macro_pin_ptr}.cellTerm.cell.size_y] set cell_width [dbget ${macro_pin_ptr}.cellTerm.cell.size_x] set pin_x [dbget ${macro_pin_ptr}.cellTerm.pt_x] set pin_y [dbget ${macro_pin_ptr}.cellTerm.pt_y] set x_offset [expr $pin_x - $cell_width/2] set y_offset [expr $pin_y - $cell_height/2] ### Attribute: x_offset ### print_float $fp "x_offset" $x_offset ### Attribute: y_offset ### print_float $fp "y_offset" $y_offset ### Attribute: X ### print_float $fp "x" $X ### Attribute: Y ### print_float $fp "y" $Y puts $fp "}" } #### Procedure to Write Std-cell ### proc write_node_stdcell { inst_ptr fp {origin_x 0} {origin_y 0}} { puts $fp "node {" set name [lindex [dbget ${inst_ptr}.name] 0] puts $fp " name: \"${name}\"" ### Print all the sinks ### foreach net_ptr [dbget [dbget ${inst_ptr}.instTerms.isOutput 1 -p ].net -e ] { print_net $net_ptr $fp } ### Attribute: ref_name ### set ref_name [dbget ${inst_ptr}.cell.name] print_placeholder $fp "ref_name" $ref_name ### Attribute: Width ### set width [dbget ${inst_ptr}.box_sizex] print_float $fp "width" $width ### Attribute: Height ### set height [dbget ${inst_ptr}.box_sizey] print_float $fp "height" $height ### Attribute: type ### print_placeholder $fp "type" "stdcell" ### Attribute: X ### set X1 [lindex [dbget ${inst_ptr}.box] 0 0] set X2 [lindex [dbget ${inst_ptr}.box] 0 2] set X [expr ($X1 + $X2)/2 - $origin_x] print_float $fp "x" $X ### Attribute: Y ### set Y1 [lindex [dbget ${inst_ptr}.box] 0 1] set Y2 [lindex [dbget ${inst_ptr}.box] 0 3] set Y [expr ($Y1 + $Y2)/2 - $origin_y] print_float $fp "y" $Y puts $fp "}" } #### Generate protobuff format netlist #### proc gen_pb_netlist { } { set design [dbget top.name] set out_file "${design}.pb.txt" set fp [open $out_file w+] print_header $fp set origin_x [dbget top.fplan.coreBox_llx] set origin_y [dbget top.fplan.coreBox_lly] foreach port_ptr [dbget top.terms] { write_node_port $port_ptr $fp $origin_x $origin_y } foreach macro_ptr [dbget top.insts.cell.subClass block -p2] { write_node_macro $macro_ptr $fp $origin_x $origin_y foreach macro_pin_ptr [dbget ${macro_ptr}.instTerms] { write_node_macro_pin $macro_pin_ptr $fp $origin_x $origin_y } } foreach inst_ptr [dbget top.insts.cell.subClass core -p2] { write_node_stdcell $inst_ptr $fp $origin_x $origin_y } close $fp puts "Output netlist: $out_file" }