Skip to content

Commit

Permalink
Merge pull request #106 from mabrains/dev
Browse files Browse the repository at this point in the history
Major Updates to LVS
  • Loading branch information
KrzysztofHerman authored May 8, 2024
2 parents e076932 + 275a484 commit 33c5b9b
Show file tree
Hide file tree
Showing 30 changed files with 611 additions and 588 deletions.
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
; ==========================================================================

[flake8]
max-line-length = 100
max-line-length = 120
max-complexity = 18

exclude =
Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,4 @@ cython_debug/
*.lvsdb
unit_tests_*
lvs_run_*

*_extracted.cir
96 changes: 71 additions & 25 deletions ihp-sg13g2/libs.tech/klayout/tech/lvs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,49 +106,69 @@ The `run_lvs.py` script takes your gds and netlist files to run LVS rule decks w

```bash
run_lvs.py (--help| -h)
run_lvs.py (--layout=<layout_path>) (--netlist=<netlist_path>) [--thr=<thr>]
run_lvs.py (--layout=<layout_path>) (--netlist=<netlist_path>)
[--run_dir=<run_dir_path>] [--topcell=<topcell_name>] [--run_mode=<run_mode>]
[--lvs_sub=<sub_name>] [--no_net_names] [--spice_comments] [--schematic_simplify]
[--net_only] [--top_lvl_pins] [--combine] [--purge] [--purge_nets] [--verbose]
[--lvs_sub=<sub_name>] [--no_net_names] [--spice_comments] [--net_only]
[--no_simplify] [--no_series_res] [--no_parallel_res] [--combine_devices]
[--top_lvl_pins] [--purge] [--purge_nets] [--verbose]
```

**Options:**

- `--help -h ` Print this help message.
- `--help -h ` Displays this help message.

- `--layout=<layout_path>` The input GDS file path.
- `--layout=<layout_path>` Specifies the file path of the input GDS file.

- `--netlist=<netlist_path>` The input netlist file path.
- `--netlist=<netlist_path>` Specifies the file path of the input netlist file.

- `--thr=<thr>` The number of threads used in run.
- `--run_dir=<run_dir_path>` Run directory to save all the generated results [default: pwd]

- `--run_dir=<run_dir_path>` Run directory to save all the results [default: pwd]
- `--topcell=<topcell_name>` Specifies the name of the top cell to be used.

- `--topcell=<topcell_name>` Topcell name to use.
- `--run_mode=<run_mode>` Selects the allowed KLayout mode. (flat, deep). [default: flat]

- `--run_mode=<run_mode>` Select Allowed klayout mode. (flat, deep). [default: flat]
- `--lvs_sub=<sub_name>` Sets the substrate name used in your design.

- `--lvs_sub=<sub_name>` Substrate name used in your design.
- `--no_net_names` Omits net names in the extracted netlist.

- `--no_net_names` Discard net names in extracted netlist.
- `--spice_comments` Includes netlist comments in the extracted netlist.

- `--spice_comments` Enable netlist comments in extracted netlist.
- `--net_only` Generates netlist objects only in the extracted netlist.

- `--net_only` Enable netlist object creation for extracted netlist.
- `--no_simplify` Disables simplification for both layout and schematic netlists.

- `--top_lvl_pins` Enable top level pins only for extracted netlist.
- `--no_series_res` Prevents the simplification of series resistors for both layout and schematic netlists.

- `--no_simplify` Disable layout simplification for extracted netlist.
- `--no_parallel_res` Avoids simplifying parallel resistors within the extracted netlist.

- `--combine` Enable netlist combination for extracted netlist.
- `--combine_devices` Enables device combination for both layout and schematic netlists.

- `--purge` Enable netlist purge all for extracted netlist.
- `--top_lvl_pins` Creates pins for top-level circuits in both layout and schematic netlists.

- `--purge_nets` Enable netlist purge nets for extracted netlist.
- `--purge` Removes unused nets from both layout and schematic netlists.

- `--schematic_simplify` Enable schematic simplification for input netlist.
- `--purge_nets` Purges floating nets from both layout and schematic netlists.

