diff --git a/compiler/bank.py b/compiler/bank.py index 89e47abf..dc57bd4f 100644 --- a/compiler/bank.py +++ b/compiler/bank.py @@ -512,10 +512,10 @@ class bank(design.design): bank_sel_line_pos = vector(xoffset_bank_sel + 0.5*self.m2_width, self.min_point) bank_sel_pin_pos=vector(self.left_vdd_x_offset, self.min_point) - self.add_center_layout_pin(text="bank_sel", - layer="metal3", - start=bank_sel_pin_pos, - end=bank_sel_line_pos) + self.add_center_layout_pin_segment(text="bank_sel", + layer="metal3", + start=bank_sel_pin_pos, + end=bank_sel_line_pos) self.add_center_via(layers=("metal2","via2","metal3"), offset=bank_sel_line_pos, rotate=90) @@ -629,10 +629,10 @@ class bank(design.design): offset=logic_pos, rotate=90) - self.add_center_layout_pin(text=input_name, - layer="metal3", - start=input_pos, - end=logic_pos) + self.add_center_layout_pin_segment(text=input_name, + layer="metal3", + start=input_pos, + end=logic_pos) diff --git a/compiler/hierarchy_layout.py b/compiler/hierarchy_layout.py index ae3e6a56..3a817116 100644 --- a/compiler/hierarchy_layout.py +++ b/compiler/hierarchy_layout.py @@ -117,8 +117,23 @@ class layout: return self.objs[-1] return None - def add_center_rect(self, layer, start, end): - """ Add a min-width rectangle from centered on the start and end points""" + def add_center_rect(self, layer, offset, width=0, height=0): + """Adds a rectangle on a given layer at the center point with width and height""" + if width==0: + width=drc["minwidth_{}".format(layer)] + if height==0: + height=drc["minwidth_{}".format(layer)] + # negative layers indicate "unused" layers in a given technology + layerNumber = techlayer[layer] + corrected_offset = offset - vector(0.5*width,0.5*height) + if layerNumber >= 0: + self.objs.append(geometry.rectangle(layerNumber, corrected_offset, width, height)) + return self.objs[-1] + return None + + + def add_center_segment(self, layer, start, end): + """ Add a min-width rectanglular segment using center line on the start to end point """ minwidth_layer = drc["minwidth_{}".format(layer)] if start.x!=end.x and start.y!=end.y: debug.error("Nonrectilinear center rect!",-1) @@ -159,7 +174,7 @@ class layout: new_name = pin.name self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height()) - def add_center_layout_pin(self, text, layer, start, end): + def add_center_layout_pin_segment(self, text, layer, start, end): """ Creates a path like pin with center-line convention """ debug.check(start.x==end.x or start.y==end.y,"Cannot have a non-manhatten layout pin.") @@ -182,7 +197,19 @@ class layout: return self.add_layout_pin(text, layer, ll_offset, width, height) - + + def add_center_layout_pin_rect(self, text, layer, offset, width=None, height=None): + """ Creates a path like pin with center-line convention """ + if width==None: + width=drc["minwidth_{0}".format(layer)] + if height==None: + height=drc["minwidth_{0}".format(layer)] + + ll_offset = offset - vector(0.5*width,0.5*height) + + return self.add_layout_pin(text, layer, ll_offset, width, height) + + def remove_layout_pin(self, text): """Delete a labeled pin (or all pins of the same name)""" self.pin_map[text]=[] @@ -287,11 +314,11 @@ class layout: def add_center_contact(self, layers, offset, size=[1,1], mirror="R0", rotate=0): """ This is just an alias for a via.""" - return self.add_centered_via(layers=layers, - offset=offset, - size=size, - mirror=mirror, - rotate=rotate) + return self.add_center_via(layers=layers, + offset=offset, + size=size, + mirror=mirror, + rotate=rotate) def add_via(self, layers, offset, size=[1,1], mirror="R0", rotate=0): """ Add a three layer via structure. """ diff --git a/compiler/options.py b/compiler/options.py index a40558ad..ef65b4a3 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -13,6 +13,7 @@ class options(optparse.Values): tech_name = "" # This is the temp directory where all intermediate results are stored. openram_temp = "/tmp/openram_{0}_{1}_temp/".format(getpass.getuser(),os.getpid()) + openram_temp = "/Users/mrg/openram_temp/" # This is the verbosity level to control debug information. 0 is none, 1 # is minimal, etc. debug_level = 0 diff --git a/compiler/ptx.py b/compiler/ptx.py index 8a08d119..c91c2602 100644 --- a/compiler/ptx.py +++ b/compiler/ptx.py @@ -8,11 +8,18 @@ import re class ptx(design.design): """ - This module generates gds and spice of a parametrically NMOS or PMOS sized transistor. - Creates a simple MOS transistor. poly_positions are the ll of the poly gate. active_contact_positions - is an array of the positions of the ll of active contacts (left to right) + This module generates gds and spice of a parametrically NMOS or + PMOS sized transistor. Pins are accessed as D, G, S, B. Width is + the transistor width. Mults is the number of transistors of the + given width. Total width is therefore mults*width. Options allow + you to connect the fingered gates and active for parallel devices. + """ def __init__(self, width=drc["minwidth_tx"], mults=1, tx_type="nmos", connect_active=False, connect_poly=False, num_contacts=None): + # We need to keep unique names because outputting to GDSII + # will use the last record with a given name. I.e., you will + # over-write a design in GDS if one has and the other doesn't + # have poly connected, for example. name = "{0}_m{1}_w{2}".format(tx_type, mults, width) if connect_active: name += "_a" @@ -20,22 +27,24 @@ class ptx(design.design): name += "_p" if num_contacts: name += "_c{}".format(num_contacts) - name=re.sub('\.','_',name) # remove periods for newer spice compatibility + # replace periods with underscore for newer spice compatibility + name=re.sub('\.','_',name) design.design.__init__(self, name) - debug.info(3, "create ptx structure {0}".format(name)) + debug.info(3, "create ptx2 structure {0}".format(name)) self.tx_type = tx_type self.mults = mults - self.gate_width = width + self.tx_width = width self.connect_active = connect_active self.connect_poly = connect_poly self.num_contacts = num_contacts self.add_pins() - self.create_layout() self.create_spice() + self.create_layout() # for run-time, we won't check every transitor DRC independently + # but this may be uncommented for debug purposes #self.DRC() def add_pins(self): @@ -43,27 +52,14 @@ class ptx(design.design): def create_layout(self): self.setup_layout_constants() - - if self.num_contacts==None: - self.num_contacts=self.calculate_num_contacts() - - # This is not actually instantiated but used for calculations - self.active_contact = contact(layer_stack=("active", "contact", "metal1"), - dimensions=(1, self.num_contacts)) - self.add_active() - self.add_implants() + self.add_well_implant() self.add_poly() self.add_active_contacts() # offset this BEFORE we add the active/poly connections - self.offset_all_coordinates() + #self.offset_all_coordinates() - if self.connect_active: - self.connect_fingered_active() - if self.connect_poly: - self.connect_fingered_poly() - def offset_attributes(self, coordinate): """Translates all stored 2d cartesian coordinates within the attr dictionary""" @@ -95,17 +91,17 @@ class ptx(design.design): if isinstance(attr_val, vector): setattr(self, attr_key, vector(attr_val - coordinate)) - def offset_all_coordinates(self): - offset = self.find_lowest_coords() - self.offset_attributes(offset) - self.translate_all(offset) + # def offset_all_coordinates(self): + # offset = self.find_lowest_coords() + # self.offset_attributes(offset) + # self.translate_all(offset) - # We can do this in ptx because we have offset all modules it uses. - # Is this really true considering the paths that connect the src/drain? - self.height = max(max(obj.offset.y + obj.height for obj in self.objs), - max(inst.offset.y + inst.mod.height for inst in self.insts)) - self.width = max(max(obj.offset.x + obj.width for obj in self.objs), - max(inst.offset.x + inst.mod.width for inst in self.insts)) + # # We can do this in ptx because we have offset all modules it uses. + # # Is this really true considering the paths that connect the src/drain? + # self.height = max(max(obj.offset.y + obj.height for obj in self.objs), + # max(inst.offset.y + inst.mod.height for inst in self.insts)) + # self.width = max(max(obj.offset.x + obj.width for obj in self.objs), + # max(inst.offset.x + inst.mod.width for inst in self.insts)) def create_spice(self): self.spice.append("\n.SUBCKT {0} {1}".format(self.name, @@ -114,60 +110,109 @@ class ptx(design.design): " ".join(self.pins), spice[self.tx_type], self.mults, - self.gate_width, + self.tx_width, drc["minwidth_poly"])) self.spice.append(".ENDS {0}".format(self.name)) def setup_layout_constants(self): - # usually contacted poly will limit the spacing, but it could be poly - # spacing in some weird technology. - self.mults_poly_to_poly = max(2 * drc["contact_to_poly"] + drc["minwidth_contact"], - drc["poly_to_poly"]) - outeractive_to_contact = max(drc["active_enclosure_contact"], - (drc["minwidth_active"] - drc["minwidth_contact"]) / 2) - self.active_width = (2 * (outeractive_to_contact + drc["minwidth_contact"] - + drc["contact_to_poly"]) - + drc["minwidth_poly"] - + (self.mults - 1) * (self.mults_poly_to_poly - + drc["minwidth_poly"])) - self.active_height = max(drc["minarea_active"] / self.active_width, - self.gate_width) - self.poly_width = drc["minwidth_poly"] # horizontal - self.poly_height = max(drc["minarea_poly"] / self.poly_width, - self.gate_width - + 2 * drc["poly_extend_active"]) # vertical - self.well_width = (self.active_width - + 2 * (drc["well_enclosure_active"])) - self.well_height = max(self.gate_width + 2 * (drc["well_enclosure_active"]), + """ + Pre-compute some handy layout parameters. + """ + + if self.num_contacts==None: + self.num_contacts=self.calculate_num_contacts() + + # This is not actually instantiated but used for calculations + self.active_contact = contact(layer_stack=("active", "contact", "metal1"), + dimensions=(1, self.num_contacts)) + + # Standard DRC rules + self.active_width = drc["minwidth_active"] + self.contact_width = drc["minwidth_contact"] + self.poly_width = drc["minwidth_poly"] + self.poly_to_active = drc["poly_to_active"] + self.poly_extend_active = drc["poly_extend_active"] + + # The contacted poly pitch (or uncontacted in an odd technology) + self.poly_pitch = max(2*drc["contact_to_poly"] + self.contact_width + self.poly_width, + drc["poly_to_poly"]) + + # The contacted poly pitch (or uncontacted in an odd technology) + self.contact_pitch = 2*drc["contact_to_poly"] + self.contact_width + self.poly_width + + # The enclosure of an active contact. Not sure about second term. + active_enclose_contact = max(drc["active_enclosure_contact"], + (self.active_width - self.contact_width)/2) + # This is the distance from the edge of poly to the contacted end of active + self.end_to_poly = active_enclose_contact + self.contact_width + drc["contact_to_poly"] + + + # Active width is determined by enclosure on both ends and contacted pitch, + # at least one poly and n-1 poly pitches + self.active_width = 2*self.end_to_poly + self.poly_width + (self.mults - 1)*self.poly_pitch + + # Active height is just the transistor width + self.active_height = self.tx_width + + # Poly height must include poly extension over active + self.poly_height = self.tx_width + 2*self.poly_extend_active + + # Well enclosure of active, ensure minwidth as well + self.well_width = max(self.active_width + 2*drc["well_enclosure_active"], + drc["minwidth_well"]) + self.well_height = max(self.tx_width + 2*drc["well_enclosure_active"], drc["minwidth_well"]) + # The active offset is due to the well extension + self.active_offset = vector([drc["well_enclosure_active"]]*2) - def connect_fingered_poly(self): - poly_connect_length = self.poly_positions[-1].x + self.poly_width \ - - self.poly_positions[0].x - poly_connect_position = self.poly_positions[0] - vector(0, self.poly_width) - if len(self.poly_positions) > 1: - self.remove_layout_pin("G") # only keep the main pin - self.add_layout_pin(text="G", - layer="poly", - offset=poly_connect_position, - width=poly_connect_length, - height=drc["minwidth_poly"]) + # This is the center of the first active contact offset (centered vertically) + self.contact_offset = self.active_offset + vector(active_enclose_contact + 0.5*self.contact_width, + 0.5*self.active_height) + + + # Min area results are just flagged for now. + debug.check(self.active_width*self.active_height>=drc["minarea_active"],"Minimum active area violated.") + # We do not want to increase the poly dimensions to fix an area problem as it would cause an LVS issue. + debug.check(self.poly_width*self.poly_height>=drc["minarea_poly"],"Minimum poly area violated.") + + def connect_fingered_poly(self, poly_positions): + """ + Connect together the poly gates and create the single gate pin. + The poly positions are the center of the poly gates + and we will add a single horizontal connection. + """ + # Nothing to do if there's one poly gate + if len(poly_positions) == 1: + return + + # The width of the poly is from the left-most to right-most poly gate + poly_width = poly_positions[-1].x - poly_positions[0].x + self.poly_width + # This can be limited by poly to active spacing or the poly extension + distance_below_active = self.poly_width + max(self.poly_to_active,0.5*self.poly_height) + poly_offset = poly_positions[0] - vector(0.5*self.poly_width, distance_below_active) + + # Remove the old pin and add the new one + self.remove_layout_pin("G") # only keep the main pin + self.add_layout_pin(text="G", + layer="poly", + offset=poly_offset, + width=poly_width, + height=drc["minwidth_poly"]) - self.poly_connect_index = len(self.objs) - 1 def pairwise(self, iterable): - #"s -> (s0,s1), (s1,s2), (s2, s3), ..." + """ + Create an iterable set of pairs from a set: + "s -> (s0,s1), (s1,s2), (s2, s3), ..." + """ from itertools import tee, izip a, b = tee(iterable) next(b, None) return izip(a, b) - def determine_active_wire_location(self): - self.determine_source_wire() - self.determine_drain_wire() def determine_source_wire(self): self.source_positions = [] @@ -185,13 +230,14 @@ class ptx(design.design): connected.y + 0.5 * drc["minwidth_metal2"])) self.source_positions.append(b + correct) - def determine_drain_wire(self): - self.drain_positions = [] - drain_contact_pos = self.active_contact_positions[1:][::2] # odd indexes + return source_positions + + def determine_drain_wire(self, contact_positions): + drain_positions = [] + drain_contact_pos = contact_positions[1:][::2] # odd indexes for c, d in self.pairwise(drain_contact_pos): correct = vector(0.5*(self.active_contact.width - - drc["minwidth_metal1"] - + drc["minwidth_contact"]), + - drc["minwidth_metal1"] + drc["minwidth_contact"]), 0.5*(self.active_contact.height - drc["minwidth_contact"]) - drc["metal1_extend_contact"]) connected = vector(d.x + drc["minwidth_metal1"], c.y - drc["metal1_to_metal1"]) @@ -201,194 +247,185 @@ class ptx(design.design): connected.y - 0.5 * drc["minwidth_metal1"])) self.drain_positions.append(vector(d + correct)) - def connect_fingered_active(self): - self.determine_active_wire_location() - # allows one to connect the source and drains - self.source_connect_index = None - if self.source_positions: + return drain_positions + + + def connect_fingered_active(self, drain_positions, source_positions): + """ + Connect each contact up/down to a source or drain pin + """ + + # This is the distance that we must route up or down from the center + # of the contacts to avoid DRC violations to the other contacts + pin_offset = vector(0, 0.5*self.active_contact.second_layer_height \ + + drc["metal1_to_metal1"] + 0.5*drc["minwidth_metal1"]) + # This is the width of a contact to extend the ends of the pin + end_offset = vector(self.active_contact.second_layer_width/2,0) + + if source_positions: # if not an empty set self.remove_layout_pin("S") # remove the individual connections - self.source_positions = path.create_rectilinear_route(self.source_positions) - self.add_path(("metal1"), self.source_positions) - # The source positions are odd since the second one is always redundant - # so we must use the THIRD one - self.add_center_layout_pin(text="S", - layer="metal1", - start=self.source_positions[2]-vector(0.5*drc["minwidth_metal1"],0), - end=self.source_positions[-2]+vector(0.5*drc["minwidth_metal1"],0)) - self.source_connect_index = len(self.insts) - 1 - self.drain_connect_index = None - if self.drain_positions: + # Add each vertical segment + for a in source_positions: + self.add_path(("metal1"), [a,a+pin_offset]) + # Add a single horizontal pin + self.add_center_layout_pin_segment(text="S", + layer="metal1", + start=source_positions[0]+pin_offset-end_offset, + end=source_positions[-1]+pin_offset+end_offset) + + if drain_positions: # if not an empty set self.remove_layout_pin("D") # remove the individual connections - self.drain_positions = path.create_rectilinear_route(self.drain_positions) - self.add_path(("metal1"), self.drain_positions) - # The source positions are odd since the second one is always redundant - # so we must use the THIRD one - self.add_center_layout_pin(text="D", - layer="metal1", - start=self.drain_positions[2]-vector(0.5*drc["minwidth_metal1"],0), - end=self.drain_positions[-2]+vector(0.5*drc["minwidth_metal1"],0)) - self.drain_connect_index = len(self.insts) - 1 + # Add each vertical segment + for a in drain_positions: + self.add_path(("metal1"), [a,a-pin_offset]) + # Add a single horizontal pin + self.add_center_layout_pin_segment(text="D", + layer="metal1", + start=drain_positions[0]-pin_offset-end_offset, + end=drain_positions[-1]-pin_offset+end_offset) def add_poly(self): - # left_most poly - poly_xoffset = self.active_contact.via_layer_position.x \ - + drc["minwidth_contact"] + drc["contact_to_poly"] - poly_yoffset = -drc["poly_extend_active"] - self.poly_positions = [] - # following poly(s) + """ + Add the poly gates(s) and (optionally) connect them. + """ + # poly is one contacted spacing from the end and down an extension + poly_offset = vector(self.active_offset.x + self.end_to_poly + 0.5*self.poly_width,0.5*self.poly_height) + + # poly_positions are the bottom center of the poly gates + poly_positions = [] + for i in range(0, self.mults): if self.connect_poly: # Add the rectangle in case we remove the pin when joining fingers - self.add_rect(layer="poly", - offset=[poly_xoffset, poly_yoffset], - width=self.poly_width, - height=self.poly_height) + self.add_center_rect(layer="poly", + offset=poly_offset, + height=self.poly_height, + width=self.poly_width) else: - self.add_layout_pin(text="G", - layer="poly", - offset=[poly_xoffset, poly_yoffset], - width=self.poly_width, - height=self.poly_height) - self.poly_positions.append(vector(poly_xoffset, poly_yoffset)) - poly_xoffset += self.mults_poly_to_poly + drc["minwidth_poly"] + self.add_center_layout_pin_rect(text="G", + layer="poly", + offset=poly_offset, + height=self.poly_height, + width=self.poly_width) + poly_positions.append(poly_offset) + poly_offset = poly_offset + vector(self.poly_pitch,0) + if self.connect_poly: + self.connect_fingered_poly(poly_positions) + def add_active(self): - """Adding the diffusion (active region = diffusion region)""" - offset = self.active_position = [0, 0] + """ + Adding the diffusion (active region = diffusion region) + """ self.add_rect(layer="active", - offset=offset, + offset=self.active_offset, width=self.active_width, height=self.active_height) - def add_implants(self): + def add_well_implant(self): + """ + Add an (optional) well and implant for the type of transistor. + """ if self.tx_type == "nmos": - self.add_nmos_implants() + implant_type = "n" + well_type = "p" elif self.tx_type == "pmos": - self.add_pmos_implants() - - def add_nmos_implants(self): - offset = self.pwell_position = [-drc["well_enclosure_active"], -drc["well_enclosure_active"]] - if info["has_pwell"]: - self.add_rect(layer="pwell", - offset=offset, + implant_type = "p" + well_type = "n" + else: + self.error("Invalid transitor type.",-1) + + if info["has_{}well".format(well_type)]: + self.add_rect(layer="{}well".format(well_type), + offset=(0,0), width=self.well_width, height=self.well_height) self.add_rect(layer="vtg", - offset=offset, + offset=(0,0), width=self.well_width, height=self.well_height) - xlength = self.active_width - ylength = self.active_height - self.add_rect(layer="nimplant", - offset=self.active_position, - width=xlength, - height=ylength) + self.add_rect(layer="{}implant".format(implant_type), + offset=self.active_offset, + width=self.active_width, + height=self.active_height) - def add_pmos_implants(self): - offset = self.nwell_position = [-drc["well_enclosure_active"], -drc["well_enclosure_active"]] - if info["has_nwell"]: - self.add_rect(layer="nwell", - offset=offset, - width=self.well_width, - height=self.well_height) - self.add_rect(layer="vtg", - offset=offset, - width=self.well_width, - height=self.well_height) - xlength = self.active_width - ylength = self.active_height - self.add_rect(layer="pimplant", - offset=self.active_position, - width=xlength, - height=ylength) def calculate_num_contacts(self): - """ Calculates the possible number of source/drain contacts in a column """ - # Used for over-riding the contact dimensions - possible_length = self.active_height - 2 * drc["active_extend_contact"] - y = 1 - while True: - temp_length = (y * drc["minwidth_contact"]) + ((y - 1) * drc["contact_to_contact"]) - if round(possible_length - temp_length, 6) < 0: - return y - 1 - y += 1 + """ + Calculates the possible number of source/drain contacts in a finger. + For now, it is hard set as 1. + """ + return 1 + + def get_contact_positions(self): + """ + Create a list of the centers of drain and source contact positions. + """ + # The first one will always be a source + source_positions = [self.contact_offset] + drain_positions = [] + + # For all but the last finger... + for i in range(self.mults-1): + if i%2: + # It's a source... so offset from previous drain. + source_positions.append(drain_positions[-1] + vector(self.contact_pitch,0)) + else: + # It's a drain... so offset from previous source. + drain_positions.append(source_positions[-1] + vector(self.contact_pitch,0)) + + # The last one will always be a drain + drain_positions.append(source_positions[-1] + vector(self.contact_pitch,0)) + + return [source_positions,drain_positions] + def add_active_contacts(self): - self.active_contact_positions = [] + """ + Add the active contacts to the transistor. + """ - # left_most contact column - contact_xoffset = 0 - contact_yoffset = (self.active_height - self.active_contact.height) / 2 - offset = vector(contact_xoffset, contact_yoffset) - contact=self.add_contact(layers=("active", "contact", "metal1"), - offset=offset, - size=(1, self.num_contacts)) - # source are even - if self.connect_active: - # Add this in case the pins get removed when fingers joined - self.add_rect(layer="metal1", - offset=offset+contact.second_layer_position, - width=contact.second_layer_width, - height=contact.second_layer_height) - else: - self.add_layout_pin(text="S", - layer="metal1", - offset=offset+contact.second_layer_position, - width=contact.second_layer_width, - height=contact.second_layer_height) - self.active_contact_positions.append(offset) + [source_positions,drain_positions] = self.get_contact_positions() - # middle contact columns - for i in range(self.mults - 1): - contact_xoffset = self.poly_positions[i].x + self.poly_width \ - + (self.mults_poly_to_poly / 2) \ - - (drc["minwidth_contact"] / 2) - \ - self.active_contact.via_layer_position.x - offset = vector(contact_xoffset, contact_yoffset) - contact=self.add_contact(layers=("active", "contact", "metal1"), - offset=offset, - size=(1, self.num_contacts)) - # source are even, drain are odd + for pos in source_positions: + contact=self.add_center_contact(layers=("active", "contact", "metal1"), + offset=pos, + size=(1, self.num_contacts)) if self.connect_active: # Add this in case the pins get removed when fingers joined - self.add_rect(layer="metal1", - offset=offset+contact.second_layer_position, - width=contact.second_layer_width, - height=contact.second_layer_height) + self.add_center_rect(layer="metal1", + offset=pos, + width=contact.second_layer_width, + height=contact.second_layer_height) else: - name = "S" if i%2==1 else "D" - self.add_layout_pin(text=name, - layer="metal1", - offset=offset+contact.second_layer_position, - width=contact.second_layer_width, - height=contact.second_layer_height) + self.add_center_layout_pin_rect(text="S", + layer="metal1", + offset=pos, + width=contact.second_layer_width, + height=contact.second_layer_height) - self.active_contact_positions.append(offset) - - # right_most contact column - contact_xoffset = self.poly_positions[-1].x \ - + self.poly_width + drc["contact_to_poly"] - \ - self.active_contact.via_layer_position.x - offset = vector(contact_xoffset, contact_yoffset) - contact=self.add_contact(layers=("active", "contact", "metal1"), - offset=offset, - size=(1, self.num_contacts)) - # source are even, drain are odd + + for pos in drain_positions: + contact=self.add_center_contact(layers=("active", "contact", "metal1"), + offset=pos, + size=(1, self.num_contacts)) + if self.connect_active: + # Add this in case the pins get removed when fingers joined + self.add_center_rect(layer="metal1", + offset=pos, + width=contact.second_layer_width, + height=contact.second_layer_height) + else: + self.add_center_layout_pin_rect(text="D", + layer="metal1", + offset=pos, + width=contact.second_layer_width, + height=contact.second_layer_height) + if self.connect_active: - self.add_rect(layer="metal1", - offset=offset+contact.second_layer_position, - width=contact.second_layer_width, - height=contact.second_layer_height) - else: - name = "D" if self.mults%2==1 else "S" - self.add_layout_pin(text=name, - layer="metal1", - offset=offset+contact.second_layer_position, - width=contact.second_layer_width, - height=contact.second_layer_height) - # Add this in case the pins get removed when fingers joined - self.active_contact_positions.append(offset) + self.connect_fingered_active(drain_positions, source_positions) + # def remove_drain_connect(self): # debug.info(3,"Removing drain on {}".format(self.name)) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index 97044bc2..966266a4 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -65,7 +65,7 @@ def run_drc(name, gds_name): implemented in gds_name.""" debug.warning("DRC using magic not implemented.") - return 0 + return 1 # the runset file contains all the options to run drc from tech import drc @@ -139,7 +139,7 @@ def run_lvs(name, gds_name, sp_name): implemented in gds_name and sp_name. """ debug.warning("LVS using magic+netgen not implemented.") - return 0 + return 1 from tech import drc lvs_rules = drc["lvs_rules"] diff --git a/compiler/wordline_driver.py b/compiler/wordline_driver.py index 69ff291d..892f705d 100644 --- a/compiler/wordline_driver.py +++ b/compiler/wordline_driver.py @@ -141,9 +141,9 @@ class wordline_driver(design.design): a_pin = inv1_inst.get_pin("A") a_pos = a_pin.lc() clk_offset = vector(en_pin.bc().x,a_pos.y) - self.add_center_rect(layer="metal1", - start=clk_offset, - end=a_pos) + self.add_center_segment(layer="metal1", + start=clk_offset, + end=a_pos) m1m2_via = self.add_center_via(layers=("metal1", "via1", "metal2"), offset=clk_offset) @@ -167,17 +167,17 @@ class wordline_driver(design.design): input_offset = vector(0,a_pos.y) mid_via_offset = vector(clk_offset.x,a_pos.y) + vector(0.5*drc["minwidth_metal2"]+drc["metal2_to_metal2"]+0.5*m1m2_via.width,0) # must under the clk line in M1 - self.add_center_layout_pin(text="in[{0}]".format(row), - layer="metal1", - start=input_offset, - end=mid_via_offset) + self.add_center_layout_pin_segment(text="in[{0}]".format(row), + layer="metal1", + start=input_offset, + end=mid_via_offset) self.add_center_via(layers=("metal1", "via1", "metal2"), offset=mid_via_offset) # now connect to the nand2 A - self.add_center_rect(layer="metal2", - start=mid_via_offset, - end=a_pos) + self.add_center_segment(layer="metal2", + start=mid_via_offset, + end=a_pos) self.add_center_via(layers=("metal1", "via1", "metal2"), offset=a_pos + vector(0.5*m1m2_via.height,0), rotate=90) @@ -185,10 +185,10 @@ class wordline_driver(design.design): # output each WL on the right wl_offset = inv2_inst.get_pin("Z").rc() - self.add_center_layout_pin(text="wl[{0}]".format(row), - layer="metal1", - start=wl_offset, - end=wl_offset-vector(drc["minwidth_metal1"],0)) + self.add_center_layout_pin_segment(text="wl[{0}]".format(row), + layer="metal1", + start=wl_offset, + end=wl_offset-vector(drc["minwidth_metal1"],0)) def analytical_delay(self, slew, load=0): diff --git a/technology/scn3me_subm/tech/tech.py b/technology/scn3me_subm/tech/tech.py index fda5d462..a33084c3 100755 --- a/technology/scn3me_subm/tech/tech.py +++ b/technology/scn3me_subm/tech/tech.py @@ -95,7 +95,7 @@ drc["active_to_active"] = 0.9 drc["well_enclosure_active"] = 1.8 drc["well_extend_active"] = 1.8 -#Implant (None in IBM) +#Implant drc["implant_to_gate"] = 0 drc["implant_to_channel"] = 0 drc["implant_to_contact"] = 0