| # Copyright 2020 Efabless Corporation |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| # NORMAL MODE: inserts diode cells |
| # OPTIMIZED MODE: inserts a fake diode, to be replaced later with a real diode if necessary |
| |
| set input_def $::env(CURRENT_DEF) |
| set input_lef $::env(MERGED_LEF_UNPADDED) |
| set output_def $::env(SAVE_DEF) |
| |
| read_lef $input_lef |
| read_def $input_def |
| |
| set ::PREFIX ANTENNA |
| set ::VERBOSE 0 |
| set ::block [[[::ord::get_db] getChip] getBlock] |
| set ::antenna_pin_name $::env(DIODE_CELL_PIN) |
| set ::nets [$::block getNets] |
| |
| if { $::env(DIODE_INSERTION_STRATEGY) == 2 } { |
| if { ! [info exists ::env(FAKEDIODE_CELL)] } { |
| puts "\[ERROR\]: FAKEDIODE_CELL is undefined. Try a different DIODE_INSERTION_STRATEGY." |
| exit 1 |
| } |
| set ::antenna_cell_name $::env(FAKEDIODE_CELL) |
| } else { |
| set ::antenna_cell_name $::env(DIODE_CELL) |
| } |
| |
| proc add_antenna_cell { iterm } { |
| set antenna_master [[::ord::get_db] findMaster $::antenna_cell_name] |
| set antenna_mterm [$antenna_master getMTerms] |
| |
| set iterm_net [$iterm getNet] |
| set iterm_inst [$iterm getInst] |
| set iterm_inst_name [$iterm_inst getName] |
| set iterm_pin_name [[$iterm getMTerm] getConstName] |
| set inst_ori [$iterm_inst getOrient] |
| |
| foreach {success avg_iterm_x avg_iterm_y} [$iterm getAvgXY] {} |
| if { ! $success } { |
| foreach {avg_iterm_x avg_iterm_y} [$iterm_inst getLocation] {} |
| } |
| |
| set antenna_inst_name ${::PREFIX}_${iterm_inst_name}_${iterm_pin_name} |
| # create a 2-node "subnet" for the antenna (for easy removal) -> doesn't work |
| # set antenna_subnet [odb::dbNet_create $::block NET_${antenna_inst_name}] |
| set antenna_inst [odb::dbInst_create $::block $antenna_master $antenna_inst_name] |
| set antenna_iterm [$antenna_inst findITerm $::antenna_pin_name] |
| |
| $antenna_inst setLocation $avg_iterm_x $avg_iterm_y |
| $antenna_inst setOrient $inst_ori |
| $antenna_inst setPlacementStatus PLACED |
| $antenna_iterm connect $iterm_net |
| |
| if { $::VERBOSE } { |
| puts "\[INFO\]: Adding $antenna_inst_name on subnet $antenna_subnet for cell $iterm_inst_name pin $iterm_pin_name" |
| } |
| } |
| |
| set count 0 |
| puts "\[INFO\]: Inserting $::antenna_cell_name..." |
| foreach net $::nets { |
| set net_name [$net getName] |
| if { [expr {$net_name eq $::env(VDD_PIN)} || {$net_name eq $::env(GND_PIN)}] } { |
| puts "\[WARN\]: Skipping $net_name" |
| } else { |
| set iterms [$net getITerms] |
| foreach iterm $iterms { |
| if { [$iterm isInputSignal] } { |
| add_antenna_cell $iterm |
| set count [expr $count + 1] |
| } |
| } |
| } |
| } |
| puts "\n\[INFO\]: $count of $::antenna_cell_name inserted!" |
| set_placement_padding -masters $::env(DIODE_CELL) -left $::env(DIODE_PADDING) |
| puts "\[INFO\]: Legalizing..." |
| detailed_placement |
| if { [info exists ::env(PL_OPTIMIZE_MIRRORING)] && $::env(PL_OPTIMIZE_MIRRORING) } { |
| optimize_mirroring |
| } |
| write_def $::env(SAVE_DEF) |
| |
| if { [catch {check_placement -verbose} errmsg] } { |
| puts stderr $errmsg |
| exit 1 |
| } |