diff --git a/compiler/base/design.py b/compiler/base/design.py index cbc2c2d4..f116d9fa 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -33,7 +33,7 @@ class design(hierarchy_design): self.poly_width = drc["minwidth_poly"] self.poly_space = drc["poly_to_poly"] self.m1_width = drc["minwidth_metal1"] - self.m1_space = drc["metal1_to_metal1"] + self.m1_space = drc["metal1_to_metal1"] self.m2_width = drc["minwidth_metal2"] self.m2_space = drc["metal2_to_metal2"] self.m3_width = drc["minwidth_metal3"] diff --git a/compiler/drc/design_rules.py b/compiler/drc/design_rules.py new file mode 100644 index 00000000..ff156e61 --- /dev/null +++ b/compiler/drc/design_rules.py @@ -0,0 +1,35 @@ +from drc_value import * +from drc_lut import * + +class design_rules(): + """ + This is a class that implements the design rules structures. + """ + def __init__(self, name): + self.tech_name = name + self.rules = {} + + def add(self, name, value): + self.rules[name] = value + + def __call__(self, name, *args): + return self.rules[name](args) + + def __setitem__(self, b, c): + """ + For backward compatibility with existing rules. + """ + self.rules[b] = c + + def __getitem__(self, b): + """ + For backward compatibility with existing rules. + """ + rule = self.rules[b] + if callable(rule): + return rule() + else: + return rule + + + diff --git a/compiler/drc/drc_lut.py b/compiler/drc/drc_lut.py new file mode 100644 index 00000000..514829e3 --- /dev/null +++ b/compiler/drc/drc_lut.py @@ -0,0 +1,40 @@ + +class drc_lut(): + """ + Implement a lookup table of rules. + Each element is a tuple with the last value being the rule. + It searches through backwards until all of the key values are + met and returns the rule value. + For exampe, the key values can be width and length, + and it would return the rule for a wire of a given width and length. + A key can be not compared by passing a None. + """ + def __init__(self, table): + self.table = table + + def __call__(self, *args): + """ + Lookup a given tuple in the table. + """ + + key_tuple = args + if not key_tuple: + key_size = len(list(self.table.keys())[0]) + key_tuple = tuple(0 for i in range(key_size)) + for key in sorted(self.table.keys(), reverse=True): + if self.match(key_tuple, key): + return self.table[key] + + def match(self, t1, t2): + """ + Determine if t1>t2 for each tuple pair. + """ + # If any one pair is less than, return False + for i in range(len(t1)): + if t1[i] < t2[i]: + return False + return True + + + + diff --git a/compiler/drc/drc_value.py b/compiler/drc/drc_value.py new file mode 100644 index 00000000..c4eab3d4 --- /dev/null +++ b/compiler/drc/drc_value.py @@ -0,0 +1,17 @@ + +class drc_value(): + """ + A single DRC value. + """ + def __init__(self, value): + self.value = value + + def __call__(self, *args): + """ + Return the value. + """ + return self.value + + + + diff --git a/compiler/globals.py b/compiler/globals.py index f16660e6..e4cbfe2a 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -287,7 +287,8 @@ def setup_paths(): # Add all of the subdirs to the python path # These subdirs are modules and don't need to be added: characterizer, verify - for subdir in ["gdsMill", "tests", "modules", "base", "pgates", "bitcells", "router"]: + subdirlist = [ item for item in os.listdir(OPENRAM_HOME) if os.path.isdir(os.path.join(OPENRAM_HOME, item)) ] + for subdir in subdirlist: full_path = "{0}/{1}".format(OPENRAM_HOME,subdir) debug.check(os.path.isdir(full_path), "$OPENRAM_HOME/{0} does not exist: {1}".format(subdir,full_path)) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index ec3bed0c..a262e059 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -1,7 +1,7 @@ import contact import design import debug -from tech import drc, parameter, spice, info +from tech import drc, parameter, spice from ptx import ptx from vector import vector from globals import OPTS @@ -110,7 +110,7 @@ class pgate(design.design): max_y_offset = self.height + 0.5*self.m1_width self.nwell_position = middle_position nwell_height = max_y_offset - middle_position.y - if info["has_nwell"]: + if drc["has_nwell"]: self.add_rect(layer="nwell", offset=middle_position, width=self.well_width, @@ -122,7 +122,7 @@ class pgate(design.design): pwell_position = vector(0,-0.5*self.m1_width) pwell_height = middle_position.y-pwell_position.y - if info["has_pwell"]: + if drc["has_pwell"]: self.add_rect(layer="pwell", offset=pwell_position, width=self.well_width, diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 8b3d1716..a838ead4 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -1,7 +1,7 @@ import contact import pgate import debug -from tech import drc, parameter, spice, info +from tech import drc, parameter, spice from ptx import ptx from vector import vector from math import ceil diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index e5a1a51b..db39c33b 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -1,6 +1,6 @@ import design import debug -from tech import drc, info, spice +from tech import drc, spice from vector import vector from contact import contact from globals import OPTS @@ -129,7 +129,7 @@ class ptx(design.design): self.active_offset = vector([self.well_enclose_active]*2) # Well enclosure of active, ensure minwidth as well - if info["has_{}well".format(self.well_type)]: + if drc["has_{}well".format(self.well_type)]: self.cell_well_width = max(self.active_width + 2*self.well_enclose_active, self.well_width) self.cell_well_height = max(self.tx_width + 2*self.well_enclose_active, @@ -280,7 +280,7 @@ class ptx(design.design): """ Add an (optional) well and implant for the type of transistor. """ - if info["has_{}well".format(self.well_type)]: + if drc["has_{}well".format(self.well_type)]: self.add_rect(layer="{}well".format(self.well_type), offset=(0,0), width=self.cell_well_width, diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index 0e1cd88f..140a47d6 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -1,6 +1,6 @@ import design import debug -from tech import drc, info +from tech import drc from vector import vector import contact from ptx import ptx diff --git a/technology/freepdk45/tech/tech.py b/technology/freepdk45/tech/tech.py index f62da9fd..f0acf8ed 100644 --- a/technology/freepdk45/tech/tech.py +++ b/technology/freepdk45/tech/tech.py @@ -1,15 +1,10 @@ import os +from design_rules import * """ File containing the process technology parameters for FreePDK 45nm. """ -info = {} -info["name"] = "freepdk45" -info["body_tie_down"] = 0 -info["has_pwell"] = True -info["has_nwell"] = True - #GDS file info GDS = {} # gds units @@ -72,7 +67,13 @@ parameter["min_tx_size"] = 0.09 parameter["beta"] = 3 drclvs_home=os.environ.get("DRCLVS_HOME") -drc={} + +drc = design_rules("freepdk45") + +drc["body_tie_down"] = 0 +drc["has_pwell"] = True +drc["has_nwell"] = True + #grid size drc["grid"] = 0.0025 @@ -83,7 +84,7 @@ drc["xrc_rules"]=drclvs_home+"/calibrexRC.rul" drc["layer_map"]=os.environ.get("OPENRAM_TECH")+"/freepdk45/layers.map" # minwidth_tx with contact (no dog bone transistors) -drc["minwidth_tx"]=0.09 +drc["minwidth_tx"] = 0.09 drc["minlength_channel"] = 0.05 # WELL.2 Minimum spacing of nwell/pwell at different potential @@ -196,7 +197,18 @@ drc["via2_to_via2"] = 0.075 # METALINT.1 Minimum width of intermediate metal drc["minwidth_metal3"] = 0.07 # METALINT.2 Minimum spacing of intermediate metal -drc["metal3_to_metal3"] = 0.07 +#drc["metal3_to_metal3"] = 0.07 +# Minimum spacing of metal3 wider than 0.09 & longer than 0.3 = 0.09 +# Minimum spacing of metal3 wider than 0.27 & longer than 0.9 = 0.27 +# Minimum spacing of metal3 wider than 0.5 & longer than 1.8 = 0.5 +# Minimum spacing of metal3 wider than 0.9 & longer than 2.7 = 0.9 +# Minimum spacing of metal3 wider than 1.5 & longer than 4.0 = 1.5 +drc["metal3_to_metal3"] = drc_lut({(0.00, 0.0) : 0.07, + (0.09, 0.3) : 0.09, + (0.27, 0.9) : 0.27, + (0.50, 1.8) : 0.5, + (0.90, 2.7) : 0.9, + (1.50, 4.0) : 1.5}) # METALINT.3 Minimum enclosure around via1 on two opposite sides drc["metal3_extend_via2"] = 0.035 # Reserved for asymmetric enclosures @@ -216,7 +228,16 @@ drc["via3_to_via3"] = 0.085 # METALSMG.1 Minimum width of semi-global metal drc["minwidth_metal4"] = 0.14 # METALSMG.2 Minimum spacing of semi-global metal -drc["metal4_to_metal4"] = 0.14 +#drc["metal4_to_metal4"] = 0.14 +# Minimum spacing of metal4 wider than 0.27 & longer than 0.9 = 0.27 +# Minimum spacing of metal4 wider than 0.5 & longer than 1.8 = 0.5 +# Minimum spacing of metal4 wider than 0.9 & longer than 2.7 = 0.9 +# Minimum spacing of metal4 wider than 1.5 & longer than 4.0 = 1.5 +drc["metal4_to_metal4"] = drc_lut({(0.00, 0.0) : 0.14, + (0.27, 0.9) : 0.27, + (0.50, 1.8) : 0.5, + (0.90, 2.7) : 0.9, + (1.50, 4.0) : 1.5}) # METALSMG.3 Minimum enclosure around via[3-6] on two opposite sides drc["metal4_extend_via3"] = 0.0025 # Reserved for asymmetric enclosure diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index e6bf6da1..f1a83f3d 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -1,15 +1,10 @@ import os +from design_rules import * """ File containing the process technology parameters for SCMOS 3me, subm, 180nm. """ -info={} -info["name"]="scn3me_subm" -info["body_tie_down"] = 0 -info["has_pwell"] = True -info["has_nwell"] = True - #GDS file info GDS={} # gds units @@ -59,7 +54,13 @@ parameter["beta"] = 2 drclvs_home=os.environ.get("DRCLVS_HOME") -drc={} +drc = design_rules("scn3me_subm") + +drc["body_tie_down"] = 0 +drc["has_pwell"] = True +drc["has_nwell"] = True + + #grid size is 1/2 a lambda drc["grid"]=0.5*_lambda_ #DRC/LVS test set_up diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index fc7440e1..34b00ec6 100755 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -1,15 +1,10 @@ import os +from design_rules import * """ File containing the process technology parameters for SCMOS 3me, subm, 180nm. """ -info={} -info["name"]="scn3me_subm" -info["body_tie_down"] = 0 -info["has_pwell"] = True -info["has_nwell"] = True - #GDS file info GDS={} # gds units @@ -61,14 +56,19 @@ parameter["beta"] = 2 drclvs_home=os.environ.get("DRCLVS_HOME") -drc={} +drc = design_rules("scn4me_sub") + +drc["body_tie_down"] = 0 +drc["has_pwell"] = True +drc["has_nwell"] = True + #grid size is 1/2 a lambda drc["grid"]=0.5*_lambda_ + #DRC/LVS test set_up drc["drc_rules"]=drclvs_home+"/calibreDRC_scn3me_subm.rul" drc["lvs_rules"]=drclvs_home+"/calibreLVS_scn3me_subm.rul" drc["layer_map"]=os.environ.get("OPENRAM_TECH")+"/scn3me_subm/layers.map" - # minwidth_tx with contact (no dog bone transistors) drc["minwidth_tx"] = 4*_lambda_