def setup_layout_constants(self): """ Determine the design rules for the enclosure layers """ self.contact_width = drc("minwidth_{0}".format(self.via_layer_name)) contact_to_contact = drc("{0}_to_{0}".format(self.via_layer_name)) self.contact_pitch = self.contact_width + contact_to_contact self.contact_array_width = self.contact_width + ( self.dimensions[0] - 1) * self.contact_pitch self.contact_array_height = self.contact_width + ( self.dimensions[1] - 1) * self.contact_pitch # DRC rules # The extend rule applies to asymmetric enclosures in one direction. # The enclosure rule applies to symmetric enclosure component. self.first_layer_minwidth = drc("minwidth_{0}".format( self.first_layer_name)) self.first_layer_enclosure = drc("{0}_enclose_{1}".format( self.first_layer_name, self.via_layer_name)) # If there's a different rule for active # FIXME: Make this more elegant if self.is_well_contact and self.first_layer_name == "active" and "tap_extend_contact" in drc.keys( ): self.first_layer_extend = drc("tap_extend_contact") else: self.first_layer_extend = drc("{0}_extend_{1}".format( self.first_layer_name, self.via_layer_name)) self.second_layer_minwidth = drc("minwidth_{0}".format( self.second_layer_name)) self.second_layer_enclosure = drc("{0}_enclose_{1}".format( self.second_layer_name, self.via_layer_name)) self.second_layer_extend = drc("{0}_extend_{1}".format( self.second_layer_name, self.via_layer_name)) # In some technologies, the minimum width may be larger # than the overlap requirement around the via, so # check this for each dimension. if self.directions[0] == "V": self.first_layer_horizontal_enclosure = max( self.first_layer_enclosure, (self.first_layer_minwidth - self.contact_array_width) / 2) self.first_layer_vertical_enclosure = max( self.first_layer_extend, (self.first_layer_minwidth - self.contact_array_height) / 2) elif self.directions[0] == "H": self.first_layer_horizontal_enclosure = max( self.first_layer_extend, (self.first_layer_minwidth - self.contact_array_width) / 2) self.first_layer_vertical_enclosure = max( self.first_layer_enclosure, (self.first_layer_minwidth - self.contact_array_height) / 2) else: debug.error( "Invalid first layer direction: ".format(self.directions[0]), -1) # In some technologies, the minimum width may be larger # than the overlap requirement around the via, so # check this for each dimension. if self.directions[1] == "V": self.second_layer_horizontal_enclosure = max( self.second_layer_enclosure, (self.second_layer_minwidth - self.contact_array_width) / 2) self.second_layer_vertical_enclosure = max( self.second_layer_extend, (self.second_layer_minwidth - self.contact_array_height) / 2) elif self.directions[1] == "H": self.second_layer_horizontal_enclosure = max( self.second_layer_extend, (self.second_layer_minwidth - self.contact_array_height) / 2) self.second_layer_vertical_enclosure = max( self.second_layer_enclosure, (self.second_layer_minwidth - self.contact_array_width) / 2) else: debug.error( "Invalid secon layer direction: ".format(self.directions[1]), -1)
def setup_drc_constants(self): """ These are some DRC constants used in many places in the compiler. """ # Make some local rules for convenience from tech import drc for rule in drc.keys(): # Single layer width rules match = re.search(r"minwidth_(.*)", rule) if match: if match.group(1) == "active_contact": setattr(self, "contact_width", drc(match.group(0))) else: setattr(self, match.group(1) + "_width", drc(match.group(0))) # Single layer area rules match = re.search(r"minarea_(.*)", rule) if match: setattr(self, match.group(0), drc(match.group(0))) # Single layer spacing rules match = re.search(r"(.*)_to_(.*)", rule) if match and match.group(1) == match.group(2): setattr(self, match.group(1) + "_space", drc(match.group(0))) elif match and match.group(1) != match.group(2): if match.group(2) == "poly_active": setattr(self, match.group(1) + "_to_contact", drc(match.group(0))) else: setattr(self, match.group(0), drc(match.group(0))) match = re.search(r"(.*)_enclose_(.*)", rule) if match: setattr(self, match.group(0), drc(match.group(0))) match = re.search(r"(.*)_extend_(.*)", rule) if match: setattr(self, match.group(0), drc(match.group(0))) # Create the maximum well extend active that gets used # by cells to extend the wells for interaction with other cells from tech import layer self.well_extend_active = 0 if "nwell" in layer: self.well_extend_active = max(self.well_extend_active, self.nwell_extend_active) if "pwell" in layer: self.well_extend_active = max(self.well_extend_active, self.pwell_extend_active) # The active offset is due to the well extension if "pwell" in layer: self.pwell_enclose_active = drc("pwell_enclose_active") else: self.pwell_enclose_active = 0 if "nwell" in layer: self.nwell_enclose_active = drc("nwell_enclose_active") else: self.nwell_enclose_active = 0 # Use the max of either so that the poly gates will align properly self.well_enclose_active = max(self.pwell_enclose_active, self.nwell_enclose_active, self.active_space) # These are for debugging previous manual rules if False: print("poly_width", self.poly_width) print("poly_space", self.poly_space) print("m1_width", self.m1_width) print("m1_space", self.m1_space) print("m2_width", self.m2_width) print("m2_space", self.m2_space) print("m3_width", self.m3_width) print("m3_space", self.m3_space) print("m4_width", self.m4_width) print("m4_space", self.m4_space) print("active_width", self.active_width) print("active_space", self.active_space) print("contact_width", self.contact_width) print("poly_to_active", self.poly_to_active) print("poly_extend_active", self.poly_extend_active) print("poly_to_contact", self.poly_to_contact) print("active_contact_to_gate", self.active_contact_to_gate) print("poly_contact_to_gate", self.poly_contact_to_gate) print("well_enclose_active", self.well_enclose_active) print("implant_enclose_active", self.implant_enclose_active) print("implant_space", self.implant_space) import sys sys.exit(1)