diff --git a/.github/workflows/lvs_regression.yml b/.github/workflows/lvs_regression.yml index ae5eb9c7..e5313079 100644 --- a/.github/workflows/lvs_regression.yml +++ b/.github/workflows/lvs_regression.yml @@ -58,9 +58,9 @@ jobs: - name: Installing Klayout run: | sudo apt update -qq -y - wget https://www.klayout.org/downloads/Ubuntu-22/klayout_0.28.14-1_amd64.deb + wget https://www.klayout.org/downloads/Ubuntu-22/klayout_0.29.0-1_amd64.deb # The dpkg command will fail complaining about missing dependencies. - sudo dpkg -i ./klayout_0.28.14-1_amd64.deb || true + sudo dpkg -i ./klayout_0.29.0-1_amd64.deb || true # The apt install command should install the missing dependencies # needed by KLayout above and finish the install. sudo apt install -f -y @@ -73,3 +73,25 @@ jobs: - name: Testing ${{ matrix.part }} for ${{ matrix.test }} run: | make test-"$(python -c 'print("${{ matrix.part }}".upper())')"-${{ matrix.test }} + + lvs_regression_cells: + runs-on: ubuntu-latest + steps: + - name: Installing Klayout + run: | + sudo apt update -qq -y + wget https://www.klayout.org/downloads/Ubuntu-22/klayout_0.29.0-1_amd64.deb + # The dpkg command will fail complaining about missing dependencies. + sudo dpkg -i ./klayout_0.29.0-1_amd64.deb || true + # The apt install command should install the missing dependencies + # needed by KLayout above and finish the install. + sudo apt install -f -y + # Check that KLayout was successfully installed! + klayout -v + + - uses: actions/checkout@v3 + with: + submodules: 'recursive' + - name: Testing LVS for SG13G2 cells + run: | + make test-LVS-cells diff --git a/.gitignore b/.gitignore index ad605536..e8c01c08 100644 --- a/.gitignore +++ b/.gitignore @@ -173,3 +173,4 @@ cython_debug/ unit_tests_* lvs_run_* *_extracted.cir +cells_tests_* \ No newline at end of file diff --git a/Makefile b/Makefile index 6cdef419..24806360 100644 --- a/Makefile +++ b/Makefile @@ -60,6 +60,14 @@ test-LVS-% : env @. $(VENV_RUN_COMMAND); echo "Running Klayout-LVS regression for $* device" @. $(VENV_RUN_COMMAND); cd $(KLAYOUT_LVS_TESTS) && make test-LVS-$* +#================================= +# -------- test-LVS-cells -------- +#================================= + +test-LVS-cells: env + @. $(VENV_RUN_COMMAND); echo "Running Klayout-LVS for SG13G2 cells" + @. $(VENV_RUN_COMMAND); cd $(KLAYOUT_LVS_TESTS) && make test-LVS-cells + #================================= # -------- test-LVS-switch ------- #================================= diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/README.md b/ihp-sg13g2/libs.tech/klayout/tech/lvs/README.md index 3bd4347a..b23de49b 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/README.md +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/README.md @@ -19,21 +19,23 @@ Explains how to use the SG13G2 LVS rule decks. ```text 📁 lvs - ┣ 📁testing Testing environment directory for SG13G2 LVS. - ┣ 📁rule_decks Holds all LVS rule decks used for SG13G2. - ┣ sg13g2.lvs Main LVS runset that call all rule decks. - ┣ 📜README.md This file to document LVS for SG13G2. - ┗ 📜run_lvs.py Main python script used for SG13G2 LVS. + ┣ 📁testing Directory for the SG13G2 LVS testing environment. + ┣ 📁rule_decks Contains all LVS rule decks used for SG13G2. + ┣ 📜sg13g2.lvs Main LVS runset that calls all rule decks. + ┣ 📜README.md Documentation for SG13G2 LVS. + ┗ 📜run_lvs.py Main Python script for SG13G2 LVS run. ``` ## Prerequisites You need the following set of tools installed to be able to run SG13G2 LVS: -At a minimum: - - Python 3.9+ -- KLayout 0.28.14+ +- KLayout 0.29.0+ + +We have tested this using the following setup: +- Python 3.9.18 +- KLayout 0.29.0 ## Installation @@ -43,59 +45,6 @@ To install the required Python packages, execute the following command: pip install -r ../../../../../requirements.txt ``` -## Devices Status - -The following table explains the list of available SG13G2 devices we have supported in our LVS runset. - -| Device | Tested | -|-----------------|------------------| -| **MOSFET** | | -| sg13_lv_nmos |:white_check_mark:| -| sg13_hv_nmos |:white_check_mark:| -| sg13_lv_pmos |:white_check_mark:| -| sg13_hv_pmos |:white_check_mark:| -| **RF-MOSFET** | | -| rfnmos |:white_check_mark:| -| rfnmosHV |:white_check_mark:| -| rfpmos |:white_check_mark:| -| rfpmosHV |:white_check_mark:| -| **BJTs** | | -| npn13G2 |:white_check_mark:| -| npn13G2L |:white_check_mark:| -| npn13G2V |:white_check_mark:| -| pnpMPA |:white_check_mark:| -| **Diodes** | | -| dantenna |:white_check_mark:| -| dpantenna |:white_check_mark:| -| schottky_nbl1 |:white_check_mark:| -| **Resistors** | | -| rsil |:white_check_mark:| -| rppd |:white_check_mark:| -| rhigh |:white_check_mark:| -| lvsres |:white_check_mark:| -| **Capacitors** | | -| SVaricap |:white_check_mark:| -| cap_cmim |:white_check_mark:| -| rfcmim |:white_check_mark:| -| **ESD** | | -| diodevdd_4kv |:white_check_mark:| -| diodevdd_2kv |:white_check_mark:| -| diodevss_4kv |:white_check_mark:| -| diodevss_2kv |:white_check_mark:| -| idiodevdd_4kv |:white_check_mark:| -| idiodevdd_2kv |:white_check_mark:| -| idiodevss_4kv |:white_check_mark:| -| idiodevss_2kv |:white_check_mark:| -| nmoscl_2 |:white_check_mark:| -| nmoscl_4 |:white_check_mark:| -| **Inductors** | | -| inductor |:white_check_mark:| -| inductor3 |:white_check_mark:| -| **Taps** | | -| ptap1 |:white_check_mark:| -| ntap1 |:white_check_mark:| - - ## Usage You have the option to execute the SG13G2-LVS through either a Python script via the command-line interface [CLI](#cli) or by the Klayout graphical user interface [GUI](#gui), as detailed in the subsequent usage sections. @@ -115,7 +64,7 @@ The `run_lvs.py` script takes your gds and netlist files to run LVS rule decks w **Options:** -- `--help -h ` Displays this help message. +- `--help -h` Displays this help message. - `--layout=` Specifies the file path of the input GDS file. diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_devices.lvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_devices.lvs index 4b571a94..cd812c02 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_devices.lvs +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_devices.lvs @@ -111,11 +111,11 @@ class DeviceCustomInd < RBA::DeviceClassInductor add_terminals(name, num, 1) # 5% tolerance for w,s,d: - equal_device_parameters = RBA::EqualDeviceParameters::new(parameter_id('w'), 0.0, 0.05) - equal_device_parameters += RBA::EqualDeviceParameters::new(parameter_id('s'), 0.0, 0.05) - equal_device_parameters += RBA::EqualDeviceParameters::new(parameter_id('d'), 0.0, 0.05) + equal_ind_parameters = RBA::EqualDeviceParameters::new(parameter_id('w'), 0.0, 0.05) + equal_ind_parameters += RBA::EqualDeviceParameters::new(parameter_id('s'), 0.0, 0.05) + equal_ind_parameters += RBA::EqualDeviceParameters::new(parameter_id('d'), 0.0, 0.05) # applies the compare delegate: - self.equal_parameters = equal_device_parameters + self.equal_parameters = equal_ind_parameters self.combiner = nil self.supports_serial_combination=false @@ -147,20 +147,17 @@ class RES2 < RBA::DeviceClassResistor end end -# MIMCAP device class -class MIMCap < RBA::DeviceClassCapacitor - def initialize - super - enable_parameter('C', false) - enable_parameter('A', true) - enable_parameter('P', true) - end -end - # Diode device class class EnDiode < RBA::DeviceClassDiode def initialize - super + + # 1% tolerance for A,P: + equal_diode_parameters = RBA::EqualDeviceParameters::new(parameter_id('A'), 0.0, 0.01) + equal_diode_parameters += RBA::EqualDeviceParameters::new(parameter_id('P'), 0.0, 0.01) + # applies the compare delegate: + self.equal_parameters = equal_diode_parameters + + # combiner self.combiner = DiodeDeviceCombiner.new self.supports_serial_combination=true self.supports_parallel_combination=true diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_mim_extractor.lvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_mim_extractor.lvs index 968203ec..60d39712 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_mim_extractor.lvs +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_mim_extractor.lvs @@ -33,9 +33,11 @@ class DeviceCustomMIM < RBA::DeviceClassCapacitor clear_equivalent_terminal_ids # Adding params - add_parameter(RBA::DeviceParameterDefinition.new('w', 'width', 0, true, 1e-6)) - add_parameter(RBA::DeviceParameterDefinition.new('l', 'length', 0, true, 1e-6)) - add_parameter(RBA::DeviceParameterDefinition.new('m', 'multiplier', 1, true, 1.0)) + add_parameter(RBA::DeviceParameterDefinition.new('w', 'width', 0, false)) + add_parameter(RBA::DeviceParameterDefinition.new('l', 'length', 0, false)) + add_parameter(RBA::DeviceParameterDefinition.new('A', 'area', 0, true)) + add_parameter(RBA::DeviceParameterDefinition.new('P', 'perimeter', 0, true)) + add_parameter(RBA::DeviceParameterDefinition.new('m', 'multiplier', 1, true)) # Adding terminals ter1 = add_terminal(RBA::DeviceTerminalDefinition.new("mim_top")) @@ -46,7 +48,7 @@ class DeviceCustomMIM < RBA::DeviceClassCapacitor # Adding extra param & terminal for rfcmim return unless name.downcase.include?('rfcmim') - add_parameter(RBA::DeviceParameterDefinition.new('wfeed', 'feed width', 0, true, 1e-6)) + add_parameter(RBA::DeviceParameterDefinition.new('wfeed', 'feed width', 0, true)) sub_ter = add_terminal(RBA::DeviceTerminalDefinition.new("mim_sub")) sub_ter.name = "mim_sub" end @@ -170,6 +172,8 @@ class MIMCAPExtractor < RBA::GenericDeviceExtractor device.set_parameter('w', width * $unit) device.set_parameter('l', length * $unit) end + device.set_parameter('A', width * length * $unit * $unit) + device.set_parameter('P', (width + length) * 2 * $unit) end diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_reader.lvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_reader.lvs index aca009a1..bf60097e 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_reader.lvs +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/custom_reader.lvs @@ -21,8 +21,37 @@ # Custom reader for subcircuit models class CustomReader < RBA::NetlistSpiceReaderDelegate + # Cleanup sch for R, C elements + def clean_sch(line, element) + line = line.delete('[]$\\/') + + # Extracting parameters with values + valid_params = line.scan(/\b\w+\s*=\s*\S+\b/) + + case element + when 'R' + # For 2 term res [ ] + num_terms = 3 + when 'C' + # Determine number of terms based on component type + num_terms = + if line.downcase.include?('varicap') + 5 + elsif line.downcase.include?('rfcmim') + 4 + else + 3 + end + end + line_no_param = line.split(' ').take(num_terms).join(' ') + "#{line_no_param.strip} #{valid_params.join(' ')}" + end + # Override parse_element method to handle exceptions gracefully def parse_element(line, element) + # Prep sch for R, C + line = clean_sch(line, element) if %w[R C].include?(element) + super rescue StandardError case element @@ -265,13 +294,11 @@ class CustomReader < RBA::NetlistSpiceReaderDelegate # Map parameters for a diode device. def map_diode_params(device, model, params) - if model.downcase.include?('diodev') || model.downcase.include?('schottky') || model.downcase.include?('nmoscl') - device.set_parameter('m', params['M'] || 1.0) - else + unless model.downcase.include?('diodev') || model.downcase.include?('schottky') || model.downcase.include?('nmoscl') device.set_parameter('A', (params['A'] || ((params['W'] || 0.0) * (params['L'] || 0.0))) * 1e12) device.set_parameter('P', (params['P'] || (((params['W'] || 0.0) + (params['L'] || 0.0)) * 2)) * 1e6) - device.set_parameter('m', params['M'] || 1.0) end + device.set_parameter('m', params['M'] || 1.0) end # Map parameters for a capacitor device. @@ -279,6 +306,11 @@ class CustomReader < RBA::NetlistSpiceReaderDelegate device.set_parameter('w', (params['W'] || 0.0) * 1e6) device.set_parameter('l', (params['L'] || 0.0) * 1e6) device.set_parameter('m', params['M'] || params['MF'] || 1.0) if model.downcase.include?('cap_cmim') + + if model.downcase.include?('mim') + device.set_parameter('A', (params['A'] || ((params['W'] || 0.0) * (params['L'] || 0.0))) * 1e12) + device.set_parameter('P', (params['P'] || (((params['W'] || 0.0) + (params['L'] || 0.0)) * 2)) * 1e6) + end return unless model.downcase.include?('rfcmim') device.set_parameter('wfeed', (params['WFEED'] || 0.0) * 1e6) @@ -288,7 +320,8 @@ class CustomReader < RBA::NetlistSpiceReaderDelegate def map_resistor_params(device, model, params) if model.downcase.include?('tap') device.set_parameter('A', (params['A'] || ((params['W'] || 0.0) * (params['L'] || 0.0))) * 1e12) - device.set_parameter('P', (params['P'] || params['PERIM'] || (((params['W'] || 0.0) + (params['L'] || 0.0)) * 2)) * 1e6) + device.set_parameter('P', + (params['P'] || params['PERIM'] || (((params['W'] || 0.0) + (params['L'] || 0.0)) * 2)) * 1e6) elsif RES_DEV.any? { |res| model.downcase.start_with?(res) } device.set_parameter('w', (params['W'] || 0.0) * 1e6) device.set_parameter('l', (params['L'] || 0.0) * 1e6) diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/diode_derivations.lvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/diode_derivations.lvs index 6006f701..2d79ab04 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/diode_derivations.lvs +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/diode_derivations.lvs @@ -29,7 +29,7 @@ diode_exclude = gatpoly_drw.join(nsd_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) +antenna_d_exc = pwell_block.join(salblock_drw) .join(nsd_block).join(diode_exclude) antenna_d_mk = recog_diode.not(antenna_d_exc) diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/general_connections.lvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/general_connections.lvs index a5356de5..5d2d5013 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/general_connections.lvs +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/general_connections.lvs @@ -49,12 +49,12 @@ connect(topvia2_drw, topmetal2_con) # Attaching labels connect(activ_drw, activ_label) connect(poly_con, gatpoly_label) -connect(metal1_con, metal1_label) -connect(metal2_drw, metal2_label) -connect(metal3_drw, metal3_label) -connect(metal4_drw, metal4_label) -connect(metal5_drw, metal5_label) -connect(topmetal1_con, topmetal1_label) -connect(topmetal2_con, topmetal2_label) +connect(metal1_con, metal1_text) +connect(metal2_drw, metal2_text) +connect(metal3_drw, metal3_text) +connect(metal4_drw, metal4_text) +connect(metal5_drw, metal5_text) +connect(topmetal1_con, topmetal1_text) +connect(topmetal2_con, topmetal2_text) logger.info('Starting SG13G2 LVS connectivity setup (Global)') diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/general_derivations.lvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/general_derivations.lvs index 5bed6542..d3eef551 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/general_derivations.lvs +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/general_derivations.lvs @@ -33,7 +33,7 @@ nwell_n_iso = nwell_drw.not(nbulay_drw) # pwell pwell_pre = pwell_drw.join(CHIP.not(nwell_drw.join(pwell_block).join(digisub_drw))) -digisub_pre = digisub_drw.sized(-1.nm) +digisub_pre = digisub_drw.sized(-1.nm).not(nwell_drw).not(pwell_block) pwell = pwell_pre.join(digisub_pre) # psd, nsd active & res @@ -70,7 +70,7 @@ ntap = nactiv.and(nwell_n_iso).not(res_mk).not(recog_diode).not(gatpoly_drw) ptap = pactiv.and(pwell).not(substrate_drw).not(res_mk).not(recog_diode).not(gatpoly_drw) # Derived - Layers (Special) -nwell_holes = nwell_drw.holes +nwell_holes = nwell_drw.holes.not(nwell_drw) ptap_holes = ptap.holes ntap_holes = ntap.holes diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_connections.lvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_connections.lvs index fbf0b2eb..3dbbd68f 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_connections.lvs +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_connections.lvs @@ -27,10 +27,9 @@ logger.info('Starting Inductor CONNECTIONS') connect(ind2_ports, ind_pin) connect(ind_pin, ind_text) connect(ind_pin, topmetal2_con) -connect(ind2_sub, pwell_block) -connect(pwell_block, pwell) +connect(ind2_sub, pwell) # ind3 connect(ind3_ports, ind_pin) connect(ind_pin, topmetal1_con) -connect(ind3_sub, pwell_block) +connect(ind3_sub, pwell) diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_derivations.lvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_derivations.lvs index 2375a66b..ed738b32 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_derivations.lvs +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_derivations.lvs @@ -43,10 +43,10 @@ ind_port_lc = ind_ports_.interacting(ind_text.texts("LC")) ind2_ports = ind_port_la.join(ind_port_lb) ind2_core = ind_core_.interacting(ind_port_la, 1).interacting(ind_port_lb, 1) ind2_mk = ind_drw.interacting(ind2_core).interacting(ind2_ports).not_interacting(ind_port_lc) -ind2_sub = pwell_block.and(ind_drw).interacting(ind2_core) +ind2_sub = pwell_block.and(ind_drw).interacting(ind2_core).sized(1.nm) # inductor3 ind3_ports = ind_port_la.join(ind_port_lb).join(ind_port_lc) ind3_core = ind_core_.interacting(ind_port_la, 1).interacting(ind_port_lb, 1).interacting(ind_port_lc, 1) ind3_mk = ind_drw.interacting(ind3_core).interacting(ind3_ports) -ind3_sub = pwell_block.and(ind_drw).interacting(ind3_core) +ind3_sub = pwell_block.and(ind_drw).interacting(ind3_core).sized(1.nm) \ No newline at end of file diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_extraction.lvs b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_extraction.lvs index 8c565ee2..7272b32b 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_extraction.lvs +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/rule_decks/ind_extraction.lvs @@ -32,9 +32,6 @@ extract_devices(GeneralNTerminalExtractor.new('inductor', 2), { 'dev_mk' => ind2_mk, 'sub_mk' => ind2_sub }) -tolerance('inductor', 'w', 0, 0.1) -tolerance('inductor', 's', 0, 0.1) -tolerance('inductor', 'd', 0, 0.1) # ind3 logger.info('Extracting Inductor3 device') @@ -45,6 +42,3 @@ extract_devices(GeneralNTerminalExtractor.new('inductor3', 3), { 'dev_mk' => ind3_mk, 'sub_mk' => ind3_sub }) -tolerance('inductor3', 'w', 0, 0.1) -tolerance('inductor3', 's', 0, 0.1) -tolerance('inductor3', 'd', 0, 0.1) diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/run_lvs.py b/ihp-sg13g2/libs.tech/klayout/tech/lvs/run_lvs.py index 46e03447..16c289e4 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/run_lvs.py +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/run_lvs.py @@ -72,14 +72,12 @@ def check_klayout_version(): logging.error("Was not able to get klayout version properly.") exit(1) elif len(klayout_v_list) >= 2 or len(klayout_v_list) <= 3: - if klayout_v_list[1] < 28 or ( - klayout_v_list[1] == 28 and klayout_v_list[2] <= 13 - ): - logging.error("Prerequisites at a minimum: KLayout 0.28.14") + if klayout_v_list[1] < 29: + logging.error("Prerequisites at a minimum: KLayout 0.29.0") logging.error( "Using this klayout version has not been assessed. Limits are unknown" ) - # exit(1) + exit(1) logging.info(f"Your Klayout version is: {klayout_v_}") @@ -191,12 +189,13 @@ def generate_klayout_switches(arguments, layout_path, netlist_path): switches = dict() if arguments["--run_mode"] in ["flat", "deep"]: - switches["run_mode"] = arguments["--run_mode"] + run_mode = arguments["--run_mode"] else: logging.error("Allowed klayout modes are (flat , deep) only") - exit() + exit(1) switches = { + "run_mode": run_mode, "no_net_names": "true" if arguments.get("--no_net_names") else "false", "spice_comments": "true" if arguments.get("--spice_comments") else "false", "net_only": "true" if arguments.get("--net_only") else "false", diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/testing/Makefile b/ihp-sg13g2/libs.tech/klayout/tech/lvs/testing/Makefile index dad87c29..2809a23c 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/testing/Makefile +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/testing/Makefile @@ -39,6 +39,15 @@ test-LVS-%: @echo "========== LVS-$* testing ==========" @ python3 run_regression.py --device=$* +#================================ +# ------ test-LVS-stdcells ------ +#================================ + +.ONESHELL: +test-LVS-cells: + @echo "========== SG13G2-Cells Testing ==========" + @ python3 run_regression_cells.py + #================================= # -------- test-LVS-switch ------- #================================= @@ -49,6 +58,10 @@ test-LVS-switch: @python3 ../run_lvs.py --layout=testcases/extraction_checking/sg13_lv_nmos.gds --netlist=testcases/extraction_checking/sg13_lv_nmos.cdl --run_mode=deep --run_dir=test_nmos_deep @python3 ../run_lvs.py --layout=testcases/extraction_checking/sg13_lv_nmos.gds --netlist=testcases/extraction_checking/sg13_lv_nmos.cdl --run_mode=flat --run_dir=test_nmos_flat +#============================== +# -------- LIST DEVICES ------- +#============================== + .ONESHELL: list-devices: @echo "test-LVS-MOS" @@ -71,6 +84,7 @@ help: @echo "... all (the default if no target is provided )" @echo "... test-LVS (To run LVS for all devices with switching test )" @echo "... test-LVS-main (To run LVS for all devices )" + @echo "... test-LVS-stdcells (To run LVS for all standard cells )" @echo "... test-LVS-switch (To run simple LVS switching test )" @echo "... test-LVS- (To run LVS for specific device group )" @echo "... list-devices (To list all available device groups )" diff --git a/ihp-sg13g2/libs.tech/klayout/tech/lvs/testing/README.md b/ihp-sg13g2/libs.tech/klayout/tech/lvs/testing/README.md index 0168e9c7..699b4884 100644 --- a/ihp-sg13g2/libs.tech/klayout/tech/lvs/testing/README.md +++ b/ihp-sg13g2/libs.tech/klayout/tech/lvs/testing/README.md @@ -6,10 +6,11 @@ Explains how to test SG13G2 LVS rule decks. ```text 📁 testing - ┣ 📜README.md This file to document the testing directory. - ┣ 📜Makefile Used for SG13G2 LVS rule deck testing. - ┣ 📜run_regression.py Main regression script used for LVS testing. - ┣ 📁testcases All testcases used for LVS testing. + ┣ 📜README.md This file documents the contents of the testing directory. + ┣ 📜Makefile Used for testing the SG13G2 LVS rule deck. + ┣ 📜run_regression.py Main regression script for testing SG13G2 devices. + ┣ 📜run_regression_cells.py Main regression script for testing SG13G2 cells. + ┣ 📁testcases Contains all test cases used for LVS testing. ``` ## Prerequisites @@ -18,11 +19,11 @@ At a minimum: You need the following set of tools installed to be able to run the regression: - Python 3.9+ -- KLayout 0.28.14+ +- KLayout 0.29.0+ We have tested this using the following setup: - Python 3.9.18 -- KLayout 0.28.16 +- KLayout 0.29.0 ## Installation @@ -32,20 +33,72 @@ To install the required Python packages, execute the following command: pip install -r ../../../../../../requirements.txt ``` -## Usage +## Devices Status + +The following table explains the list of available SG13G2 devices we have supported in our LVS runset. + +| Device | Tested | +|-----------------|------------------| +| **MOSFET** | | +| sg13_lv_nmos |:white_check_mark:| +| sg13_hv_nmos |:white_check_mark:| +| sg13_lv_pmos |:white_check_mark:| +| sg13_hv_pmos |:white_check_mark:| +| **RF-MOSFET** | | +| rfnmos |:white_check_mark:| +| rfnmosHV |:white_check_mark:| +| rfpmos |:white_check_mark:| +| rfpmosHV |:white_check_mark:| +| **BJTs** | | +| npn13G2 |:white_check_mark:| +| npn13G2L |:white_check_mark:| +| npn13G2V |:white_check_mark:| +| pnpMPA |:white_check_mark:| +| **Diodes** | | +| dantenna |:white_check_mark:| +| dpantenna |:white_check_mark:| +| schottky_nbl1 |:white_check_mark:| +| **Resistors** | | +| rsil |:white_check_mark:| +| rppd |:white_check_mark:| +| rhigh |:white_check_mark:| +| lvsres |:white_check_mark:| +| **Capacitors** | | +| SVaricap |:white_check_mark:| +| cap_cmim |:white_check_mark:| +| rfcmim |:white_check_mark:| +| **ESD** | | +| diodevdd_4kv |:white_check_mark:| +| diodevdd_2kv |:white_check_mark:| +| diodevss_4kv |:white_check_mark:| +| diodevss_2kv |:white_check_mark:| +| idiodevdd_4kv |:white_check_mark:| +| idiodevdd_2kv |:white_check_mark:| +| idiodevss_4kv |:white_check_mark:| +| idiodevss_2kv |:white_check_mark:| +| nmoscl_2 |:white_check_mark:| +| nmoscl_4 |:white_check_mark:| +| **Inductors** | | +| inductor |:white_check_mark:| +| inductor3 |:white_check_mark:| +| **Taps** | | +| ptap1 |:white_check_mark:| +| ntap1 |:white_check_mark:| + +## Devices Regression Usage ```bash - run_regression.py (--help| -h) - run_regression.py [--device=] [--run_dir=] [--mp=] + run_regression.py (--help| -h) + run_regression.py [--device=] [--run_dir=] [--mp=] ``` Example: ```bash - python3 run_regression.py --device_name=MOS --run_dir=test_mos + python3 run_regression.py --device_name=MOS --run_dir=test_mos ``` -### Options +**Options** - `--help -h` Print this help message. @@ -56,17 +109,48 @@ Example: - `--mp=` The number of threads used in run. -Another approach for testing LVS devices, you could make a full test for SG13G2 LVS rule deck, by executing the following command in current testing directory: +Another approach for testing SG13G2 devices, you could make a full test for SG13G2 LVS rule deck, by executing the following command in current testing directory: ```bash -make all + make test-LVS-main ``` +## Cells Regression Usage + +```bash + run_regression_cells.py (--help| -h) + run_regression_cells.py [--cell=] [--run_dir=] [--mp=] +``` + +Example: + +```bash +python3 run_regression_cells.py --cell=sg13g2_inv_1 --run_dir=test_inv +``` + +**Options** + +- `--help -h` Print this help message. + +- `--cell=` Specify the cell to run; all cells run if not specified. + +- `--run_dir=` Run directory to save all the results [default: pwd] + +- `--mp=` The number of threads used in run. + + +Another approach for testing SG13G2 cells, you could make a full test for SG13G2 cells, by executing the following command in current testing directory: + +```bash + make test-LVS-cells +``` + + ## LVS Outputs You could find the regression run results at your run directory if you previously specified it through `--run_name=`. Default path of run directory is `unit_tests__