- `--verbose` Detailed rule execution log for debugging.
- `--verbose` Enables detailed rule execution logs for debugging purposes.


---
**NOTE**

* By utilizing the `no_simplify` option, you can prevent layout simplification for both layout and schematic netlists. Simplification is enabled by default, incorporating steps such as `make_top_level_pins`, `purge`, `combine_devices`, and `purge_nets`.
<br/>

* When you use the `no_simplify` option to disable simplification, you can then use the `make_top_level_pins`, `purge`, `combine_devices`, and `purge_nets` options individually to fine-tune the behavior according to your needs.
<br/>

* Series resistors with identical parameters (except length) will combine into one resistor with the total length.
<br/>

* Parallel resistors will merge into a single resistor with the parameter `m` representing the number of parallel resistors, provided they share identical parameters.
<br/>

* The options `no_series_res` and `no_parallel_res` are specifically designed to disable layout simplification for resistors exclusively. When specified, they take priority over `combine_devices` option.
---

**Example:**

Expand Down Expand Up @@ -218,15 +238,41 @@ KLAYOUT_PATH=$PDKPATH/libs.tech/klayout:$PDKPATH/libs.tech/klayout/tech/ klayout

Then, you will get the LVS menus for SG13G2, you could set your desired options as shown below:

> **_NOTE:_** You need to select the path of the netlist will be used in the LVS run. If no path is specified, the tool will automatically search for the netlist file in the same directory as the layout file, considering files with the extensions .cdl, .spice, or .cir and has same name of the layout file.
<p align="center">
<img src="images/lvs_menus_1.png" width="70%" >
</p>
<p align="center">
Fig. 5. Setting up LVS Options-GUI - 1
</p>

<p align="center">
<img src="images/lvs_menus.png" width="60%" >
<img src="images/lvs_menus_2.png" width="50%" >
</p>
<p align="center">
Fig. 5. Visualization of LVS results on Klayout-GUI
Fig. 6. Setting up LVS Options-GUI - 2
</p>

Finally, you could run the LVS using `Run Klayout LVS` option.
---
**NOTE**

* To utilize the LVS options, an active cell must be present. The currently active cell is automatically chosen as the default for running LVS. You could change it using `Top Cell` option.
<br/>

* To conduct the LVS comparison, you must specify the path to the schematic netlist via `Netlist Path` option. If no path is provided, the tool will search for the netlist file automatically. It will look for files with extensions such as .cdl, .spice, or .cir in the same directory as the layout file, matching the name of the layout file.

---

