From 2fb08af6846c59e989f295f0c7c55fbed82da029 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 17 Nov 2021 17:22:03 -0800 Subject: [PATCH 01/22] change col mux array poly routing from straight to 'L' --- compiler/modules/column_mux_array.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/compiler/modules/column_mux_array.py b/compiler/modules/column_mux_array.py index 544b37e1..34c75390 100644 --- a/compiler/modules/column_mux_array.py +++ b/compiler/modules/column_mux_array.py @@ -177,13 +177,16 @@ class column_mux_array(design.design): # height to connect the gate to the correct horizontal row # sel_height = self.get_pin("sel_{}".format(sel_index)).by() # use the y offset from the sel pin and the x offset from the gate + offset = vector(gate_offset.x, self.get_pin("sel_{}".format(sel_index)).cy()) + + bl_offset = offset + vector((self.mux_inst[col].get_pin("br_out").bc().x - self.mux_inst[col].get_pin("bl_out").bc().x)/2, 0) self.add_via_stack_center(from_layer="poly", to_layer=self.sel_layer, - offset=offset, + offset=bl_offset, directions=self.via_directions) - self.add_path("poly", [offset, gate_offset]) + self.add_path("poly", [offset, gate_offset, bl_offset]) def route_bitlines(self): """ Connect the output bit-lines to form the appropriate width mux """ From 7d7ffe76e0301fd288ed5273baf7092ad355ea84 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Sep 2021 16:54:52 -0700 Subject: [PATCH 02/22] Debugging klayout for SCMOS and FreePDK45. --- compiler/verify/klayout.py | 35 +++- technology/freepdk45/tech/freepdk45.lylvs | 11 +- technology/freepdk45/tech/tech.py | 3 + technology/scn4m_subm/tech/scn4m_subm.lylvs | 214 ++++++++++++++++++++ technology/scn4m_subm/tech/tech.py | 3 + 5 files changed, 258 insertions(+), 8 deletions(-) create mode 100644 technology/scn4m_subm/tech/scn4m_subm.lylvs diff --git a/compiler/verify/klayout.py b/compiler/verify/klayout.py index b5e1fb82..ca19e79b 100644 --- a/compiler/verify/klayout.py +++ b/compiler/verify/klayout.py @@ -41,6 +41,16 @@ def write_drc_script(cell_name, gds_name, extract, final_verification, output_pa else: debug.warning("Could not locate file: {}".format(full_drc_file)) + # Copy .gds file into the output directory + if os.path.isabs(gds_name): + shutil.copy(gds_name, output_path) + gds_name = os.path.basename(gds_name) + + # Copy .sp file into the output directory + if sp_name and os.path.isabs(sp_name): + shutil.copy(sp_name, output_path) + sp_name = os.path.basename(sp_name) + # Create an auxiliary script to run calibre with the runset run_file = output_path + "run_drc.sh" f = open(run_file, "w") @@ -111,14 +121,29 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out else: debug.warning("Could not locate file: {}".format(full_lvs_file)) + # Copy .gds file into the output directory + if os.path.isabs(gds_name): + shutil.copy(gds_name, output_path) + gds_name = os.path.basename(gds_name) + + # Copy .sp file into the output directory + if os.path.isabs(sp_name): + shutil.copy(sp_name, output_path) + sp_name = os.path.basename(sp_name) + run_file = output_path + "/run_lvs.sh" f = open(run_file, "w") f.write("#!/bin/sh\n") - cmd = "{0} -b -r {1} -rd input={2} -rd report={4}.lvs.report -rd schematic={3} -rd target_netlist={4}.spice".format(OPTS.lvs_exe[1], - lvs_file, - gds_name, - sp_name, - cell_name) + if final_verification: + connect_supplies = "" + else: + connect_supplies = "-rd connect_supplies=1" + cmd = "{0} -b -r {1} -rd input={2} -rd report={4}.lvs.report -rd schematic={3} -rd target_netlist={4}.spice {5}".format(OPTS.lvs_exe[1], + lvs_file, + gds_name, + sp_name, + cell_name, + connect_supplies) f.write(cmd) f.write("\n") f.close() diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 5d8e50b3..64fde014 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -205,9 +205,14 @@ connect(metal10, metal10_pin) # Global schematic.simplify -connect_global(pwell, "PWELL") -connect_global(nwell, "NWELL") -connect_global(bulk, "BULK") +if $connect_supplies + connect_implicit("vdd") + connect_implicit("gnd") +end + +#connect_global(pwell, "PWELL") +#connect_global(nwell, "NWELL") +#connect_global(bulk, "BULK") #for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) # connect_explicit(pat, [ "NWELL", "vdd" ]) diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index fd477077..2ae9c06c 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -480,5 +480,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "calibre" lvs_name = "calibre" pex_name = "calibre" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs new file mode 100644 index 00000000..16dd5c6e --- /dev/null +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -0,0 +1,214 @@ + + + + + lvs + + + + false + false + + true + lvs_scripts + tools_menu.lvs.end + dsl + lvs-dsl-xml + # +# Extraction for freePDK45 +# +############################ +tstart = Time.now + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=my_report.lyrdb -rd schematic=reference_netlist.cir -rd target_netlist=extracted_netlist.cir -r lvs_freepdk45.lvs +if $input + source($input) +end + +if $report + report_lvs($report) +else + report_lvs("lvs_report.lvsdb") +end + +if $schematic +#reference netlist + schematic($schematic) +else + schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp")) +end + +# true: use net names instead of numbers +# false: use numbers for nets +spice_with_net_names = true + +# true: put in comments with details +# false: no comments +spice_with_comments = true + +if $target_netlist + target_netlist($target_netlist) +else + # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "The netlist comment goes here.") + target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), write_spice(spice_with_net_names, spice_with_comments), "Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}") +end + +# Hierarchical mode +deep +# Use 4 CPU cores +threads(4) +# Print details +verbose(true) + + +# layers definitions +######################## +info("Layers definitions") + + DNW = input(38,0) + nwell = input(42,0) + pwell = input(41,0) + CW = input(59,0) + active = input(43,0) + TA = input(60,0) + PBase = input(58,0) + poly = input(46,0) + SB = input(29,0) + nplus = input(45,0) + pplus = input(44,0) + PO2 = input(56,0) + HR = input(34,0) + Contact = input(25,0) + ContactPoly = input(47,0) + ContactActive = input(48,0) + ContactPoly2 = input(55, 0) + CT = Contact + ContactPoly + ContactActive + ContactPoly2 + M1 = input(49,0) + V1 = input(50,0) + M2 = input(51,0) + V2 = input(61,0) + M3 = input(62,0) + V3 = input(30,0) + M4 = input(31,0) + CTM = input(35,0) + V4 = input(32,0) + M5 = input(33,0) + V5 = input(36,0) + M6 = input(37,0) + Glass = input(52,0) + Pads = input(26,0) + +# layers processing +######################## +info("Layers processing") + +# Bulk layer for terminal provisioning +bulk = polygon_layer + +active_in_nwell = active & nwell +pactive = active_in_nwell & pplus +ntie = active_in_nwell & nplus +pgate = pactive & poly +psd = pactive - pgate + +active_in_pwell = active & pwell +nactive = active_in_pwell & nplus +ptie = active_in_pwell & pplus +ngate = nactive & poly +nsd = nactive - ngate + + +cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "dff","wordline_driver_0") { + +# PMOS transistor device extraction +extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) + +# NMOS transistor device extraction +extract_devices(mos4("n"), { "SD" => nsd, "G" => ngate, "tS" => nsd, "tD" => nsd, "tG" => poly, "W" => pwell }) + +} + +# Define connectivity for netlist extraction + +# Inter-layer +connect(nwell, ntie) +connect(pwell, ptie) +connect(CT, ntie) +connect(CT, ptie) +connect(psd, CT) +connect(nsd, CT) +connect(poly, CT) +connect(CT, M1) +connect(CT, M1) +connect(M1, V1) +connect(V1, M2) +connect(M2, V2) +connect(V2, M3) +connect(M3, V3) +connect(V3, M4) +connect(M4, V4) +connect(V4, M5) +connect(M5, V5) +connect(V5, M6) + + +# Global +schematic.simplify + +if $connect_supplies + connect_implicit("vdd") + connect_implicit("gnd") +end + +connect_global(pwell, "PWELL") +connect_global(nwell, "NWELL") +#connect_global(bulk, "BULK") + +#for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) +# connect_explicit(pat, [ "NWELL", "vdd" ]) +# connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +#end + +#for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL* +# FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*) +# connect_explicit(pat, [ "NWELL", "VDD" ]) +# connect_explicit(pat, [ "BULK", "VSS" ]) +#end + +# Actually performs the extraction +netlist # ... not really required + +# Flatten cells which are present in one netlist only +align +# SIMPLIFICATION of the netlist +#netlist.make_top_level_pins +#netlist.combine_devices +#netlist.purge +#netlist.purge_nets +netlist.simplify + +# Tolerances for the devices extracted parameters +# tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance]) +tolerance("P", "W", :absolute => 1.nm, :relative => 0.001) +tolerance("N", "W", :absolute => 1.nm, :relative => 0.001) + +#max_res(1000000) +#min_caps(1e-15) + +max_branch_complexity(65536) +max_depth(16) + +if ! compare + #raise "ERROR : Netlists don't match" + puts "ERROR : Netlists don't match" +else + puts "CONGRATULATIONS! Netlists match." +end + +# time spent for the LVS +time = Time.now +hours = ((time - tstart)/3600).to_i +minutes = ((time - tstart)/60 - hours * 60).to_i +seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i +$stdout.write "LVS finished at : #{time.hour}:#{time.min}:#{time.sec} - LVS duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" + diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index a8c44996..374ba4c8 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,5 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False From 141b42dc0eb9a256c3e49012a8f0396a14003806 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Sep 2021 17:06:37 -0700 Subject: [PATCH 03/22] Add DRC rules and display files --- technology/freepdk45/tech/scn4m_subm.lyp | 2518 +++++++++++++++++++ technology/freepdk45/tech/scn4m_subm.lyt | 205 ++ technology/scn4m_subm/tech/scn4m_subm.lydrc | 804 ++++++ 3 files changed, 3527 insertions(+) create mode 100644 technology/freepdk45/tech/scn4m_subm.lyp create mode 100644 technology/freepdk45/tech/scn4m_subm.lyt create mode 100644 technology/scn4m_subm/tech/scn4m_subm.lydrc diff --git a/technology/freepdk45/tech/scn4m_subm.lyp b/technology/freepdk45/tech/scn4m_subm.lyp new file mode 100644 index 00000000..2aa688d3 --- /dev/null +++ b/technology/freepdk45/tech/scn4m_subm.lyp @@ -0,0 +1,2518 @@ + + + + #ff80ff + #ff80ff + 0 + 0 + C56 + + true + true + false + 2 + false + false + 0 + DeepNwell.drawing - 38/0 + 38/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C56 + + true + true + false + 2 + false + false + 0 + Nwell.drawing - 42/0 + 42/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C61 + + true + true + false + 1 + false + false + 0 + Pwell.drawing - 41/0 + 41/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C68 + + true + true + false + 1 + false + false + 0 + CapWell.drawing - 59/0 + 59/0@1 + + + #00ff00 + #00ff00 + 0 + 0 + C58 + + true + true + false + 1 + false + false + 0 + Active.drawing - 43/0 + 43/0@1 + + + #8c8ca6 + #8c8ca6 + 0 + 0 + C58 + + true + true + false + 1 + false + false + 0 + ThickActive.drawing - 60/0 + 60/0@1 + + + #ffff00 + #ffff00 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + pBase.drawing - 60/0 + 60/0@1 + + + #ff0000 + #ff0000 + 0 + 0 + I11 + + true + true + false + 1 + false + false + 0 + Poly.drawing - 46/0 + 46/0@1 + + + #ff0000 + #ff0000 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Poly.text - 46/1 + 46/1@1 + + + #008050 + #008050 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + SiBlock.drawing - 29/0 + 29/0@1 + + + #ff80a8 + #ff80a8 + 0 + 0 + C57 + + true + true + false + 1 + false + false + 0 + Nselect.drawing - 45/0 + 45/0@1 + + + #bf4026 + #bf4026 + 0 + 0 + C76 + + true + true + false + 1 + false + false + 0 + Pselect.drawing - 44/0 + 44/0@1 + + + #ff8000 + #ff8000 + 0 + 0 + C76 + + true + true + false + 1 + false + false + 0 + Poly2.drawing - 56/0 + 56/0@1 + + + #802626 + #802626 + 0 + 0 + C66 + + true + true + false + 1 + false + false + 0 + HiRes.drawing - 34/0 + 34/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Contact.drawing - 25/0 + 25/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + ContactPoly.drawing - 47/0 + 47/0@1 + + + #00cc66 + #00cc66 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + ContactActive.drawing - 48/0 + 48/0@1 + + + #0000ff + #0000ff + 0 + 0 + C39 + + true + true + false + 1 + false + false + 0 + Metal1.drawing - 49/0 + 49/0@1 + + + #0000ff + #0000ff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal1.text - 49/1 + 49/1@1 + + + #ffff00 + #ffff00 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via.drawing - 50/0 + 50/0@1 + + + #00ffff + #00ffff + 0 + 0 + C40 + + true + true + false + 1 + false + false + 0 + Metal2.drawing - 51/0 + 51/0@1 + + + #00ffff + #00ffff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal2.text - 51/1 + 51/1@1 + + + #d9e6ff + #d9e6ff + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via2.drawing - 61/0 + 61/0@1 + + + #ffff00 + #ffff00 + 0 + 0 + I8 + + true + true + false + 1 + false + false + 0 + Metal3.drawing - 62/0 + 62/0@1 + + + #ffff00 + #ffff00 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal3.text - 62/1 + 62/1@1 + + + #91ff00 + #91ff00 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via3.drawing - 30/0 + 30/0@1 + + + #7a732d + #7a732d + 0 + 0 + C39 + + true + true + false + 1 + false + false + 0 + Metal4.drawing - 31/0 + 31/0@1 + + + #7a732d + #7a732d + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal4.text - 31/1 + 31/1@1 + + + #8000ff + #8000ff + 0 + 0 + I6 + + true + true + false + 1 + false + false + 0 + CapTopMetal.drawing - 35/0 + 35/0@1 + + + #008000 + #008000 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via4.drawing - 32/0 + 32/0@1 + + + #7777ff + #7777ff + 0 + 0 + I11 + + true + true + false + 1 + false + false + 0 + Metal5.drawing - 33/0 + 33/0@1 + + + #7777ff + #7777ff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal5.text - 33/1 + 33/1@1 + + + #004080 + #004080 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via5.drawing - 36/0 + 36/0@1 + + + #ff9933 + #ff9933 + 0 + 0 + I7 + + true + true + false + 1 + false + false + 0 + Metal6.drawing - 37/0 + 37/0@1 + + + #ff9933 + #ff9933 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal6.text - 37/1 + 37/1@1 + + + #808000 + #808000 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via6.drawing - 127/0 + 127/0@1 + + + #ff7777 + #ff7777 + 0 + 0 + I11 + + true + true + false + 1 + false + false + 0 + Metal7.drawing - 126/0 + 126/0@1 + + + #ff7777 + #ff7777 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal7.text - 126/1 + 126/1@1 + + + #804080 + #804080 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via7.drawing - 129/0 + 129/0@1 + + + #3399ff + #3399ff + 0 + 0 + I7 + + true + true + false + 1 + false + false + 0 + Metal8.drawing - 53/0 + 53/0@1 + + + #3399ff + #3399ff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal8.text - 53/1 + 53/1@1 + + + #008080 + #008080 + 0 + 0 + I1 + + true + true + false + 2 + false + true + 0 + Via8.drawing - 26/0 + 26/0@1 + + + #77ff77 + #77ff77 + 0 + 0 + I11 + + true + true + false + 1 + false + false + 0 + Metal9.drawing - 54/0 + 54/0@1 + + + #77ff77 + #77ff77 + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Metal9.text - 54/1 + 54/1@1 + + + #33aaff + #33aaff + 0 + 0 + I1 + I2 + true + true + false + 3 + false + false + 0 + Glass.drawing - 52/0 + 52/0@1 + + + #ffffff + #ffffff + 0 + 0 + I15 + + true + true + false + 3 + false + false + 0 + Pads.drawing - 26/0 + 26/0@1 + + + #ffffff + #ffffff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Text.drawing - 63/0 + 63/0@1 + + + #ffffff + #ffffff + 0 + 0 + I1 + + true + true + false + 1 + false + false + 0 + Text.drawing - 83/0 + 83/0@1 + + + + + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + + 1 + SCst4 + + + + ................ + ....*.*.....*.*. + .....*.......*.. + ....*.*.....*.*. + ................ + .*.*.....*.*.... + .*.......*...... + .*.*.....*.*.... + ................ + ....*.*.....*.*. + .....*.......*.. + ....*.*.....*.*. + ................ + .*.*.....*.*.... + .*.......*...... + .*.*.....*.*.... + + 2 + SCst3 + + + + ................ + ....*.*.....*.*. + .....*.......*.. + ....*.*.....*.*. + ................ + *.*.....*.*..... + .*.......*...... + *.*.....*.*..... + ................ + ....*.*.....*.*. + .....*.......*.. + ....*.*.....*.*. + ................ + *.*.....*.*..... + .*.......*...... + *.*.....*.*..... + + 3 + SCst2 + + + + *.*.*.*. + .*.*.*.* + *.*.*.*. + .*.*.*.* + *.*.*.*. + .*.*.*.* + *.*.*.*. + .*.*.*.* + + 4 + SCst1 + + + + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + ....*....*....*. + + 5 + verLine + + + + ................ + **************** + ................ + ................ + ................ + ................ + **************** + ................ + ................ + ................ + ................ + **************** + ................ + ................ + ................ + ................ + + 6 + horLine + + + + ................ + ................ + ................ + ................ + ................ + ..........*..... + .........*...... + ........*....... + .......*........ + ......*......... + .....*.......... + ................ + ................ + ................ + ................ + ................ + + 7 + stipple35 + + + + ................ + ................ + ................ + ................ + ................ + .....*.......... + ......*......... + .......*........ + ........*....... + .........*...... + ..........*..... + ................ + ................ + ................ + ................ + ................ + + 8 + stipple34 + + + + ....*.......*... + ................ + ................ + ................ + *.......*....... + ................ + ................ + ................ + ....*.......*... + ................ + ................ + ................ + *.......*....... + ................ + ................ + ................ + + 9 + stipple33 + + + + *.......*....... + ................ + ................ + ................ + ....*.......*... + ................ + ................ + ................ + *.......*....... + ................ + ................ + ................ + ....*.......*... + ................ + ................ + ................ + + 10 + stipple32 + + + + ...............* + ..............*. + .............*.. + ............*... + ...........*.... + ..........*..... + .........*...... + ........*....... + .......*........ + ......*......... + .....*.......... + ....*........... + ...*............ + ..*............. + .*.............. + *............... + + 11 + stipple31 + + + + .....*.......*.. + ....*.......*... + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + .....*.......*.. + ....*.......*... + ...*.......*.... + ..*.......*..... + .*.......*...... + *.......*....... + .......*.......* + ......*.......*. + + 12 + stipple30 + + + + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + + 13 + stipple29 + + + + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + + 14 + stipple28 + + + + ..*....*..*....* + .**...*..**...*. + *....*..*....*.. + *...*..**...*..* + ...*..*....*..*. + ..*..**...*..**. + .*..*....*..*... + *..**...*..**... + ..*....*..*....* + .**...*..**...*. + *....*..*....*.. + *...*..**...*..* + ...*..*....*..*. + ..*..**...*..**. + .*..*....*..*... + *..**...*..**... + + 15 + stipple27 + + + + ...*..*....*..*. + ....***.....***. + .*..*....*..*... + ..***.....***... + ..*....*..*....* + ***.....***..... + *....*..*....*.. + *.....***.....** + ...*..*....*..*. + ....***.....***. + .*..*....*..*... + ..***.....***... + ..*....*..*....* + ***.....***..... + *....*..*....*.. + *.....***.....** + + 16 + stipple26 + + + + ..**...*..**...* + .**...*..**...*. + **...*..**...*.. + *...*..**...*..* + ...*..**...*..** + ..*..**...*..**. + .*..**...*..**.. + *..**...*..**... + ..**...*..**...* + .**...*..**...*. + **...*..**...*.. + *...*..**...*..* + ...*..**...*..** + ..*..**...*..**. + .*..**...*..**.. + *..**...*..**... + + 17 + stipple25 + + + + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + + 18 + stipple24 + + + + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + + 19 + stipple23 + + + + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + + 20 + stipple22 + + + + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + + 21 + stipple21 + + + + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + ..**..**..**..** + ..**..**..**..** + **..**..**..**.. + **..**..**..**.. + + 22 + stipple20 + + + + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + *.*.*.*.*.*.*.*. + ................ + + 23 + stipple19 + + + + ................ + .*.*.*.*.*.*.*.* + ................ + *.*.*.*.*.*.*.*. + ................ + .*.*.*.*.*.*.*.* + ................ + *.*.*.*.*.*.*.*. + ................ + .*.*.*.*.*.*.*.* + ................ + *.*.*.*.*.*.*.*. + ................ + .*.*.*.*.*.*.*.* + ................ + *.*.*.*.*.*.*.*. + + 24 + stipple18 + + + + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + *.*.*.*.*.*.*.*. + + 25 + stipple17 + + + + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + ................ + **************** + + 26 + stipple16 + + + + *.......*....... + *.......*....... + .*.......*...... + .*.......*...... + ..*.......*..... + ..*.......*..... + ...*.......*.... + ...*.......*.... + ....*.......*... + ....*.......*... + .....*.......*.. + .....*.......*.. + ......*.......*. + ......*.......*. + .......*.......* + .......*.......* + + 27 + stipple15 + + + + .......*.......* + .......*.......* + ......*.......*. + ......*.......*. + .....*.......*.. + .....*.......*.. + ....*.......*... + ....*.......*... + ...*.......*.... + ...*.......*.... + ..*.......*..... + ..*.......*..... + .*.......*...... + .*.......*...... + *.......*....... + *.......*....... + + 28 + stipple14 + + + + *............... + .*.............. + ..*............. + ...*............ + ....*........... + .....*.......... + ......*......... + .......*........ + ........*....... + .........*...... + ..........*..... + ...........*.... + ............*... + .............*.. + ..............*. + ...............* + + 29 + stipple13 + + + + *..**..**..**..* + **..**..**..**.. + .**..**..**..**. + ..**..**..**..** + *..**..**..**..* + **..**..**..**.. + .**..**..**..**. + ..**..**..**..** + *..**..**..**..* + **..**..**..**.. + .**..**..**..**. + ..**..**..**..** + *..**..**..**..* + **..**..**..**.. + .**..**..**..**. + ..**..**..**..** + + 30 + stipple12 + + + + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + + 31 + stipple11 + + + + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + .......*.......* + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*.......*.... + ..*.*.....*.*... + .*...*...*...*.. + *.....*.*.....*. + .......*.......* + *.....*.*.....*. + .*...*...*...*.. + ..*.*.....*.*... + ...*.......*.... + + 32 + stipple10 + + + + *...........*... + .*...........*.. + ..*...........*. + ...*...........* + ....*........... + .....*.......... + ......*......... + .......*........ + ........*....... + .........*...... + ..........*..... + ...........*.... + *...........*... + .*...........*.. + ..*...........*. + ...*...........* + + 33 + stipple9 + + + + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + ................ + .*.*.*.*.*.*.*.* + + 34 + stipple8 + + + + *...*...*...*... + ................ + ................ + ................ + *...*...*...*... + ................ + ................ + ................ + *...*...*...*... + ................ + ................ + ................ + *...*...*...*... + ................ + ................ + ................ + + 35 + stipple7 + + + + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + .**..**..**..**. + *...*...*...*... + ...*...*...*...* + .**..**..**..**. + .**..**..**..**. + ...*...*...*...* + *...*...*...*... + .**..**..**..**. + + 36 + stipple6 + + + + ...*...*...*...* + ...*...*...*...* + *...*...*...*... + *...*...*...*... + ...*...*...*...* + ...*...*...*...* + *...*...*...*... + *...*...*...*... + ...*...*...*...* + ...*...*...*...* + *...*...*...*... + *...*...*...*... + ...*...*...*...* + ...*...*...*...* + *...*...*...*... + *...*...*...*... + + 37 + stipple5 + + + + ...**......**... + ..*..*....*..*.. + .*....*..*....*. + *......**......* + *......**......* + .*....*..*....*. + ..*..*....*..*.. + ...**......**... + ...**......**... + ..*..*....*..*.. + .*....*..*....*. + *......**......* + *......**......* + .*....*..*....*. + ..*..*....*..*.. + ...**......**... + + 38 + stipple4 + + + + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + *...*...*...*... + ................ + ..*...*...*...*. + ................ + + 39 + stipple3 + + + + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + ...*...*...*...* + ..*...*...*...*. + .*...*...*...*.. + *...*...*...*... + + 40 + stipple2 + + + + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + *...*...*...*... + .*...*...*...*.. + ..*...*...*...*. + ...*...*...*...* + + 41 + stipple1 + + + + * + + 42 + stipple0 + + + + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + + 43 + x + + + + ................ + ................ + .......********* + ........*.....*. + .........*...*.. + ..........*.*... + ...........*.... + ................ + ................ + ................ + *********....... + .*.....*........ + ..*...*......... + ...*.*.......... + ....*........... + ................ + + 44 + triangle + + + + .....*.......*.. + .....*.......*.. + .....*.......*.. + ...*****...***** + .....*.......*.. + .....*.......*.. + .....*.......*.. + ................ + ..*.......*..... + ..*.......*..... + ..*.......*..... + *****...*****... + ..*.......*..... + ..*.......*..... + ..*.......*..... + ................ + + 45 + dagger + + + + ......*.......*. + ......*.......*. + ......*.......*. + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + + 46 + brick + + + + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + .....*.......*.. + .....*.......*.. + .....*.......*.. + + 47 + vCurb + + + + ................ + ................ + ****...*****...* + ...*...*...*...* + ...*...*...*...* + ...*****...***** + ................ + ................ + ................ + ................ + ****...*****...* + ...*...*...*...* + ...*...*...*...* + ...*****...***** + ................ + ................ + + 48 + hCurb + + + + ....*.....*....* + ....*....*....*. + ...*....*.....*. + ..*.....*....*.. + ..*....*....*... + .*....*.....*... + *.....*....*.... + *....*....*..... + ....*.....*....* + ....*....*....*. + ...*....*.....*. + ..*.....*....*.. + ..*....*....*... + .*....*.....*... + *.....*....*.... + *....*....*..... + + 49 + vZigZag + + + + .......*.......* + .....**......**. + ....*.......*... + ..**......**.... + .*.......*...... + *......**......* + ......*.......*. + ....**......**.. + ...*.......*.... + .**......**..... + *.......*....... + ......**......** + .....*.......*.. + ...**......**... + ..*.......*..... + **......**...... + + 50 + hZigZag + + + + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + + 51 + grid + + + + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + + 52 + vLine + + + + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + + 53 + hLine + + + + ................ + ................ + ................ + ....*.*.*.*..... + ...*.*.*.*.*.... + ....*........... + ...*............ + ....*........... + ...*...*........ + ....*...*....... + ...*.*.*........ + ....*.*.*....... + ................ + ................ + ................ + ................ + + 54 + spiral + + + + ................ + ......*.*.*.*... + .....*.*.*.*.*.. + ......*......... + .....*.......... + ......*......... + .....*...*...... + ......*...*..... + .....*.*.*...... + ......*.*.*..... + ................ + ................ + ................ + ................ + ................ + ................ + + 55 + spiral22 + + + + *...*........... + .*...*.......*.. + ......*.......*. + ...*...*.......* + *...*........... + .*...*...*...... + ..*...*...*..... + ...*...*...*.... + ........*...*... + .....*...*...*.. + ......*.......*. + .......*...*...* + ........*...*... + .*.......*...*.. + ..*.......*...*. + ...*.......*...* + + 56 + slash3Fill + + + + ................ + .*........*..... + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ................ + ...*........*... + ................ + ................ + ................ + ................ + + 57 + dats5 + + + + *.....*.....*... + ................ + ................ + ...*.....*.....* + ................ + ................ + *.....*.....*... + ................ + ................ + ...*.....*.....* + ................ + ................ + *.....*.....*... + ................ + ................ + ...*.....*.....* + + 58 + dots4 + + + + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + + 59 + dots2 + + + + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + + 60 + stipple11 + + + + *.......*....... + ................ + ................ + ................ + ................ + ................ + ................ + ................ + *.......*....... + ................ + ................ + ................ + ................ + ................ + ................ + ................ + + 61 + stipple10 + + + + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + .*...*...*...*.. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + ..*...*...*...*. + + 62 + stipple9 + + + + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + ...*...*...*...* + *...*...*...*... + + 63 + stipple8 + + + + ..****....****.. + .*....*..*....*. + *......**......* + *......**......* + *......**......* + *......**......* + .*....*..*....*. + ..****....****.. + ..****....****.. + .*....*..*....*. + *......**......* + *......**......* + *......**......* + *......**......* + .*....*..*....*. + ..****....****.. + + 64 + stipple7 + + + + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + *...*...*...*... + + 65 + stipple3 + + + + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + ****....****.... + ****....****.... + ****....****.... + ****....****.... + ....****....**** + ....****....**** + ....****....**** + ....****....**** + + 66 + stipple2 + + + + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + *...*...*...*... + .*.*.*.*.*.*.*.* + ..*...*...*...*. + .*.*.*.*.*.*.*.* + + 67 + x + + + + ................ + ....*........... + ...*.*.......... + ..*...*......... + .*.....*........ + *********....... + ................ + ................ + ................ + ...........*.... + ..........*.*... + .........*...*.. + ........*.....*. + .......********* + ................ + ................ + + 68 + triangle + + + + ................ + ..*.......*..... + ..*.......*..... + ..*.......*..... + *****...*****... + ..*.......*..... + ..*.......*..... + ..*.......*..... + ................ + .....*.......*.. + .....*.......*.. + .....*.......*.. + ...*****...***** + .....*.......*.. + .....*.......*.. + .....*.......*.. + + 69 + dagger + + + + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + **************** + ..*.......*..... + ..*.......*..... + ..*.......*..... + **************** + ......*.......*. + ......*.......*. + ......*.......*. + + 70 + brick + + + + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + .....*.......*.. + .....*.......*.. + .....*.......*.. + ..****....****.. + ..*.......*..... + ..*.......*..... + ..*.......*..... + ..****....****.. + + 71 + vCurb + + + + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + ................ + ................ + ...*****...***** + ...*...*...*...* + ...*...*...*...* + ****...*****...* + ................ + ................ + + 72 + hCurb + + + + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + *....*....*..... + *.....*....*.... + .*....*.....*... + ..*....*....*... + ..*.....*....*.. + ...*....*.....*. + ....*....*....*. + ....*.....*....* + + 73 + vZigZag + + + + **......**...... + ..*.......*..... + ...**......**... + .....*.......*.. + ......**......** + *.......*....... + .**......**..... + ...*.......*.... + ....**......**.. + ......*.......*. + *......**......* + .*.......*...... + ..**......**.... + ....*.......*... + .....**......**. + .......*.......* + + 74 + hZigZag + + + + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + ...*...*...*...* + ...*...*...*...* + ...*...*...*...* + **************** + + 75 + grid + + + + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + ................ + ................ + ................ + **************** + + 76 + hLine + + + + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + ...*...*...*...* + ................ + .*...*...*...*.. + ................ + + 77 + dots1 + + + + * + + 0 + + + + + * + + 0 + + + + + * + + 0 + + + + + * + + 0 + + + diff --git a/technology/freepdk45/tech/scn4m_subm.lyt b/technology/freepdk45/tech/scn4m_subm.lyt new file mode 100644 index 00000000..714dcc92 --- /dev/null +++ b/technology/freepdk45/tech/scn4m_subm.lyt @@ -0,0 +1,205 @@ + + + MOSIS_SCMOS + MOSIS SCMOS lambda based process + + 0.001 + $(appdata_path)/tech/MOSIS_SCMOS + MOSIS_SCMOS.lyp + true + + + 1 + true + true + + + true + layer_map() + true + true + + + true + layer_map() + 0.001 + true + #1 + true + #1 + false + #1 + true + OUTLINE + true + PLACEMENT_BLK + true + REGIONS + true + + 0 + true + .PIN + 2 + true + .PIN + 2 + true + .FILL + 5 + true + .OBS + 3 + true + .BLK + 4 + true + .LABEL + 1 + true + + 0 + true + + 0 + VIA_ + true + default + false + + + + false + true + true + 64 + 0 + 1 + 0 + DATA + 0 + 0 + BORDER + layer_map() + true + + + 0.001 + 1 + 100 + 100 + 0 + 0 + 0 + false + false + false + true + layer_map() + + + 0 + 0.001 + layer_map() + true + false + + + 1 + 0.001 + layer_map() + true + false + true + + + + + + + true + false + false + false + false + false + 8000 + 32000 + LIB + + + 2 + false + false + 1 + * + false + + + 0 + + + false + false + + + 0 + + true + + + + # Provide z stack information here +# Each line is one layer. The specification consists of a layer specification, a colon and arguments. +# The arguments are named (like "x=...") or in serial. Parameters are separated by comma or blanks. +# Named arguments are: +# +# zstart The lower z position of the extruded layer in µm +# zstop The upper z position of the extruded layer in µm +# height The height of the extruded layer in µm +# +# 'height', 'zstart' and 'zstop' can be used in any combination. If no value is given for 'zstart', # the upper level of the previous layer will be used. +# +# If a single unnamed parameter is given, it corresponds to 'height'. Two parameters correspond to +# 'zstart' and 'zstop'. +# +# Examples: +# 1: 0.5 1.5 # extrude layer 1/0 from 0.5 to 1.5 vertically +# 1/0: 0.5 1.5 # same with explicit datatype +# 1: zstop=1.5, zstart=0.5 # same with named parameters +# 1: height=1.0, zstop=1.5 # same with z stop minus height +# 1: 1.0 zstop=1.5 # same with height as unnamed parameter +42: zstart=-0.1 , height=0.1 +41: zstart=-0.1 , height=0.1 +13: zstart=0.001 , height=0.25 +46: zstart=0.1 , height=0.15 +49: zstart=0.2 , height=0.05 +50: zstart=0.2 , height=0.15 +51: zstart=0.3 , height=0.05 +61: zstart=0.3 , height=0.15 +62: zstart=0.4 , height=0.05 +30: zstart=0.4 , height=0.15 +31: zstart=0.5 , height=0.05 +32: zstart=0.5 , height=0.15 +33: zstart=0.6 , height=0.05 +36: zstart=0.6 , height=0.15 +37: zstart=0.7 , height=0.05 +127: zstart=0.7 , height=0.15 +126: zstart=0.8 , height=0.05 +129: zstart=0.9 , height=0.15 +53: zstart=0.8 , height=0.05 +26: zstart=0.9 , height=0.15 +54: zstart=0.9 , height=0.2 + + + + poly,25,49 + 56,55,49 + 49,50,51 + 51,61,62 + 62,30,31 + 31,32,33 + 33,36,37 + poly='46-34' + + diff --git a/technology/scn4m_subm/tech/scn4m_subm.lydrc b/technology/scn4m_subm/tech/scn4m_subm.lydrc new file mode 100644 index 00000000..345f4a41 --- /dev/null +++ b/technology/scn4m_subm/tech/scn4m_subm.lydrc @@ -0,0 +1,804 @@ + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# MOSIS SCMOS DRC +# +######################## +tstart = Time.now + +# optionnal for a batch launch : klayout -b r drc_SCMOS.lydrc -rd input=my_layout.gds -rd topcell=your_topcell -rd output=SCMOS_DRC.lyrdb +if $input + if $topcell + source($input,$topcell) + else + source($input) + end +end + +if $output + report("SCMOS DRC runset", $output) +else + report("SCMOS DRC runset", "SCMOS_DRC.lyrdb") +end + + +# PROCESS OPTIONS +######################## +LAMBDA = 0.2 +SUBM = true +DEEP = false +NBR_OF_METALS = 6 + +DFM = false + +# design rules limits definitions +######################## +R1_3 = ( 6 *LAMBDA ).round(3) +R2_1 = ( 3 *LAMBDA ).round(3) +R2_2 = ( 3 *LAMBDA ).round(3) +R2_4 = ( 3 *LAMBDA ).round(3) +R2_5 = ( 4 *LAMBDA ).round(3) +R3_1 = ( 2 *LAMBDA ).round(3) +R3_5 = ( 1 *LAMBDA ).round(3) +R4_1 = ( 3 *LAMBDA ).round(3) +R4_2 = ( 2 *LAMBDA ).round(3) +R5_1 = ( 2 *LAMBDA ).round(3) +R5_2 = ( 1.5 *LAMBDA ).round(3) +R5_4 = ( 2 *LAMBDA ).round(3) +R5_2_b = ( 1 *LAMBDA ).round(3) +R5_6_b = ( 2 *LAMBDA ).round(3) +R5_7_b = ( 3 *LAMBDA ).round(3) +R6_1 = ( 2 *LAMBDA ).round(3) +R6_2 = ( 1.5 *LAMBDA ).round(3) +R6_4 = ( 2 *LAMBDA ).round(3) +R6_2_b = ( 1 *LAMBDA ).round(3) +R6_5_b = ( 5 *LAMBDA ).round(3) +R6_6_b = ( 2 *LAMBDA ).round(3) +R6_7_b = ( 3 *LAMBDA ).round(3) +R6_8_b = ( 4 *LAMBDA ).round(3) +R7_1 = ( 3 *LAMBDA ).round(3) +R7_3 = ( 1 *LAMBDA ).round(3) +R8_2 = ( 3 *LAMBDA ).round(3) +R8_3 = ( 1 *LAMBDA ).round(3) +R8_4 = ( 2 *LAMBDA ).round(3) +R9_1 = ( 3 *LAMBDA ).round(3) +R9_3 = ( 1 *LAMBDA ).round(3) +R10_1 = ( 60 *LAMBDA ).round(3) +R10_2 = ( 20 *LAMBDA ).round(3) +R10_3 = ( 6 *LAMBDA ).round(3) +R10_4 = ( 30 *LAMBDA ).round(3) +R10_5 = ( 15 *LAMBDA ).round(3) +R11_2 = ( 3 *LAMBDA ).round(3) +R11_4 = ( 2 *LAMBDA ).round(3) +R11_6 = ( 2 *LAMBDA ).round(3) +R12_1 = ( 2 *LAMBDA ).round(3) +R12_2 = ( 3 *LAMBDA ).round(3) +R12_3 = ( 2 *LAMBDA ).round(3) +R12_4 = ( 1 *LAMBDA ).round(3) +R12_5 = ( 2 *LAMBDA ).round(3) +R12_6 = ( 3 *LAMBDA ).round(3) +R13_1 = ( 2 *LAMBDA ).round(3) +R13_3 = ( 3 *LAMBDA ).round(3) +R13_4 = ( 2 *LAMBDA ).round(3) +R13_5 = ( 3 *LAMBDA ).round(3) +R14_2 = ( 3 *LAMBDA ).round(3) +R14_3 = ( 1 *LAMBDA ).round(3) +R14_4 = ( 2 *LAMBDA ).round(3) +if NBR_OF_METALS > 3 + R15_3 = ( 1 *LAMBDA ).round(3) +else + R15_3 = ( 2 *LAMBDA ).round(3) +end +R16_1 = ( 2 *LAMBDA ).round(3) +R16_2 = ( 3 *LAMBDA ).round(3) +R16_3 = ( 2 *LAMBDA ).round(3) +R16_4 = ( 4 *LAMBDA ).round(3) +R16_5 = ( 2 *LAMBDA ).round(3) +R16_6 = ( 2 *LAMBDA ).round(3) +R16_7 = ( 6 *LAMBDA ).round(3) +R16_8 = ( 4 *LAMBDA ).round(3) +R16_9 = ( 2 *LAMBDA ).round(3) +R16_10 = ( 3 *LAMBDA ).round(3) +R16_11 = ( 2 *LAMBDA ).round(3) +R18_1 = ( 3 *LAMBDA ).round(3) +R18_2 = ( 2 *LAMBDA ).round(3) +R18_3 = ( 3 *LAMBDA ).round(3) +R18_4 = ( 2 *LAMBDA ).round(3) +R18_5 = ( 6 *LAMBDA ).round(3) +R20_1 = ( 4 *LAMBDA ).round(3) +R20_2 = ( 4 *LAMBDA ).round(3) +R20_3 = ( 2 *LAMBDA ).round(3) +R20_4 = ( 2 *LAMBDA ).round(3) +R20_5 = ( 2 *LAMBDA ).round(3) +R20_7 = ( 5 *LAMBDA ).round(3) +R20_8 = ( 7 *LAMBDA ).round(3) +R20_9 = ( 2 *LAMBDA ).round(3) +R20_10 = ( 3 *LAMBDA ).round(3) +R21_2 = ( 3 *LAMBDA ).round(3) +R21_3 = ( 1 *LAMBDA ).round(3) +if NBR_OF_METALS > 4 + R22_3 = ( 1 *LAMBDA ).round(3) +else + R22_3 = ( 2 *LAMBDA ).round(3) +end +R23_1 = ( 8 *LAMBDA ).round(3) +R23_2 = ( 4 *LAMBDA ).round(3) +R23_3 = ( 8 *LAMBDA ).round(3) +R23_4 = ( 3 *LAMBDA ).round(3) +R23_5 = ( 2 *LAMBDA ).round(3) +R23_6 = ( 2 *LAMBDA ).round(3) +R23_7 = ( 2 *LAMBDA ).round(3) +R23_8 = ( 4 *LAMBDA ).round(3) +R23_9 = ( 2 *LAMBDA ).round(3) +R24_1 = ( 4 *LAMBDA ).round(3) +R24_2 = ( 4 *LAMBDA ).round(3) +R24_3 = ( 4 *LAMBDA ).round(3) +R24_4 = ( 4 *LAMBDA ).round(3) +R24_5 = ( 3 *LAMBDA ).round(3) +R27_1 = ( 4 *LAMBDA ).round(3) +R27_2 = ( 4 *LAMBDA ).round(3) +R27_3 = ( 2 *LAMBDA ).round(3) +R27_4 = ( 2 *LAMBDA ).round(3) +R27_5 = ( 2 *LAMBDA ).round(3) +R27_7 = ( 5 *LAMBDA ).round(3) +R27_8 = ( 7 *LAMBDA ).round(3) +R27_9 = ( 2 *LAMBDA ).round(3) + + +if !SUBM && !DEEP + R1_1 = ( 10 *LAMBDA ).round(3) + R1_2 = ( 9 *LAMBDA ).round(3) + R2_3 = ( 5 *LAMBDA ).round(3) + R3_2 = ( 2 *LAMBDA ).round(3) + R3_2_a = ( 2 *LAMBDA ).round(3) + R3_3 = ( 2 *LAMBDA ).round(3) + R3_4 = ( 3 *LAMBDA ).round(3) + R4_3 = ( 1 *LAMBDA ).round(3) + R4_4 = ( 2 *LAMBDA ).round(3) + R5_3 = ( 2 *LAMBDA ).round(3) + R5_5_b = ( 4 *LAMBDA ).round(3) + R6_3 = ( 2 *LAMBDA ).round(3) + R7_2 = ( 2 *LAMBDA ).round(3) + R7_4 = ( 4 *LAMBDA ).round(3) + R8_1 = ( 2 *LAMBDA ).round(3) + R8_5 = ( 2 *LAMBDA ).round(3) + R9_2 = ( 3 *LAMBDA ).round(3) + R9_4 = ( 6 *LAMBDA ).round(3) + R11_1 = ( 3 *LAMBDA ).round(3) + R11_3 = ( 2 *LAMBDA ).round(3) + R11_5 = ( 3 *LAMBDA ).round(3) + R13_2 = ( 2 *LAMBDA ).round(3) + R14_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + else + R15_1 = ( 6 *LAMBDA ).round(3) + R15_2 = ( 4 *LAMBDA ).round(3) + R15_4 = ( 8 *LAMBDA ).round(3) + end + R17_1 = ( 10 *LAMBDA ).round(3) + R17_2 = ( 9 *LAMBDA ).round(3) + R17_3 = ( 5 *LAMBDA ).round(3) + R17_4 = ( 5 *LAMBDA ).round(3) + R20_11 = ( 3 *LAMBDA ).round(3) + R21_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 3 *LAMBDA ).round(3) + R22_4 = ( 6 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end +end + +if SUBM + R1_1 = ( 12 *LAMBDA ).round(3) + R1_2 = ( 18 *LAMBDA ).round(3) + R2_3 = ( 6 *LAMBDA ).round(3) + R3_2 = ( 3 *LAMBDA ).round(3) + R3_2_a = ( 3 *LAMBDA ).round(3) + R3_3 = ( 2 *LAMBDA ).round(3) + R3_4 = ( 3 *LAMBDA ).round(3) + R4_3 = ( 1 *LAMBDA ).round(3) + R4_4 = ( 2 *LAMBDA ).round(3) + R5_3 = ( 3 *LAMBDA ).round(3) + R5_5_b = ( 5 *LAMBDA ).round(3) + R6_3 = ( 3 *LAMBDA ).round(3) + R7_2 = ( 3 *LAMBDA ).round(3) + R7_4 = ( 6 *LAMBDA ).round(3) + R8_1 = ( 2 *LAMBDA ).round(3) + R8_5 = ( 2 *LAMBDA ).round(3) + R9_2 = ( 3 *LAMBDA ).round(3) + R9_4 = ( 6 *LAMBDA ).round(3) + R11_1 = ( 7 *LAMBDA ).round(3) + R11_3 = ( 5 *LAMBDA ).round(3) + R11_5 = ( 6 *LAMBDA ).round(3) + R13_2 = ( 3 *LAMBDA ).round(3) + R14_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + else + R15_1 = ( 5 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + end + R17_1 = ( 12 *LAMBDA ).round(3) + R17_2 = ( 18 *LAMBDA ).round(3) + R17_3 = ( 6 *LAMBDA ).round(3) + R17_4 = ( 6 *LAMBDA ).round(3) + R20_11 = ( 5 *LAMBDA ).round(3) + R21_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 3 *LAMBDA ).round(3) + R22_4 = ( 6 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end + R25_1 = ( 2 *LAMBDA ).round(3) + R25_2 = ( 3 *LAMBDA ).round(3) + R25_3 = ( 1 *LAMBDA ).round(3) + if NBR_OF_METALS > 5 + R26_1 = ( 3 *LAMBDA ).round(3) + R26_2 = ( 3 *LAMBDA ).round(3) + R26_3 = ( 1 *LAMBDA ).round(3) + R26_4 = ( 6 *LAMBDA ).round(3) + else + R26_1 = ( 4 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 2 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + end + R28_1 = ( 40 *LAMBDA ).round(3) + R28_2 = ( 12 *LAMBDA ).round(3) + R28_3 = ( 4 *LAMBDA ).round(3) + R28_4 = ( 3 *LAMBDA ).round(3) + R28_5 = ( 4 *LAMBDA ).round(3) + R28_6 = ( 2 *LAMBDA ).round(3) + R28_7 = ( 25 *LAMBDA ).round(3) + R28_8 = ( 4 *LAMBDA ).round(3) + R28_9 = ( 8 *LAMBDA ).round(3) + R28_10 = ( 20 *LAMBDA ).round(3) + R28_11 = ( 40 *LAMBDA ).round(3) + R29_1 = ( 3 *LAMBDA ).round(3) + R29_2 = ( 4 *LAMBDA ).round(3) + R29_3 = ( 1 *LAMBDA ).round(3) + R30_1 = ( 5 *LAMBDA ).round(3) + R30_2 = ( 5 *LAMBDA ).round(3) + R30_3 = ( 1 *LAMBDA ).round(3) + R30_4 = ( 10 *LAMBDA ).round(3) + R31_1 = ( 30 *LAMBDA ).round(3) + R31_2 = ( 50 *LAMBDA ).round(3) + R31_3 = ( 15 *LAMBDA ).round(3) + R31_4 = ( 20 *LAMBDA ).round(3) + R31_5 = ( 35 *LAMBDA ).round(3) + R31_6 = ( 5 *LAMBDA ).round(3) + R31_7 = ( 30 *LAMBDA ).round(3) + R31_8 = ( 10 *LAMBDA ).round(3) +end + +if DEEP + R1_1 = ( 12 *LAMBDA ).round(3) + R1_2 = ( 18 *LAMBDA ).round(3) + R2_3 = ( 6 *LAMBDA ).round(3) + R3_2 = ( 3 *LAMBDA ).round(3) + R3_2_a = ( 4 *LAMBDA ).round(3) + R3_3 = ( 2.5 *LAMBDA ).round(3) + R3_4 = ( 4 *LAMBDA ).round(3) + R4_3 = ( 1.5 *LAMBDA ).round(3) + R4_4 = ( 4 *LAMBDA ).round(3) + R5_3 = ( 4 *LAMBDA ).round(3) + R5_5_b = ( 5 *LAMBDA ).round(3) + R6_3 = ( 4 *LAMBDA ).round(3) + R7_2 = ( 3 *LAMBDA ).round(3) + R7_4 = ( 6 *LAMBDA ).round(3) + R8_1 = ( 3 *LAMBDA ).round(3) + R9_2 = ( 4 *LAMBDA ).round(3) + R9_4 = ( 8 *LAMBDA ).round(3) + R11_1 = ( 7 *LAMBDA ).round(3) + R11_3 = ( 5 *LAMBDA ).round(3) + R11_5 = ( 6 *LAMBDA ).round(3) + R13_2 = ( 3 *LAMBDA ).round(3) + R14_1 = ( 3 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 4 *LAMBDA ).round(3) + R15_4 = ( 8 *LAMBDA ).round(3) + else + R15_1 = ( 5 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + end + R17_1 = ( 12 *LAMBDA ).round(3) + R17_2 = ( 18 *LAMBDA ).round(3) + R17_3 = ( 6 *LAMBDA ).round(3) + R17_4 = ( 6 *LAMBDA ).round(3) + R20_11 = ( 5 *LAMBDA ).round(3) + R21_1 = ( 3 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 4 *LAMBDA ).round(3) + R22_4 = ( 8 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end + R25_1 = ( 3 *LAMBDA ).round(3) + R25_2 = ( 3 *LAMBDA ).round(3) + R25_3 = ( 1 *LAMBDA ).round(3) + if NBR_OF_METALS > 5 + R26_1 = ( 3 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 1 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + else + R26_1 = ( 4 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 2 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + end + R28_1 = ( 45 *LAMBDA ).round(3) + R28_2 = ( 14 *LAMBDA ).round(3) + R28_3 = ( 5 *LAMBDA ).round(3) + R28_4 = ( 3 *LAMBDA ).round(3) + R28_5 = ( 5 *LAMBDA ).round(3) + R28_6 = ( 2 *LAMBDA ).round(3) + R28_7 = ( 25 *LAMBDA ).round(3) + R28_8 = ( 5 *LAMBDA ).round(3) + R28_9 = ( 9 *LAMBDA ).round(3) + R28_10 = ( 23 *LAMBDA ).round(3) + R28_11 = ( 45 *LAMBDA ).round(3) + R29_1 = ( 4 *LAMBDA ).round(3) + R29_2 = ( 4 *LAMBDA ).round(3) + R29_3 = ( 1 *LAMBDA ).round(3) + R30_1 = ( 5 *LAMBDA ).round(3) + R30_2 = ( 5 *LAMBDA ).round(3) + R30_3 = ( 2 *LAMBDA ).round(3) + R30_4 = ( 10 *LAMBDA ).round(3) + R31_1 = ( 34 *LAMBDA ).round(3) + R31_2 = ( 56 *LAMBDA ).round(3) + R31_3 = ( 17 *LAMBDA ).round(3) + R31_4 = ( 23 *LAMBDA ).round(3) + R31_5 = ( 39 *LAMBDA ).round(3) + R31_6 = ( 6 *LAMBDA ).round(3) + R31_7 = ( 34 *LAMBDA ).round(3) + R31_8 = ( 13 *LAMBDA ).round(3) +end + + +# KLAYOUT setttings +######################## +# Use a tile size of 1mm +tiles(1000.um) +# Use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# Use 4 CPU cores +threads(4) +verbose(true) + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# layers definitions +######################## +info("Layers definitions") + + DNW = input(38,0) + NW = input(42,0) + PW = input(41,0) + CW = input(59,0) + AA = input(43,0) + TA = input(60,0) + PBase = input(58,0) + PL = input(46,0) + SB = input(29,0) + Nselect = input(45,0) + Pselect = input(44,0) + PO2 = input(56,0) + HR = input(34,0) + Contact = input(25,0) + ContactPoly = input(47,0) + ContactActive = input(48,0) + ContactPoly2 = input(55, 0) + CT = Contact + ContactPoly + ContactActive + ContactPoly2 + M1 = input(49,0) + V1 = input(50,0) + M2 = input(51,0) + V2 = input(61,0) + M3 = input(62,0) + V3 = input(30,0) + M4 = input(31,0) + CTM = input(35,0) + V4 = input(32,0) + M5 = input(33,0) + V5 = input(36,0) + M6 = input(37,0) + Glass = input(52,0) + Pads = input(26,0) + +# layers processing +######################## +info("Layers processing") +#CHIP = extent.sized(1.0) +NP = AA & Nselect +PP = AA & Pselect +NSTP = NP.and(NW) +PSTP = PP.not(NW) +GATE = PL & AA + +# DRC section +######################## +info("DRC section") + +### Deep NWell +DNW.ongrid(0.5*LAMBDA).output("DNW_offgrid", "Offgrid vertex on DNW") +DNW.with_angle(0 .. 45).output("DNW_angle", "Non 45 degree angle DNW") +DNW.edges.and(PW).output("DNW_PW","DNW cannot cross PWell") +DNW.width(R31_1, euclidian).output("31.1 DNW_width", "31.1 : Min. DNW width : #{R31_1}um") +DNW.isolated(R31_2, euclidian).output("31.2 DNW_space", "31.2 : Min. DNW spacing : #{R31_2}um") +NW.enclosing(DNW, R31_3, euclidian).output("31.3 NW_enc_DNW", "31.3 : Min. NWell enclosing DNW : #{R31_3}um") +DNW.enclosing(NW, R31_4, euclidian).output("31.4 DNW_enc_NW", "31.4 : Min. DNW enclosing NWell : #{R31_4}um") +DNW.separation(NW, R31_5, euclidian).output("31.5 DNW_sep_NW", "31.5 : Min. DNW separation NWell : #{R31_5}um") +DNW.not(NW).enclosing(NP, R31_6, euclidian).output("31.6 DNW_enc_NP", "31.6 : Min. PW in DNW enclosing N+ : #{R31_6}um") +DNW.separation(NP, R31_7, euclidian).output("31.7 DNW_sep_NP", "31.7 : Min. DNW separation N+ : #{R31_7}um") + +### Nwell / Pwell +NW.ongrid(0.5*LAMBDA).output("NW_offgrid", "Offgrid vertex on NWell") +NW.with_angle(0 .. 45).output("NW_angle", "Non 45 degree angle NWell") +NW.and(PW).output("NW_PW","NW over PW not allowed") +NW.width(R1_1, euclidian).output("1.1 NW_width", "1.1 : Min. NWell width : #{R1_1}um") +NW.isolated(R1_2, euclidian).output("1.2 NW_space", "1.2 : Min. NWell spacing : #{R1_2}um") +NW.and(TA).isolated(18, euclidian).output("1.3 NW_TA_space", "1.3 : Min. NWell-TA spacing : #{R1_3}um") +PW.width(R1_1, euclidian).output("1.1 PW_width", "1.1 : Min. PWell width : #{R1_1}um") +PW.isolated(R1_2, euclidian).output("1.2 PW_space", "1.2 : Min. PWell spacing : #{R1_2}um") +PW.and(TA).isolated(R1_3, euclidian).output("1.3 PW_TA_space", "1.3 : Min. PWell-TA spacing : #{R1_3}um") + +### Active +AA.ongrid(0.5*LAMBDA).output("AA_offgrid", "Offgrid vertex on AA") +AA.with_angle(0 .. 45).output("AA_angle", "Non 45 degree angle AA") +AA.width(R2_1, euclidian).output("2.1 AA_width", "2.1 : Min. active width : #{R2_1}um") +AA.space(R2_2, euclidian).output("2.2 AA_space", "2.2 : Min. active spacing : #{R2_2}3um") +NW.enclosing(PP.interacting(GATE), R2_3, euclidian).output("2.3 NW_enc_PP", "2.3 : Min. NWell enclosing Source/Drain : #{R2_3}um") +PW.enclosing(NP.interacting(GATE), R2_3, euclidian).output("2.3 PW_enc_NP", "2.3 : Min. PWell enclosing Source/Drain : #{R2_3}um") +NW.enclosing(NP, R2_4, euclidian).output("2.4 NW_enc_NP", "2.4 : Min. NWell enclosing Nstrap : #{R2_4}um") +PW.enclosing(PP, R2_4, euclidian).output("2.4 PW_enc_PP", "2.4 : Min. PWell enclosing Pstrap : #{R2_4}um") +NP.separation(PP, R2_5, euclidian).polygons.without_area(0).output("2.5 NP_space_PP", "2.5 : Min. N+ space P+ : #{R2_5}um (if not abutted)") + +### TA Thick Active +TA.ongrid(0.5*LAMBDA).output("TA_offgrid", "Offgrid vertex on TA") +TA.with_angle(0 .. 45).output("TA_angle", "Non 45 degree angle TA") +TA.width(R24_1, euclidian).output("24.1 TA_width", "24.1 : Min. TA width : #{R24_1}um") +TA.space(R24_2, euclidian).output("24.2 TA_space", "24.2 : Min. TA spacing : #{R24_2}um") +TA.enclosing(AA, R24_3, euclidian).output("24.3 TA_enc_AA", "24.3 : Min. TA enclosing Active : #{R24_3}um") +TA.separation(AA, R24_4, euclidian).output("24.4 TA_space_AA", "24.4 : Min. TA spacing Active : #{R24_4}um") +TA.and(GATE).width(R24_5, euclidian).output("24.5 TA_gate_width", "24.5 : Min. TA Gate width : #{R24_5}um") +AA.edges.and(TA).output("24.6 AA_in_TA","24.6 : Active edge cannot cross TA") + +### Poly +PL.ongrid(0.5*LAMBDA).output("POLY_offgrid", "Offgrid vertex on Poly") +PL.with_angle(0 .. 45).output("POLY_angle", "Non 45 degree angle Poly") +PL.width(R3_1, euclidian).output("3.1 POLY_width", "3.1 : Min. Poly width : #{R3_1}um") +PL.space(R3_2, euclidian).output("3.2 Poly_space", "3.2 : Min. Poly spacing : #{R3_2}um") +GATE.space(R3_2_a, euclidian).output("3.2a Gate_space", "3.2a : Min. Gate spacing : #{R3_2_a}um") +PL.enclosing(GATE, R3_3, projection).polygons.without_area(0).output("3.3 PL_enc_GATE", "3.3 : Min. Poly extention Gate : #{R3_3}um") +AA.enclosing(GATE, R3_4, projection).polygons.without_area(0).output("3.4 AA_enc_GATE", "3.4 : Min. Source/Drain length : #{R3_4}um") +PL.not(AA).separation(AA, 1, euclidian).polygons.without_area(0).output("3.5 PL_space_AA", "3.5 : Min. Poly on Field spacing Active : #{R3_5}um") + +### Poly2 +if !DEEP +PO2.ongrid(0.5*LAMBDA).output("POLY2_offgrid", "Offgrid vertex on Poly2") +PO2.with_angle(0 .. 45).output("POLY2_angle", "Non 45 degree angle Poly2") +PO2.width(R12_1, euclidian).output("12.1 POLY2_width", "12.1 : Min. Poly2 width : #{R12_1}um") +PO2.space(R12_2, euclidian).output("12.2 POLY2_space", "12.2 : Min. Poly2 space : #{R12_2}um") +# rule R12.3 not coded +PO2.not(AA).separation(AA, R12_4, euclidian).output("12.4 POLY2_space_AA"," 12.4 : Min. Poly2 on Field spacing Active : #{R12_4}um") +PO2.not(PL).separation(PL, R12_5, euclidian).output("12.5 POLY2_space_PL"," 12.5 : Min. Poly2 spacing Poly : #{R12_5}um") +PO2.enclosing(PL, R12_5, euclidian).output("12.5 POLY2_overlap_PL"," 12.5 : Min. Poly2 overlap of Poly : #{R12_5}um") +PO2.separation(AA.or(PL).and(CT), R12_6, euclidian).output("12.6 POLY2_space_CT"," 12.5 : Min. Poly2 spacing Poly or Active contact: #{R12_6}um") +PO2cap = PL & PO2 +PO2cap.width(R11_1, euclidian).output("11.1 POLY2CAP_width", "11.1 : Min. Poly2 Capacitor width : #{R11_1}um") +PO2cap.space(R11_2, euclidian).output("11.2 POLY2CAP_space", "11.2 : Min. Poly2 Capacitor space : #{R11_2}um") +PL.enclosing(PO2cap, R11_3, euclidian).output("12.3 PL_overlap_POLY2CAP"," 11.3 : Min. Poly overlap of Poly2 Capacitor : #{R11_3}um") +PO2cap.edges.separation(AA.or(NW).edges, R11_4, euclidian).output("11.4 POLY2CAP_space_AA/NW"," 11.4 : Min. Poly2 Capacitor spacing Active or Well: #{R11_4}um") +PO2cap.separation(PL.and(CT), R11_5, euclidian).output("11.5 POLY2CAP_space_PLCT"," 11.5 : Min. Poly2 Capacitor spacing Poly contact: #{R11_5}um") +PO2cap.separation(M1.or(M2).or(M3), R11_6, euclidian).output("11.6 POLY2CAP_space_METAL"," 11.6 : Min. Poly2 Capacitor spacing any Metal: #{R11_6}um") +PO2cap.forget + +### Capacitor Well +CW.ongrid(0.5*LAMBDA).output("CW_offgrid", "Offgrid vertex on CapacitorWell") +CW.with_angle(0 .. 45).output("CW_angle", "Non 45 degree angle CapacitorWell") +CW.width(R17_1, euclidian).output("17.1 CW_width", "17.1 : Min. CapacitorWell width : #{R17_1}um") +CW.space(R17_2, euclidian).output("17.2 CW_space", "17.2 : Min. CapacitorWell space : #{R17_2}um") +AA.not(CW).separation(CW, R17_3, euclidian).output("17.3 CW_space_AA"," 17.3 : Min. CapacitorWell spacing Active : #{R17_3}um") +CW.enclosing(AA, R17_4, euclidian).output("17.4 CW_overlap_AA"," 17.4 : Min. CapacitorWell overlap of Active : #{R17_4}um") +LinCap = PL & CW +LinCap.width(R18_1, euclidian).output("18.1 LC_width", "18.1 : Min. Linear Capacitor width : #{R18_1}um") +LinCap.space(R18_2, euclidian).output("18.2 LC_space", "18.2 : Min. Linear Capacitor space : #{R18_2}um") +LinCap.separation(AA.and(CT), R18_3, euclidian).output("18.3 LC_space_AACT"," 18.3 : Min. Linear Capacitor spacing Active contact : #{R18_3}um") +LinCap.separation(PL.and(CT), R18_4, euclidian).output("18.4 LC_space_PLCT"," 18.4 : Min. Linear Capacitor spacing Poly contact : #{R18_4}um") +LinCap.forget +end + +### N+/P+ Select +Nselect.ongrid(0.5*LAMBDA).output("NSel_offgrid", "Offgrid vertex on Nselect") +Pselect.ongrid(0.5*LAMBDA).output("PSel_offgrid", "Offgrid vertex on Pselect") +Nselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Nselect") +Pselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Pselect") +NP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 N+_enc_GATE", "4.1 : Min. N+ extention Gate on Source/Drain : #{R4_1}um") +PP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 P+_enc_GATE", "4.1 : Min. P+ extention Gate on Source/Drain : #{R4_1}um") +Nselect.enclosing(AA, R4_2, euclidian).output("4.2 N+_enc_AA", "4.2 : Min. N+ enclosing Active : #{R4_2}um") +Pselect.enclosing(AA, R4_2, euclidian).output("4.2 P+_enc_AA", "4.2 : Min. P+ enclosing Active : #{R4_2}um") +Nselect.enclosing(CT, R4_3, euclidian).output("4. N+_enc_CT", "4.3 : Min. N+ enclosing Contact : #{R4_3}um") +Pselect.enclosing(CT, R4_3, euclidian).output("4.3 P+_enc_CT", "4.3 : Min. P+ enclosing Contact : #{R4_3}um") +Nselect.width(R4_4,euclidian).output("4.4 N+_width", "4.4 : Min. N+ width : #{R4_4}um") +Pselect.width(R4_4,euclidian).output("4.4 P+_width", "4.4 : Min. N+ width : #{R4_4}um") +Nselect.space(R4_4,euclidian).output("4.4 N+_space", "4.4 : Min. N+ spacing : #{R4_4}um") +Pselect.space(R4_4,euclidian).output("4.4 P+_space", "4.4 : Min. N+ spacing : #{R4_4}um") +Nselect.and(Pselect).output("4.4 N+_and_P+", "4.4 : N+ over P+ not allowed") + +### HR - High Resistive +HR.ongrid(0.5*LAMBDA).output("HR_offgrid", "Offgrid vertex on HighRes") +HR.with_angle(0 .. 45).output("HR_angle", "Non 45 degree angle HighRes") +HR.width(R27_1, euclidian).output("27.1 HR_width", "27.1 : Min. HiRes width : #{R27_1}um") +HR.space(R27_2, euclidian).output("27.2 HR_space", "27.2 : Min. HiRes spacing : #{R27_2}um") +HR.and(CT).output("27.3 CT_and_HR", "27.3 : Contact on HiRes not allowed") +HR.separation(CT, R27_3, euclidian).output("27.3 HR_space_CT", "27.3 : Min. HiRes space to Contact : #{R27_3}um") +HR.separation(AA, R27_5, euclidian).output("27.4 HR_space_AA", "27.4 : Min. HiRes space to Active : #{R27_4}um") +HR.separation(PO2, R27_5, euclidian).output("27.5 HR_space_PO2", "27.5 : Min. HiRes space to Poly2 : #{R27_5}um") +HR.and(PO2).and(AA).output("27.6 HR_and_active", "27.6 : HiRes Po2 over Active not allowed") +HR.and(PO2).and(NW.or(PW)).output("27.6 HR_and_Well", "27.6 : HiRes Po2 over Well not allowed") +HR.and(PO2).width(R27_7,euclidian).output("27.7 HRPO2_width", "27.7 : Min. HiRes Poly2 width : #{R27_7}um") +HR.and(PO2).space(R27_8,euclidian).output("27.8 HRPO2_space", "27.8 : Min. HiRes Poly2 space : #{R27_8}um") +HR.enclosing(PO2, R27_9, projection).output("27.9 HR_enc_PO2", "27.9 : Min. HiRes enclosing Poly2 : #{R27_9}um") + +### SB - Silicide block +SB.ongrid(0.5*LAMBDA).output("SB_offgrid", "Offgrid vertex on Sil. Block") +SB.with_angle(0 .. 45).output("SB_angle", "Non 45 degree angle Sil. Block") +SB.width(R20_1, euclidian).output("20.1 SB_width", "20.1 : Min. Sil. Block width : #{R20_1}um") +SB.space(R20_2, euclidian).output("20.2 SB_space", "20.2 : Min. Sil. Block spacing : #{R20_2}um") +SB.separation(CT, R20_3, euclidian).output("20.3 SB_space_CT", "20.3 : Min. Sil. Block space to Contact : #{R20_3}um") +SB.and(CT).output("20.3 SB_and_CT", "20.3 : Sil. Block over Contact not allowed") +SB.separation(AA, R20_4, euclidian).output("20.4 SB_space_AA", "20.4 : Min. Sil. Block space to Active : #{R20_4}um") +SB.separation(PL, R20_5, euclidian).output("20.5 SB_space_PL", "20.5 : Min. Sil. Block space to Poly : #{R20_5}um") +SB.and(GATE).output("20.6 SBres_overAA","20.6 : SB resistor over Active not allowed") +SB.and(PL).and(Nselect.or(Pselect)).output("20.6 SBres_over_WELL","20.6 : SB resistor over Well not allowed") +SB.and(PL).width(R20_7,euclidian).output("20.6 SBres_width", "20.7 : Min. SB resistor width : #{R20_7}um") +SB.and(PL).space(R20_7,euclidian).output("20.7 SBres_space", "20.7 : Min. SB resistor space : #{R20_7}um") +SB.enclosing(AA, R20_8, projection).polygons.without_area(0).output("20.8 SB_enc_AA", "20.8 : Min. Sil. Block enclosing Active : #{R20_8}um") +AA.enclosing(SB, R20_9, projection).polygons.without_area(0).output("20.9 AA_enc_SB", "20.9 : Min. Active enclosing Sil. Block : #{R20_9}um") +SB.enclosing(PL, R20_9, projection).output("20.8 SB_enc_PL", "20.8 : Min. Sil. Block enclosing Poly : #{R20_8}um") +PL.enclosing(SB, R20_8, projection).polygons.without_area(0).output("20.9 PL_enc_SB", "20.9 : Min. Poly enclosing Sil. Block : #{R20_9}um") +SB.separation(GATE, R20_11, euclidian).output("20.11 SB_space_GATE", "20.11 : Min. Sil. Block space to Gate : #{R20_11}um") + +### Contact +CT.ongrid(0.5*LAMBDA).output("CT_offgrid", "Offgrid vertex on Contact") +CT.with_angle(0 .. 90).output("CT_angle", "Non 90 degree angle Contact") +CT.and(GATE).output("CT_and_GATE", "Contact on Gate not allowed") +CT.not(M1).output("CT_not_M1", "Contact without Metal1 not recommended") +# CT.drc(length != R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") +CT.width(R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") +CT.without_area(R5_1*R5_1).output("5.1 CT_area", "5.1 : Exact Contact Area : #{R5_1*R5_1}um2") +CT.space(R5_3, euclidian).output("5.3 CT_space", "5.3 : Contact spacing : #{R5_3}um") +PL.enclosing(CT, R5_2_b, euclidian).output("5.2 PL_enc_CT", "5.2 : Min. Poly enclosing Contact : #{R5_2_b}um") +AA.enclosing(CT, R6_2_b, euclidian).output("6.2 AA_enc_CT", "6.2 : Min. Active enclosing Contact : #{R6_2_b}um") +PO2.enclosing(CT, R13_3, euclidian).output("13.3 PO2_enc_CT", "13.3 : Min. Poly2 enclosing Contact : #{R13_3}um") +CT.and(AA).separation(GATE, R5_4, euclidian).output("5.4 CTAA_space_GATE", "5.4 : Min. ActiveContact space to Gate : #{R5_4}um") +CT.and(PL).separation(PL, R5_5_b, euclidian).polygons.without_area(0).output("5.5.b CTPL_space_Poly", "5.5.b : Min. PolyContact space to Poly : #{R5_5_b}um") +CT.and(PL).separation(AA, R5_6_b, euclidian).output("5.6.b CTPL_space_AA", "5.6.b : Min. PolyContact space to AA : #{R5_6_b}um") +# rule 5.7.b not coded +CT.and(AA).separation(AA, R6_5_b, euclidian).polygons.without_area(0).output("6.5.b CTAA_space_AA", "6.5.b : Min. ActiveContact space to AA : #{R6_5_b}um") +CT.and(AA).separation(PL, R6_6_b, euclidian).output("6.6.b CTAA_space_PL", "6.6.b : Min. ActiveContact space to Poly : #{R6_6_b}um") +CT.and(AA).separation(CT.and(PL), R6_7_b, euclidian).output("6.7.b CTAA_space_CTPL", "6.7.b : Min. ActiveContact space to PolyContact : #{R6_7_b}um") +# rule 6.8.b not coded +CT.and(PO2).separation(AA, R13_5, euclidian).output("13.5 CTPO2_space_AA", "13.5 : Min. Poly2Contact space to AA : #{R13_5}um") +CT.and(PO2).separation(PL, R13_5, euclidian).output("13.5 CTPO2_space_PL", "13.5 : Min. Poly2Contact space to Poly : #{R13_5}um") +M1.enclosing(CT, R7_3, euclidian).output("7.3 M1_enc_CT", "7.3 : Min. Metal1 enclosing Contact : #{R7_3}um") + +### Metal 1 +M1.ongrid(0.5*LAMBDA).output("M1_offgrid", "Offgrid vertex on ME1") +M1.with_angle(0 .. 45).output("M1_angle", "Non 45 degree angle ME1") +M1.holes.with_area(0 .. R7_1*R7_1).output("M1_holes", "Min. Metal1 holes area : #{R7_1*R7_1}um2") +M1.width(R7_1, euclidian).output("7.1 M1_width", "7.1 : Min. Metal1 width : #{R7_1}um") +M1.space(R7_2, euclidian).output("7.2 M1_space", "7.2 : Min. Metal1 spacing : #{R7_2}um") +M1.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M1,R7_4,euclidian).polygons.without_area(0).output("7.4 M1_10_space", "7.4 : Space if at least one metal1 line width is > #{10*LAMBDA}um : #{R7_4}um") + +### Via 1 +V1.ongrid(0.5*LAMBDA).output("V1_offgrid", "Offgrid vertex on Via1") +V1.not(M1).output("V1_not_M1", "Via1 without Metal1 not allowed") +V1.not(M2).output("V1_not_M2", "Via1 without Metal2 not allowed") +V1.with_angle(0 .. 90).output("V1_angle", "Non 90 degree angle Via1") +V1.width(R8_1,square).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um") +V1.without_area(R8_1*R8_1).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um2") +V1.space(R8_2,euclidian).output("8.2 V1_space", "8.2 : Via1 spacing : #{R8_2}um") +M1.enclosing(V1, R8_3, euclidian).output("8.3 M1_enc_V1", "8.3 : Min. Metal1 enclosing Via1 : #{R8_3}um") +M2.enclosing(V1, R8_3, euclidian).output("9.3 M2_enc_V1", "9.3 : Min. Metal2 enclosing Via1 : #{R9_3}um") +if !DEEP && NBR_OF_METALS < 4 + V1.and(CT).or(V1.separation(CT, R8_4, euclidian).polygons).output("8.4 V1_space_CT", "8.4 : Via1 space CT : #{R8_4}um") + V1.separation(PL + AA, R8_5, euclidian).output("8.5 V1_space_PL/AAedges", "8.5 : Via1 space to Poly orActive edges : #{R8_5}um") +end +if DFM + M1.and(M2).not(V1).with_holes(1,1).output("2_V1", "Min. 2 Via1 are needed") +end + +### Metal 2 +M2.ongrid(0.5*LAMBDA).output("M2_offgrid", "Offgrid vertex on ME2") +M2.with_angle(0 .. 45).output("M2_angle", "Non 45 degree angle ME2") +M2.width(R9_1, euclidian).output("9.1 M2_width", "9.1 : Min. Metal2 width : #{R9_1}um") +M2.space(R9_2, euclidian).output("9.2 M2_space", "9.2 : Min. Metal2 spacing : #{R9_2}um") +M2.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M2,R9_4,euclidian).polygons.without_area(0).output("9.4 M2_10_space", "9.4 : Space if at least one metal2 line width is > #{10*LAMBDA}um : #{R9_4}um") + +### Via 2 +V2.ongrid(0.5*LAMBDA).output("V2_offgrid", "Offgrid vertex on Via2") +V2.not(M3).output("V2_not_M3", "Via2 without Metal3 not allowed") +V2.not(M2).output("V2_not_M2", "Via2 without Metal2 not allowed") +V2.with_angle(0 .. 90).output("V2_angle", "Non 90 degree angle Via2") +V2.width(R14_1, square).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um") +V2.without_area(R14_1*R14_1).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um2") +V2.space(R14_2, euclidian).output("14.2 V2_space", "14.2 : Via2 spacing : #{R14_2}um") +M2.enclosing(V2, R14_3, euclidian).output("14.3 M2_enc_V2", "14.3 : Min. Metal2 enclosing Via2 : #{R14_3}um") +M3.enclosing(V2, R15_3, euclidian).output("15.3 M3_enc_V2", "15.3 : Min. Metal3 enclosing Via2 : #{R15_3}um") +if !DEEP && NBR_OF_METALS < 4 + V2.and(V1).or(V2.separation(V1, R14_4, euclidian).polygons).output("14.4 V2_space_V1", "14.4 : Via2 space Via1 : #{R14_4}um") +end +if DFM + M2.and(M3).not(V2).with_holes(1,1).output("2_V2", "Min. 2 Via2 are needed") +end + +### Metal 3 +M3.ongrid(0.5*LAMBDA).output("M3_offgrid", "Offgrid vertex on ME3") +M3.with_angle(0 .. 45).output("M3_angle", "Non 45 degree angle ME3") +M3.width(R15_1, euclidian).output("15.1 M3_width", "15.1 : Min. Metal3 width : #{R15_1}um") +M3.space(R15_2, euclidian).output("15.2 M3_space", "15.2 : Min. Metal3 spacing : #{R15_2}um") +M3.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M3, R15_4, euclidian).polygons.without_area(0).output("15.4 M3_10_space", "15.4 : Space if at least one metal3 line width is > #{10*LAMBDA}um : #{R15_4}um") + +### Cap Top Metal +if SUBM || DEEP +CTM.ongrid(0.5*LAMBDA).output("CTM_offgrid", "Offgrid vertex on CTM") +CTM.with_angle(0 .. 45).output("CTM_angle", "Non 45 degree angle CTM") +CTM.width(R28_1, euclidian).output("28.1 CTM_width", "28.1 : Min. Cap Top Metal width : #{R28_1}um") +CTM.space(R28_2, euclidian).output("28.2 CTM_space", "28.2 : Min. Cap Top Metal spacing : #{R28_2}um") +if NBR_OF_METALS == 4 + TM = M4 + VT = V3 + TB = V2 +end +if NBR_OF_METALS == 5 + TM = M5 + VT = V4 + VB = V3 +end +if NBR_OF_METALS == 6 + TM = M6 + VT = V5 + VB = V4 +end +TM.enclosing(CTM, R28_3, euclidian).output("28.3 TM_overlap_CTM", "28.3 : Min. Top Metal overlap Cap Top Metal : #{R28_3}um") +CTM.enclosing(VT, R28_4, euclidian).output("28.4 CTM_overlap_VT", "28.4 : Min. Cap Top Metal overlap Top Via : #{R28_4}um") +CTM.separation(VB, R28_5, euclidian).output("28.5 CTM_space_VB", "28.5 : Min. Cap Top Metal space Bottom Via : #{R28_5}um") +CTM.separation(VT, R28_5, euclidian).output("28.5 CTM_space_VT", "28.5 : Min. Cap Top Metal space Top Via : #{R28_5}um") +TM.enclosing(VB, R28_6, euclidian).output("28.6 TM_overlap_VB", "28.6 : Min. Top Metal overlap Bottom Via : #{R28_6}um") +# rule 28.7 not coded +CTM.not_interacting(VT).width(R28_8, euclidian).output("28.8 CTMdummies_width", "28.8 : Min. dummies Cap Top Metal width : #{R28_8}um") +TM.interacting(CTM).space(R28_9, euclidian).output("28.9 VT_space", "28.9 : Min. Top Metal spacing : #{R28_9}um") +VT.interacting(CTM).space(R28_10, euclidian).output("28.10 VT_space", "28.10 : Min. Top Via spacing : #{R28_10}um") +VB.interacting(TM.interacting(CTM)).space(R28_11, euclidian).output("28.11 VB_space", "28.11 : Min. Bottom Via spacing : #{R28_11}um") +CTM.sized(-15.um).sized(15.um).output("28.12 CTM_width", "28.12 : Max. CTM width/length : 30um") +TM.interacting(CTM).sized(-17.5.um).sized(17.5.um).output("28.13 TM_width", "28.13 : Max. Top Metal width/length : 35um") +CTM.and(VB).output("28.14 CTM_VB", "28.14 : no VB under CTM allowed") +CTM.and(AA.or(PL)).output("28.15 CTM_AA", "28.15 : no active or passive circuitry under CTM allowed") +end + +### Via 3 +if NBR_OF_METALS > 3 +V3.ongrid(0.5*LAMBDA).output("V3_offgrid", "Offgrid vertex on Via3") +V3.not(M3).output("V3_not_M3", "Via3 without Metal3 not allowed") +V3.not(M4).output("V3_not_M4", "Via3 without Metal4 not allowed") +V3.with_angle(0 .. 90).output("V3_angle", "Non 90 degree angle Via3") +V3.width(R21_1, square).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um") +V3.without_area(R21_1*R21_1).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um2") +V3.space(R21_2, euclidian).output("21.2 V3_space", "21.2 : Via3 spacing : #{R21_2}um") +M3.enclosing(V3, R21_3, euclidian).output("21.3 M3_enc_V3", "21.3 : Min. Metal3 enclosing Via3 : #{R21_3}um") +M4.enclosing(V3, R22_3, euclidian).output("22.3 M4_enc_V3", "22.3 : Min. Metal4 enclosing Via3 : #{R22_3}um") +if DFM + M3.and(M4).not(V3).with_holes(1,1).output("2_V3", "Min. 2 Via3 are needed") +end + +### Metal 4 +M4.ongrid(0.5*LAMBDA).output("M4_offgrid", "Offgrid vertex on ME4") +M4.with_angle(0 .. 45).output("M4_angle", "Non 45 degree angle ME4") +M4.width(R22_1, euclidian).output("22.1 M4_width", "22.1 : Min. Metal4 width : #{R22_1}um") +M4.space(R22_2, euclidian).output("22.2 M4_space", "22.2 : Min. Metal4 spacing : #{R22_2}um") +M4.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M4, R22_4, euclidian).polygons.without_area(0).output("22.4 M4_10_space", "22.4 : Space if at least one metal4 line width is > #{10*LAMBDA}um : #{R22_4}um") + +### Via 4 +if NBR_OF_METALS > 4 +V4.ongrid(0.5*LAMBDA).output("V4_offgrid", "Offgrid vertex on Via4") +V4.not(M5).output("V4_not_M5", "Via4 without Metal5 not allowed") +V4.not(M4).output("V4_not_M4", "Via4 without Metal4 not allowed") +V4.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via4") +V4.width(R25_1, square).output("25.1 V4_width", "25.1 : Exact Via4 width : #{R25_1}um") +V4.without_area(R25_1*R25_1).output("25.1 V4_width", "25.1 : Via4 width : #{R25_1}um2") +V4.space(R25_2, euclidian).output("25.2 V4_space", "25.2 : Exact Via4 spacing : #{R25_2}um") +M4.enclosing(V4, R25_3, euclidian).output("25.3 M4_enc_V4", "25.3 : Min. Metal4 enclosing Via4 : #{R25_3}um") +M5.enclosing(V4, R26_3, euclidian).output("26.3 M5_enc_V4", "26.3 : Min. Metal5 enclosing Via4 : #{R26_3}um") +if DFM + M4.and(M5).not(V4).with_holes(1,1).output("2_V4", "Min. 2 Via4 are needed") +end + +### Metal 5 +M5.ongrid(0.5*LAMBDA).output("M5_offgrid", "Offgrid vertex on ME5") +M5.with_angle(0 .. 45).output("M5_angle", "Non 45 degree angle ME5") +M5.width(R26_1, euclidian).output("26.1 M5_width", "26.1 : Min. Metal5 width : #{R26_1}um") +M5.space(R26_2, euclidian).output("26.2 M5_space", "26.2 : Min. Metal5 spacing : #{R26_2}um") +M5.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, R26_4, euclidian).polygons.without_area(0).output("26.4 M5_10_space", "26 .4 : Space if at least one metal5 line width is > #{10*LAMBDA}um : #{R26_4}um") + +### Via 5 +if NBR_OF_METALS > 5 +V5.ongrid(0.5*LAMBDA).output("V5_offgrid", "Offgrid vertex on Via5") +V5.not(M5).output("V5_not_M5", "Via5 without Metal5 not allowed") +V5.not(M6).output("V5_not_M6", "Via5 without Metal6 not allowed") +V5.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via5") +V5.width(R29_1, square).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um") +V5.without_area(R29_1*R29_1).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um2") +V5.space(R29_2, euclidian).output("29.2 V5_space", "29.2 : Via5 spacing : #{R29_2}um") +M5.enclosing(V5, R29_3, euclidian).output("29.3 M5_enc_V5", "29.3 : Min. Metal5 enclosing Via5 : #{R29_3}um") +M6.enclosing(V5, R30_3, euclidian).output("30.3 M3_enc_V5", "30.3 : Min. Metal6 enclosing Via5 : #{R30_3}um") +if DFM + M5.and(M6).not(V5).with_holes(1,1).output("2_V5", "Min. 2 Via5 are needed") +end + +### Metal 6 +M6.ongrid(0.5*LAMBDA).output("M6_offgrid", "Offgrid vertex on ME6") +M6.with_angle(0 .. 45).output("M6_angle", "Non 45 degree angle ME5") +M6.width(R30_1, euclidian).output("30.1 M6_width", "30.1 : Min. Metal6 width : #{R30_1}um") +M6.space(R30_2, euclidian).output("30.2 M6_space", "30.2 : Min. Metal6 spacing : #{R30_2}um") +M6.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, 10, euclidian).polygons.without_area(0).output("30.4 M6_10_space", "30.4 : Space if at least one metal6 line width is > #{10*LAMBDA}um : #{R30_4}um") + +end +end +end + +# time spent for the DRC +time = Time.now +hours = ((time - tstart)/3600).to_i +minutes = ((time - tstart)/60 - hours * 60).to_i +seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i +$stdout.write "DRC finished at : #{time.hour}:#{time.min}:#{time.sec} - DRC duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" + From acc9b2d223947c8456e1a5fc0e69479337561d81 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 27 Sep 2021 12:30:06 -0700 Subject: [PATCH 04/22] Connect pwell and bulk when no tap --- technology/freepdk45/tech/freepdk45.lylvs | 8 ++++---- technology/scn4m_subm/tech/scn4m_subm.lylvs | 14 ++++---------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 64fde014..91009968 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -214,10 +214,10 @@ end #connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -#for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) -# connect_explicit(pat, [ "NWELL", "vdd" ]) -# connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) -#end +for pat in %w(pnand* and?_dec port_address* replica_bitcell_array) + connect_explicit(pat, [ "NWELL", "vdd" ]) + connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +end #for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL* # FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index 16dd5c6e..46a6c12a 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -164,16 +164,10 @@ connect_global(pwell, "PWELL") connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -#for pat in %w(pnand*_0 and2_dec_0 port_address* replica_bitcell_array) -# connect_explicit(pat, [ "NWELL", "vdd" ]) -# connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) -#end - -#for pat in %w(XOR* XNOR* TLAT* TINV* TBUF* SDFF* OR* OAI* NOR* NAND* MUX* LOGIC* INV* HA* FILLCELL* -# FA* DLL* DLH* DFF* DFFS* DFFR* DFFRS* CLKGATE* CLKBUF* BUF* AOI* ANTENNA* AND*) -# connect_explicit(pat, [ "NWELL", "VDD" ]) -# connect_explicit(pat, [ "BULK", "VSS" ]) -#end +for pat in %w(pnand* and?_dec port_address* replica_bitcell_array) + connect_explicit(pat, [ "NWELL", "vdd" ]) + connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +end # Actually performs the extraction netlist # ... not really required From 2e846cb22f63319bee4a7c31576ef78f72cdcab0 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 27 Sep 2021 15:21:26 -0700 Subject: [PATCH 05/22] Fix regexes for cells without well taps --- technology/freepdk45/tech/freepdk45.lylvs | 2 +- technology/scn4m_subm/tech/scn4m_subm.lylvs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 91009968..bf4852d8 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -214,7 +214,7 @@ end #connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -for pat in %w(pnand* and?_dec port_address* replica_bitcell_array) +for pat in %w(pinv* pnor* pnand* and?_dec* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) end diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index 46a6c12a..4421d627 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -164,7 +164,7 @@ connect_global(pwell, "PWELL") connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -for pat in %w(pnand* and?_dec port_address* replica_bitcell_array) +for pat in %w(pinv* pnor* pnand* and?_dec* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) end From 5dc885a67445cf581cd4ea19058b1f91542edc59 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 29 Sep 2021 09:34:01 -0700 Subject: [PATCH 06/22] Update nwell spacing to be same potential --- technology/scn4m_subm/tech/scn4m_subm.lydrc | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lydrc b/technology/scn4m_subm/tech/scn4m_subm.lydrc index 345f4a41..afaf01a8 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lydrc +++ b/technology/scn4m_subm/tech/scn4m_subm.lydrc @@ -161,7 +161,8 @@ R27_9 = ( 2 *LAMBDA ).round(3) if !SUBM && !DEEP R1_1 = ( 10 *LAMBDA ).round(3) - R1_2 = ( 9 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) + #R1_2 = ( 9 *LAMBDA ).round(3) R2_3 = ( 5 *LAMBDA ).round(3) R3_2 = ( 2 *LAMBDA ).round(3) R3_2_a = ( 2 *LAMBDA ).round(3) @@ -211,7 +212,10 @@ end if SUBM R1_1 = ( 12 *LAMBDA ).round(3) - R1_2 = ( 18 *LAMBDA ).round(3) + # We are assuming the wells are at the same potential since + # DRC can't tell otherwise + #R1_2 = ( 18 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) R2_3 = ( 6 *LAMBDA ).round(3) R3_2 = ( 3 *LAMBDA ).round(3) R3_2_a = ( 3 *LAMBDA ).round(3) @@ -301,7 +305,10 @@ end if DEEP R1_1 = ( 12 *LAMBDA ).round(3) - R1_2 = ( 18 *LAMBDA ).round(3) + # We are assuming the wells are at the same potential since + # DRC can't tell otherwise + #R1_2 = ( 18 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) R2_3 = ( 6 *LAMBDA ).round(3) R3_2 = ( 3 *LAMBDA ).round(3) R3_2_a = ( 4 *LAMBDA ).round(3) @@ -414,7 +421,7 @@ class DRC::DRCLayer end DRC::DRCLayer::new(@engine, new_data) end -end +end # layers definitions ######################## @@ -456,7 +463,7 @@ info("Layers definitions") # layers processing ######################## info("Layers processing") -#CHIP = extent.sized(1.0) +#CHIP = extent.sized(1.0) NP = AA & Nselect PP = AA & Pselect NSTP = NP.and(NW) From 5d33db0ee4c520bfb3c38fd083d2718d7882df0f Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 29 Sep 2021 10:00:54 -0700 Subject: [PATCH 07/22] Add write driver to well connect list --- technology/freepdk45/tech/freepdk45.lylvs | 2 +- technology/scn4m_subm/tech/scn4m_subm.lylvs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index bf4852d8..73a5c351 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -214,7 +214,7 @@ end #connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -for pat in %w(pinv* pnor* pnand* and?_dec* port_address* replica_bitcell_array*) +for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) end diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index 4421d627..be9e8ac2 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -164,7 +164,7 @@ connect_global(pwell, "PWELL") connect_global(nwell, "NWELL") #connect_global(bulk, "BULK") -for pat in %w(pinv* pnor* pnand* and?_dec* port_address* replica_bitcell_array*) +for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) end From 6ee4697711c2566fad10e9c72d80e06eb8a1f8c3 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 4 Oct 2021 14:14:07 -0700 Subject: [PATCH 08/22] Change cell names in lvs file --- technology/scn4m_subm/tech/scn4m_subm.lylvs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index be9e8ac2..ea768eef 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -118,7 +118,7 @@ ngate = nactive & poly nsd = nactive - ngate -cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "dff","wordline_driver_0") { +cheat("cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "pbitcell", "dummy_pbitcell", "dff") { # PMOS transistor device extraction extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) From 8f296810bee73317b5fe5ccbca314a442f941d86 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 11:53:30 -0700 Subject: [PATCH 09/22] Fix cheat on wordline driver name. --- technology/freepdk45/tech/freepdk45.lylvs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 73a5c351..e4587656 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -135,7 +135,7 @@ lv_ngate = ngate - vtg - thkox gv_ngate = ngate & vtg - vth - thkox hv_ngate = ngate - vtg - vth & thkox -cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "dff","wordline_driver_0") { +cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "dff","wordline_driver*") { # PMOS transistor device extraction extract_devices(mos4("PMOS_VTL"), { "SD" => psd, "G" => lv_pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) @@ -206,13 +206,13 @@ connect(metal10, metal10_pin) schematic.simplify if $connect_supplies - connect_implicit("vdd") - connect_implicit("gnd") +connect_implicit("*", "vdd") +connect_implicit("*", "gnd") end -#connect_global(pwell, "PWELL") -#connect_global(nwell, "NWELL") -#connect_global(bulk, "BULK") +connect_global(pwell, "PWELL") +connect_global(nwell, "NWELL") +connect_global(bulk, "BULK") for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) From 43bbd2e722d3ca4ebfcf4b5fe08eaacd7d361945 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 12:05:55 -0700 Subject: [PATCH 10/22] Fixed incorrect via2 spacing rule in tech file. --- technology/freepdk45/tech/tech.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 2ae9c06c..9303ba3d 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -337,7 +337,7 @@ drc.add_enclosure("m2", # VIA2-3.2 Minimum spacing of Via[2-3] drc.add_layer("via2", width=0.065, - spacing=0.075) + spacing=0.085) # METALINT.1 Minimum width of intermediate metal # METALINT.2 Minimum spacing of intermediate metal From b7362ba011b0d0d5bb2c5b02163103a0e071a08b Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 8 Nov 2021 14:27:41 -0800 Subject: [PATCH 11/22] Do not run same well spacing for backwards compatibility. Add pbitcell cheat. --- compiler/bitcells/pbitcell.py | 6 ++---- technology/freepdk45/tech/freepdk45.lydrc | 5 +++-- technology/freepdk45/tech/freepdk45.lylvs | 2 +- technology/scn4m_subm/tech/scn4m_subm.lylvs | 2 +- technology/scn4m_subm/tech/tech.py | 6 +++--- 5 files changed, 10 insertions(+), 11 deletions(-) diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index 71679bd1..d605f492 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -425,7 +425,6 @@ class pbitcell(bitcell_base.bitcell_base): width=self.width) self.add_power_pin("gnd", vector(0, gnd_ypos), directions=("H", "H")) - vdd_ypos = self.inverter_nmos_ypos \ + self.inverter_nmos.active_height \ + self.inverter_gap \ @@ -1013,7 +1012,7 @@ class pbitcell(bitcell_base.bitcell_base): well_height = max_nmos_well_height + self.port_ypos \ - self.nwell_enclose_active - self.gnd_position.y # FIXME fudge factor xpos - well_width = self.width + 2*self.nwell_enclose_active + well_width = self.width + 2 * self.nwell_enclose_active offset = vector(self.leftmost_xpos - self.nwell_enclose_active, self.botmost_ypos) self.add_rect(layer="pwell", offset=offset, @@ -1163,7 +1162,7 @@ class pbitcell(bitcell_base.bitcell_base): return pin_dict = {pin: port for pin, port in zip(self.pins, port_nets)} - + # Edges added wl->bl, wl->br for every port except write ports rw_pin_names = zip(self.r_wl_names, self.r_bl_names, self.r_br_names) r_pin_names = zip(self.rw_wl_names, self.rw_bl_names, self.rw_br_names) @@ -1172,4 +1171,3 @@ class pbitcell(bitcell_base.bitcell_base): for wl, bl, br in pin_zip: graph.add_edge(pin_dict[wl], pin_dict[bl], self) graph.add_edge(pin_dict[wl], pin_dict[br], self) - diff --git a/technology/freepdk45/tech/freepdk45.lydrc b/technology/freepdk45/tech/freepdk45.lydrc index 91c7c30f..0c380c50 100644 --- a/technology/freepdk45/tech/freepdk45.lydrc +++ b/technology/freepdk45/tech/freepdk45.lydrc @@ -110,8 +110,9 @@ end # Wells nwell.and(pwell).output("WELL.1", "WELL.1 : nwell/pwell must not overlap") # the rule "WELL.2 : Minimum spacing of well at different potential : 225nm" was not coded : see : https://www.klayout.de/forum/discussion/comment/6021 -nwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of nwell at same potential : 135nm") -pwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of pwell at same potential : 135nm") +# the rule WELL.3 was not detected in the original FreePDK45 rule deck +#nwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of nwell at same potential : 135nm") +#pwell.space(135.nm, euclidian).output("WELL.3", "WELL.3 : Minimum spacing of pwell at same potential : 135nm") well.separation(well, 200.nm, euclidian).output("WELL.4", "WELL.4 : Minimum width of nwell/pwell : 200nm") vtg.not(well).output("VT.1","VT.1 : Vtg adjust layers must coincide with well") vth.not(well).output("VT.1","VT.1 : Vth adjust layers must coincide with well") diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index e4587656..9c3b5971 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -135,7 +135,7 @@ lv_ngate = ngate - vtg - thkox gv_ngate = ngate & vtg - vth - thkox hv_ngate = ngate - vtg - vth & thkox -cheat("cell_6t", "dummy_cell_6t", "cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "dff","wordline_driver*") { +cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { # PMOS transistor device extraction extract_devices(mos4("PMOS_VTL"), { "SD" => psd, "G" => lv_pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index ea768eef..7a7c1371 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -118,7 +118,7 @@ ngate = nactive & poly nsd = nactive - ngate -cheat("cell_1rw", "dummy_cell_1rw", "cell_2rw", "dummy_cell_2rw", "pbitcell", "dummy_pbitcell", "dff") { +cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { # PMOS transistor device extraction extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 374ba4c8..ee63203c 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -drc_name = "klayout" -lvs_name = "klayout" -pex_name = "klayout" +# drc_name = "klayout" +# lvs_name = "klayout" +# pex_name = "klayout" blackbox_bitcell = False From 552811b41bed2900d8d0974383a66981d0cdcf58 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 16 Nov 2021 14:37:24 -0800 Subject: [PATCH 12/22] Use klayout in SCMOS too. --- technology/scn4m_subm/tech/tech.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index ee63203c..374ba4c8 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -# drc_name = "klayout" -# lvs_name = "klayout" -# pex_name = "klayout" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False From 735f9cf450e647df4a9b2ea31eb1a42ddd9fc29a Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 19 Nov 2021 13:43:54 -0800 Subject: [PATCH 13/22] Remove klayout from scmos --- technology/scn4m_subm/tech/tech.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 374ba4c8..a8c44996 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,5 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -drc_name = "klayout" -lvs_name = "klayout" -pex_name = "klayout" blackbox_bitcell = False From b94dd79125201cada139697a4f1408dfac0fa839 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Nov 2021 10:37:26 -0800 Subject: [PATCH 14/22] Add labels to noconn in dummy bitcell for klayout lvs --- compiler/bitcells/pbitcell.py | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index d605f492..aaa403dd 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -474,6 +474,7 @@ class pbitcell(bitcell_base.bitcell_base): self.connect_inst([self.Q_bar, self.rw_wl_names[k], br_name, "gnd"]) + def place_readwrite_ports(self): """ Places read/write ports in the bit cell """ # define read/write transistor variables as empty arrays @@ -528,6 +529,21 @@ class pbitcell(bitcell_base.bitcell_base): offset=self.rwbr_positions[k], height=self.height) + if self.dummy_bitcell: + bl_name = self.rw_bl_names[k] + br_name = self.rw_br_names[k] + bl_name += "_noconn" + br_name += "_noconn" + + # This helps with LVS matching in klayout + drain_pin = self.readwrite_nmos_left[k].get_pin("S") + self.add_label(bl_name, drain_pin.layer, drain_pin.center()) + + # This helps with LVS matching in klayout + source_pin = self.readwrite_nmos_right[k].get_pin("D") + self.add_label(br_name, source_pin.layer, source_pin.center()) + + # update furthest left and right transistor edges self.left_building_edge = left_readwrite_transistor_xpos self.right_building_edge = right_readwrite_transistor_xpos \ @@ -625,6 +641,20 @@ class pbitcell(bitcell_base.bitcell_base): offset=self.wbr_positions[k], height=self.height) + if self.dummy_bitcell: + bl_name = self.w_bl_names[k] + br_name = self.w_br_names[k] + bl_name += "_noconn" + br_name += "_noconn" + + # This helps with LVS matching in klayout + drain_pin = self.write_nmos_left[k].get_pin("S") + self.add_label(bl_name, drain_pin.layer, drain_pin.center()) + + # This helps with LVS matching in klayout + source_pin = self.write_nmos_right[k].get_pin("D") + self.add_label(br_name, source_pin.layer, source_pin.center()) + # update furthest left and right transistor edges self.left_building_edge = left_write_transistor_xpos self.right_building_edge = right_write_transistor_xpos \ @@ -752,6 +782,20 @@ class pbitcell(bitcell_base.bitcell_base): offset=self.rbr_positions[k], height=self.height) + if self.dummy_bitcell: + bl_name = self.r_bl_names[k] + br_name = self.r_br_names[k] + bl_name += "_noconn" + br_name += "_noconn" + + # This helps with LVS matching in klayout + drain_pin = self.read_access_nmos_left[k].get_pin("S") + self.add_label(bl_name, drain_pin.layer, drain_pin.center()) + + # This helps with LVS matching in klayout + source_pin = self.read_access_nmos_right[k].get_pin("D") + self.add_label(br_name, source_pin.layer, source_pin.center()) + def route_wordlines(self): """ Routes gate of transistors to their respective wordlines """ port_transistors = [] From 0c3ee643ab5b64ed2cb64a8e7821757e69c8e7d5 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Nov 2021 10:51:40 -0800 Subject: [PATCH 15/22] Remove add_mod and add module whenever calling add_inst. --- compiler/base/hierarchy_layout.py | 4 +--- compiler/base/hierarchy_spice.py | 22 ++++++++----------- compiler/bitcells/dummy_pbitcell.py | 1 - compiler/bitcells/pbitcell.py | 5 ----- compiler/bitcells/replica_pbitcell.py | 2 -- compiler/modules/and2_dec.py | 3 --- compiler/modules/and3_dec.py | 3 --- compiler/modules/and4_dec.py | 4 ---- compiler/modules/bank.py | 5 ----- compiler/modules/bank_select.py | 5 ----- compiler/modules/bitcell_array.py | 5 ++--- compiler/modules/col_cap_array.py | 4 +--- compiler/modules/column_mux_array.py | 1 - compiler/modules/control_logic.py | 17 ++------------- compiler/modules/delay_chain.py | 8 +++---- compiler/modules/dff_array.py | 1 - compiler/modules/dff_buf.py | 5 +---- compiler/modules/dff_buf_array.py | 1 - compiler/modules/dff_inv.py | 7 ++---- compiler/modules/dff_inv_array.py | 1 - compiler/modules/dummy_array.py | 1 - compiler/modules/global_bitcell_array.py | 3 --- compiler/modules/hierarchical_decoder.py | 6 ------ compiler/modules/hierarchical_predecode.py | 17 ++++++--------- compiler/modules/local_bitcell_array.py | 2 -- compiler/modules/multibank.py | 11 ---------- compiler/modules/orig_bitcell_array.py | 1 - compiler/modules/port_address.py | 6 +----- compiler/modules/port_data.py | 11 +++------- compiler/modules/precharge_array.py | 5 +---- compiler/modules/replica_bitcell_array.py | 13 +++-------- compiler/modules/replica_column.py | 12 +++++------ compiler/modules/row_cap_array.py | 4 +--- compiler/modules/sense_amp_array.py | 1 - compiler/modules/tri_gate_array.py | 3 +-- compiler/modules/wordline_buffer_array.py | 1 - compiler/modules/wordline_driver_array.py | 2 -- compiler/modules/write_driver_array.py | 2 -- compiler/modules/write_mask_and_array.py | 4 +--- compiler/pgates/column_mux.py | 1 - compiler/pgates/pand2.py | 9 +++----- compiler/pgates/pand3.py | 3 --- compiler/pgates/pand4.py | 4 ---- compiler/pgates/pbuf.py | 3 --- compiler/pgates/pbuf_dec.py | 2 -- compiler/pgates/pdriver.py | 1 - compiler/pgates/pinv.py | 21 ++++++++---------- compiler/pgates/pinvbuf.py | 3 --- compiler/pgates/pnand2.py | 22 +++++++------------ compiler/pgates/pnand3.py | 25 ++++++++-------------- compiler/pgates/pnand4.py | 6 ------ compiler/pgates/pnor2.py | 4 ---- compiler/pgates/precharge.py | 2 -- compiler/pgates/ptristate_inv.py | 2 -- compiler/pgates/pwrite_driver.py | 3 --- compiler/pgates/wordline_driver.py | 3 --- compiler/sram/sram_base.py | 21 +++++------------- technology/freepdk45/tech/freepdk45.lylvs | 2 +- 58 files changed, 78 insertions(+), 268 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 8bbc72c7..c30408c7 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -232,6 +232,7 @@ class layout(): # Check that the instance name is unique debug.check(name not in self.inst_names, "Duplicate named instance in {0}: {1}".format(self.cell_name, name)) + self.mods.add(mod) self.inst_names.add(name) self.insts.append(geometry.instance(name, mod, offset, mirror, rotate)) debug.info(3, "adding instance {}".format(self.insts[-1])) @@ -638,7 +639,6 @@ class layout(): directions=directions, implant_type=implant_type, well_type=well_type) - self.add_mod(via) inst = self.add_inst(name=via.name, mod=via, offset=offset) @@ -664,7 +664,6 @@ class layout(): corrected_offset = offset + vector(-0.5 * width, -0.5 * height) - self.add_mod(via) inst = self.add_inst(name=via.name, mod=via, offset=corrected_offset) @@ -756,7 +755,6 @@ class layout(): mos = ptx.ptx(width=width, mults=mults, tx_type=tx_type) - self.add_mod(mos) inst = self.add_inst(name=mos.name, mod=mos, offset=offset, diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 5a10ff97..33ac02b9 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -45,10 +45,10 @@ class spice(): self.lvs_file = lvs_dir + cell_name + ".sp" else: self.lvs_file = self.sp_file - + self.valid_signal_types = ["INOUT", "INPUT", "OUTPUT", "BIAS", "POWER", "GROUND"] # Holds subckts/mods for this module - self.mods = [] + self.mods = set() # Holds the pins for this module (in order) self.pins = [] # The type map of each pin: INPUT, OUTPUT, INOUT, POWER, GROUND @@ -128,7 +128,7 @@ class spice(): new_list = [input_list[x] for x in self.pin_indices] return new_list - + def add_pin_types(self, type_list): """ Add pin types for all the cell's pins. @@ -140,7 +140,7 @@ class spice(): \n Module names={}\ ".format(self.name, self.pins, type_list), 1) self.pin_type = {pin: type for pin, type in zip(self.pins, type_list)} - + def get_pin_type(self, name): """ Returns the type of the signal pin. """ pin_type = self.pin_type[name] @@ -187,10 +187,6 @@ class spice(): inout_list.append(pin) return inout_list - def add_mod(self, mod): - """Adds a subckt/submodule to the subckt hierarchy""" - self.mods.append(mod) - def connect_inst(self, args, check=True): """ Connects the pins of the last instance added @@ -199,13 +195,13 @@ class spice(): where we dynamically generate groups of connections after a group of modules are generated. """ - + num_pins = len(self.insts[-1].mod.pins) num_args = len(args) # Order the arguments if the hard cell has a custom port order ordered_args = self.get_ordered_inputs(args) - + if (check and num_pins != num_args): if num_pins < num_args: mod_pins = self.insts[-1].mod.pins + [""] * (num_args - num_pins) @@ -372,15 +368,15 @@ class spice(): # these are wires and paths if self.conns[i] == []: continue - + # Instance with no devices in it needs no subckt/instance if self.insts[i].mod.no_instances: continue - + # If this is a trimmed netlist, skip it by adding comment char if trim and self.insts[i].name in self.trim_insts: sp.write("* ") - + if lvs and hasattr(self.insts[i].mod, "lvs_device"): sp.write(self.insts[i].mod.lvs_device.format(self.insts[i].name, " ".join(self.conns[i]))) diff --git a/compiler/bitcells/dummy_pbitcell.py b/compiler/bitcells/dummy_pbitcell.py index c2082033..7cf8f664 100644 --- a/compiler/bitcells/dummy_pbitcell.py +++ b/compiler/bitcells/dummy_pbitcell.py @@ -56,7 +56,6 @@ class dummy_pbitcell(design.design): def add_modules(self): self.prbc = factory.create(module_type="pbitcell", dummy_bitcell=True) - self.add_mod(self.prbc) self.height = self.prbc.height self.width = self.prbc.width diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index aaa403dd..fc131d0f 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -179,26 +179,21 @@ class pbitcell(bitcell_base.bitcell_base): # create ptx for inverter transistors self.inverter_nmos = ptx(width=inverter_nmos_width, tx_type="nmos") - self.add_mod(self.inverter_nmos) self.inverter_pmos = ptx(width=inverter_pmos_width, tx_type="pmos") - self.add_mod(self.inverter_pmos) # create ptx for readwrite transitors self.readwrite_nmos = ptx(width=readwrite_nmos_width, tx_type="nmos") - self.add_mod(self.readwrite_nmos) # create ptx for write transitors self.write_nmos = ptx(width=write_nmos_width, tx_type="nmos") - self.add_mod(self.write_nmos) # create ptx for read transistors self.read_nmos = ptx(width=read_nmos_width, tx_type="nmos") - self.add_mod(self.read_nmos) def calculate_spacing(self): """ Calculate transistor spacings """ diff --git a/compiler/bitcells/replica_pbitcell.py b/compiler/bitcells/replica_pbitcell.py index e3212d6d..bf2fa032 100644 --- a/compiler/bitcells/replica_pbitcell.py +++ b/compiler/bitcells/replica_pbitcell.py @@ -58,7 +58,6 @@ class replica_pbitcell(design.design): def add_modules(self): self.prbc = factory.create(module_type="pbitcell", replica_bitcell=True) - self.add_mod(self.prbc) self.height = self.prbc.height self.width = self.prbc.width @@ -88,4 +87,3 @@ class replica_pbitcell(design.design): self.copy_layout_pin(self.prbc_inst, "wl{}".format(port)) self.copy_layout_pin(self.prbc_inst, "vdd") self.copy_layout_pin(self.prbc_inst, "gnd") - diff --git a/compiler/modules/and2_dec.py b/compiler/modules/and2_dec.py index d448e3ff..92130b7b 100644 --- a/compiler/modules/and2_dec.py +++ b/compiler/modules/and2_dec.py @@ -43,9 +43,6 @@ class and2_dec(design.design): height=self.height, size=self.size) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if "li" in layer: diff --git a/compiler/modules/and3_dec.py b/compiler/modules/and3_dec.py index 410b2379..6f788824 100644 --- a/compiler/modules/and3_dec.py +++ b/compiler/modules/and3_dec.py @@ -41,9 +41,6 @@ class and3_dec(design.design): height=self.height, size=self.size) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if "li" in layer: self.route_layer = "li" diff --git a/compiler/modules/and4_dec.py b/compiler/modules/and4_dec.py index 99026bab..879f581b 100644 --- a/compiler/modules/and4_dec.py +++ b/compiler/modules/and4_dec.py @@ -43,9 +43,6 @@ class and4_dec(design.design): height=self.height, size=self.size) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if "li" in layer: self.route_layer = "li" @@ -129,4 +126,3 @@ class and4_dec(design.design): offset=pin.center(), width=pin.width(), height=pin.height()) - diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 7a36abf6..bd3fc0a4 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -389,7 +389,6 @@ class bank(design.design): self.bitcell_array = factory.create(module_type="replica_bitcell_array", cols=self.num_cols + self.num_spare_cols, rows=self.num_rows) - self.add_mod(self.bitcell_array) self.port_address = [] for port in self.all_ports: @@ -397,7 +396,6 @@ class bank(design.design): cols=self.num_cols + self.num_spare_cols, rows=self.num_rows, port=port)) - self.add_mod(self.port_address[port]) self.port_data = [] self.bit_offsets = self.get_column_offsets() @@ -407,11 +405,9 @@ class bank(design.design): port=port, bit_offsets=self.bit_offsets) self.port_data.append(temp_pre) - self.add_mod(self.port_data[port]) if(self.num_banks > 1): self.bank_select = factory.create(module_type="bank_select") - self.add_mod(self.bank_select) def create_bitcell_array(self): """ Creating Bitcell Array """ @@ -547,7 +543,6 @@ class bank(design.design): else: # No error checking before? debug.error("Invalid column decoder?", -1) - self.add_mod(self.column_decoder) self.column_decoder_inst = [None] * len(self.all_ports) for port in self.all_ports: diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py index dcaec9d7..9b375c00 100644 --- a/compiler/modules/bank_select.py +++ b/compiler/modules/bank_select.py @@ -78,20 +78,15 @@ class bank_select(design.design): # 1x Inverter self.inv_sel = factory.create(module_type="pinv", height=height) - self.add_mod(self.inv_sel) # 4x Inverter self.inv4x = factory.create(module_type="pinv", height=height, size=4) - self.add_mod(self.inv4x) self.nor2 = factory.create(module_type="pnor2", height=height) - self.add_mod(self.nor2) self.inv4x_nor = factory.create(module_type="pinv", height=height, size=4) - self.add_mod(self.inv4x_nor) self.nand2 = factory.create(module_type="pnand2", height=height) - self.add_mod(self.nand2) def calculate_module_offsets(self): diff --git a/compiler/modules/bitcell_array.py b/compiler/modules/bitcell_array.py index 238d499f..d08e3f48 100644 --- a/compiler/modules/bitcell_array.py +++ b/compiler/modules/bitcell_array.py @@ -53,7 +53,6 @@ class bitcell_array(bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ self.cell = factory.create(module_type=OPTS.bitcell) - self.add_mod(self.cell) def create_instances(self): """ Create the module instances used in this design """ @@ -64,11 +63,11 @@ class bitcell_array(bitcell_base_array): self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell) self.connect_inst(self.get_bitcell_pins(row, col)) - + # If it is a "core" cell, it could be trimmed for sim time if col>0 and col0 and row 1 else []) - self.add_mod(la) self.local_mods.append(la) return @@ -90,7 +89,6 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): cols=cols, rbl=self.rbl) - self.add_mod(la) self.local_mods.append(la) def add_pins(self): @@ -344,4 +342,3 @@ class global_bitcell_array(bitcell_base_array.bitcell_base_array): """Exclude dffs from graph as they do not represent critical path""" self.graph_inst_exclude.add(self.ctrl_dff_inst) - diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index 24267719..c0f42ac8 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -69,14 +69,11 @@ class hierarchical_decoder(design.design): def add_modules(self): self.and2 = factory.create(module_type="and2_dec", height=self.cell_height) - self.add_mod(self.and2) self.and3 = factory.create(module_type="and3_dec", height=self.cell_height) - self.add_mod(self.and3) # TBD # self.and4 = factory.create(module_type="and4_dec") - # self.add_mod(self.and4) self.add_decoders() @@ -84,15 +81,12 @@ class hierarchical_decoder(design.design): """ Create the decoders based on the number of pre-decodes """ self.pre2_4 = factory.create(module_type="hierarchical_predecode2x4", height=self.cell_height) - self.add_mod(self.pre2_4) self.pre3_8 = factory.create(module_type="hierarchical_predecode3x8", height=self.cell_height) - self.add_mod(self.pre3_8) self.pre4_16 = factory.create(module_type="hierarchical_predecode4x16", height=self.cell_height) - self.add_mod(self.pre4_16) def determine_predecodes(self, num_inputs): """ diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index 30908c4c..a8da372a 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -31,7 +31,7 @@ class hierarchical_predecode(design.design): self.cell_height = b.height else: self.cell_height = height - + self.column_decoder = column_decoder self.input_and_rail_pos = [] self.number_of_outputs = int(math.pow(2, self.number_of_inputs)) @@ -59,13 +59,11 @@ class hierarchical_predecode(design.design): inv_type = "inv_dec" self.and_mod = factory.create(module_type=and_type, height=self.cell_height) - self.add_mod(self.and_mod) # This uses the pinv_dec parameterized cell self.inv = factory.create(module_type=inv_type, height=self.cell_height, size=1) - self.add_mod(self.inv) def create_layout(self): """ The general organization is from left to right: @@ -189,13 +187,13 @@ class hierarchical_predecode(design.design): self.route_input_inverters() self.route_input_ands() self.route_output_inverters() - self.route_inputs_to_rails() + self.route_inputs_to_rails() self.route_output_ands() self.route_vdd_gnd() def route_inputs_to_rails(self): """ Route the uninverted inputs to the second set of rails """ - + top_and_gate = self.and_inst[-1] for num in range(self.number_of_inputs): if num == 0: @@ -221,7 +219,7 @@ class hierarchical_predecode(design.design): to_layer=self.bus_layer, offset=[self.input_rails[in_pin].cx(), y_offset], directions= ("H", "H")) - + self.add_via_stack_center(from_layer=self.input_layer, to_layer=self.bus_layer, offset=[self.decode_rails[a_pin].cx(), y_offset], @@ -306,7 +304,7 @@ class hierarchical_predecode(design.design): else: # grow the stack down search_id = 2 next_id = 0 - + curr_stack = next(filter(lambda stack: stack[search_id] == cur_layer, layer_stacks), None) via = factory.create(module_type="contact", @@ -343,7 +341,7 @@ class hierarchical_predecode(design.design): """ Route the different permutations of the NAND/AND decocer cells. """ - + # This 2D array defines the connection mapping and_input_line_combination = self.get_and_input_line_combination() for k in range(self.number_of_outputs): @@ -419,6 +417,3 @@ class hierarchical_predecode(design.design): self.and_inst[0].lx() - self.bus_space]: pin_pos = vector(xoffset, and_pin.cy()) self.copy_power_pin(and_pin, loc=pin_pos) - - - diff --git a/compiler/modules/local_bitcell_array.py b/compiler/modules/local_bitcell_array.py index 6049f3b1..49e8ed76 100644 --- a/compiler/modules/local_bitcell_array.py +++ b/compiler/modules/local_bitcell_array.py @@ -73,12 +73,10 @@ class local_bitcell_array(bitcell_base_array.bitcell_base_array): rbl=self.rbl, left_rbl=self.left_rbl, right_rbl=self.right_rbl) - self.add_mod(self.bitcell_array) self.wl_array = factory.create(module_type="wordline_buffer_array", rows=self.rows + 1, cols=self.cols) - self.add_mod(self.wl_array) def add_pins(self): # Outputs from the wordline driver (by port) diff --git a/compiler/modules/multibank.py b/compiler/modules/multibank.py index 408c91c5..45f46496 100644 --- a/compiler/modules/multibank.py +++ b/compiler/modules/multibank.py @@ -172,47 +172,36 @@ class multibank(design.design): self.bitcell_array = self.mod_bitcell_array(cols=self.num_cols, rows=self.num_rows) - self.add_mod(self.bitcell_array) self.precharge_array = self.mod_precharge_array(columns=self.num_cols) - self.add_mod(self.precharge_array) if self.col_addr_size > 0: self.column_mux_array = self.mod_column_mux_array(columns=self.num_cols, word_size=self.word_size) - self.add_mod(self.column_mux_array) self.sense_amp_array = self.mod_sense_amp_array(word_size=self.word_size, words_per_row=self.words_per_row) - self.add_mod(self.sense_amp_array) if self.write_size: self.write_mask_driver_array = self.mod_write_mask_driver_array(columns=self.num_cols, word_size=self.word_size, write_size=self.write_size) - self.add_mod(self.write_mask_driver_array) else: self.write_driver_array = self.mod_write_driver_array(columns=self.num_cols, word_size=self.word_size) - self.add_mod(self.write_driver_array) self.row_decoder = self.mod_decoder(rows=self.num_rows) - self.add_mod(self.row_decoder) self.tri_gate_array = self.mod_tri_gate_array(columns=self.num_cols, word_size=self.word_size) - self.add_mod(self.tri_gate_array) self.wordline_driver = self.mod_wordline_driver(rows=self.num_rows) - self.add_mod(self.wordline_driver) self.inv = pinv() - self.add_mod(self.inv) if(self.num_banks > 1): self.bank_select = self.mod_bank_select() - self.add_mod(self.bank_select) def add_bitcell_array(self): diff --git a/compiler/modules/orig_bitcell_array.py b/compiler/modules/orig_bitcell_array.py index 42ebdc33..ab154bec 100644 --- a/compiler/modules/orig_bitcell_array.py +++ b/compiler/modules/orig_bitcell_array.py @@ -47,7 +47,6 @@ class bitcell_array(bitcell_base_array): def add_modules(self): """ Add the modules used in this design """ self.cell = factory.create(module_type=OPTS.bitcell) - self.add_mod(self.cell) def create_instances(self): """ Create the module instances used in this design """ diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 0f456a2d..27dd7e6a 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -145,12 +145,10 @@ class port_address(design.design): self.row_decoder = factory.create(module_type="decoder", num_outputs=self.num_rows) - self.add_mod(self.row_decoder) self.wordline_driver_array = factory.create(module_type="wordline_driver_array", rows=self.num_rows, cols=self.num_cols) - self.add_mod(self.wordline_driver_array) local_array_size = OPTS.local_array_size if local_array_size > 0: @@ -174,8 +172,6 @@ class port_address(design.design): size=driver_size, height=b.height) - self.add_mod(self.rbl_driver) - def create_row_decoder(self): """ Create the hierarchical row decoder """ @@ -235,7 +231,7 @@ class port_address(design.design): # The wordline driver also had an extra gap on the right, so use this offset well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active") x_offset = self.wordline_driver_array_inst.rx() - well_gap - self.rbl_driver.width - + if self.port == 0: rbl_driver_offset = vector(x_offset, 0) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 01ddad8a..aca8cd02 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -29,7 +29,7 @@ class port_data(design.design): self.num_wmasks = int(math.ceil(self.word_size / self.write_size)) else: self.num_wmasks = 0 - + if num_spare_cols is not None: self.num_spare_cols = num_spare_cols + self.num_spare_cols if self.num_spare_cols is None: @@ -215,7 +215,6 @@ class port_data(design.design): bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port], column_offset=self.port - 1) - self.add_mod(self.precharge_array) if self.port in self.read_ports: # RBLs don't get a sense amp @@ -224,7 +223,6 @@ class port_data(design.design): offsets=self.bit_offsets, words_per_row=self.words_per_row, num_spare_cols=self.num_spare_cols) - self.add_mod(self.sense_amp_array) else: self.sense_amp_array = None @@ -236,7 +234,6 @@ class port_data(design.design): offsets=self.bit_offsets, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port]) - self.add_mod(self.column_mux_array) else: self.column_mux_array = None @@ -248,7 +245,6 @@ class port_data(design.design): offsets=self.bit_offsets, write_size=self.write_size, num_spare_cols=self.num_spare_cols) - self.add_mod(self.write_driver_array) if self.write_size is not None: # RBLs don't get a write mask self.write_mask_and_array = factory.create(module_type="write_mask_and_array", @@ -256,7 +252,6 @@ class port_data(design.design): offsets=self.bit_offsets, word_size=self.word_size, write_size=self.write_size) - self.add_mod(self.write_mask_and_array) else: self.write_mask_and_array = None @@ -858,10 +853,10 @@ class port_data(design.design): """ if self.column_mux_array: self.column_mux_array.graph_exclude_columns(column_include_num) - + def graph_clear_column_mux(self): """ Clear mux exclusions to allow different bit tests. """ if self.column_mux_array: - self.column_mux_array.init_graph_params() + self.column_mux_array.init_graph_params() diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index ed19b387..4ff6930e 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -76,8 +76,7 @@ class precharge_array(design.design): size=self.size, bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) - - self.add_mod(self.pc_cell) + self.cell = factory.create(module_type=OPTS.bitcell) def add_layout_pins(self): @@ -130,5 +129,3 @@ class precharge_array(design.design): offset = vector(tempx, 0) self.local_insts[i].place(offset=offset, mirror=mirror) - - diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index baf83964..a459c266 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -110,7 +110,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=1 + len(self.left_rbl), cols=self.column_size, rows=self.row_size) - self.add_mod(self.bitcell_array) # Replica bitlines self.replica_columns = {} @@ -138,7 +137,6 @@ class replica_bitcell_array(bitcell_base_array): rbl=self.rbl, column_offset=column_offset, replica_bit=replica_bit) - self.add_mod(self.replica_columns[port]) # Dummy row self.dummy_row = factory.create(module_type="dummy_array", @@ -147,7 +145,6 @@ class replica_bitcell_array(bitcell_base_array): # dummy column + left replica column column_offset=1 + len(self.left_rbl), mirror=0) - self.add_mod(self.dummy_row) # Dummy Row or Col Cap, depending on bitcell array properties col_cap_module_type = ("col_cap_array" if self.cell.end_caps else "dummy_array") @@ -158,7 +155,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=1 + len(self.left_rbl), mirror=0, location="top") - self.add_mod(self.col_cap_top) self.col_cap_bottom = factory.create(module_type=col_cap_module_type, cols=self.column_size, @@ -167,7 +163,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=1 + len(self.left_rbl), mirror=0, location="bottom") - self.add_mod(self.col_cap_bottom) # Dummy Col or Row Cap, depending on bitcell array properties row_cap_module_type = ("row_cap_array" if self.cell.end_caps else "dummy_array") @@ -177,7 +172,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=0, rows=self.row_size + self.extra_rows, mirror=(self.rbl[0] + 1) % 2) - self.add_mod(self.row_cap_left) self.row_cap_right = factory.create(module_type=row_cap_module_type, cols=1, @@ -188,7 +182,6 @@ class replica_bitcell_array(bitcell_base_array): column_offset=1 + len(self.left_rbl) + self.column_size + self.rbl[0], rows=self.row_size + self.extra_rows, mirror=(self.rbl[0] + 1) %2) - self.add_mod(self.row_cap_right) def add_pins(self): @@ -401,7 +394,7 @@ class replica_bitcell_array(bitcell_base_array): dummy_row_offset = self.bitcell_offset.scale(0, self.rbl[1] + flip_dummy) + self.bitcell_array_inst.ul() self.dummy_row_insts[1].place(offset=dummy_row_offset, mirror="MX" if flip_dummy else "R0") - + # Far bottom dummy row (first row below array IS flipped) flip_dummy = (self.rbl[0] + 1) % 2 dummy_row_offset = self.bitcell_offset.scale(0, -self.rbl[0] - 1 + flip_dummy) + self.unused_offset @@ -411,7 +404,7 @@ class replica_bitcell_array(bitcell_base_array): # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array dummy_col_offset = self.bitcell_offset.scale(-len(self.left_rbl) - 1, -self.rbl[0] - 1) + self.unused_offset self.dummy_col_insts[0].place(offset=dummy_col_offset) - + # Far right dummy col # Shifted down by the number of left RBLs even if we aren't adding replica column to this bitcell array dummy_col_offset = self.bitcell_offset.scale(len(self.right_rbl), -self.rbl[0] - 1) + self.bitcell_array_inst.lr() @@ -430,7 +423,7 @@ class replica_bitcell_array(bitcell_base_array): offset=pin.ll().scale(0, 1), width=self.width, height=pin.height()) - + # Replica wordlines (go by the row instead of replica column because we may have to add a pin # even though the column is in another local bitcell array) for (names, inst) in zip(self.rbl_wordline_names, self.dummy_row_replica_insts): diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index d237bcc8..b50acfa9 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -37,7 +37,7 @@ class replica_column(bitcell_base_array): self.left_rbl = rbl[0] self.right_rbl = rbl[1] self.replica_bit = replica_bit - + # Total size includes the replica rows and column cap rows self.total_size = self.left_rbl + rows + self.right_rbl + 2 @@ -63,7 +63,7 @@ class replica_column(bitcell_base_array): def create_layout(self): self.place_instances() - + self.height = self.cell_inst[-1].uy() self.width = self.cell_inst[0].rx() @@ -85,15 +85,14 @@ class replica_column(bitcell_base_array): def add_modules(self): self.replica_cell = factory.create(module_type=OPTS.replica_bitcell) - self.add_mod(self.replica_cell) + self.dummy_cell = factory.create(module_type=OPTS.dummy_bitcell) - self.add_mod(self.dummy_cell) + try: edge_module_type = ("col_cap" if self.cell.end_caps else "dummy") except AttributeError: edge_module_type = "dummy" self.edge_cell = factory.create(module_type=edge_module_type + "_" + OPTS.bitcell) - self.add_mod(self.edge_cell) def create_instances(self): self.cell_inst = [] @@ -103,7 +102,7 @@ class replica_column(bitcell_base_array): real_row = row if self.cell.end_caps: real_row -= 1 - + # Regular array cells are replica cells # Replic bit specifies which other bit (in the full range (0,total_size) to make a replica cell. if (row == 0 or row == self.total_size - 1): @@ -238,4 +237,3 @@ class replica_column(bitcell_base_array): for row, cell in enumerate(self.cell_inst): if row != self.replica_bit: self.graph_inst_exclude.add(cell) - diff --git a/compiler/modules/row_cap_array.py b/compiler/modules/row_cap_array.py index a4e7d063..e7dc9816 100644 --- a/compiler/modules/row_cap_array.py +++ b/compiler/modules/row_cap_array.py @@ -37,14 +37,13 @@ class row_cap_array(bitcell_base_array): self.width = max([x.rx() for x in self.insts]) self.height = max([x.uy() for x in self.insts]) - + self.add_boundary() self.DRC_LVS() def add_modules(self): """ Add the modules used in this design """ self.dummy_cell = factory.create(module_type="row_cap_{}".format(OPTS.bitcell)) - self.add_mod(self.dummy_cell) self.cell = factory.create(module_type=OPTS.bitcell) @@ -114,4 +113,3 @@ class row_cap_array(bitcell_base_array): for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): self.copy_power_pin(pin) - diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 713f4daf..fbfd0c5a 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -91,7 +91,6 @@ class sense_amp_array(design.design): def add_modules(self): self.amp = factory.create(module_type="sense_amp") - self.add_mod(self.amp) # This is just used for measurements, # so don't add the module diff --git a/compiler/modules/tri_gate_array.py b/compiler/modules/tri_gate_array.py index 106c9169..b1e9eebe 100644 --- a/compiler/modules/tri_gate_array.py +++ b/compiler/modules/tri_gate_array.py @@ -46,7 +46,6 @@ class tri_gate_array(design.design): def add_modules(self): self.tri = factory.create(module_type="tri_gate") - self.add_mod(self.tri) def add_pins(self): """create the name of pins depend on the word size""" @@ -120,4 +119,4 @@ class tri_gate_array(design.design): layer="m1", offset=enbar_pin.ll().scale(0, 1), width=width, - height=drc("minwidth_m1")) \ No newline at end of file + height=drc("minwidth_m1")) diff --git a/compiler/modules/wordline_buffer_array.py b/compiler/modules/wordline_buffer_array.py index 31730980..b62ea872 100644 --- a/compiler/modules/wordline_buffer_array.py +++ b/compiler/modules/wordline_buffer_array.py @@ -64,7 +64,6 @@ class wordline_buffer_array(design.design): self.wl_driver = factory.create(module_type="inv_dec", size=self.cols, height=b.height) - self.add_mod(self.wl_driver) def route_vdd_gnd(self): """ diff --git a/compiler/modules/wordline_driver_array.py b/compiler/modules/wordline_driver_array.py index 79906a3a..4faf622f 100644 --- a/compiler/modules/wordline_driver_array.py +++ b/compiler/modules/wordline_driver_array.py @@ -65,8 +65,6 @@ class wordline_driver_array(design.design): self.wl_driver = factory.create(module_type="wordline_driver", cols=self.cols) - self.add_mod(self.wl_driver) - def route_vdd_gnd(self): """ Add a pin for each row of vdd/gnd which diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 07c2ce60..7c4ea52a 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -94,7 +94,6 @@ class write_driver_array(design.design): def add_modules(self): self.driver = factory.create(module_type="write_driver") - self.add_mod(self.driver) # This is just used for measurements, # so don't add the module @@ -259,4 +258,3 @@ class write_driver_array(design.design): layer="m1", offset=inst.get_pin(inst.mod.en_name).ll().scale(0, 1), width=self.width) - diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index 2ccf34a1..f7818e12 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -63,7 +63,6 @@ class write_mask_and_array(design.design): # Assume stage effort of 3 to compute the size self.and2 = factory.create(module_type="pand2", size=max(self.write_size / 4.0, 1)) - self.add_mod(self.and2) def create_and2_array(self): self.and2_insts = {} @@ -146,7 +145,7 @@ class write_mask_and_array(design.design): self.add_via_stack_center(from_layer=supply_pin.layer, to_layer="m1", offset=supply_pin.center()) - + for supply in ["gnd", "vdd"]: supply_pin = self.and2_insts[0].get_pin(supply) supply_pin_yoffset = supply_pin.cy() @@ -158,4 +157,3 @@ class write_mask_and_array(design.design): to_layer="m1", offset=loc) self.copy_power_pin(supply_pin, loc=loc) - diff --git a/compiler/pgates/column_mux.py b/compiler/pgates/column_mux.py index 0dd923ba..a4a83dcc 100644 --- a/compiler/pgates/column_mux.py +++ b/compiler/pgates/column_mux.py @@ -77,7 +77,6 @@ class column_mux(pgate.pgate): self.ptx_width = self.tx_size * drc("minwidth_tx") self.nmos = factory.create(module_type="ptx", width=self.ptx_width) - self.add_mod(self.nmos) # Space it in the center self.nmos_lower = self.add_inst(name="mux_tx1", diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 48b5d3a7..7e8f4043 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -39,9 +39,6 @@ class pand2(pgate.pgate): height=self.height, add_wells=self.add_wells) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if self.vertical: self.height = 2 * self.nand.height @@ -146,8 +143,8 @@ class pand2(pgate.pgate): offset=pin.center(), width=pin.width(), height=pin.height()) - + def is_non_inverting(self): """Return input to output polarity for module""" - - return True \ No newline at end of file + + return True diff --git a/compiler/pgates/pand3.py b/compiler/pgates/pand3.py index 713178cc..477872c8 100644 --- a/compiler/pgates/pand3.py +++ b/compiler/pgates/pand3.py @@ -43,9 +43,6 @@ class pand3(pgate.pgate): height=self.height, add_wells=self.add_wells) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if self.vertical: self.height = 2 * self.nand.height diff --git a/compiler/pgates/pand4.py b/compiler/pgates/pand4.py index 63eb1133..8911364c 100644 --- a/compiler/pgates/pand4.py +++ b/compiler/pgates/pand4.py @@ -43,9 +43,6 @@ class pand4(pgate.pgate): height=self.height, add_wells=self.add_wells) - self.add_mod(self.nand) - self.add_mod(self.inv) - def create_layout(self): if self.vertical: self.height = 2 * self.nand.height @@ -162,4 +159,3 @@ class pand4(pgate.pgate): slew=nand_delay.slew, load=load) return nand_delay + inv_delay - diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index 22a28bb9..5ed11f39 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -52,13 +52,11 @@ class pbuf(pgate.pgate): self.inv1 = factory.create(module_type="pinv", size=input_size, height=self.height) - self.add_mod(self.inv1) self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.height, add_wells=False) - self.add_mod(self.inv2) def create_insts(self): self.inv1_inst = self.add_inst(name="buf_inv1", @@ -96,4 +94,3 @@ class pbuf(pgate.pgate): offset=a_pin.center(), width=a_pin.width(), height=a_pin.height()) - diff --git a/compiler/pgates/pbuf_dec.py b/compiler/pgates/pbuf_dec.py index 8552e265..a0cbafca 100644 --- a/compiler/pgates/pbuf_dec.py +++ b/compiler/pgates/pbuf_dec.py @@ -52,12 +52,10 @@ class pbuf_dec(pgate.pgate): self.inv1 = factory.create(module_type="pinv_dec", size=input_size, height=self.height) - self.add_mod(self.inv1) self.inv2 = factory.create(module_type="pinv_dec", size=self.size, height=self.height) - self.add_mod(self.inv2) def create_insts(self): self.inv1_inst = self.add_inst(name="buf_inv1", diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index bbadb9ab..1948b839 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -93,7 +93,6 @@ class pdriver(pgate.pgate): height=self.height, add_wells=self.add_wells) self.inv_list.append(temp_inv) - self.add_mod(temp_inv) def create_insts(self): self.inv_inst_list = [] diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index a3e467b7..c458a3f0 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -207,7 +207,6 @@ class pinv(pgate.pgate): add_drain_contact=self.route_layer, connect_poly=True, connect_drain_active=True) - self.add_mod(self.nmos) self.pmos = factory.create(module_type="ptx", width=self.pmos_width, @@ -217,7 +216,6 @@ class pinv(pgate.pgate): add_drain_contact=self.route_layer, connect_poly=True, connect_drain_active=True) - self.add_mod(self.pmos) def create_ptx(self): """ @@ -337,30 +335,29 @@ class pinv(pgate.pgate): Overrides base class function. """ self.add_graph_edges(graph, port_nets) - + def is_non_inverting(self): """Return input to output polarity for module""" - - return False + return False def get_on_resistance(self): """On resistance of pinv, defined by single nmos""" is_nchannel = True stack = 1 is_cell = False - return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) + return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) def get_input_capacitance(self): """Input cap of input, passes width of gates to gate cap function""" - return self.gate_c(self.nmos_width+self.pmos_width) - + return self.gate_c(self.nmos_width+self.pmos_width) + def get_intrinsic_capacitance(self): """Get the drain capacitances of the TXs in the gate.""" nmos_stack = 1 - nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, + nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, nmos_stack, self.tx_mults) - pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, + pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, 1, - self.tx_mults) - return nmos_drain_c + pmos_drain_c \ No newline at end of file + self.tx_mults) + return nmos_drain_c + pmos_drain_c diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index d232cabe..a48f1cf9 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -65,17 +65,14 @@ class pinvbuf(pgate.pgate): self.inv = factory.create(module_type="pinv", size=input_size, height=self.row_height) - self.add_mod(self.inv) self.inv1 = factory.create(module_type="pinv", size=self.predriver_size, height=self.row_height) - self.add_mod(self.inv1) self.inv2 = factory.create(module_type="pinv", size=self.size, height=self.row_height) - self.add_mod(self.inv2) def create_insts(self): # Create INV1 (capacitance shield) diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 1fafc210..08b01d4c 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -79,7 +79,6 @@ class pnand2(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact="active") - self.add_mod(self.nmos_left) self.nmos_right = factory.create(module_type="ptx", width=self.nmos_width, @@ -87,7 +86,6 @@ class pnand2(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact=self.route_layer) - self.add_mod(self.nmos_right) self.pmos_left = factory.create(module_type="ptx", width=self.pmos_width, @@ -95,7 +93,6 @@ class pnand2(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_left) self.pmos_right = factory.create(module_type="ptx", width=self.pmos_width, @@ -103,7 +100,6 @@ class pnand2(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_right) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ @@ -317,28 +313,26 @@ class pnand2(pgate.pgate): def is_non_inverting(self): """Return input to output polarity for module""" - return False - + def get_on_resistance(self): """On resistance of pnand, defined by stacked NMOS""" is_nchannel = True stack = 2 is_cell = False - return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) - + return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) + def get_input_capacitance(self): """Input cap of input, passes width of gates to gate cap function""" - return self.gate_c(self.nmos_width+self.pmos_width) + return self.gate_c(self.nmos_width+self.pmos_width) def get_intrinsic_capacitance(self): """Get the drain capacitances of the TXs in the gate.""" nmos_stack = 2 - nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, + nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, nmos_stack, self.tx_mults) - pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, + pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, 1, - self.tx_mults) - return nmos_drain_c + pmos_drain_c - \ No newline at end of file + self.tx_mults) + return nmos_drain_c + pmos_drain_c diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index b59d0064..0186907f 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -82,7 +82,6 @@ class pnand3(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact="active") - self.add_mod(self.nmos_center) self.nmos_right = factory.create(module_type="ptx", width=self.nmos_width, @@ -90,7 +89,6 @@ class pnand3(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact=self.route_layer) - self.add_mod(self.nmos_right) self.nmos_left = factory.create(module_type="ptx", width=self.nmos_width, @@ -98,7 +96,6 @@ class pnand3(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact="active") - self.add_mod(self.nmos_left) self.pmos_left = factory.create(module_type="ptx", width=self.pmos_width, @@ -106,7 +103,6 @@ class pnand3(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_left) self.pmos_center = factory.create(module_type="ptx", width=self.pmos_width, @@ -114,7 +110,6 @@ class pnand3(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_center) self.pmos_right = factory.create(module_type="ptx", width=self.pmos_width, @@ -122,7 +117,6 @@ class pnand3(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_right) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ @@ -350,27 +344,26 @@ class pnand3(pgate.pgate): def is_non_inverting(self): """Return input to output polarity for module""" - return False - + def get_on_resistance(self): """On resistance of pnand, defined by stacked NMOS""" is_nchannel = True stack = 3 is_cell = False - return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) - + return self.tr_r_on(self.nmos_width, is_nchannel, stack, is_cell) + def get_input_capacitance(self): """Input cap of input, passes width of gates to gate cap function""" - return self.gate_c(self.nmos_width+self.pmos_width) - + return self.gate_c(self.nmos_width+self.pmos_width) + def get_intrinsic_capacitance(self): """Get the drain capacitances of the TXs in the gate.""" nmos_stack = 3 - nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, + nmos_drain_c = self.drain_c_(self.nmos_width*self.tx_mults, nmos_stack, self.tx_mults) - pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, + pmos_drain_c = self.drain_c_(self.pmos_width*self.tx_mults, 1, - self.tx_mults) - return nmos_drain_c + pmos_drain_c \ No newline at end of file + self.tx_mults) + return nmos_drain_c + pmos_drain_c diff --git a/compiler/pgates/pnand4.py b/compiler/pgates/pnand4.py index 80607331..eed71eb9 100644 --- a/compiler/pgates/pnand4.py +++ b/compiler/pgates/pnand4.py @@ -82,7 +82,6 @@ class pnand4(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact="active") - self.add_mod(self.nmos_center) self.nmos_right = factory.create(module_type="ptx", width=self.nmos_width, @@ -90,7 +89,6 @@ class pnand4(pgate.pgate): tx_type="nmos", add_source_contact="active", add_drain_contact=self.route_layer) - self.add_mod(self.nmos_right) self.nmos_left = factory.create(module_type="ptx", width=self.nmos_width, @@ -98,7 +96,6 @@ class pnand4(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact="active") - self.add_mod(self.nmos_left) self.pmos_left = factory.create(module_type="ptx", width=self.pmos_width, @@ -106,7 +103,6 @@ class pnand4(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_left) self.pmos_center = factory.create(module_type="ptx", width=self.pmos_width, @@ -114,7 +110,6 @@ class pnand4(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_center) self.pmos_right = factory.create(module_type="ptx", width=self.pmos_width, @@ -122,7 +117,6 @@ class pnand4(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.pmos_right) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index d59f28fe..d6384676 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -77,7 +77,6 @@ class pnor2(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.nmos_left) self.nmos_right = factory.create(module_type="ptx", width=self.nmos_width, @@ -85,7 +84,6 @@ class pnor2(pgate.pgate): tx_type="nmos", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - self.add_mod(self.nmos_right) self.pmos_left = factory.create(module_type="ptx", width=self.pmos_width, @@ -93,7 +91,6 @@ class pnor2(pgate.pgate): tx_type="pmos", add_source_contact=self.route_layer, add_drain_contact="active") - self.add_mod(self.pmos_left) self.pmos_right = factory.create(module_type="ptx", width=self.pmos_width, @@ -101,7 +98,6 @@ class pnor2(pgate.pgate): tx_type="pmos", add_source_contact="active", add_drain_contact=self.route_layer) - self.add_mod(self.pmos_right) def setup_layout_constants(self): """ Pre-compute some handy layout parameters. """ diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index 951fe834..2042dc7c 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -90,7 +90,6 @@ class precharge(design.design): width=self.ptx_width, mults=self.ptx_mults, tx_type="pmos") - self.add_mod(self.pmos) def route_vdd_rail(self): """ @@ -305,4 +304,3 @@ class precharge(design.design): self.add_path(self.bitline_layer, [left_pos, right_pos], width=pmos_pin.height()) - diff --git a/compiler/pgates/ptristate_inv.py b/compiler/pgates/ptristate_inv.py index 8cac43c0..b37c36ae 100644 --- a/compiler/pgates/ptristate_inv.py +++ b/compiler/pgates/ptristate_inv.py @@ -85,13 +85,11 @@ class ptristate_inv(pgate.pgate): width=self.nmos_width, mults=1, tx_type="nmos") - self.add_mod(self.nmos) self.pmos = factory.create(module_type="ptx", width=self.pmos_width, mults=1, tx_type="pmos") - self.add_mod(self.pmos) def route_supply_rails(self): """ Add vdd/gnd rails to the top and bottom. """ diff --git a/compiler/pgates/pwrite_driver.py b/compiler/pgates/pwrite_driver.py index 2b4a3679..103e902b 100644 --- a/compiler/pgates/pwrite_driver.py +++ b/compiler/pgates/pwrite_driver.py @@ -66,19 +66,16 @@ class pwrite_driver(design.design): # Tristate inverter self.tri = factory.create(module_type="ptristate_inv", height="min") - self.add_mod(self.tri) debug.check(self.tri.width2: self.msb_decoder = self.bank.decoder.pre2_4 - self.add_mod(self.msb_decoder) def add_modules(self): self.bitcell = factory.create(module_type=OPTS.bitcell) @@ -480,30 +478,24 @@ class sram_base(design, verilog, lef): # Create the bank module (up to four are instantiated) self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank") - self.add_mod(self.bank) self.num_spare_cols = self.bank.num_spare_cols # Create the address and control flops (but not the clk) self.row_addr_dff = factory.create("dff_array", module_name="row_addr_dff", rows=self.row_addr_size, columns=1) - self.add_mod(self.row_addr_dff) if self.col_addr_size > 0: self.col_addr_dff = factory.create("dff_array", module_name="col_addr_dff", rows=1, columns=self.col_addr_size) - self.add_mod(self.col_addr_dff) else: self.col_addr_dff = None self.data_dff = factory.create("dff_array", module_name="data_dff", rows=1, columns=self.word_size + self.num_spare_cols) - self.add_mod(self.data_dff) if self.write_size: self.wmask_dff = factory.create("dff_array", module_name="wmask_dff", rows=1, columns=self.num_wmasks) - self.add_mod(self.wmask_dff) if self.num_spare_cols: self.spare_wen_dff = factory.create("dff_array", module_name="spare_wen_dff", rows=1, columns=self.num_spare_cols) - self.add_mod(self.spare_wen_dff) # Create bank decoder if(self.num_banks > 1): @@ -515,30 +507,27 @@ class sram_base(design, verilog, lef): self.mod_control_logic = getattr(c, OPTS.control_logic) # Create the control logic module for each port type - if len(self.readwrite_ports)>0: + if len(self.readwrite_ports) > 0: self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, spare_columns=self.num_spare_cols, sram=self, port_type="rw") - self.add_mod(self.control_logic_rw) - if len(self.writeonly_ports)>0: + if len(self.writeonly_ports) > 0: self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, spare_columns=self.num_spare_cols, sram=self, port_type="w") - self.add_mod(self.control_logic_w) - if len(self.readonly_ports)>0: + if len(self.readonly_ports) > 0: self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, spare_columns=self.num_spare_cols, sram=self, port_type="r") - self.add_mod(self.control_logic_r) def create_bank(self, bank_num): """ Create a bank """ @@ -779,13 +768,13 @@ class sram_base(design, verilog, lef): Clears the bit exclusions """ self.bank.clear_exclude_bits() - + def graph_exclude_column_mux(self, column_include_num, port): """ Excludes all columns muxes unrelated to the target bit being simulated. """ self.bank.graph_exclude_column_mux(column_include_num, port) - + def graph_clear_column_mux(self, port): """ Clear mux exclusions to allow different bit tests. diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 9c3b5971..934a981c 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -135,7 +135,7 @@ lv_ngate = ngate - vtg - thkox gv_ngate = ngate & vtg - vth - thkox hv_ngate = ngate - vtg - vth & thkox -cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { +cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell*", "dummy_pbitcell*", "replica_pbitcell*", "dff", "wordline_driver*") { # PMOS transistor device extraction extract_devices(mos4("PMOS_VTL"), { "SD" => psd, "G" => lv_pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) From 779d6ad2b2d1502fa46da1db5debab1c55c2a566 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Sep 2021 16:54:52 -0700 Subject: [PATCH 16/22] Debugging klayout for SCMOS and FreePDK45. --- technology/freepdk45/tech/freepdk45.lylvs | 10 +- technology/scn4m_subm/tech/scn4m_subm.lylvs | 416 ++++++++++---------- technology/scn4m_subm/tech/tech.py | 3 + 3 files changed, 216 insertions(+), 213 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 934a981c..97fbf85e 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -206,13 +206,13 @@ connect(metal10, metal10_pin) schematic.simplify if $connect_supplies -connect_implicit("*", "vdd") -connect_implicit("*", "gnd") + connect_implicit("vdd") + connect_implicit("gnd") end -connect_global(pwell, "PWELL") -connect_global(nwell, "NWELL") -connect_global(bulk, "BULK") +#connect_global(pwell, "PWELL") +#connect_global(nwell, "NWELL") +#connect_global(bulk, "BULK") for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lylvs b/technology/scn4m_subm/tech/scn4m_subm.lylvs index 7a7c1371..80185ede 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lylvs +++ b/technology/scn4m_subm/tech/scn4m_subm.lylvs @@ -1,208 +1,208 @@ - - - - - lvs - - - - false - false - - true - lvs_scripts - tools_menu.lvs.end - dsl - lvs-dsl-xml - # -# Extraction for freePDK45 -# -############################ -tstart = Time.now - -# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=my_report.lyrdb -rd schematic=reference_netlist.cir -rd target_netlist=extracted_netlist.cir -r lvs_freepdk45.lvs -if $input - source($input) -end - -if $report - report_lvs($report) -else - report_lvs("lvs_report.lvsdb") -end - -if $schematic -#reference netlist - schematic($schematic) -else - schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp")) -end - -# true: use net names instead of numbers -# false: use numbers for nets -spice_with_net_names = true - -# true: put in comments with details -# false: no comments -spice_with_comments = true - -if $target_netlist - target_netlist($target_netlist) -else - # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "The netlist comment goes here.") - target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), write_spice(spice_with_net_names, spice_with_comments), "Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}") -end - -# Hierarchical mode -deep -# Use 4 CPU cores -threads(4) -# Print details -verbose(true) - - -# layers definitions -######################## -info("Layers definitions") - - DNW = input(38,0) - nwell = input(42,0) - pwell = input(41,0) - CW = input(59,0) - active = input(43,0) - TA = input(60,0) - PBase = input(58,0) - poly = input(46,0) - SB = input(29,0) - nplus = input(45,0) - pplus = input(44,0) - PO2 = input(56,0) - HR = input(34,0) - Contact = input(25,0) - ContactPoly = input(47,0) - ContactActive = input(48,0) - ContactPoly2 = input(55, 0) - CT = Contact + ContactPoly + ContactActive + ContactPoly2 - M1 = input(49,0) - V1 = input(50,0) - M2 = input(51,0) - V2 = input(61,0) - M3 = input(62,0) - V3 = input(30,0) - M4 = input(31,0) - CTM = input(35,0) - V4 = input(32,0) - M5 = input(33,0) - V5 = input(36,0) - M6 = input(37,0) - Glass = input(52,0) - Pads = input(26,0) - -# layers processing -######################## -info("Layers processing") - -# Bulk layer for terminal provisioning -bulk = polygon_layer - -active_in_nwell = active & nwell -pactive = active_in_nwell & pplus -ntie = active_in_nwell & nplus -pgate = pactive & poly -psd = pactive - pgate - -active_in_pwell = active & pwell -nactive = active_in_pwell & nplus -ptie = active_in_pwell & pplus -ngate = nactive & poly -nsd = nactive - ngate - - -cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { - -# PMOS transistor device extraction -extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) - -# NMOS transistor device extraction -extract_devices(mos4("n"), { "SD" => nsd, "G" => ngate, "tS" => nsd, "tD" => nsd, "tG" => poly, "W" => pwell }) - -} - -# Define connectivity for netlist extraction - -# Inter-layer -connect(nwell, ntie) -connect(pwell, ptie) -connect(CT, ntie) -connect(CT, ptie) -connect(psd, CT) -connect(nsd, CT) -connect(poly, CT) -connect(CT, M1) -connect(CT, M1) -connect(M1, V1) -connect(V1, M2) -connect(M2, V2) -connect(V2, M3) -connect(M3, V3) -connect(V3, M4) -connect(M4, V4) -connect(V4, M5) -connect(M5, V5) -connect(V5, M6) - - -# Global -schematic.simplify - -if $connect_supplies - connect_implicit("vdd") - connect_implicit("gnd") -end - -connect_global(pwell, "PWELL") -connect_global(nwell, "NWELL") -#connect_global(bulk, "BULK") - -for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) - connect_explicit(pat, [ "NWELL", "vdd" ]) - connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) -end - -# Actually performs the extraction -netlist # ... not really required - -# Flatten cells which are present in one netlist only -align -# SIMPLIFICATION of the netlist -#netlist.make_top_level_pins -#netlist.combine_devices -#netlist.purge -#netlist.purge_nets -netlist.simplify - -# Tolerances for the devices extracted parameters -# tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance]) -tolerance("P", "W", :absolute => 1.nm, :relative => 0.001) -tolerance("N", "W", :absolute => 1.nm, :relative => 0.001) - -#max_res(1000000) -#min_caps(1e-15) - -max_branch_complexity(65536) -max_depth(16) - -if ! compare - #raise "ERROR : Netlists don't match" - puts "ERROR : Netlists don't match" -else - puts "CONGRATULATIONS! Netlists match." -end - -# time spent for the LVS -time = Time.now -hours = ((time - tstart)/3600).to_i -minutes = ((time - tstart)/60 - hours * 60).to_i -seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i -$stdout.write "LVS finished at : #{time.hour}:#{time.min}:#{time.sec} - LVS duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" - + + + + + lvs + + + + false + false + + true + lvs_scripts + tools_menu.lvs.end + dsl + lvs-dsl-xml + # +# Extraction for freePDK45 +# +############################ +tstart = Time.now + +# optionnal for a batch launch : klayout -b -rd input=my_layout.gds -rd report=my_report.lyrdb -rd schematic=reference_netlist.cir -rd target_netlist=extracted_netlist.cir -r lvs_freepdk45.lvs +if $input + source($input) +end + +if $report + report_lvs($report) +else + report_lvs("lvs_report.lvsdb") +end + +if $schematic +#reference netlist + schematic($schematic) +else + schematic(RBA::CellView::active.filename.sub(/\.(oas|gds|oas.gz|gds.gz)$/, ".sp")) +end + +# true: use net names instead of numbers +# false: use numbers for nets +spice_with_net_names = true + +# true: put in comments with details +# false: no comments +spice_with_comments = true + +if $target_netlist + target_netlist($target_netlist) +else + # target_netlist("netlist.cir", write_spice(spice_with_net_names, spice_with_comments), "The netlist comment goes here.") + target_netlist(File.join(File.dirname(RBA::CellView::active.filename), source.cell_name+"_extracted.cir"), write_spice(spice_with_net_names, spice_with_comments), "Extracted by KLayout on : #{Time.now.strftime("%d/%m/%Y %H:%M")}") +end + +# Hierarchical mode +deep +# Use 4 CPU cores +threads(4) +# Print details +verbose(true) + + +# layers definitions +######################## +info("Layers definitions") + + DNW = input(38,0) + nwell = input(42,0) + pwell = input(41,0) + CW = input(59,0) + active = input(43,0) + TA = input(60,0) + PBase = input(58,0) + poly = input(46,0) + SB = input(29,0) + nplus = input(45,0) + pplus = input(44,0) + PO2 = input(56,0) + HR = input(34,0) + Contact = input(25,0) + ContactPoly = input(47,0) + ContactActive = input(48,0) + ContactPoly2 = input(55, 0) + CT = Contact + ContactPoly + ContactActive + ContactPoly2 + M1 = input(49,0) + V1 = input(50,0) + M2 = input(51,0) + V2 = input(61,0) + M3 = input(62,0) + V3 = input(30,0) + M4 = input(31,0) + CTM = input(35,0) + V4 = input(32,0) + M5 = input(33,0) + V5 = input(36,0) + M6 = input(37,0) + Glass = input(52,0) + Pads = input(26,0) + +# layers processing +######################## +info("Layers processing") + +# Bulk layer for terminal provisioning +bulk = polygon_layer + +active_in_nwell = active & nwell +pactive = active_in_nwell & pplus +ntie = active_in_nwell & nplus +pgate = pactive & poly +psd = pactive - pgate + +active_in_pwell = active & pwell +nactive = active_in_pwell & nplus +ptie = active_in_pwell & pplus +ngate = nactive & poly +nsd = nactive - ngate + + +cheat("cell_1rw", "dummy_cell_1rw", "replica_cell_1rw", "cell_2rw", "dummy_cell_2rw", "replica_cell_2rw", "pbitcell", "dummy_pbitcell", "replica_pbitcell", "dff", "wordline_driver*") { + +# PMOS transistor device extraction +extract_devices(mos4("p"), { "SD" => psd, "G" => pgate, "tS" => psd, "tD" => psd, "tG" => poly, "W" => nwell }) + +# NMOS transistor device extraction +extract_devices(mos4("n"), { "SD" => nsd, "G" => ngate, "tS" => nsd, "tD" => nsd, "tG" => poly, "W" => pwell }) + +} + +# Define connectivity for netlist extraction + +# Inter-layer +connect(nwell, ntie) +connect(pwell, ptie) +connect(CT, ntie) +connect(CT, ptie) +connect(psd, CT) +connect(nsd, CT) +connect(poly, CT) +connect(CT, M1) +connect(CT, M1) +connect(M1, V1) +connect(V1, M2) +connect(M2, V2) +connect(V2, M3) +connect(M3, V3) +connect(V3, M4) +connect(M4, V4) +connect(V4, M5) +connect(M5, V5) +connect(V5, M6) + + +# Global +schematic.simplify + +if $connect_supplies + connect_implicit("vdd") + connect_implicit("gnd") +end + +connect_global(pwell, "PWELL") +connect_global(nwell, "NWELL") +#connect_global(bulk, "BULK") + +for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) + connect_explicit(pat, [ "NWELL", "vdd" ]) + connect_explicit(pat, [ "BULK", "PWELL", "gnd" ]) +end + +# Actually performs the extraction +netlist # ... not really required + +# Flatten cells which are present in one netlist only +align +# SIMPLIFICATION of the netlist +#netlist.make_top_level_pins +#netlist.combine_devices +#netlist.purge +#netlist.purge_nets +netlist.simplify + +# Tolerances for the devices extracted parameters +# tolerance(device_class_name, parameter_name [, :absolute => absolute_tolerance] [, :relative => relative_tolerance]) +tolerance("P", "W", :absolute => 1.nm, :relative => 0.001) +tolerance("N", "W", :absolute => 1.nm, :relative => 0.001) + +#max_res(1000000) +#min_caps(1e-15) + +max_branch_complexity(65536) +max_depth(16) + +if ! compare + #raise "ERROR : Netlists don't match" + puts "ERROR : Netlists don't match" +else + puts "CONGRATULATIONS! Netlists match." +end + +# time spent for the LVS +time = Time.now +hours = ((time - tstart)/3600).to_i +minutes = ((time - tstart)/60 - hours * 60).to_i +seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i +$stdout.write "LVS finished at : #{time.hour}:#{time.min}:#{time.sec} - LVS duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" + diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index a8c44996..374ba4c8 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,5 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False From bfb33ecbb49e49068b4cb1af18f0f02c2b45a755 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Sep 2021 17:06:37 -0700 Subject: [PATCH 17/22] Add DRC rules and display files --- technology/scn4m_subm/tech/scn4m_subm.lydrc | 1621 +++++++++---------- 1 file changed, 810 insertions(+), 811 deletions(-) diff --git a/technology/scn4m_subm/tech/scn4m_subm.lydrc b/technology/scn4m_subm/tech/scn4m_subm.lydrc index afaf01a8..68804569 100644 --- a/technology/scn4m_subm/tech/scn4m_subm.lydrc +++ b/technology/scn4m_subm/tech/scn4m_subm.lydrc @@ -1,811 +1,810 @@ - - - - - drc - - - - false - false - - true - drc_scripts - tools_menu.drc.end - dsl - drc-dsl-xml - # -# MOSIS SCMOS DRC -# -######################## -tstart = Time.now - -# optionnal for a batch launch : klayout -b r drc_SCMOS.lydrc -rd input=my_layout.gds -rd topcell=your_topcell -rd output=SCMOS_DRC.lyrdb -if $input - if $topcell - source($input,$topcell) - else - source($input) - end -end - -if $output - report("SCMOS DRC runset", $output) -else - report("SCMOS DRC runset", "SCMOS_DRC.lyrdb") -end - - -# PROCESS OPTIONS -######################## -LAMBDA = 0.2 -SUBM = true -DEEP = false -NBR_OF_METALS = 6 - -DFM = false - -# design rules limits definitions -######################## -R1_3 = ( 6 *LAMBDA ).round(3) -R2_1 = ( 3 *LAMBDA ).round(3) -R2_2 = ( 3 *LAMBDA ).round(3) -R2_4 = ( 3 *LAMBDA ).round(3) -R2_5 = ( 4 *LAMBDA ).round(3) -R3_1 = ( 2 *LAMBDA ).round(3) -R3_5 = ( 1 *LAMBDA ).round(3) -R4_1 = ( 3 *LAMBDA ).round(3) -R4_2 = ( 2 *LAMBDA ).round(3) -R5_1 = ( 2 *LAMBDA ).round(3) -R5_2 = ( 1.5 *LAMBDA ).round(3) -R5_4 = ( 2 *LAMBDA ).round(3) -R5_2_b = ( 1 *LAMBDA ).round(3) -R5_6_b = ( 2 *LAMBDA ).round(3) -R5_7_b = ( 3 *LAMBDA ).round(3) -R6_1 = ( 2 *LAMBDA ).round(3) -R6_2 = ( 1.5 *LAMBDA ).round(3) -R6_4 = ( 2 *LAMBDA ).round(3) -R6_2_b = ( 1 *LAMBDA ).round(3) -R6_5_b = ( 5 *LAMBDA ).round(3) -R6_6_b = ( 2 *LAMBDA ).round(3) -R6_7_b = ( 3 *LAMBDA ).round(3) -R6_8_b = ( 4 *LAMBDA ).round(3) -R7_1 = ( 3 *LAMBDA ).round(3) -R7_3 = ( 1 *LAMBDA ).round(3) -R8_2 = ( 3 *LAMBDA ).round(3) -R8_3 = ( 1 *LAMBDA ).round(3) -R8_4 = ( 2 *LAMBDA ).round(3) -R9_1 = ( 3 *LAMBDA ).round(3) -R9_3 = ( 1 *LAMBDA ).round(3) -R10_1 = ( 60 *LAMBDA ).round(3) -R10_2 = ( 20 *LAMBDA ).round(3) -R10_3 = ( 6 *LAMBDA ).round(3) -R10_4 = ( 30 *LAMBDA ).round(3) -R10_5 = ( 15 *LAMBDA ).round(3) -R11_2 = ( 3 *LAMBDA ).round(3) -R11_4 = ( 2 *LAMBDA ).round(3) -R11_6 = ( 2 *LAMBDA ).round(3) -R12_1 = ( 2 *LAMBDA ).round(3) -R12_2 = ( 3 *LAMBDA ).round(3) -R12_3 = ( 2 *LAMBDA ).round(3) -R12_4 = ( 1 *LAMBDA ).round(3) -R12_5 = ( 2 *LAMBDA ).round(3) -R12_6 = ( 3 *LAMBDA ).round(3) -R13_1 = ( 2 *LAMBDA ).round(3) -R13_3 = ( 3 *LAMBDA ).round(3) -R13_4 = ( 2 *LAMBDA ).round(3) -R13_5 = ( 3 *LAMBDA ).round(3) -R14_2 = ( 3 *LAMBDA ).round(3) -R14_3 = ( 1 *LAMBDA ).round(3) -R14_4 = ( 2 *LAMBDA ).round(3) -if NBR_OF_METALS > 3 - R15_3 = ( 1 *LAMBDA ).round(3) -else - R15_3 = ( 2 *LAMBDA ).round(3) -end -R16_1 = ( 2 *LAMBDA ).round(3) -R16_2 = ( 3 *LAMBDA ).round(3) -R16_3 = ( 2 *LAMBDA ).round(3) -R16_4 = ( 4 *LAMBDA ).round(3) -R16_5 = ( 2 *LAMBDA ).round(3) -R16_6 = ( 2 *LAMBDA ).round(3) -R16_7 = ( 6 *LAMBDA ).round(3) -R16_8 = ( 4 *LAMBDA ).round(3) -R16_9 = ( 2 *LAMBDA ).round(3) -R16_10 = ( 3 *LAMBDA ).round(3) -R16_11 = ( 2 *LAMBDA ).round(3) -R18_1 = ( 3 *LAMBDA ).round(3) -R18_2 = ( 2 *LAMBDA ).round(3) -R18_3 = ( 3 *LAMBDA ).round(3) -R18_4 = ( 2 *LAMBDA ).round(3) -R18_5 = ( 6 *LAMBDA ).round(3) -R20_1 = ( 4 *LAMBDA ).round(3) -R20_2 = ( 4 *LAMBDA ).round(3) -R20_3 = ( 2 *LAMBDA ).round(3) -R20_4 = ( 2 *LAMBDA ).round(3) -R20_5 = ( 2 *LAMBDA ).round(3) -R20_7 = ( 5 *LAMBDA ).round(3) -R20_8 = ( 7 *LAMBDA ).round(3) -R20_9 = ( 2 *LAMBDA ).round(3) -R20_10 = ( 3 *LAMBDA ).round(3) -R21_2 = ( 3 *LAMBDA ).round(3) -R21_3 = ( 1 *LAMBDA ).round(3) -if NBR_OF_METALS > 4 - R22_3 = ( 1 *LAMBDA ).round(3) -else - R22_3 = ( 2 *LAMBDA ).round(3) -end -R23_1 = ( 8 *LAMBDA ).round(3) -R23_2 = ( 4 *LAMBDA ).round(3) -R23_3 = ( 8 *LAMBDA ).round(3) -R23_4 = ( 3 *LAMBDA ).round(3) -R23_5 = ( 2 *LAMBDA ).round(3) -R23_6 = ( 2 *LAMBDA ).round(3) -R23_7 = ( 2 *LAMBDA ).round(3) -R23_8 = ( 4 *LAMBDA ).round(3) -R23_9 = ( 2 *LAMBDA ).round(3) -R24_1 = ( 4 *LAMBDA ).round(3) -R24_2 = ( 4 *LAMBDA ).round(3) -R24_3 = ( 4 *LAMBDA ).round(3) -R24_4 = ( 4 *LAMBDA ).round(3) -R24_5 = ( 3 *LAMBDA ).round(3) -R27_1 = ( 4 *LAMBDA ).round(3) -R27_2 = ( 4 *LAMBDA ).round(3) -R27_3 = ( 2 *LAMBDA ).round(3) -R27_4 = ( 2 *LAMBDA ).round(3) -R27_5 = ( 2 *LAMBDA ).round(3) -R27_7 = ( 5 *LAMBDA ).round(3) -R27_8 = ( 7 *LAMBDA ).round(3) -R27_9 = ( 2 *LAMBDA ).round(3) - - -if !SUBM && !DEEP - R1_1 = ( 10 *LAMBDA ).round(3) - R1_2 = ( 6 *LAMBDA ).round(3) - #R1_2 = ( 9 *LAMBDA ).round(3) - R2_3 = ( 5 *LAMBDA ).round(3) - R3_2 = ( 2 *LAMBDA ).round(3) - R3_2_a = ( 2 *LAMBDA ).round(3) - R3_3 = ( 2 *LAMBDA ).round(3) - R3_4 = ( 3 *LAMBDA ).round(3) - R4_3 = ( 1 *LAMBDA ).round(3) - R4_4 = ( 2 *LAMBDA ).round(3) - R5_3 = ( 2 *LAMBDA ).round(3) - R5_5_b = ( 4 *LAMBDA ).round(3) - R6_3 = ( 2 *LAMBDA ).round(3) - R7_2 = ( 2 *LAMBDA ).round(3) - R7_4 = ( 4 *LAMBDA ).round(3) - R8_1 = ( 2 *LAMBDA ).round(3) - R8_5 = ( 2 *LAMBDA ).round(3) - R9_2 = ( 3 *LAMBDA ).round(3) - R9_4 = ( 6 *LAMBDA ).round(3) - R11_1 = ( 3 *LAMBDA ).round(3) - R11_3 = ( 2 *LAMBDA ).round(3) - R11_5 = ( 3 *LAMBDA ).round(3) - R13_2 = ( 2 *LAMBDA ).round(3) - R14_1 = ( 2 *LAMBDA ).round(3) - if NBR_OF_METALS > 3 - R15_1 = ( 3 *LAMBDA ).round(3) - R15_2 = ( 3 *LAMBDA ).round(3) - R15_4 = ( 6 *LAMBDA ).round(3) - else - R15_1 = ( 6 *LAMBDA ).round(3) - R15_2 = ( 4 *LAMBDA ).round(3) - R15_4 = ( 8 *LAMBDA ).round(3) - end - R17_1 = ( 10 *LAMBDA ).round(3) - R17_2 = ( 9 *LAMBDA ).round(3) - R17_3 = ( 5 *LAMBDA ).round(3) - R17_4 = ( 5 *LAMBDA ).round(3) - R20_11 = ( 3 *LAMBDA ).round(3) - R21_1 = ( 2 *LAMBDA ).round(3) - if NBR_OF_METALS > 4 - R22_1 = ( 3 *LAMBDA ).round(3) - R22_2 = ( 3 *LAMBDA ).round(3) - R22_4 = ( 6 *LAMBDA ).round(3) - else - R22_1 = ( 6 *LAMBDA ).round(3) - R22_2 = ( 6 *LAMBDA ).round(3) - R22_4 = ( 12 *LAMBDA ).round(3) - end -end - -if SUBM - R1_1 = ( 12 *LAMBDA ).round(3) - # We are assuming the wells are at the same potential since - # DRC can't tell otherwise - #R1_2 = ( 18 *LAMBDA ).round(3) - R1_2 = ( 6 *LAMBDA ).round(3) - R2_3 = ( 6 *LAMBDA ).round(3) - R3_2 = ( 3 *LAMBDA ).round(3) - R3_2_a = ( 3 *LAMBDA ).round(3) - R3_3 = ( 2 *LAMBDA ).round(3) - R3_4 = ( 3 *LAMBDA ).round(3) - R4_3 = ( 1 *LAMBDA ).round(3) - R4_4 = ( 2 *LAMBDA ).round(3) - R5_3 = ( 3 *LAMBDA ).round(3) - R5_5_b = ( 5 *LAMBDA ).round(3) - R6_3 = ( 3 *LAMBDA ).round(3) - R7_2 = ( 3 *LAMBDA ).round(3) - R7_4 = ( 6 *LAMBDA ).round(3) - R8_1 = ( 2 *LAMBDA ).round(3) - R8_5 = ( 2 *LAMBDA ).round(3) - R9_2 = ( 3 *LAMBDA ).round(3) - R9_4 = ( 6 *LAMBDA ).round(3) - R11_1 = ( 7 *LAMBDA ).round(3) - R11_3 = ( 5 *LAMBDA ).round(3) - R11_5 = ( 6 *LAMBDA ).round(3) - R13_2 = ( 3 *LAMBDA ).round(3) - R14_1 = ( 2 *LAMBDA ).round(3) - if NBR_OF_METALS > 3 - R15_1 = ( 3 *LAMBDA ).round(3) - R15_2 = ( 3 *LAMBDA ).round(3) - R15_4 = ( 6 *LAMBDA ).round(3) - else - R15_1 = ( 5 *LAMBDA ).round(3) - R15_2 = ( 3 *LAMBDA ).round(3) - R15_4 = ( 6 *LAMBDA ).round(3) - end - R17_1 = ( 12 *LAMBDA ).round(3) - R17_2 = ( 18 *LAMBDA ).round(3) - R17_3 = ( 6 *LAMBDA ).round(3) - R17_4 = ( 6 *LAMBDA ).round(3) - R20_11 = ( 5 *LAMBDA ).round(3) - R21_1 = ( 2 *LAMBDA ).round(3) - if NBR_OF_METALS > 4 - R22_1 = ( 3 *LAMBDA ).round(3) - R22_2 = ( 3 *LAMBDA ).round(3) - R22_4 = ( 6 *LAMBDA ).round(3) - else - R22_1 = ( 6 *LAMBDA ).round(3) - R22_2 = ( 6 *LAMBDA ).round(3) - R22_4 = ( 12 *LAMBDA ).round(3) - end - R25_1 = ( 2 *LAMBDA ).round(3) - R25_2 = ( 3 *LAMBDA ).round(3) - R25_3 = ( 1 *LAMBDA ).round(3) - if NBR_OF_METALS > 5 - R26_1 = ( 3 *LAMBDA ).round(3) - R26_2 = ( 3 *LAMBDA ).round(3) - R26_3 = ( 1 *LAMBDA ).round(3) - R26_4 = ( 6 *LAMBDA ).round(3) - else - R26_1 = ( 4 *LAMBDA ).round(3) - R26_2 = ( 4 *LAMBDA ).round(3) - R26_3 = ( 2 *LAMBDA ).round(3) - R26_4 = ( 8 *LAMBDA ).round(3) - end - R28_1 = ( 40 *LAMBDA ).round(3) - R28_2 = ( 12 *LAMBDA ).round(3) - R28_3 = ( 4 *LAMBDA ).round(3) - R28_4 = ( 3 *LAMBDA ).round(3) - R28_5 = ( 4 *LAMBDA ).round(3) - R28_6 = ( 2 *LAMBDA ).round(3) - R28_7 = ( 25 *LAMBDA ).round(3) - R28_8 = ( 4 *LAMBDA ).round(3) - R28_9 = ( 8 *LAMBDA ).round(3) - R28_10 = ( 20 *LAMBDA ).round(3) - R28_11 = ( 40 *LAMBDA ).round(3) - R29_1 = ( 3 *LAMBDA ).round(3) - R29_2 = ( 4 *LAMBDA ).round(3) - R29_3 = ( 1 *LAMBDA ).round(3) - R30_1 = ( 5 *LAMBDA ).round(3) - R30_2 = ( 5 *LAMBDA ).round(3) - R30_3 = ( 1 *LAMBDA ).round(3) - R30_4 = ( 10 *LAMBDA ).round(3) - R31_1 = ( 30 *LAMBDA ).round(3) - R31_2 = ( 50 *LAMBDA ).round(3) - R31_3 = ( 15 *LAMBDA ).round(3) - R31_4 = ( 20 *LAMBDA ).round(3) - R31_5 = ( 35 *LAMBDA ).round(3) - R31_6 = ( 5 *LAMBDA ).round(3) - R31_7 = ( 30 *LAMBDA ).round(3) - R31_8 = ( 10 *LAMBDA ).round(3) -end - -if DEEP - R1_1 = ( 12 *LAMBDA ).round(3) - # We are assuming the wells are at the same potential since - # DRC can't tell otherwise - #R1_2 = ( 18 *LAMBDA ).round(3) - R1_2 = ( 6 *LAMBDA ).round(3) - R2_3 = ( 6 *LAMBDA ).round(3) - R3_2 = ( 3 *LAMBDA ).round(3) - R3_2_a = ( 4 *LAMBDA ).round(3) - R3_3 = ( 2.5 *LAMBDA ).round(3) - R3_4 = ( 4 *LAMBDA ).round(3) - R4_3 = ( 1.5 *LAMBDA ).round(3) - R4_4 = ( 4 *LAMBDA ).round(3) - R5_3 = ( 4 *LAMBDA ).round(3) - R5_5_b = ( 5 *LAMBDA ).round(3) - R6_3 = ( 4 *LAMBDA ).round(3) - R7_2 = ( 3 *LAMBDA ).round(3) - R7_4 = ( 6 *LAMBDA ).round(3) - R8_1 = ( 3 *LAMBDA ).round(3) - R9_2 = ( 4 *LAMBDA ).round(3) - R9_4 = ( 8 *LAMBDA ).round(3) - R11_1 = ( 7 *LAMBDA ).round(3) - R11_3 = ( 5 *LAMBDA ).round(3) - R11_5 = ( 6 *LAMBDA ).round(3) - R13_2 = ( 3 *LAMBDA ).round(3) - R14_1 = ( 3 *LAMBDA ).round(3) - if NBR_OF_METALS > 3 - R15_1 = ( 3 *LAMBDA ).round(3) - R15_2 = ( 4 *LAMBDA ).round(3) - R15_4 = ( 8 *LAMBDA ).round(3) - else - R15_1 = ( 5 *LAMBDA ).round(3) - R15_2 = ( 3 *LAMBDA ).round(3) - R15_4 = ( 6 *LAMBDA ).round(3) - end - R17_1 = ( 12 *LAMBDA ).round(3) - R17_2 = ( 18 *LAMBDA ).round(3) - R17_3 = ( 6 *LAMBDA ).round(3) - R17_4 = ( 6 *LAMBDA ).round(3) - R20_11 = ( 5 *LAMBDA ).round(3) - R21_1 = ( 3 *LAMBDA ).round(3) - if NBR_OF_METALS > 4 - R22_1 = ( 3 *LAMBDA ).round(3) - R22_2 = ( 4 *LAMBDA ).round(3) - R22_4 = ( 8 *LAMBDA ).round(3) - else - R22_1 = ( 6 *LAMBDA ).round(3) - R22_2 = ( 6 *LAMBDA ).round(3) - R22_4 = ( 12 *LAMBDA ).round(3) - end - R25_1 = ( 3 *LAMBDA ).round(3) - R25_2 = ( 3 *LAMBDA ).round(3) - R25_3 = ( 1 *LAMBDA ).round(3) - if NBR_OF_METALS > 5 - R26_1 = ( 3 *LAMBDA ).round(3) - R26_2 = ( 4 *LAMBDA ).round(3) - R26_3 = ( 1 *LAMBDA ).round(3) - R26_4 = ( 8 *LAMBDA ).round(3) - else - R26_1 = ( 4 *LAMBDA ).round(3) - R26_2 = ( 4 *LAMBDA ).round(3) - R26_3 = ( 2 *LAMBDA ).round(3) - R26_4 = ( 8 *LAMBDA ).round(3) - end - R28_1 = ( 45 *LAMBDA ).round(3) - R28_2 = ( 14 *LAMBDA ).round(3) - R28_3 = ( 5 *LAMBDA ).round(3) - R28_4 = ( 3 *LAMBDA ).round(3) - R28_5 = ( 5 *LAMBDA ).round(3) - R28_6 = ( 2 *LAMBDA ).round(3) - R28_7 = ( 25 *LAMBDA ).round(3) - R28_8 = ( 5 *LAMBDA ).round(3) - R28_9 = ( 9 *LAMBDA ).round(3) - R28_10 = ( 23 *LAMBDA ).round(3) - R28_11 = ( 45 *LAMBDA ).round(3) - R29_1 = ( 4 *LAMBDA ).round(3) - R29_2 = ( 4 *LAMBDA ).round(3) - R29_3 = ( 1 *LAMBDA ).round(3) - R30_1 = ( 5 *LAMBDA ).round(3) - R30_2 = ( 5 *LAMBDA ).round(3) - R30_3 = ( 2 *LAMBDA ).round(3) - R30_4 = ( 10 *LAMBDA ).round(3) - R31_1 = ( 34 *LAMBDA ).round(3) - R31_2 = ( 56 *LAMBDA ).round(3) - R31_3 = ( 17 *LAMBDA ).round(3) - R31_4 = ( 23 *LAMBDA ).round(3) - R31_5 = ( 39 *LAMBDA ).round(3) - R31_6 = ( 6 *LAMBDA ).round(3) - R31_7 = ( 34 *LAMBDA ).round(3) - R31_8 = ( 13 *LAMBDA ).round(3) -end - - -# KLAYOUT setttings -######################## -# Use a tile size of 1mm -tiles(1000.um) -# Use a tile border of 10 micron: -tile_borders(1.um) -#no_borders - -# Use 4 CPU cores -threads(4) -verbose(true) - -# Define a new custom function that selects polygons by their number of holes: -# It will return a new layer containing those polygons with min to max holes. -# max can be nil to omit the upper limit. -class DRC::DRCLayer - def with_holes(min, max) - new_data = RBA::Region::new - self.data.each do |p| - if p.holes >= (min || 0) && (!max || p.holes <= max) - new_data.insert(p) - end - end - DRC::DRCLayer::new(@engine, new_data) - end -end - -# layers definitions -######################## -info("Layers definitions") - - DNW = input(38,0) - NW = input(42,0) - PW = input(41,0) - CW = input(59,0) - AA = input(43,0) - TA = input(60,0) - PBase = input(58,0) - PL = input(46,0) - SB = input(29,0) - Nselect = input(45,0) - Pselect = input(44,0) - PO2 = input(56,0) - HR = input(34,0) - Contact = input(25,0) - ContactPoly = input(47,0) - ContactActive = input(48,0) - ContactPoly2 = input(55, 0) - CT = Contact + ContactPoly + ContactActive + ContactPoly2 - M1 = input(49,0) - V1 = input(50,0) - M2 = input(51,0) - V2 = input(61,0) - M3 = input(62,0) - V3 = input(30,0) - M4 = input(31,0) - CTM = input(35,0) - V4 = input(32,0) - M5 = input(33,0) - V5 = input(36,0) - M6 = input(37,0) - Glass = input(52,0) - Pads = input(26,0) - -# layers processing -######################## -info("Layers processing") -#CHIP = extent.sized(1.0) -NP = AA & Nselect -PP = AA & Pselect -NSTP = NP.and(NW) -PSTP = PP.not(NW) -GATE = PL & AA - -# DRC section -######################## -info("DRC section") - -### Deep NWell -DNW.ongrid(0.5*LAMBDA).output("DNW_offgrid", "Offgrid vertex on DNW") -DNW.with_angle(0 .. 45).output("DNW_angle", "Non 45 degree angle DNW") -DNW.edges.and(PW).output("DNW_PW","DNW cannot cross PWell") -DNW.width(R31_1, euclidian).output("31.1 DNW_width", "31.1 : Min. DNW width : #{R31_1}um") -DNW.isolated(R31_2, euclidian).output("31.2 DNW_space", "31.2 : Min. DNW spacing : #{R31_2}um") -NW.enclosing(DNW, R31_3, euclidian).output("31.3 NW_enc_DNW", "31.3 : Min. NWell enclosing DNW : #{R31_3}um") -DNW.enclosing(NW, R31_4, euclidian).output("31.4 DNW_enc_NW", "31.4 : Min. DNW enclosing NWell : #{R31_4}um") -DNW.separation(NW, R31_5, euclidian).output("31.5 DNW_sep_NW", "31.5 : Min. DNW separation NWell : #{R31_5}um") -DNW.not(NW).enclosing(NP, R31_6, euclidian).output("31.6 DNW_enc_NP", "31.6 : Min. PW in DNW enclosing N+ : #{R31_6}um") -DNW.separation(NP, R31_7, euclidian).output("31.7 DNW_sep_NP", "31.7 : Min. DNW separation N+ : #{R31_7}um") - -### Nwell / Pwell -NW.ongrid(0.5*LAMBDA).output("NW_offgrid", "Offgrid vertex on NWell") -NW.with_angle(0 .. 45).output("NW_angle", "Non 45 degree angle NWell") -NW.and(PW).output("NW_PW","NW over PW not allowed") -NW.width(R1_1, euclidian).output("1.1 NW_width", "1.1 : Min. NWell width : #{R1_1}um") -NW.isolated(R1_2, euclidian).output("1.2 NW_space", "1.2 : Min. NWell spacing : #{R1_2}um") -NW.and(TA).isolated(18, euclidian).output("1.3 NW_TA_space", "1.3 : Min. NWell-TA spacing : #{R1_3}um") -PW.width(R1_1, euclidian).output("1.1 PW_width", "1.1 : Min. PWell width : #{R1_1}um") -PW.isolated(R1_2, euclidian).output("1.2 PW_space", "1.2 : Min. PWell spacing : #{R1_2}um") -PW.and(TA).isolated(R1_3, euclidian).output("1.3 PW_TA_space", "1.3 : Min. PWell-TA spacing : #{R1_3}um") - -### Active -AA.ongrid(0.5*LAMBDA).output("AA_offgrid", "Offgrid vertex on AA") -AA.with_angle(0 .. 45).output("AA_angle", "Non 45 degree angle AA") -AA.width(R2_1, euclidian).output("2.1 AA_width", "2.1 : Min. active width : #{R2_1}um") -AA.space(R2_2, euclidian).output("2.2 AA_space", "2.2 : Min. active spacing : #{R2_2}3um") -NW.enclosing(PP.interacting(GATE), R2_3, euclidian).output("2.3 NW_enc_PP", "2.3 : Min. NWell enclosing Source/Drain : #{R2_3}um") -PW.enclosing(NP.interacting(GATE), R2_3, euclidian).output("2.3 PW_enc_NP", "2.3 : Min. PWell enclosing Source/Drain : #{R2_3}um") -NW.enclosing(NP, R2_4, euclidian).output("2.4 NW_enc_NP", "2.4 : Min. NWell enclosing Nstrap : #{R2_4}um") -PW.enclosing(PP, R2_4, euclidian).output("2.4 PW_enc_PP", "2.4 : Min. PWell enclosing Pstrap : #{R2_4}um") -NP.separation(PP, R2_5, euclidian).polygons.without_area(0).output("2.5 NP_space_PP", "2.5 : Min. N+ space P+ : #{R2_5}um (if not abutted)") - -### TA Thick Active -TA.ongrid(0.5*LAMBDA).output("TA_offgrid", "Offgrid vertex on TA") -TA.with_angle(0 .. 45).output("TA_angle", "Non 45 degree angle TA") -TA.width(R24_1, euclidian).output("24.1 TA_width", "24.1 : Min. TA width : #{R24_1}um") -TA.space(R24_2, euclidian).output("24.2 TA_space", "24.2 : Min. TA spacing : #{R24_2}um") -TA.enclosing(AA, R24_3, euclidian).output("24.3 TA_enc_AA", "24.3 : Min. TA enclosing Active : #{R24_3}um") -TA.separation(AA, R24_4, euclidian).output("24.4 TA_space_AA", "24.4 : Min. TA spacing Active : #{R24_4}um") -TA.and(GATE).width(R24_5, euclidian).output("24.5 TA_gate_width", "24.5 : Min. TA Gate width : #{R24_5}um") -AA.edges.and(TA).output("24.6 AA_in_TA","24.6 : Active edge cannot cross TA") - -### Poly -PL.ongrid(0.5*LAMBDA).output("POLY_offgrid", "Offgrid vertex on Poly") -PL.with_angle(0 .. 45).output("POLY_angle", "Non 45 degree angle Poly") -PL.width(R3_1, euclidian).output("3.1 POLY_width", "3.1 : Min. Poly width : #{R3_1}um") -PL.space(R3_2, euclidian).output("3.2 Poly_space", "3.2 : Min. Poly spacing : #{R3_2}um") -GATE.space(R3_2_a, euclidian).output("3.2a Gate_space", "3.2a : Min. Gate spacing : #{R3_2_a}um") -PL.enclosing(GATE, R3_3, projection).polygons.without_area(0).output("3.3 PL_enc_GATE", "3.3 : Min. Poly extention Gate : #{R3_3}um") -AA.enclosing(GATE, R3_4, projection).polygons.without_area(0).output("3.4 AA_enc_GATE", "3.4 : Min. Source/Drain length : #{R3_4}um") -PL.not(AA).separation(AA, 1, euclidian).polygons.without_area(0).output("3.5 PL_space_AA", "3.5 : Min. Poly on Field spacing Active : #{R3_5}um") - -### Poly2 -if !DEEP -PO2.ongrid(0.5*LAMBDA).output("POLY2_offgrid", "Offgrid vertex on Poly2") -PO2.with_angle(0 .. 45).output("POLY2_angle", "Non 45 degree angle Poly2") -PO2.width(R12_1, euclidian).output("12.1 POLY2_width", "12.1 : Min. Poly2 width : #{R12_1}um") -PO2.space(R12_2, euclidian).output("12.2 POLY2_space", "12.2 : Min. Poly2 space : #{R12_2}um") -# rule R12.3 not coded -PO2.not(AA).separation(AA, R12_4, euclidian).output("12.4 POLY2_space_AA"," 12.4 : Min. Poly2 on Field spacing Active : #{R12_4}um") -PO2.not(PL).separation(PL, R12_5, euclidian).output("12.5 POLY2_space_PL"," 12.5 : Min. Poly2 spacing Poly : #{R12_5}um") -PO2.enclosing(PL, R12_5, euclidian).output("12.5 POLY2_overlap_PL"," 12.5 : Min. Poly2 overlap of Poly : #{R12_5}um") -PO2.separation(AA.or(PL).and(CT), R12_6, euclidian).output("12.6 POLY2_space_CT"," 12.5 : Min. Poly2 spacing Poly or Active contact: #{R12_6}um") -PO2cap = PL & PO2 -PO2cap.width(R11_1, euclidian).output("11.1 POLY2CAP_width", "11.1 : Min. Poly2 Capacitor width : #{R11_1}um") -PO2cap.space(R11_2, euclidian).output("11.2 POLY2CAP_space", "11.2 : Min. Poly2 Capacitor space : #{R11_2}um") -PL.enclosing(PO2cap, R11_3, euclidian).output("12.3 PL_overlap_POLY2CAP"," 11.3 : Min. Poly overlap of Poly2 Capacitor : #{R11_3}um") -PO2cap.edges.separation(AA.or(NW).edges, R11_4, euclidian).output("11.4 POLY2CAP_space_AA/NW"," 11.4 : Min. Poly2 Capacitor spacing Active or Well: #{R11_4}um") -PO2cap.separation(PL.and(CT), R11_5, euclidian).output("11.5 POLY2CAP_space_PLCT"," 11.5 : Min. Poly2 Capacitor spacing Poly contact: #{R11_5}um") -PO2cap.separation(M1.or(M2).or(M3), R11_6, euclidian).output("11.6 POLY2CAP_space_METAL"," 11.6 : Min. Poly2 Capacitor spacing any Metal: #{R11_6}um") -PO2cap.forget - -### Capacitor Well -CW.ongrid(0.5*LAMBDA).output("CW_offgrid", "Offgrid vertex on CapacitorWell") -CW.with_angle(0 .. 45).output("CW_angle", "Non 45 degree angle CapacitorWell") -CW.width(R17_1, euclidian).output("17.1 CW_width", "17.1 : Min. CapacitorWell width : #{R17_1}um") -CW.space(R17_2, euclidian).output("17.2 CW_space", "17.2 : Min. CapacitorWell space : #{R17_2}um") -AA.not(CW).separation(CW, R17_3, euclidian).output("17.3 CW_space_AA"," 17.3 : Min. CapacitorWell spacing Active : #{R17_3}um") -CW.enclosing(AA, R17_4, euclidian).output("17.4 CW_overlap_AA"," 17.4 : Min. CapacitorWell overlap of Active : #{R17_4}um") -LinCap = PL & CW -LinCap.width(R18_1, euclidian).output("18.1 LC_width", "18.1 : Min. Linear Capacitor width : #{R18_1}um") -LinCap.space(R18_2, euclidian).output("18.2 LC_space", "18.2 : Min. Linear Capacitor space : #{R18_2}um") -LinCap.separation(AA.and(CT), R18_3, euclidian).output("18.3 LC_space_AACT"," 18.3 : Min. Linear Capacitor spacing Active contact : #{R18_3}um") -LinCap.separation(PL.and(CT), R18_4, euclidian).output("18.4 LC_space_PLCT"," 18.4 : Min. Linear Capacitor spacing Poly contact : #{R18_4}um") -LinCap.forget -end - -### N+/P+ Select -Nselect.ongrid(0.5*LAMBDA).output("NSel_offgrid", "Offgrid vertex on Nselect") -Pselect.ongrid(0.5*LAMBDA).output("PSel_offgrid", "Offgrid vertex on Pselect") -Nselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Nselect") -Pselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Pselect") -NP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 N+_enc_GATE", "4.1 : Min. N+ extention Gate on Source/Drain : #{R4_1}um") -PP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 P+_enc_GATE", "4.1 : Min. P+ extention Gate on Source/Drain : #{R4_1}um") -Nselect.enclosing(AA, R4_2, euclidian).output("4.2 N+_enc_AA", "4.2 : Min. N+ enclosing Active : #{R4_2}um") -Pselect.enclosing(AA, R4_2, euclidian).output("4.2 P+_enc_AA", "4.2 : Min. P+ enclosing Active : #{R4_2}um") -Nselect.enclosing(CT, R4_3, euclidian).output("4. N+_enc_CT", "4.3 : Min. N+ enclosing Contact : #{R4_3}um") -Pselect.enclosing(CT, R4_3, euclidian).output("4.3 P+_enc_CT", "4.3 : Min. P+ enclosing Contact : #{R4_3}um") -Nselect.width(R4_4,euclidian).output("4.4 N+_width", "4.4 : Min. N+ width : #{R4_4}um") -Pselect.width(R4_4,euclidian).output("4.4 P+_width", "4.4 : Min. N+ width : #{R4_4}um") -Nselect.space(R4_4,euclidian).output("4.4 N+_space", "4.4 : Min. N+ spacing : #{R4_4}um") -Pselect.space(R4_4,euclidian).output("4.4 P+_space", "4.4 : Min. N+ spacing : #{R4_4}um") -Nselect.and(Pselect).output("4.4 N+_and_P+", "4.4 : N+ over P+ not allowed") - -### HR - High Resistive -HR.ongrid(0.5*LAMBDA).output("HR_offgrid", "Offgrid vertex on HighRes") -HR.with_angle(0 .. 45).output("HR_angle", "Non 45 degree angle HighRes") -HR.width(R27_1, euclidian).output("27.1 HR_width", "27.1 : Min. HiRes width : #{R27_1}um") -HR.space(R27_2, euclidian).output("27.2 HR_space", "27.2 : Min. HiRes spacing : #{R27_2}um") -HR.and(CT).output("27.3 CT_and_HR", "27.3 : Contact on HiRes not allowed") -HR.separation(CT, R27_3, euclidian).output("27.3 HR_space_CT", "27.3 : Min. HiRes space to Contact : #{R27_3}um") -HR.separation(AA, R27_5, euclidian).output("27.4 HR_space_AA", "27.4 : Min. HiRes space to Active : #{R27_4}um") -HR.separation(PO2, R27_5, euclidian).output("27.5 HR_space_PO2", "27.5 : Min. HiRes space to Poly2 : #{R27_5}um") -HR.and(PO2).and(AA).output("27.6 HR_and_active", "27.6 : HiRes Po2 over Active not allowed") -HR.and(PO2).and(NW.or(PW)).output("27.6 HR_and_Well", "27.6 : HiRes Po2 over Well not allowed") -HR.and(PO2).width(R27_7,euclidian).output("27.7 HRPO2_width", "27.7 : Min. HiRes Poly2 width : #{R27_7}um") -HR.and(PO2).space(R27_8,euclidian).output("27.8 HRPO2_space", "27.8 : Min. HiRes Poly2 space : #{R27_8}um") -HR.enclosing(PO2, R27_9, projection).output("27.9 HR_enc_PO2", "27.9 : Min. HiRes enclosing Poly2 : #{R27_9}um") - -### SB - Silicide block -SB.ongrid(0.5*LAMBDA).output("SB_offgrid", "Offgrid vertex on Sil. Block") -SB.with_angle(0 .. 45).output("SB_angle", "Non 45 degree angle Sil. Block") -SB.width(R20_1, euclidian).output("20.1 SB_width", "20.1 : Min. Sil. Block width : #{R20_1}um") -SB.space(R20_2, euclidian).output("20.2 SB_space", "20.2 : Min. Sil. Block spacing : #{R20_2}um") -SB.separation(CT, R20_3, euclidian).output("20.3 SB_space_CT", "20.3 : Min. Sil. Block space to Contact : #{R20_3}um") -SB.and(CT).output("20.3 SB_and_CT", "20.3 : Sil. Block over Contact not allowed") -SB.separation(AA, R20_4, euclidian).output("20.4 SB_space_AA", "20.4 : Min. Sil. Block space to Active : #{R20_4}um") -SB.separation(PL, R20_5, euclidian).output("20.5 SB_space_PL", "20.5 : Min. Sil. Block space to Poly : #{R20_5}um") -SB.and(GATE).output("20.6 SBres_overAA","20.6 : SB resistor over Active not allowed") -SB.and(PL).and(Nselect.or(Pselect)).output("20.6 SBres_over_WELL","20.6 : SB resistor over Well not allowed") -SB.and(PL).width(R20_7,euclidian).output("20.6 SBres_width", "20.7 : Min. SB resistor width : #{R20_7}um") -SB.and(PL).space(R20_7,euclidian).output("20.7 SBres_space", "20.7 : Min. SB resistor space : #{R20_7}um") -SB.enclosing(AA, R20_8, projection).polygons.without_area(0).output("20.8 SB_enc_AA", "20.8 : Min. Sil. Block enclosing Active : #{R20_8}um") -AA.enclosing(SB, R20_9, projection).polygons.without_area(0).output("20.9 AA_enc_SB", "20.9 : Min. Active enclosing Sil. Block : #{R20_9}um") -SB.enclosing(PL, R20_9, projection).output("20.8 SB_enc_PL", "20.8 : Min. Sil. Block enclosing Poly : #{R20_8}um") -PL.enclosing(SB, R20_8, projection).polygons.without_area(0).output("20.9 PL_enc_SB", "20.9 : Min. Poly enclosing Sil. Block : #{R20_9}um") -SB.separation(GATE, R20_11, euclidian).output("20.11 SB_space_GATE", "20.11 : Min. Sil. Block space to Gate : #{R20_11}um") - -### Contact -CT.ongrid(0.5*LAMBDA).output("CT_offgrid", "Offgrid vertex on Contact") -CT.with_angle(0 .. 90).output("CT_angle", "Non 90 degree angle Contact") -CT.and(GATE).output("CT_and_GATE", "Contact on Gate not allowed") -CT.not(M1).output("CT_not_M1", "Contact without Metal1 not recommended") -# CT.drc(length != R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") -CT.width(R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") -CT.without_area(R5_1*R5_1).output("5.1 CT_area", "5.1 : Exact Contact Area : #{R5_1*R5_1}um2") -CT.space(R5_3, euclidian).output("5.3 CT_space", "5.3 : Contact spacing : #{R5_3}um") -PL.enclosing(CT, R5_2_b, euclidian).output("5.2 PL_enc_CT", "5.2 : Min. Poly enclosing Contact : #{R5_2_b}um") -AA.enclosing(CT, R6_2_b, euclidian).output("6.2 AA_enc_CT", "6.2 : Min. Active enclosing Contact : #{R6_2_b}um") -PO2.enclosing(CT, R13_3, euclidian).output("13.3 PO2_enc_CT", "13.3 : Min. Poly2 enclosing Contact : #{R13_3}um") -CT.and(AA).separation(GATE, R5_4, euclidian).output("5.4 CTAA_space_GATE", "5.4 : Min. ActiveContact space to Gate : #{R5_4}um") -CT.and(PL).separation(PL, R5_5_b, euclidian).polygons.without_area(0).output("5.5.b CTPL_space_Poly", "5.5.b : Min. PolyContact space to Poly : #{R5_5_b}um") -CT.and(PL).separation(AA, R5_6_b, euclidian).output("5.6.b CTPL_space_AA", "5.6.b : Min. PolyContact space to AA : #{R5_6_b}um") -# rule 5.7.b not coded -CT.and(AA).separation(AA, R6_5_b, euclidian).polygons.without_area(0).output("6.5.b CTAA_space_AA", "6.5.b : Min. ActiveContact space to AA : #{R6_5_b}um") -CT.and(AA).separation(PL, R6_6_b, euclidian).output("6.6.b CTAA_space_PL", "6.6.b : Min. ActiveContact space to Poly : #{R6_6_b}um") -CT.and(AA).separation(CT.and(PL), R6_7_b, euclidian).output("6.7.b CTAA_space_CTPL", "6.7.b : Min. ActiveContact space to PolyContact : #{R6_7_b}um") -# rule 6.8.b not coded -CT.and(PO2).separation(AA, R13_5, euclidian).output("13.5 CTPO2_space_AA", "13.5 : Min. Poly2Contact space to AA : #{R13_5}um") -CT.and(PO2).separation(PL, R13_5, euclidian).output("13.5 CTPO2_space_PL", "13.5 : Min. Poly2Contact space to Poly : #{R13_5}um") -M1.enclosing(CT, R7_3, euclidian).output("7.3 M1_enc_CT", "7.3 : Min. Metal1 enclosing Contact : #{R7_3}um") - -### Metal 1 -M1.ongrid(0.5*LAMBDA).output("M1_offgrid", "Offgrid vertex on ME1") -M1.with_angle(0 .. 45).output("M1_angle", "Non 45 degree angle ME1") -M1.holes.with_area(0 .. R7_1*R7_1).output("M1_holes", "Min. Metal1 holes area : #{R7_1*R7_1}um2") -M1.width(R7_1, euclidian).output("7.1 M1_width", "7.1 : Min. Metal1 width : #{R7_1}um") -M1.space(R7_2, euclidian).output("7.2 M1_space", "7.2 : Min. Metal1 spacing : #{R7_2}um") -M1.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M1,R7_4,euclidian).polygons.without_area(0).output("7.4 M1_10_space", "7.4 : Space if at least one metal1 line width is > #{10*LAMBDA}um : #{R7_4}um") - -### Via 1 -V1.ongrid(0.5*LAMBDA).output("V1_offgrid", "Offgrid vertex on Via1") -V1.not(M1).output("V1_not_M1", "Via1 without Metal1 not allowed") -V1.not(M2).output("V1_not_M2", "Via1 without Metal2 not allowed") -V1.with_angle(0 .. 90).output("V1_angle", "Non 90 degree angle Via1") -V1.width(R8_1,square).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um") -V1.without_area(R8_1*R8_1).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um2") -V1.space(R8_2,euclidian).output("8.2 V1_space", "8.2 : Via1 spacing : #{R8_2}um") -M1.enclosing(V1, R8_3, euclidian).output("8.3 M1_enc_V1", "8.3 : Min. Metal1 enclosing Via1 : #{R8_3}um") -M2.enclosing(V1, R8_3, euclidian).output("9.3 M2_enc_V1", "9.3 : Min. Metal2 enclosing Via1 : #{R9_3}um") -if !DEEP && NBR_OF_METALS < 4 - V1.and(CT).or(V1.separation(CT, R8_4, euclidian).polygons).output("8.4 V1_space_CT", "8.4 : Via1 space CT : #{R8_4}um") - V1.separation(PL + AA, R8_5, euclidian).output("8.5 V1_space_PL/AAedges", "8.5 : Via1 space to Poly orActive edges : #{R8_5}um") -end -if DFM - M1.and(M2).not(V1).with_holes(1,1).output("2_V1", "Min. 2 Via1 are needed") -end - -### Metal 2 -M2.ongrid(0.5*LAMBDA).output("M2_offgrid", "Offgrid vertex on ME2") -M2.with_angle(0 .. 45).output("M2_angle", "Non 45 degree angle ME2") -M2.width(R9_1, euclidian).output("9.1 M2_width", "9.1 : Min. Metal2 width : #{R9_1}um") -M2.space(R9_2, euclidian).output("9.2 M2_space", "9.2 : Min. Metal2 spacing : #{R9_2}um") -M2.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M2,R9_4,euclidian).polygons.without_area(0).output("9.4 M2_10_space", "9.4 : Space if at least one metal2 line width is > #{10*LAMBDA}um : #{R9_4}um") - -### Via 2 -V2.ongrid(0.5*LAMBDA).output("V2_offgrid", "Offgrid vertex on Via2") -V2.not(M3).output("V2_not_M3", "Via2 without Metal3 not allowed") -V2.not(M2).output("V2_not_M2", "Via2 without Metal2 not allowed") -V2.with_angle(0 .. 90).output("V2_angle", "Non 90 degree angle Via2") -V2.width(R14_1, square).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um") -V2.without_area(R14_1*R14_1).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um2") -V2.space(R14_2, euclidian).output("14.2 V2_space", "14.2 : Via2 spacing : #{R14_2}um") -M2.enclosing(V2, R14_3, euclidian).output("14.3 M2_enc_V2", "14.3 : Min. Metal2 enclosing Via2 : #{R14_3}um") -M3.enclosing(V2, R15_3, euclidian).output("15.3 M3_enc_V2", "15.3 : Min. Metal3 enclosing Via2 : #{R15_3}um") -if !DEEP && NBR_OF_METALS < 4 - V2.and(V1).or(V2.separation(V1, R14_4, euclidian).polygons).output("14.4 V2_space_V1", "14.4 : Via2 space Via1 : #{R14_4}um") -end -if DFM - M2.and(M3).not(V2).with_holes(1,1).output("2_V2", "Min. 2 Via2 are needed") -end - -### Metal 3 -M3.ongrid(0.5*LAMBDA).output("M3_offgrid", "Offgrid vertex on ME3") -M3.with_angle(0 .. 45).output("M3_angle", "Non 45 degree angle ME3") -M3.width(R15_1, euclidian).output("15.1 M3_width", "15.1 : Min. Metal3 width : #{R15_1}um") -M3.space(R15_2, euclidian).output("15.2 M3_space", "15.2 : Min. Metal3 spacing : #{R15_2}um") -M3.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M3, R15_4, euclidian).polygons.without_area(0).output("15.4 M3_10_space", "15.4 : Space if at least one metal3 line width is > #{10*LAMBDA}um : #{R15_4}um") - -### Cap Top Metal -if SUBM || DEEP -CTM.ongrid(0.5*LAMBDA).output("CTM_offgrid", "Offgrid vertex on CTM") -CTM.with_angle(0 .. 45).output("CTM_angle", "Non 45 degree angle CTM") -CTM.width(R28_1, euclidian).output("28.1 CTM_width", "28.1 : Min. Cap Top Metal width : #{R28_1}um") -CTM.space(R28_2, euclidian).output("28.2 CTM_space", "28.2 : Min. Cap Top Metal spacing : #{R28_2}um") -if NBR_OF_METALS == 4 - TM = M4 - VT = V3 - TB = V2 -end -if NBR_OF_METALS == 5 - TM = M5 - VT = V4 - VB = V3 -end -if NBR_OF_METALS == 6 - TM = M6 - VT = V5 - VB = V4 -end -TM.enclosing(CTM, R28_3, euclidian).output("28.3 TM_overlap_CTM", "28.3 : Min. Top Metal overlap Cap Top Metal : #{R28_3}um") -CTM.enclosing(VT, R28_4, euclidian).output("28.4 CTM_overlap_VT", "28.4 : Min. Cap Top Metal overlap Top Via : #{R28_4}um") -CTM.separation(VB, R28_5, euclidian).output("28.5 CTM_space_VB", "28.5 : Min. Cap Top Metal space Bottom Via : #{R28_5}um") -CTM.separation(VT, R28_5, euclidian).output("28.5 CTM_space_VT", "28.5 : Min. Cap Top Metal space Top Via : #{R28_5}um") -TM.enclosing(VB, R28_6, euclidian).output("28.6 TM_overlap_VB", "28.6 : Min. Top Metal overlap Bottom Via : #{R28_6}um") -# rule 28.7 not coded -CTM.not_interacting(VT).width(R28_8, euclidian).output("28.8 CTMdummies_width", "28.8 : Min. dummies Cap Top Metal width : #{R28_8}um") -TM.interacting(CTM).space(R28_9, euclidian).output("28.9 VT_space", "28.9 : Min. Top Metal spacing : #{R28_9}um") -VT.interacting(CTM).space(R28_10, euclidian).output("28.10 VT_space", "28.10 : Min. Top Via spacing : #{R28_10}um") -VB.interacting(TM.interacting(CTM)).space(R28_11, euclidian).output("28.11 VB_space", "28.11 : Min. Bottom Via spacing : #{R28_11}um") -CTM.sized(-15.um).sized(15.um).output("28.12 CTM_width", "28.12 : Max. CTM width/length : 30um") -TM.interacting(CTM).sized(-17.5.um).sized(17.5.um).output("28.13 TM_width", "28.13 : Max. Top Metal width/length : 35um") -CTM.and(VB).output("28.14 CTM_VB", "28.14 : no VB under CTM allowed") -CTM.and(AA.or(PL)).output("28.15 CTM_AA", "28.15 : no active or passive circuitry under CTM allowed") -end - -### Via 3 -if NBR_OF_METALS > 3 -V3.ongrid(0.5*LAMBDA).output("V3_offgrid", "Offgrid vertex on Via3") -V3.not(M3).output("V3_not_M3", "Via3 without Metal3 not allowed") -V3.not(M4).output("V3_not_M4", "Via3 without Metal4 not allowed") -V3.with_angle(0 .. 90).output("V3_angle", "Non 90 degree angle Via3") -V3.width(R21_1, square).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um") -V3.without_area(R21_1*R21_1).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um2") -V3.space(R21_2, euclidian).output("21.2 V3_space", "21.2 : Via3 spacing : #{R21_2}um") -M3.enclosing(V3, R21_3, euclidian).output("21.3 M3_enc_V3", "21.3 : Min. Metal3 enclosing Via3 : #{R21_3}um") -M4.enclosing(V3, R22_3, euclidian).output("22.3 M4_enc_V3", "22.3 : Min. Metal4 enclosing Via3 : #{R22_3}um") -if DFM - M3.and(M4).not(V3).with_holes(1,1).output("2_V3", "Min. 2 Via3 are needed") -end - -### Metal 4 -M4.ongrid(0.5*LAMBDA).output("M4_offgrid", "Offgrid vertex on ME4") -M4.with_angle(0 .. 45).output("M4_angle", "Non 45 degree angle ME4") -M4.width(R22_1, euclidian).output("22.1 M4_width", "22.1 : Min. Metal4 width : #{R22_1}um") -M4.space(R22_2, euclidian).output("22.2 M4_space", "22.2 : Min. Metal4 spacing : #{R22_2}um") -M4.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M4, R22_4, euclidian).polygons.without_area(0).output("22.4 M4_10_space", "22.4 : Space if at least one metal4 line width is > #{10*LAMBDA}um : #{R22_4}um") - -### Via 4 -if NBR_OF_METALS > 4 -V4.ongrid(0.5*LAMBDA).output("V4_offgrid", "Offgrid vertex on Via4") -V4.not(M5).output("V4_not_M5", "Via4 without Metal5 not allowed") -V4.not(M4).output("V4_not_M4", "Via4 without Metal4 not allowed") -V4.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via4") -V4.width(R25_1, square).output("25.1 V4_width", "25.1 : Exact Via4 width : #{R25_1}um") -V4.without_area(R25_1*R25_1).output("25.1 V4_width", "25.1 : Via4 width : #{R25_1}um2") -V4.space(R25_2, euclidian).output("25.2 V4_space", "25.2 : Exact Via4 spacing : #{R25_2}um") -M4.enclosing(V4, R25_3, euclidian).output("25.3 M4_enc_V4", "25.3 : Min. Metal4 enclosing Via4 : #{R25_3}um") -M5.enclosing(V4, R26_3, euclidian).output("26.3 M5_enc_V4", "26.3 : Min. Metal5 enclosing Via4 : #{R26_3}um") -if DFM - M4.and(M5).not(V4).with_holes(1,1).output("2_V4", "Min. 2 Via4 are needed") -end - -### Metal 5 -M5.ongrid(0.5*LAMBDA).output("M5_offgrid", "Offgrid vertex on ME5") -M5.with_angle(0 .. 45).output("M5_angle", "Non 45 degree angle ME5") -M5.width(R26_1, euclidian).output("26.1 M5_width", "26.1 : Min. Metal5 width : #{R26_1}um") -M5.space(R26_2, euclidian).output("26.2 M5_space", "26.2 : Min. Metal5 spacing : #{R26_2}um") -M5.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, R26_4, euclidian).polygons.without_area(0).output("26.4 M5_10_space", "26 .4 : Space if at least one metal5 line width is > #{10*LAMBDA}um : #{R26_4}um") - -### Via 5 -if NBR_OF_METALS > 5 -V5.ongrid(0.5*LAMBDA).output("V5_offgrid", "Offgrid vertex on Via5") -V5.not(M5).output("V5_not_M5", "Via5 without Metal5 not allowed") -V5.not(M6).output("V5_not_M6", "Via5 without Metal6 not allowed") -V5.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via5") -V5.width(R29_1, square).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um") -V5.without_area(R29_1*R29_1).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um2") -V5.space(R29_2, euclidian).output("29.2 V5_space", "29.2 : Via5 spacing : #{R29_2}um") -M5.enclosing(V5, R29_3, euclidian).output("29.3 M5_enc_V5", "29.3 : Min. Metal5 enclosing Via5 : #{R29_3}um") -M6.enclosing(V5, R30_3, euclidian).output("30.3 M3_enc_V5", "30.3 : Min. Metal6 enclosing Via5 : #{R30_3}um") -if DFM - M5.and(M6).not(V5).with_holes(1,1).output("2_V5", "Min. 2 Via5 are needed") -end - -### Metal 6 -M6.ongrid(0.5*LAMBDA).output("M6_offgrid", "Offgrid vertex on ME6") -M6.with_angle(0 .. 45).output("M6_angle", "Non 45 degree angle ME5") -M6.width(R30_1, euclidian).output("30.1 M6_width", "30.1 : Min. Metal6 width : #{R30_1}um") -M6.space(R30_2, euclidian).output("30.2 M6_space", "30.2 : Min. Metal6 spacing : #{R30_2}um") -M6.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, 10, euclidian).polygons.without_area(0).output("30.4 M6_10_space", "30.4 : Space if at least one metal6 line width is > #{10*LAMBDA}um : #{R30_4}um") - -end -end -end - -# time spent for the DRC -time = Time.now -hours = ((time - tstart)/3600).to_i -minutes = ((time - tstart)/60 - hours * 60).to_i -seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i -$stdout.write "DRC finished at : #{time.hour}:#{time.min}:#{time.sec} - DRC duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" - + + + + + drc + + + + false + false + + true + drc_scripts + tools_menu.drc.end + dsl + drc-dsl-xml + # +# MOSIS SCMOS DRC +# +######################## +tstart = Time.now + +# optionnal for a batch launch : klayout -b r drc_SCMOS.lydrc -rd input=my_layout.gds -rd topcell=your_topcell -rd output=SCMOS_DRC.lyrdb +if $input + if $topcell + source($input,$topcell) + else + source($input) + end +end + +if $output + report("SCMOS DRC runset", $output) +else + report("SCMOS DRC runset", "SCMOS_DRC.lyrdb") +end + + +# PROCESS OPTIONS +######################## +LAMBDA = 0.2 +SUBM = true +DEEP = false +NBR_OF_METALS = 6 + +DFM = false + +# design rules limits definitions +######################## +R1_3 = ( 6 *LAMBDA ).round(3) +R2_1 = ( 3 *LAMBDA ).round(3) +R2_2 = ( 3 *LAMBDA ).round(3) +R2_4 = ( 3 *LAMBDA ).round(3) +R2_5 = ( 4 *LAMBDA ).round(3) +R3_1 = ( 2 *LAMBDA ).round(3) +R3_5 = ( 1 *LAMBDA ).round(3) +R4_1 = ( 3 *LAMBDA ).round(3) +R4_2 = ( 2 *LAMBDA ).round(3) +R5_1 = ( 2 *LAMBDA ).round(3) +R5_2 = ( 1.5 *LAMBDA ).round(3) +R5_4 = ( 2 *LAMBDA ).round(3) +R5_2_b = ( 1 *LAMBDA ).round(3) +R5_6_b = ( 2 *LAMBDA ).round(3) +R5_7_b = ( 3 *LAMBDA ).round(3) +R6_1 = ( 2 *LAMBDA ).round(3) +R6_2 = ( 1.5 *LAMBDA ).round(3) +R6_4 = ( 2 *LAMBDA ).round(3) +R6_2_b = ( 1 *LAMBDA ).round(3) +R6_5_b = ( 5 *LAMBDA ).round(3) +R6_6_b = ( 2 *LAMBDA ).round(3) +R6_7_b = ( 3 *LAMBDA ).round(3) +R6_8_b = ( 4 *LAMBDA ).round(3) +R7_1 = ( 3 *LAMBDA ).round(3) +R7_3 = ( 1 *LAMBDA ).round(3) +R8_2 = ( 3 *LAMBDA ).round(3) +R8_3 = ( 1 *LAMBDA ).round(3) +R8_4 = ( 2 *LAMBDA ).round(3) +R9_1 = ( 3 *LAMBDA ).round(3) +R9_3 = ( 1 *LAMBDA ).round(3) +R10_1 = ( 60 *LAMBDA ).round(3) +R10_2 = ( 20 *LAMBDA ).round(3) +R10_3 = ( 6 *LAMBDA ).round(3) +R10_4 = ( 30 *LAMBDA ).round(3) +R10_5 = ( 15 *LAMBDA ).round(3) +R11_2 = ( 3 *LAMBDA ).round(3) +R11_4 = ( 2 *LAMBDA ).round(3) +R11_6 = ( 2 *LAMBDA ).round(3) +R12_1 = ( 2 *LAMBDA ).round(3) +R12_2 = ( 3 *LAMBDA ).round(3) +R12_3 = ( 2 *LAMBDA ).round(3) +R12_4 = ( 1 *LAMBDA ).round(3) +R12_5 = ( 2 *LAMBDA ).round(3) +R12_6 = ( 3 *LAMBDA ).round(3) +R13_1 = ( 2 *LAMBDA ).round(3) +R13_3 = ( 3 *LAMBDA ).round(3) +R13_4 = ( 2 *LAMBDA ).round(3) +R13_5 = ( 3 *LAMBDA ).round(3) +R14_2 = ( 3 *LAMBDA ).round(3) +R14_3 = ( 1 *LAMBDA ).round(3) +R14_4 = ( 2 *LAMBDA ).round(3) +if NBR_OF_METALS > 3 + R15_3 = ( 1 *LAMBDA ).round(3) +else + R15_3 = ( 2 *LAMBDA ).round(3) +end +R16_1 = ( 2 *LAMBDA ).round(3) +R16_2 = ( 3 *LAMBDA ).round(3) +R16_3 = ( 2 *LAMBDA ).round(3) +R16_4 = ( 4 *LAMBDA ).round(3) +R16_5 = ( 2 *LAMBDA ).round(3) +R16_6 = ( 2 *LAMBDA ).round(3) +R16_7 = ( 6 *LAMBDA ).round(3) +R16_8 = ( 4 *LAMBDA ).round(3) +R16_9 = ( 2 *LAMBDA ).round(3) +R16_10 = ( 3 *LAMBDA ).round(3) +R16_11 = ( 2 *LAMBDA ).round(3) +R18_1 = ( 3 *LAMBDA ).round(3) +R18_2 = ( 2 *LAMBDA ).round(3) +R18_3 = ( 3 *LAMBDA ).round(3) +R18_4 = ( 2 *LAMBDA ).round(3) +R18_5 = ( 6 *LAMBDA ).round(3) +R20_1 = ( 4 *LAMBDA ).round(3) +R20_2 = ( 4 *LAMBDA ).round(3) +R20_3 = ( 2 *LAMBDA ).round(3) +R20_4 = ( 2 *LAMBDA ).round(3) +R20_5 = ( 2 *LAMBDA ).round(3) +R20_7 = ( 5 *LAMBDA ).round(3) +R20_8 = ( 7 *LAMBDA ).round(3) +R20_9 = ( 2 *LAMBDA ).round(3) +R20_10 = ( 3 *LAMBDA ).round(3) +R21_2 = ( 3 *LAMBDA ).round(3) +R21_3 = ( 1 *LAMBDA ).round(3) +if NBR_OF_METALS > 4 + R22_3 = ( 1 *LAMBDA ).round(3) +else + R22_3 = ( 2 *LAMBDA ).round(3) +end +R23_1 = ( 8 *LAMBDA ).round(3) +R23_2 = ( 4 *LAMBDA ).round(3) +R23_3 = ( 8 *LAMBDA ).round(3) +R23_4 = ( 3 *LAMBDA ).round(3) +R23_5 = ( 2 *LAMBDA ).round(3) +R23_6 = ( 2 *LAMBDA ).round(3) +R23_7 = ( 2 *LAMBDA ).round(3) +R23_8 = ( 4 *LAMBDA ).round(3) +R23_9 = ( 2 *LAMBDA ).round(3) +R24_1 = ( 4 *LAMBDA ).round(3) +R24_2 = ( 4 *LAMBDA ).round(3) +R24_3 = ( 4 *LAMBDA ).round(3) +R24_4 = ( 4 *LAMBDA ).round(3) +R24_5 = ( 3 *LAMBDA ).round(3) +R27_1 = ( 4 *LAMBDA ).round(3) +R27_2 = ( 4 *LAMBDA ).round(3) +R27_3 = ( 2 *LAMBDA ).round(3) +R27_4 = ( 2 *LAMBDA ).round(3) +R27_5 = ( 2 *LAMBDA ).round(3) +R27_7 = ( 5 *LAMBDA ).round(3) +R27_8 = ( 7 *LAMBDA ).round(3) +R27_9 = ( 2 *LAMBDA ).round(3) + + +if !SUBM && !DEEP + R1_1 = ( 10 *LAMBDA ).round(3) + R1_2 = ( 9 *LAMBDA ).round(3) + R2_3 = ( 5 *LAMBDA ).round(3) + R3_2 = ( 2 *LAMBDA ).round(3) + R3_2_a = ( 2 *LAMBDA ).round(3) + R3_3 = ( 2 *LAMBDA ).round(3) + R3_4 = ( 3 *LAMBDA ).round(3) + R4_3 = ( 1 *LAMBDA ).round(3) + R4_4 = ( 2 *LAMBDA ).round(3) + R5_3 = ( 2 *LAMBDA ).round(3) + R5_5_b = ( 4 *LAMBDA ).round(3) + R6_3 = ( 2 *LAMBDA ).round(3) + R7_2 = ( 2 *LAMBDA ).round(3) + R7_4 = ( 4 *LAMBDA ).round(3) + R8_1 = ( 2 *LAMBDA ).round(3) + R8_5 = ( 2 *LAMBDA ).round(3) + R9_2 = ( 3 *LAMBDA ).round(3) + R9_4 = ( 6 *LAMBDA ).round(3) + R11_1 = ( 3 *LAMBDA ).round(3) + R11_3 = ( 2 *LAMBDA ).round(3) + R11_5 = ( 3 *LAMBDA ).round(3) + R13_2 = ( 2 *LAMBDA ).round(3) + R14_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + else + R15_1 = ( 6 *LAMBDA ).round(3) + R15_2 = ( 4 *LAMBDA ).round(3) + R15_4 = ( 8 *LAMBDA ).round(3) + end + R17_1 = ( 10 *LAMBDA ).round(3) + R17_2 = ( 9 *LAMBDA ).round(3) + R17_3 = ( 5 *LAMBDA ).round(3) + R17_4 = ( 5 *LAMBDA ).round(3) + R20_11 = ( 3 *LAMBDA ).round(3) + R21_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 3 *LAMBDA ).round(3) + R22_4 = ( 6 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end +end + +if SUBM + R1_1 = ( 12 *LAMBDA ).round(3) + # We are assuming the wells are at the same potential since + # DRC can't tell otherwise + #R1_2 = ( 18 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) + R2_3 = ( 6 *LAMBDA ).round(3) + R3_2 = ( 3 *LAMBDA ).round(3) + R3_2_a = ( 3 *LAMBDA ).round(3) + R3_3 = ( 2 *LAMBDA ).round(3) + R3_4 = ( 3 *LAMBDA ).round(3) + R4_3 = ( 1 *LAMBDA ).round(3) + R4_4 = ( 2 *LAMBDA ).round(3) + R5_3 = ( 3 *LAMBDA ).round(3) + R5_5_b = ( 5 *LAMBDA ).round(3) + R6_3 = ( 3 *LAMBDA ).round(3) + R7_2 = ( 3 *LAMBDA ).round(3) + R7_4 = ( 6 *LAMBDA ).round(3) + R8_1 = ( 2 *LAMBDA ).round(3) + R8_5 = ( 2 *LAMBDA ).round(3) + R9_2 = ( 3 *LAMBDA ).round(3) + R9_4 = ( 6 *LAMBDA ).round(3) + R11_1 = ( 7 *LAMBDA ).round(3) + R11_3 = ( 5 *LAMBDA ).round(3) + R11_5 = ( 6 *LAMBDA ).round(3) + R13_2 = ( 3 *LAMBDA ).round(3) + R14_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + else + R15_1 = ( 5 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + end + R17_1 = ( 12 *LAMBDA ).round(3) + R17_2 = ( 18 *LAMBDA ).round(3) + R17_3 = ( 6 *LAMBDA ).round(3) + R17_4 = ( 6 *LAMBDA ).round(3) + R20_11 = ( 5 *LAMBDA ).round(3) + R21_1 = ( 2 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 3 *LAMBDA ).round(3) + R22_4 = ( 6 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end + R25_1 = ( 2 *LAMBDA ).round(3) + R25_2 = ( 3 *LAMBDA ).round(3) + R25_3 = ( 1 *LAMBDA ).round(3) + if NBR_OF_METALS > 5 + R26_1 = ( 3 *LAMBDA ).round(3) + R26_2 = ( 3 *LAMBDA ).round(3) + R26_3 = ( 1 *LAMBDA ).round(3) + R26_4 = ( 6 *LAMBDA ).round(3) + else + R26_1 = ( 4 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 2 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + end + R28_1 = ( 40 *LAMBDA ).round(3) + R28_2 = ( 12 *LAMBDA ).round(3) + R28_3 = ( 4 *LAMBDA ).round(3) + R28_4 = ( 3 *LAMBDA ).round(3) + R28_5 = ( 4 *LAMBDA ).round(3) + R28_6 = ( 2 *LAMBDA ).round(3) + R28_7 = ( 25 *LAMBDA ).round(3) + R28_8 = ( 4 *LAMBDA ).round(3) + R28_9 = ( 8 *LAMBDA ).round(3) + R28_10 = ( 20 *LAMBDA ).round(3) + R28_11 = ( 40 *LAMBDA ).round(3) + R29_1 = ( 3 *LAMBDA ).round(3) + R29_2 = ( 4 *LAMBDA ).round(3) + R29_3 = ( 1 *LAMBDA ).round(3) + R30_1 = ( 5 *LAMBDA ).round(3) + R30_2 = ( 5 *LAMBDA ).round(3) + R30_3 = ( 1 *LAMBDA ).round(3) + R30_4 = ( 10 *LAMBDA ).round(3) + R31_1 = ( 30 *LAMBDA ).round(3) + R31_2 = ( 50 *LAMBDA ).round(3) + R31_3 = ( 15 *LAMBDA ).round(3) + R31_4 = ( 20 *LAMBDA ).round(3) + R31_5 = ( 35 *LAMBDA ).round(3) + R31_6 = ( 5 *LAMBDA ).round(3) + R31_7 = ( 30 *LAMBDA ).round(3) + R31_8 = ( 10 *LAMBDA ).round(3) +end + +if DEEP + R1_1 = ( 12 *LAMBDA ).round(3) + # We are assuming the wells are at the same potential since + # DRC can't tell otherwise + #R1_2 = ( 18 *LAMBDA ).round(3) + R1_2 = ( 6 *LAMBDA ).round(3) + R2_3 = ( 6 *LAMBDA ).round(3) + R3_2 = ( 3 *LAMBDA ).round(3) + R3_2_a = ( 4 *LAMBDA ).round(3) + R3_3 = ( 2.5 *LAMBDA ).round(3) + R3_4 = ( 4 *LAMBDA ).round(3) + R4_3 = ( 1.5 *LAMBDA ).round(3) + R4_4 = ( 4 *LAMBDA ).round(3) + R5_3 = ( 4 *LAMBDA ).round(3) + R5_5_b = ( 5 *LAMBDA ).round(3) + R6_3 = ( 4 *LAMBDA ).round(3) + R7_2 = ( 3 *LAMBDA ).round(3) + R7_4 = ( 6 *LAMBDA ).round(3) + R8_1 = ( 3 *LAMBDA ).round(3) + R9_2 = ( 4 *LAMBDA ).round(3) + R9_4 = ( 8 *LAMBDA ).round(3) + R11_1 = ( 7 *LAMBDA ).round(3) + R11_3 = ( 5 *LAMBDA ).round(3) + R11_5 = ( 6 *LAMBDA ).round(3) + R13_2 = ( 3 *LAMBDA ).round(3) + R14_1 = ( 3 *LAMBDA ).round(3) + if NBR_OF_METALS > 3 + R15_1 = ( 3 *LAMBDA ).round(3) + R15_2 = ( 4 *LAMBDA ).round(3) + R15_4 = ( 8 *LAMBDA ).round(3) + else + R15_1 = ( 5 *LAMBDA ).round(3) + R15_2 = ( 3 *LAMBDA ).round(3) + R15_4 = ( 6 *LAMBDA ).round(3) + end + R17_1 = ( 12 *LAMBDA ).round(3) + R17_2 = ( 18 *LAMBDA ).round(3) + R17_3 = ( 6 *LAMBDA ).round(3) + R17_4 = ( 6 *LAMBDA ).round(3) + R20_11 = ( 5 *LAMBDA ).round(3) + R21_1 = ( 3 *LAMBDA ).round(3) + if NBR_OF_METALS > 4 + R22_1 = ( 3 *LAMBDA ).round(3) + R22_2 = ( 4 *LAMBDA ).round(3) + R22_4 = ( 8 *LAMBDA ).round(3) + else + R22_1 = ( 6 *LAMBDA ).round(3) + R22_2 = ( 6 *LAMBDA ).round(3) + R22_4 = ( 12 *LAMBDA ).round(3) + end + R25_1 = ( 3 *LAMBDA ).round(3) + R25_2 = ( 3 *LAMBDA ).round(3) + R25_3 = ( 1 *LAMBDA ).round(3) + if NBR_OF_METALS > 5 + R26_1 = ( 3 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 1 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + else + R26_1 = ( 4 *LAMBDA ).round(3) + R26_2 = ( 4 *LAMBDA ).round(3) + R26_3 = ( 2 *LAMBDA ).round(3) + R26_4 = ( 8 *LAMBDA ).round(3) + end + R28_1 = ( 45 *LAMBDA ).round(3) + R28_2 = ( 14 *LAMBDA ).round(3) + R28_3 = ( 5 *LAMBDA ).round(3) + R28_4 = ( 3 *LAMBDA ).round(3) + R28_5 = ( 5 *LAMBDA ).round(3) + R28_6 = ( 2 *LAMBDA ).round(3) + R28_7 = ( 25 *LAMBDA ).round(3) + R28_8 = ( 5 *LAMBDA ).round(3) + R28_9 = ( 9 *LAMBDA ).round(3) + R28_10 = ( 23 *LAMBDA ).round(3) + R28_11 = ( 45 *LAMBDA ).round(3) + R29_1 = ( 4 *LAMBDA ).round(3) + R29_2 = ( 4 *LAMBDA ).round(3) + R29_3 = ( 1 *LAMBDA ).round(3) + R30_1 = ( 5 *LAMBDA ).round(3) + R30_2 = ( 5 *LAMBDA ).round(3) + R30_3 = ( 2 *LAMBDA ).round(3) + R30_4 = ( 10 *LAMBDA ).round(3) + R31_1 = ( 34 *LAMBDA ).round(3) + R31_2 = ( 56 *LAMBDA ).round(3) + R31_3 = ( 17 *LAMBDA ).round(3) + R31_4 = ( 23 *LAMBDA ).round(3) + R31_5 = ( 39 *LAMBDA ).round(3) + R31_6 = ( 6 *LAMBDA ).round(3) + R31_7 = ( 34 *LAMBDA ).round(3) + R31_8 = ( 13 *LAMBDA ).round(3) +end + + +# KLAYOUT setttings +######################## +# Use a tile size of 1mm +tiles(1000.um) +# Use a tile border of 10 micron: +tile_borders(1.um) +#no_borders + +# Use 4 CPU cores +threads(4) +verbose(true) + +# Define a new custom function that selects polygons by their number of holes: +# It will return a new layer containing those polygons with min to max holes. +# max can be nil to omit the upper limit. +class DRC::DRCLayer + def with_holes(min, max) + new_data = RBA::Region::new + self.data.each do |p| + if p.holes >= (min || 0) && (!max || p.holes <= max) + new_data.insert(p) + end + end + DRC::DRCLayer::new(@engine, new_data) + end +end + +# layers definitions +######################## +info("Layers definitions") + + DNW = input(38,0) + NW = input(42,0) + PW = input(41,0) + CW = input(59,0) + AA = input(43,0) + TA = input(60,0) + PBase = input(58,0) + PL = input(46,0) + SB = input(29,0) + Nselect = input(45,0) + Pselect = input(44,0) + PO2 = input(56,0) + HR = input(34,0) + Contact = input(25,0) + ContactPoly = input(47,0) + ContactActive = input(48,0) + ContactPoly2 = input(55, 0) + CT = Contact + ContactPoly + ContactActive + ContactPoly2 + M1 = input(49,0) + V1 = input(50,0) + M2 = input(51,0) + V2 = input(61,0) + M3 = input(62,0) + V3 = input(30,0) + M4 = input(31,0) + CTM = input(35,0) + V4 = input(32,0) + M5 = input(33,0) + V5 = input(36,0) + M6 = input(37,0) + Glass = input(52,0) + Pads = input(26,0) + +# layers processing +######################## +info("Layers processing") +#CHIP = extent.sized(1.0) +NP = AA & Nselect +PP = AA & Pselect +NSTP = NP.and(NW) +PSTP = PP.not(NW) +GATE = PL & AA + +# DRC section +######################## +info("DRC section") + +### Deep NWell +DNW.ongrid(0.5*LAMBDA).output("DNW_offgrid", "Offgrid vertex on DNW") +DNW.with_angle(0 .. 45).output("DNW_angle", "Non 45 degree angle DNW") +DNW.edges.and(PW).output("DNW_PW","DNW cannot cross PWell") +DNW.width(R31_1, euclidian).output("31.1 DNW_width", "31.1 : Min. DNW width : #{R31_1}um") +DNW.isolated(R31_2, euclidian).output("31.2 DNW_space", "31.2 : Min. DNW spacing : #{R31_2}um") +NW.enclosing(DNW, R31_3, euclidian).output("31.3 NW_enc_DNW", "31.3 : Min. NWell enclosing DNW : #{R31_3}um") +DNW.enclosing(NW, R31_4, euclidian).output("31.4 DNW_enc_NW", "31.4 : Min. DNW enclosing NWell : #{R31_4}um") +DNW.separation(NW, R31_5, euclidian).output("31.5 DNW_sep_NW", "31.5 : Min. DNW separation NWell : #{R31_5}um") +DNW.not(NW).enclosing(NP, R31_6, euclidian).output("31.6 DNW_enc_NP", "31.6 : Min. PW in DNW enclosing N+ : #{R31_6}um") +DNW.separation(NP, R31_7, euclidian).output("31.7 DNW_sep_NP", "31.7 : Min. DNW separation N+ : #{R31_7}um") + +### Nwell / Pwell +NW.ongrid(0.5*LAMBDA).output("NW_offgrid", "Offgrid vertex on NWell") +NW.with_angle(0 .. 45).output("NW_angle", "Non 45 degree angle NWell") +NW.and(PW).output("NW_PW","NW over PW not allowed") +NW.width(R1_1, euclidian).output("1.1 NW_width", "1.1 : Min. NWell width : #{R1_1}um") +NW.isolated(R1_2, euclidian).output("1.2 NW_space", "1.2 : Min. NWell spacing : #{R1_2}um") +NW.and(TA).isolated(18, euclidian).output("1.3 NW_TA_space", "1.3 : Min. NWell-TA spacing : #{R1_3}um") +PW.width(R1_1, euclidian).output("1.1 PW_width", "1.1 : Min. PWell width : #{R1_1}um") +PW.isolated(R1_2, euclidian).output("1.2 PW_space", "1.2 : Min. PWell spacing : #{R1_2}um") +PW.and(TA).isolated(R1_3, euclidian).output("1.3 PW_TA_space", "1.3 : Min. PWell-TA spacing : #{R1_3}um") + +### Active +AA.ongrid(0.5*LAMBDA).output("AA_offgrid", "Offgrid vertex on AA") +AA.with_angle(0 .. 45).output("AA_angle", "Non 45 degree angle AA") +AA.width(R2_1, euclidian).output("2.1 AA_width", "2.1 : Min. active width : #{R2_1}um") +AA.space(R2_2, euclidian).output("2.2 AA_space", "2.2 : Min. active spacing : #{R2_2}3um") +NW.enclosing(PP.interacting(GATE), R2_3, euclidian).output("2.3 NW_enc_PP", "2.3 : Min. NWell enclosing Source/Drain : #{R2_3}um") +PW.enclosing(NP.interacting(GATE), R2_3, euclidian).output("2.3 PW_enc_NP", "2.3 : Min. PWell enclosing Source/Drain : #{R2_3}um") +NW.enclosing(NP, R2_4, euclidian).output("2.4 NW_enc_NP", "2.4 : Min. NWell enclosing Nstrap : #{R2_4}um") +PW.enclosing(PP, R2_4, euclidian).output("2.4 PW_enc_PP", "2.4 : Min. PWell enclosing Pstrap : #{R2_4}um") +NP.separation(PP, R2_5, euclidian).polygons.without_area(0).output("2.5 NP_space_PP", "2.5 : Min. N+ space P+ : #{R2_5}um (if not abutted)") + +### TA Thick Active +TA.ongrid(0.5*LAMBDA).output("TA_offgrid", "Offgrid vertex on TA") +TA.with_angle(0 .. 45).output("TA_angle", "Non 45 degree angle TA") +TA.width(R24_1, euclidian).output("24.1 TA_width", "24.1 : Min. TA width : #{R24_1}um") +TA.space(R24_2, euclidian).output("24.2 TA_space", "24.2 : Min. TA spacing : #{R24_2}um") +TA.enclosing(AA, R24_3, euclidian).output("24.3 TA_enc_AA", "24.3 : Min. TA enclosing Active : #{R24_3}um") +TA.separation(AA, R24_4, euclidian).output("24.4 TA_space_AA", "24.4 : Min. TA spacing Active : #{R24_4}um") +TA.and(GATE).width(R24_5, euclidian).output("24.5 TA_gate_width", "24.5 : Min. TA Gate width : #{R24_5}um") +AA.edges.and(TA).output("24.6 AA_in_TA","24.6 : Active edge cannot cross TA") + +### Poly +PL.ongrid(0.5*LAMBDA).output("POLY_offgrid", "Offgrid vertex on Poly") +PL.with_angle(0 .. 45).output("POLY_angle", "Non 45 degree angle Poly") +PL.width(R3_1, euclidian).output("3.1 POLY_width", "3.1 : Min. Poly width : #{R3_1}um") +PL.space(R3_2, euclidian).output("3.2 Poly_space", "3.2 : Min. Poly spacing : #{R3_2}um") +GATE.space(R3_2_a, euclidian).output("3.2a Gate_space", "3.2a : Min. Gate spacing : #{R3_2_a}um") +PL.enclosing(GATE, R3_3, projection).polygons.without_area(0).output("3.3 PL_enc_GATE", "3.3 : Min. Poly extention Gate : #{R3_3}um") +AA.enclosing(GATE, R3_4, projection).polygons.without_area(0).output("3.4 AA_enc_GATE", "3.4 : Min. Source/Drain length : #{R3_4}um") +PL.not(AA).separation(AA, 1, euclidian).polygons.without_area(0).output("3.5 PL_space_AA", "3.5 : Min. Poly on Field spacing Active : #{R3_5}um") + +### Poly2 +if !DEEP +PO2.ongrid(0.5*LAMBDA).output("POLY2_offgrid", "Offgrid vertex on Poly2") +PO2.with_angle(0 .. 45).output("POLY2_angle", "Non 45 degree angle Poly2") +PO2.width(R12_1, euclidian).output("12.1 POLY2_width", "12.1 : Min. Poly2 width : #{R12_1}um") +PO2.space(R12_2, euclidian).output("12.2 POLY2_space", "12.2 : Min. Poly2 space : #{R12_2}um") +# rule R12.3 not coded +PO2.not(AA).separation(AA, R12_4, euclidian).output("12.4 POLY2_space_AA"," 12.4 : Min. Poly2 on Field spacing Active : #{R12_4}um") +PO2.not(PL).separation(PL, R12_5, euclidian).output("12.5 POLY2_space_PL"," 12.5 : Min. Poly2 spacing Poly : #{R12_5}um") +PO2.enclosing(PL, R12_5, euclidian).output("12.5 POLY2_overlap_PL"," 12.5 : Min. Poly2 overlap of Poly : #{R12_5}um") +PO2.separation(AA.or(PL).and(CT), R12_6, euclidian).output("12.6 POLY2_space_CT"," 12.5 : Min. Poly2 spacing Poly or Active contact: #{R12_6}um") +PO2cap = PL & PO2 +PO2cap.width(R11_1, euclidian).output("11.1 POLY2CAP_width", "11.1 : Min. Poly2 Capacitor width : #{R11_1}um") +PO2cap.space(R11_2, euclidian).output("11.2 POLY2CAP_space", "11.2 : Min. Poly2 Capacitor space : #{R11_2}um") +PL.enclosing(PO2cap, R11_3, euclidian).output("12.3 PL_overlap_POLY2CAP"," 11.3 : Min. Poly overlap of Poly2 Capacitor : #{R11_3}um") +PO2cap.edges.separation(AA.or(NW).edges, R11_4, euclidian).output("11.4 POLY2CAP_space_AA/NW"," 11.4 : Min. Poly2 Capacitor spacing Active or Well: #{R11_4}um") +PO2cap.separation(PL.and(CT), R11_5, euclidian).output("11.5 POLY2CAP_space_PLCT"," 11.5 : Min. Poly2 Capacitor spacing Poly contact: #{R11_5}um") +PO2cap.separation(M1.or(M2).or(M3), R11_6, euclidian).output("11.6 POLY2CAP_space_METAL"," 11.6 : Min. Poly2 Capacitor spacing any Metal: #{R11_6}um") +PO2cap.forget + +### Capacitor Well +CW.ongrid(0.5*LAMBDA).output("CW_offgrid", "Offgrid vertex on CapacitorWell") +CW.with_angle(0 .. 45).output("CW_angle", "Non 45 degree angle CapacitorWell") +CW.width(R17_1, euclidian).output("17.1 CW_width", "17.1 : Min. CapacitorWell width : #{R17_1}um") +CW.space(R17_2, euclidian).output("17.2 CW_space", "17.2 : Min. CapacitorWell space : #{R17_2}um") +AA.not(CW).separation(CW, R17_3, euclidian).output("17.3 CW_space_AA"," 17.3 : Min. CapacitorWell spacing Active : #{R17_3}um") +CW.enclosing(AA, R17_4, euclidian).output("17.4 CW_overlap_AA"," 17.4 : Min. CapacitorWell overlap of Active : #{R17_4}um") +LinCap = PL & CW +LinCap.width(R18_1, euclidian).output("18.1 LC_width", "18.1 : Min. Linear Capacitor width : #{R18_1}um") +LinCap.space(R18_2, euclidian).output("18.2 LC_space", "18.2 : Min. Linear Capacitor space : #{R18_2}um") +LinCap.separation(AA.and(CT), R18_3, euclidian).output("18.3 LC_space_AACT"," 18.3 : Min. Linear Capacitor spacing Active contact : #{R18_3}um") +LinCap.separation(PL.and(CT), R18_4, euclidian).output("18.4 LC_space_PLCT"," 18.4 : Min. Linear Capacitor spacing Poly contact : #{R18_4}um") +LinCap.forget +end + +### N+/P+ Select +Nselect.ongrid(0.5*LAMBDA).output("NSel_offgrid", "Offgrid vertex on Nselect") +Pselect.ongrid(0.5*LAMBDA).output("PSel_offgrid", "Offgrid vertex on Pselect") +Nselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Nselect") +Pselect.with_angle(0 .. 45).output("N+_angle", "Non 45 degree angle Pselect") +NP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 N+_enc_GATE", "4.1 : Min. N+ extention Gate on Source/Drain : #{R4_1}um") +PP.enclosing(GATE, R4_1, projection).polygons.without_area(0).output("4.1 P+_enc_GATE", "4.1 : Min. P+ extention Gate on Source/Drain : #{R4_1}um") +Nselect.enclosing(AA, R4_2, euclidian).output("4.2 N+_enc_AA", "4.2 : Min. N+ enclosing Active : #{R4_2}um") +Pselect.enclosing(AA, R4_2, euclidian).output("4.2 P+_enc_AA", "4.2 : Min. P+ enclosing Active : #{R4_2}um") +Nselect.enclosing(CT, R4_3, euclidian).output("4. N+_enc_CT", "4.3 : Min. N+ enclosing Contact : #{R4_3}um") +Pselect.enclosing(CT, R4_3, euclidian).output("4.3 P+_enc_CT", "4.3 : Min. P+ enclosing Contact : #{R4_3}um") +Nselect.width(R4_4,euclidian).output("4.4 N+_width", "4.4 : Min. N+ width : #{R4_4}um") +Pselect.width(R4_4,euclidian).output("4.4 P+_width", "4.4 : Min. N+ width : #{R4_4}um") +Nselect.space(R4_4,euclidian).output("4.4 N+_space", "4.4 : Min. N+ spacing : #{R4_4}um") +Pselect.space(R4_4,euclidian).output("4.4 P+_space", "4.4 : Min. N+ spacing : #{R4_4}um") +Nselect.and(Pselect).output("4.4 N+_and_P+", "4.4 : N+ over P+ not allowed") + +### HR - High Resistive +HR.ongrid(0.5*LAMBDA).output("HR_offgrid", "Offgrid vertex on HighRes") +HR.with_angle(0 .. 45).output("HR_angle", "Non 45 degree angle HighRes") +HR.width(R27_1, euclidian).output("27.1 HR_width", "27.1 : Min. HiRes width : #{R27_1}um") +HR.space(R27_2, euclidian).output("27.2 HR_space", "27.2 : Min. HiRes spacing : #{R27_2}um") +HR.and(CT).output("27.3 CT_and_HR", "27.3 : Contact on HiRes not allowed") +HR.separation(CT, R27_3, euclidian).output("27.3 HR_space_CT", "27.3 : Min. HiRes space to Contact : #{R27_3}um") +HR.separation(AA, R27_5, euclidian).output("27.4 HR_space_AA", "27.4 : Min. HiRes space to Active : #{R27_4}um") +HR.separation(PO2, R27_5, euclidian).output("27.5 HR_space_PO2", "27.5 : Min. HiRes space to Poly2 : #{R27_5}um") +HR.and(PO2).and(AA).output("27.6 HR_and_active", "27.6 : HiRes Po2 over Active not allowed") +HR.and(PO2).and(NW.or(PW)).output("27.6 HR_and_Well", "27.6 : HiRes Po2 over Well not allowed") +HR.and(PO2).width(R27_7,euclidian).output("27.7 HRPO2_width", "27.7 : Min. HiRes Poly2 width : #{R27_7}um") +HR.and(PO2).space(R27_8,euclidian).output("27.8 HRPO2_space", "27.8 : Min. HiRes Poly2 space : #{R27_8}um") +HR.enclosing(PO2, R27_9, projection).output("27.9 HR_enc_PO2", "27.9 : Min. HiRes enclosing Poly2 : #{R27_9}um") + +### SB - Silicide block +SB.ongrid(0.5*LAMBDA).output("SB_offgrid", "Offgrid vertex on Sil. Block") +SB.with_angle(0 .. 45).output("SB_angle", "Non 45 degree angle Sil. Block") +SB.width(R20_1, euclidian).output("20.1 SB_width", "20.1 : Min. Sil. Block width : #{R20_1}um") +SB.space(R20_2, euclidian).output("20.2 SB_space", "20.2 : Min. Sil. Block spacing : #{R20_2}um") +SB.separation(CT, R20_3, euclidian).output("20.3 SB_space_CT", "20.3 : Min. Sil. Block space to Contact : #{R20_3}um") +SB.and(CT).output("20.3 SB_and_CT", "20.3 : Sil. Block over Contact not allowed") +SB.separation(AA, R20_4, euclidian).output("20.4 SB_space_AA", "20.4 : Min. Sil. Block space to Active : #{R20_4}um") +SB.separation(PL, R20_5, euclidian).output("20.5 SB_space_PL", "20.5 : Min. Sil. Block space to Poly : #{R20_5}um") +SB.and(GATE).output("20.6 SBres_overAA","20.6 : SB resistor over Active not allowed") +SB.and(PL).and(Nselect.or(Pselect)).output("20.6 SBres_over_WELL","20.6 : SB resistor over Well not allowed") +SB.and(PL).width(R20_7,euclidian).output("20.6 SBres_width", "20.7 : Min. SB resistor width : #{R20_7}um") +SB.and(PL).space(R20_7,euclidian).output("20.7 SBres_space", "20.7 : Min. SB resistor space : #{R20_7}um") +SB.enclosing(AA, R20_8, projection).polygons.without_area(0).output("20.8 SB_enc_AA", "20.8 : Min. Sil. Block enclosing Active : #{R20_8}um") +AA.enclosing(SB, R20_9, projection).polygons.without_area(0).output("20.9 AA_enc_SB", "20.9 : Min. Active enclosing Sil. Block : #{R20_9}um") +SB.enclosing(PL, R20_9, projection).output("20.8 SB_enc_PL", "20.8 : Min. Sil. Block enclosing Poly : #{R20_8}um") +PL.enclosing(SB, R20_8, projection).polygons.without_area(0).output("20.9 PL_enc_SB", "20.9 : Min. Poly enclosing Sil. Block : #{R20_9}um") +SB.separation(GATE, R20_11, euclidian).output("20.11 SB_space_GATE", "20.11 : Min. Sil. Block space to Gate : #{R20_11}um") + +### Contact +CT.ongrid(0.5*LAMBDA).output("CT_offgrid", "Offgrid vertex on Contact") +CT.with_angle(0 .. 90).output("CT_angle", "Non 90 degree angle Contact") +CT.and(GATE).output("CT_and_GATE", "Contact on Gate not allowed") +CT.not(M1).output("CT_not_M1", "Contact without Metal1 not recommended") +# CT.drc(length != R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") +CT.width(R5_1).output("5.1 CT_width", "5.1 : Exact Contact width : #{R5_1}um") +CT.without_area(R5_1*R5_1).output("5.1 CT_area", "5.1 : Exact Contact Area : #{R5_1*R5_1}um2") +CT.space(R5_3, euclidian).output("5.3 CT_space", "5.3 : Contact spacing : #{R5_3}um") +PL.enclosing(CT, R5_2_b, euclidian).output("5.2 PL_enc_CT", "5.2 : Min. Poly enclosing Contact : #{R5_2_b}um") +AA.enclosing(CT, R6_2_b, euclidian).output("6.2 AA_enc_CT", "6.2 : Min. Active enclosing Contact : #{R6_2_b}um") +PO2.enclosing(CT, R13_3, euclidian).output("13.3 PO2_enc_CT", "13.3 : Min. Poly2 enclosing Contact : #{R13_3}um") +CT.and(AA).separation(GATE, R5_4, euclidian).output("5.4 CTAA_space_GATE", "5.4 : Min. ActiveContact space to Gate : #{R5_4}um") +CT.and(PL).separation(PL, R5_5_b, euclidian).polygons.without_area(0).output("5.5.b CTPL_space_Poly", "5.5.b : Min. PolyContact space to Poly : #{R5_5_b}um") +CT.and(PL).separation(AA, R5_6_b, euclidian).output("5.6.b CTPL_space_AA", "5.6.b : Min. PolyContact space to AA : #{R5_6_b}um") +# rule 5.7.b not coded +CT.and(AA).separation(AA, R6_5_b, euclidian).polygons.without_area(0).output("6.5.b CTAA_space_AA", "6.5.b : Min. ActiveContact space to AA : #{R6_5_b}um") +CT.and(AA).separation(PL, R6_6_b, euclidian).output("6.6.b CTAA_space_PL", "6.6.b : Min. ActiveContact space to Poly : #{R6_6_b}um") +CT.and(AA).separation(CT.and(PL), R6_7_b, euclidian).output("6.7.b CTAA_space_CTPL", "6.7.b : Min. ActiveContact space to PolyContact : #{R6_7_b}um") +# rule 6.8.b not coded +CT.and(PO2).separation(AA, R13_5, euclidian).output("13.5 CTPO2_space_AA", "13.5 : Min. Poly2Contact space to AA : #{R13_5}um") +CT.and(PO2).separation(PL, R13_5, euclidian).output("13.5 CTPO2_space_PL", "13.5 : Min. Poly2Contact space to Poly : #{R13_5}um") +M1.enclosing(CT, R7_3, euclidian).output("7.3 M1_enc_CT", "7.3 : Min. Metal1 enclosing Contact : #{R7_3}um") + +### Metal 1 +M1.ongrid(0.5*LAMBDA).output("M1_offgrid", "Offgrid vertex on ME1") +M1.with_angle(0 .. 45).output("M1_angle", "Non 45 degree angle ME1") +M1.holes.with_area(0 .. R7_1*R7_1).output("M1_holes", "Min. Metal1 holes area : #{R7_1*R7_1}um2") +M1.width(R7_1, euclidian).output("7.1 M1_width", "7.1 : Min. Metal1 width : #{R7_1}um") +M1.space(R7_2, euclidian).output("7.2 M1_space", "7.2 : Min. Metal1 spacing : #{R7_2}um") +M1.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M1,R7_4,euclidian).polygons.without_area(0).output("7.4 M1_10_space", "7.4 : Space if at least one metal1 line width is > #{10*LAMBDA}um : #{R7_4}um") + +### Via 1 +V1.ongrid(0.5*LAMBDA).output("V1_offgrid", "Offgrid vertex on Via1") +V1.not(M1).output("V1_not_M1", "Via1 without Metal1 not allowed") +V1.not(M2).output("V1_not_M2", "Via1 without Metal2 not allowed") +V1.with_angle(0 .. 90).output("V1_angle", "Non 90 degree angle Via1") +V1.width(R8_1,square).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um") +V1.without_area(R8_1*R8_1).output("8.1 V1_width", "8.1 : Exact Via1 width : #{R8_1}um2") +V1.space(R8_2,euclidian).output("8.2 V1_space", "8.2 : Via1 spacing : #{R8_2}um") +M1.enclosing(V1, R8_3, euclidian).output("8.3 M1_enc_V1", "8.3 : Min. Metal1 enclosing Via1 : #{R8_3}um") +M2.enclosing(V1, R8_3, euclidian).output("9.3 M2_enc_V1", "9.3 : Min. Metal2 enclosing Via1 : #{R9_3}um") +if !DEEP && NBR_OF_METALS < 4 + V1.and(CT).or(V1.separation(CT, R8_4, euclidian).polygons).output("8.4 V1_space_CT", "8.4 : Via1 space CT : #{R8_4}um") + V1.separation(PL + AA, R8_5, euclidian).output("8.5 V1_space_PL/AAedges", "8.5 : Via1 space to Poly orActive edges : #{R8_5}um") +end +if DFM + M1.and(M2).not(V1).with_holes(1,1).output("2_V1", "Min. 2 Via1 are needed") +end + +### Metal 2 +M2.ongrid(0.5*LAMBDA).output("M2_offgrid", "Offgrid vertex on ME2") +M2.with_angle(0 .. 45).output("M2_angle", "Non 45 degree angle ME2") +M2.width(R9_1, euclidian).output("9.1 M2_width", "9.1 : Min. Metal2 width : #{R9_1}um") +M2.space(R9_2, euclidian).output("9.2 M2_space", "9.2 : Min. Metal2 spacing : #{R9_2}um") +M2.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M2,R9_4,euclidian).polygons.without_area(0).output("9.4 M2_10_space", "9.4 : Space if at least one metal2 line width is > #{10*LAMBDA}um : #{R9_4}um") + +### Via 2 +V2.ongrid(0.5*LAMBDA).output("V2_offgrid", "Offgrid vertex on Via2") +V2.not(M3).output("V2_not_M3", "Via2 without Metal3 not allowed") +V2.not(M2).output("V2_not_M2", "Via2 without Metal2 not allowed") +V2.with_angle(0 .. 90).output("V2_angle", "Non 90 degree angle Via2") +V2.width(R14_1, square).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um") +V2.without_area(R14_1*R14_1).output("14.1 V2_width", "14.1 : Exact Via2 width : #{R14_1}um2") +V2.space(R14_2, euclidian).output("14.2 V2_space", "14.2 : Via2 spacing : #{R14_2}um") +M2.enclosing(V2, R14_3, euclidian).output("14.3 M2_enc_V2", "14.3 : Min. Metal2 enclosing Via2 : #{R14_3}um") +M3.enclosing(V2, R15_3, euclidian).output("15.3 M3_enc_V2", "15.3 : Min. Metal3 enclosing Via2 : #{R15_3}um") +if !DEEP && NBR_OF_METALS < 4 + V2.and(V1).or(V2.separation(V1, R14_4, euclidian).polygons).output("14.4 V2_space_V1", "14.4 : Via2 space Via1 : #{R14_4}um") +end +if DFM + M2.and(M3).not(V2).with_holes(1,1).output("2_V2", "Min. 2 Via2 are needed") +end + +### Metal 3 +M3.ongrid(0.5*LAMBDA).output("M3_offgrid", "Offgrid vertex on ME3") +M3.with_angle(0 .. 45).output("M3_angle", "Non 45 degree angle ME3") +M3.width(R15_1, euclidian).output("15.1 M3_width", "15.1 : Min. Metal3 width : #{R15_1}um") +M3.space(R15_2, euclidian).output("15.2 M3_space", "15.2 : Min. Metal3 spacing : #{R15_2}um") +M3.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M3, R15_4, euclidian).polygons.without_area(0).output("15.4 M3_10_space", "15.4 : Space if at least one metal3 line width is > #{10*LAMBDA}um : #{R15_4}um") + +### Cap Top Metal +if SUBM || DEEP +CTM.ongrid(0.5*LAMBDA).output("CTM_offgrid", "Offgrid vertex on CTM") +CTM.with_angle(0 .. 45).output("CTM_angle", "Non 45 degree angle CTM") +CTM.width(R28_1, euclidian).output("28.1 CTM_width", "28.1 : Min. Cap Top Metal width : #{R28_1}um") +CTM.space(R28_2, euclidian).output("28.2 CTM_space", "28.2 : Min. Cap Top Metal spacing : #{R28_2}um") +if NBR_OF_METALS == 4 + TM = M4 + VT = V3 + TB = V2 +end +if NBR_OF_METALS == 5 + TM = M5 + VT = V4 + VB = V3 +end +if NBR_OF_METALS == 6 + TM = M6 + VT = V5 + VB = V4 +end +TM.enclosing(CTM, R28_3, euclidian).output("28.3 TM_overlap_CTM", "28.3 : Min. Top Metal overlap Cap Top Metal : #{R28_3}um") +CTM.enclosing(VT, R28_4, euclidian).output("28.4 CTM_overlap_VT", "28.4 : Min. Cap Top Metal overlap Top Via : #{R28_4}um") +CTM.separation(VB, R28_5, euclidian).output("28.5 CTM_space_VB", "28.5 : Min. Cap Top Metal space Bottom Via : #{R28_5}um") +CTM.separation(VT, R28_5, euclidian).output("28.5 CTM_space_VT", "28.5 : Min. Cap Top Metal space Top Via : #{R28_5}um") +TM.enclosing(VB, R28_6, euclidian).output("28.6 TM_overlap_VB", "28.6 : Min. Top Metal overlap Bottom Via : #{R28_6}um") +# rule 28.7 not coded +CTM.not_interacting(VT).width(R28_8, euclidian).output("28.8 CTMdummies_width", "28.8 : Min. dummies Cap Top Metal width : #{R28_8}um") +TM.interacting(CTM).space(R28_9, euclidian).output("28.9 VT_space", "28.9 : Min. Top Metal spacing : #{R28_9}um") +VT.interacting(CTM).space(R28_10, euclidian).output("28.10 VT_space", "28.10 : Min. Top Via spacing : #{R28_10}um") +VB.interacting(TM.interacting(CTM)).space(R28_11, euclidian).output("28.11 VB_space", "28.11 : Min. Bottom Via spacing : #{R28_11}um") +CTM.sized(-15.um).sized(15.um).output("28.12 CTM_width", "28.12 : Max. CTM width/length : 30um") +TM.interacting(CTM).sized(-17.5.um).sized(17.5.um).output("28.13 TM_width", "28.13 : Max. Top Metal width/length : 35um") +CTM.and(VB).output("28.14 CTM_VB", "28.14 : no VB under CTM allowed") +CTM.and(AA.or(PL)).output("28.15 CTM_AA", "28.15 : no active or passive circuitry under CTM allowed") +end + +### Via 3 +if NBR_OF_METALS > 3 +V3.ongrid(0.5*LAMBDA).output("V3_offgrid", "Offgrid vertex on Via3") +V3.not(M3).output("V3_not_M3", "Via3 without Metal3 not allowed") +V3.not(M4).output("V3_not_M4", "Via3 without Metal4 not allowed") +V3.with_angle(0 .. 90).output("V3_angle", "Non 90 degree angle Via3") +V3.width(R21_1, square).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um") +V3.without_area(R21_1*R21_1).output("21.1 V3_width", "21.1 : Exact Via3 width : #{R21_1}um2") +V3.space(R21_2, euclidian).output("21.2 V3_space", "21.2 : Via3 spacing : #{R21_2}um") +M3.enclosing(V3, R21_3, euclidian).output("21.3 M3_enc_V3", "21.3 : Min. Metal3 enclosing Via3 : #{R21_3}um") +M4.enclosing(V3, R22_3, euclidian).output("22.3 M4_enc_V3", "22.3 : Min. Metal4 enclosing Via3 : #{R22_3}um") +if DFM + M3.and(M4).not(V3).with_holes(1,1).output("2_V3", "Min. 2 Via3 are needed") +end + +### Metal 4 +M4.ongrid(0.5*LAMBDA).output("M4_offgrid", "Offgrid vertex on ME4") +M4.with_angle(0 .. 45).output("M4_angle", "Non 45 degree angle ME4") +M4.width(R22_1, euclidian).output("22.1 M4_width", "22.1 : Min. Metal4 width : #{R22_1}um") +M4.space(R22_2, euclidian).output("22.2 M4_space", "22.2 : Min. Metal4 spacing : #{R22_2}um") +M4.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M4, R22_4, euclidian).polygons.without_area(0).output("22.4 M4_10_space", "22.4 : Space if at least one metal4 line width is > #{10*LAMBDA}um : #{R22_4}um") + +### Via 4 +if NBR_OF_METALS > 4 +V4.ongrid(0.5*LAMBDA).output("V4_offgrid", "Offgrid vertex on Via4") +V4.not(M5).output("V4_not_M5", "Via4 without Metal5 not allowed") +V4.not(M4).output("V4_not_M4", "Via4 without Metal4 not allowed") +V4.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via4") +V4.width(R25_1, square).output("25.1 V4_width", "25.1 : Exact Via4 width : #{R25_1}um") +V4.without_area(R25_1*R25_1).output("25.1 V4_width", "25.1 : Via4 width : #{R25_1}um2") +V4.space(R25_2, euclidian).output("25.2 V4_space", "25.2 : Exact Via4 spacing : #{R25_2}um") +M4.enclosing(V4, R25_3, euclidian).output("25.3 M4_enc_V4", "25.3 : Min. Metal4 enclosing Via4 : #{R25_3}um") +M5.enclosing(V4, R26_3, euclidian).output("26.3 M5_enc_V4", "26.3 : Min. Metal5 enclosing Via4 : #{R26_3}um") +if DFM + M4.and(M5).not(V4).with_holes(1,1).output("2_V4", "Min. 2 Via4 are needed") +end + +### Metal 5 +M5.ongrid(0.5*LAMBDA).output("M5_offgrid", "Offgrid vertex on ME5") +M5.with_angle(0 .. 45).output("M5_angle", "Non 45 degree angle ME5") +M5.width(R26_1, euclidian).output("26.1 M5_width", "26.1 : Min. Metal5 width : #{R26_1}um") +M5.space(R26_2, euclidian).output("26.2 M5_space", "26.2 : Min. Metal5 spacing : #{R26_2}um") +M5.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, R26_4, euclidian).polygons.without_area(0).output("26.4 M5_10_space", "26 .4 : Space if at least one metal5 line width is > #{10*LAMBDA}um : #{R26_4}um") + +### Via 5 +if NBR_OF_METALS > 5 +V5.ongrid(0.5*LAMBDA).output("V5_offgrid", "Offgrid vertex on Via5") +V5.not(M5).output("V5_not_M5", "Via5 without Metal5 not allowed") +V5.not(M6).output("V5_not_M6", "Via5 without Metal6 not allowed") +V5.with_angle(0 .. 90).output("V4_angle", "Non 90 degree angle Via5") +V5.width(R29_1, square).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um") +V5.without_area(R29_1*R29_1).output("29.1 V5_width", "29.1 : Exact Via5 width : #{R29_1}um2") +V5.space(R29_2, euclidian).output("29.2 V5_space", "29.2 : Via5 spacing : #{R29_2}um") +M5.enclosing(V5, R29_3, euclidian).output("29.3 M5_enc_V5", "29.3 : Min. Metal5 enclosing Via5 : #{R29_3}um") +M6.enclosing(V5, R30_3, euclidian).output("30.3 M3_enc_V5", "30.3 : Min. Metal6 enclosing Via5 : #{R30_3}um") +if DFM + M5.and(M6).not(V5).with_holes(1,1).output("2_V5", "Min. 2 Via5 are needed") +end + +### Metal 6 +M6.ongrid(0.5*LAMBDA).output("M6_offgrid", "Offgrid vertex on ME6") +M6.with_angle(0 .. 45).output("M6_angle", "Non 45 degree angle ME5") +M6.width(R30_1, euclidian).output("30.1 M6_width", "30.1 : Min. Metal6 width : #{R30_1}um") +M6.space(R30_2, euclidian).output("30.2 M6_space", "30.2 : Min. Metal6 spacing : #{R30_2}um") +M6.sized(-10*LAMBDA).sized(10*LAMBDA).separation(M5, 10, euclidian).polygons.without_area(0).output("30.4 M6_10_space", "30.4 : Space if at least one metal6 line width is > #{10*LAMBDA}um : #{R30_4}um") + +end +end +end + +# time spent for the DRC +time = Time.now +hours = ((time - tstart)/3600).to_i +minutes = ((time - tstart)/60 - hours * 60).to_i +seconds = ((time - tstart) - (minutes * 60 + hours * 3600)).to_i +$stdout.write "DRC finished at : #{time.hour}:#{time.min}:#{time.sec} - DRC duration = #{hours} hrs. #{minutes} min. #{seconds} sec.\n" + From 48e35588f4ddc569488c2c7793b898074ebaf549 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 3 Nov 2021 11:53:30 -0700 Subject: [PATCH 18/22] Fix cheat on wordline driver name. --- technology/freepdk45/tech/freepdk45.lylvs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/technology/freepdk45/tech/freepdk45.lylvs b/technology/freepdk45/tech/freepdk45.lylvs index 97fbf85e..934a981c 100644 --- a/technology/freepdk45/tech/freepdk45.lylvs +++ b/technology/freepdk45/tech/freepdk45.lylvs @@ -206,13 +206,13 @@ connect(metal10, metal10_pin) schematic.simplify if $connect_supplies - connect_implicit("vdd") - connect_implicit("gnd") +connect_implicit("*", "vdd") +connect_implicit("*", "gnd") end -#connect_global(pwell, "PWELL") -#connect_global(nwell, "NWELL") -#connect_global(bulk, "BULK") +connect_global(pwell, "PWELL") +connect_global(nwell, "NWELL") +connect_global(bulk, "BULK") for pat in %w(pinv* pnor* pnand* and?_dec* write_driver* port_address* replica_bitcell_array*) connect_explicit(pat, [ "NWELL", "vdd" ]) From 32c7e90662d8c047a0984405f2e609f1cb3128b0 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 8 Nov 2021 14:27:41 -0800 Subject: [PATCH 19/22] Do not run same well spacing for backwards compatibility. Add pbitcell cheat. --- technology/scn4m_subm/tech/tech.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 374ba4c8..ee63203c 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -drc_name = "klayout" -lvs_name = "klayout" -pex_name = "klayout" +# drc_name = "klayout" +# lvs_name = "klayout" +# pex_name = "klayout" blackbox_bitcell = False From fc0516460d0c1ab6c9713c3b077ba8007845fb96 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 16 Nov 2021 14:37:24 -0800 Subject: [PATCH 20/22] Use klayout in SCMOS too. --- technology/scn4m_subm/tech/tech.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index ee63203c..374ba4c8 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,8 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -# drc_name = "klayout" -# lvs_name = "klayout" -# pex_name = "klayout" +drc_name = "klayout" +lvs_name = "klayout" +pex_name = "klayout" blackbox_bitcell = False From 66c9501621666582c3e6d169b56194f11a5f6c0e Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 19 Nov 2021 13:43:54 -0800 Subject: [PATCH 21/22] Remove klayout from scmos --- technology/scn4m_subm/tech/tech.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 374ba4c8..a8c44996 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -428,8 +428,5 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa drc_name = "magic" lvs_name = "netgen" pex_name = "magic" -drc_name = "klayout" -lvs_name = "klayout" -pex_name = "klayout" blackbox_bitcell = False From d8d8636d0fe035c854fde78462d1bf5b00c461c6 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 22 Nov 2021 15:54:22 -0800 Subject: [PATCH 22/22] Comment out calibre in freepdk45 --- technology/freepdk45/tech/tech.py | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index 9303ba3d..d351ae36 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -457,10 +457,10 @@ parameter["sa_inv_nmos_size"] = 0.27 # micro-meters parameter["bitcell_drain_cap"] = 0.1 # In Femto-Farad, approximation of drain capacitance # Spice Values uses to calculate analytical delay based on CACTI equations -spice["i_on_n"] = 0.0004463 # A/um +spice["i_on_n"] = 0.0004463 # A/um spice["i_on_p"] = 0.0000771 # A/um spice["tox"] = 0.00114 # microns -spice["eps_ox"] = 0.00245e-14 # F/um, calculated from CACTI 45nm data +spice["eps_ox"] = 0.00245e-14 # F/um, calculated from CACTI 45nm data spice["cox"] = spice["eps_ox"]/spice["tox"] # F/um^2 spice["c_g_ideal"] = spice["cox"]*drc["minlength_channel"] # F/um spice["c_overlap"] = 0.2*spice["c_g_ideal"] # F/um @@ -477,9 +477,10 @@ spice["sa_transconductance"] = (spice["mobility_n"])*spice["cox"]*(parameter["sa # Technology Tool Preferences ################################################### -drc_name = "calibre" -lvs_name = "calibre" -pex_name = "calibre" +#drc_name = "calibre" +#lvs_name = "calibre" +#pex_name = "calibre" + drc_name = "klayout" lvs_name = "klayout" pex_name = "klayout"