For additional details on GUI options, please refer to the [CLI Options section](#cli).

Finally, after setting your option, you could execute the LVS using `Run Klayout LVS` from the dropdown menu.

<p align="center">
<img src="images/lvs_menus_3.png" width="70%" >
</p>
<p align="center">
Fig. 7. Running LVS using Klayout menus
</p>

Upon executing the LVS, the result database will appear on your layout interface, allowing you to verify the outcome of the run similarly as shown above in Fig. 4.

Additionally, you can find the extracted netlist generated from your design at (`<layout_name>_extracted.cir`) in the same directory as the layout file.
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,17 @@ logger.info('Starting BJT DERIVATIONS')
logger.info('Starting NPN-BJT DERIVATIONS')

bjt_exclude = gatpoly_drw.join(pwell_block).join(nsd_drw)
.join(heatres_drw).join(salblock_drw).join(polyres_drw)
.join(mim_drw).join(extblock_drw).join(res_drw)
.join(recog_diode).join(recog_esd).join(ind_drw)
.join(ind_pin).join(substrate_drw)
.join(salblock_drw).join(polyres_drw).join(extblock_drw)
.join(res_drw).join(recog_diode).join(recog_esd)
.join(ind_drw).join(ind_pin).join(substrate_drw)

npn_exclude = nwell_drw.join(psd_drw).join(nbulay_drw).join(bjt_exclude)

# ---------- General NPN ----------
npn_mk = trans_drw.and(pwell).and(ptap_holes)
npn_c_exc = emwind_drw.join(emwihv_drw).join(activ_mask)
.join(nsd_block).join(heattrans_drw).join(npn_exclude)
npn_b_exc = emwind_drw.join(emwihv_drw).join(heattrans_drw).join(npn_exclude)
.join(nsd_block).join(npn_exclude)
npn_b_exc = emwind_drw.join(emwihv_drw).join(npn_exclude)
npn_sub = npn_mk.not(npn_exclude)
npn_dev = activ_drw.join(activ_mask).and(npn_mk)

Expand All @@ -51,7 +50,7 @@ npn13G2_e_exc = activ_drw.join(emwihv_drw).join(npn_exclude)
npn13G2_b_exc = npn_b_exc.join(activ_mask)

# npn13G2 nodes
npn13G2_e_ = emwind_drw.and(activ_mask).and(heattrans_drw).and(nsd_block).and(npn_mk).not(npn13G2_e_exc)
npn13G2_e_ = emwind_drw.and(activ_mask).and(nsd_block).and(npn_mk).not(npn13G2_e_exc)
# npn13G2 is a fixed device (0.07um X 0.9um)
npn13G2_e_pin = npn13G2_e_.with_bbox_min(0.07.um).with_bbox_max(0.9.um).with_area(0.063.um)
npn13G2_b_pin = nsd_block.and(npn_mk).not(npn13G2_b_exc)
Expand All @@ -71,7 +70,7 @@ npn13G2l_e_exc = activ_mask.join(nsd_block).join(emwihv_drw).join(npn_exclude)
npn13G2l_b_exc = npn_b_exc.join(activ_drw).join(nsd_block)

# npn13G2L nodes
npn13G2l_e_ = emwind_drw.and(activ_drw).and(heattrans_drw).and(npn_mk).not(npn13G2l_e_exc)
npn13G2l_e_ = emwind_drw.and(activ_drw).and(npn_mk).not(npn13G2l_e_exc)
# npn13G2L has fixed width (0.07um), Length could vary from 1:2.5 um
npn13G2l_e_pin = npn13G2l_e_.with_bbox_min(0.07.um).with_bbox_max(1.um, 2.5.um).with_area(0.07.um, 0.175.um)
npn13G2l_b_pin = activ_mask.and(npn_mk).not(npn13G2l_b_exc)
Expand All @@ -90,7 +89,7 @@ npn13G2l_te = npn13G2l_e
npn13G2v_e_exc = activ_mask.join(nsd_block).join(emwind_drw).join(npn_exclude)

# npn13G2V nodes
npn13G2v_e_ = emwihv_drw.and(activ_drw).and(heattrans_drw).and(npn_mk).not(npn13G2v_e_exc)
npn13G2v_e_ = emwihv_drw.and(activ_drw).and(npn_mk).not(npn13G2v_e_exc)
# npn13G2L has fixed width (0.12um), Length could vary from 1:5 um
npn13G2v_e_pin = npn13G2v_e_.with_bbox_min(0.12.um).with_bbox_max(1.um, 5.um).with_area(0.12.um, 0.6.um)
npn13G2v_b_pin = npn13G2l_b_pin
Expand All @@ -110,7 +109,7 @@ npn13G2v_te = npn13G2v_e

logger.info('Starting PNP-BJT DERIVATIONS')

pnp_exclude = heattrans_drw.join(trans_drw).join(emwind_drw)
pnp_exclude = trans_drw.join(emwind_drw)
.join(emwihv_drw).join(nsd_block).join(bjt_exclude)

pnp_mk = ptap_holes.not(pnp_exclude)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,10 @@

logger.info('Starting CAP DERIVATIONS')

cap_exc = nsd_drw.join(heattrans_drw).join(trans_drw)
.join(emwind_drw).join(emwihv_drw).join(heatres_drw)
.join(salblock_drw).join(polyres_drw).join(extblock_drw)
.join(res_drw).join(activ_mask).join(recog_diode)
.join(recog_esd).join(ind_drw).join(ind_pin)
.join(substrate_drw)

rfmimcap_exc = gatpoly_drw.join(nsd_block).join(psd)
.join(nbulay_drw).join(thickgateox_drw).join(cap_exc)
rfmimcap_exc = ind_drw.join(ind_pin)

# === MIMCAP ===
mimcap_exclude = rfmimcap_exc.join(pwell_block).join(ptap_holes)
mimcap_exclude = pwell_block.join(rfmimcap_exc)

mim_top = mim_drw.overlapping(topmetal1_drw).and(metal5_drw)
mim_btm = metal5_drw.and(mim_drw).sized(0.6.um)
Expand All @@ -55,8 +47,13 @@ rfmim_sub = ptap.extents.interacting(rfmim_area)
rfmeas_mk = metal5_drw.overlapping(rfmim_btm).and(rfmim_area)

# === svaricap ===
varicap_exc = pwell.join(pwell_block).join(nwell_holes)
.join(mim_drw).join(cap_exc)
cap_exc = nsd_drw.join(trans_drw).join(emwind_drw)
.join(emwihv_drw).join(salblock_drw).join(polyres_drw)
.join(extblock_drw).join(res_drw).join(activ_mask)
.join(recog_diode).join(recog_esd).join(ind_drw)
.join(ind_pin).join(substrate_drw)

varicap_exc = pwell.join(pwell_block).join(nwell_holes).join(cap_exc)

varicap_core = ngate_hv_base.and(nwell_iso).not(varicap_exc)
varicap_diff_port = nactiv.interacting(varicap_core).not(varicap_core)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ module DeviceCombinerMethods
b_net = b.net_for_terminal(name)

# same polarity
same_po = a_net.cluster_id == b_net.cluster_id if a_net && b_net
same_po = a_net.expanded_name == b_net.expanded_name if a_net && b_net
a_net && b_net && same_po
end

Expand All @@ -45,11 +45,12 @@ module DeviceCombinerMethods
b_net1 = b.net_for_terminal(net1)
b_net2 = b.net_for_terminal(net2)

if a_net1 && b_net1 && a_net2 && b_net2
same_po = a_net1.cluster_id == b_net1.cluster_id && a_net2.cluster_id == b_net2.cluster_id
diff_po = a_net1.cluster_id == b_net2.cluster_id && a_net2.cluster_id == b_net1.cluster_id
end
a_net1 && b_net1 && a_net2 && b_net2 && (same_po || diff_po)
return false unless a_net1 && b_net1 && a_net2 && b_net2

same_po = a_net1.expanded_name == b_net1.expanded_name && a_net2.expanded_name == b_net2.expanded_name
diff_po = a_net1.expanded_name == b_net2.expanded_name && a_net2.expanded_name == b_net1.expanded_name

same_po || diff_po
end

# A helper function to check whether two device connected in series
Expand All @@ -59,24 +60,30 @@ module DeviceCombinerMethods
b_net1 = b.net_for_terminal(net1)
b_net2 = b.net_for_terminal(net2)

if a_net1 && b_net1 && a_net2 && b_net2
series_con1 = a_net1.cluster_id == b_net1.cluster_id || a_net2.cluster_id == b_net2.cluster_id
series_con2 = a_net1.cluster_id == b_net2.cluster_id || a_net2.cluster_id == b_net1.cluster_id
series_con = series_con1 || series_con2
end
return false unless a_net1 && b_net1 && a_net2 && b_net2

series_con_a1 = a_net1.expanded_name == b_net1.expanded_name || a_net1.expanded_name == b_net2.expanded_name
series_con_a2 = a_net2.expanded_name == b_net1.expanded_name || a_net2.expanded_name == b_net2.expanded_name
series_con = series_con_a1 || series_con_a2

# Reroute terminal connections based on cluster IDs
if a_net1.cluster_id == b_net1.cluster_id
a.connect_terminal(0, b_net2)
elsif a_net2.cluster_id == b_net2.cluster_id
a.connect_terminal(1, b_net1)
elsif a_net1.cluster_id == b_net2.cluster_id
a.connect_terminal(0, b_net1)
elsif a_net2.cluster_id == b_net1.cluster_id
a.connect_terminal(1, b_net2)
if series_con_a1
if a_net1.expanded_name == b_net1.expanded_name
a.connect_terminal(0, b_net2)
else
a.connect_terminal(0, b_net1)
end
end

a_net1 && b_net1 && a_net2 && b_net2 && series_con
if series_con_a2
if a_net2.expanded_name == b_net1.expanded_name
a.connect_terminal(1, b_net2)
else
a.connect_terminal(1, b_net1)
end
end

series_con
end

# A helper function to check whether two parameters have approximately the same value
Expand Down Expand Up @@ -168,12 +175,17 @@ class RESDeviceCombiner < RBA::GenericDeviceCombiner
res_nets = [0, 1] # Using id instead of names

# Check if same parameters
return false unless %w[w l ps b].all? { |param| same_parameter(a, b, param) }

# Check if terminals series or parallel
# Check if terminals series or parallel (With same params)
if supp_parallel(a, b, 0, 1)
return false unless PARALLEL_RES
return false unless %w[w l ps b].all? { |param| same_parameter(a, b, param) }

a.set_parameter('m', a.parameter('m') + b.parameter('m'))
elsif supp_series(a, b, 0, 1)
return false unless SERIES_RES
return false unless %w[w ps b m].all? { |param| same_parameter(a, b, param) }

a.set_parameter('l', a.parameter('l') + b.parameter('l'))
else
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,11 @@ class DeviceCustomRes < RBA::DeviceClassResistor
add_parameters('w', 'l', 'ps', 'b')
add_parameter(RBA::DeviceParameterDefinition.new('m', 'multiplier', 1, true))

self.combiner = RESDeviceCombiner.new
self.supports_serial_combination=true
self.supports_parallel_combination=true
if SERIES_RES || PARALLEL_RES
self.combiner = RESDeviceCombiner.new
else
self.combiner =nil
end

add_terminals(name, num, 0)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class GeneralNTerminalExtractor < RBA::GenericDeviceExtractor

# Length
length_edges = dev.edges.interacting(width_edges).not(width_edges)
length = get_uniq_length(length_edges)
length, _ = get_min_max_length(length_edges)

# Bends
corners = meas_mk.interacting(dev).corners.not_interacting(ports).count
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,11 @@

logger.info('Starting DIODE DERIVATIONS')

diode_exclude = gatpoly_drw.join(nsd_drw).join(heattrans_drw)
diode_exclude = gatpoly_drw.join(nsd_drw)
.join(trans_drw).join(emwind_drw).join(emwihv_drw)
.join(heatres_drw).join(polyres_drw).join(mim_drw)
.join(extblock_drw).join(res_drw).join(activ_mask)
.join(recog_esd).join(ind_drw).join(ind_pin)
.join(substrate_drw)
.join(polyres_drw).join(extblock_drw).join(res_drw)
.join(activ_mask).join(recog_esd).join(ind_drw)
.join(ind_pin).join(substrate_drw)

antenna_d_exc = pwell_block.join(nbulay_drw).join(salblock_drw)
.join(nsd_block).join(diode_exclude)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,11 @@
logger.info('Starting ESD DERIVATIONS')

# General
esd_exclude = nsd_block.join(nsd_drw).join(heattrans_drw)
.join(trans_drw).join(emwind_drw).join(emwihv_drw)
.join(heatres_drw).join(polyres_drw).join(mim_drw)
esd_exclude = nsd_block.join(nsd_drw).join(trans_drw)
.join(emwind_drw).join(emwihv_drw).join(polyres_drw)
.join(extblock_drw).join(res_drw).join(recog_diode)
.join(substrate_drw).join(ind_drw).join(ind_pin)


esd_exc_d = gatpoly_drw.join(thickgateox_drw).join(salblock_drw)
.join(esd_exclude)

Expand Down
Loading

0 comments on commit 33c5b9b

Please sign in to comment.