diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index caf8d02b..bfb1c2d2 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -68,8 +68,10 @@ class layout(): return (base_offset, y_dir) def find_lowest_coords(self): - """Finds the lowest set of 2d cartesian coordinates within - this layout""" + """ + Finds the lowest set of 2d cartesian coordinates within + this layout + """ if len(self.objs) > 0: lowestx1 = min(obj.lx() for obj in self.objs if obj.name != "label") @@ -116,6 +118,54 @@ class layout(): return vector(max(highestx1, highestx2), max(highesty1, highesty2)) + def find_highest_layer_coords(self, layer): + """ + Finds the highest set of 2d cartesian coordinates within + this layout on a layer + """ + # Only consider the layer not the purpose for now + layerNumber = techlayer[layer][0] + try: + highestx = max(obj.rx() for obj in self.objs if obj.layerNumber == layerNumber) + except ValueError: + highestx =0 + try: + highesty = max(obj.uy() for obj in self.objs if obj.layerNumber == layerNumber) + except ValueError: + highesty = 0 + + for inst in self.insts: + # This really should be rotated/mirrored etc... + subcoord = inst.mod.find_highest_layer_coords(layer) + inst.offset + highestx = max(highestx, subcoord.x) + highesty = max(highesty, subcoord.y) + + return vector(highestx, highesty) + + def find_lowest_layer_coords(self, layer): + """ + Finds the highest set of 2d cartesian coordinates within + this layout on a layer + """ + # Only consider the layer not the purpose for now + layerNumber = techlayer[layer][0] + try: + lowestx = min(obj.lx() for obj in self.objs if obj.layerNumber == layerNumber) + except ValueError: + lowestx = 0 + try: + lowesty = min(obj.by() for obj in self.objs if obj.layerNumber == layerNumber) + except ValueError: + lowesty = 0 + + for inst in self.insts: + # This really should be rotated/mirrored etc... + subcoord = inst.mod.find_lowest_layer_coords(layer) + inst.offset + lowestx = min(lowestx, subcoord.x) + lowesty = min(lowesty, subcoord.y) + + return vector(lowestx, lowesty) + def translate_all(self, offset): """ Translates all objects, instances, and pins by the given (x,y) offset @@ -429,7 +479,7 @@ class layout(): return inst def add_via_center(self, layers, offset, directions=None, size=[1,1], implant_type=None, well_type=None): - """ + """ Add a three layer via structure by the center coordinate accounting for mirroring and rotation. """ @@ -466,7 +516,7 @@ class layout(): mults=mults, tx_type=tx_type) self.add_mod(mos) - inst = self.add_inst(name=mos.name, + inst = self.add_inst(name=mos.name, mod=mos, offset=offset, mirror=mirror, @@ -652,22 +702,21 @@ class layout(): vertical=False, make_pins=False) - def create_bus(self, layer, pitch, offset, names, length, vertical, make_pins): """ Create a horizontal or vertical bus. It can be either just rectangles, or actual - layout pins. It returns an map of line center line positions indexed by name. + layout pins. It returns an map of line center line positions indexed by name. The other coordinate is a 0 since the bus provides a range. TODO: combine with channel router. """ # half minwidth so we can return the center line offsets - half_minwidth = 0.5*drc["minwidth_{}".format(layer)] + half_minwidth = 0.5 * drc["minwidth_{}".format(layer)] line_positions = {} if vertical: for i in range(len(names)): - line_offset = offset + vector(i*pitch,0) + line_offset = offset + vector(i * pitch, 0) if make_pins: self.add_layout_pin(text=names[i], layer=layer, @@ -885,7 +934,7 @@ class layout(): return g def vcg_nets_overlap(net1, net2, vertical, pitch): - """ + """ Check all the pin pairs on two nets and return a pin overlap if any pin overlaps. """ diff --git a/compiler/bitcells/pbitcell.py b/compiler/bitcells/pbitcell.py index d809c6f1..6de87507 100644 --- a/compiler/bitcells/pbitcell.py +++ b/compiler/bitcells/pbitcell.py @@ -977,12 +977,12 @@ class pbitcell(bitcell_base.bitcell_base): """ # extend pwell to encompass entire nmos region of the cell up to the # height of the tallest nmos transistor - max_nmos_well_height = max(self.inverter_nmos.cell_well_height, - self.readwrite_nmos.cell_well_height, - self.write_nmos.cell_well_height, - self.read_nmos.cell_well_height) + max_nmos_well_height = max(self.inverter_nmos.well_height, + self.readwrite_nmos.well_height, + self.write_nmos.well_height, + self.read_nmos.well_height) well_height = max_nmos_well_height + self.port_ypos \ - - self.well_enclose_active - self.gnd_position.y + - self.nwell_enclose_active - self.gnd_position.y offset = vector(self.leftmost_xpos, self.botmost_ypos) self.add_rect(layer="pwell", offset=offset, @@ -992,16 +992,16 @@ class pbitcell(bitcell_base.bitcell_base): # extend nwell to encompass inverter_pmos # calculate offset of the left pmos well inverter_well_xpos = -(self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \ - - self.well_enclose_active + - self.nwell_enclose_active inverter_well_ypos = self.inverter_nmos_ypos + self.inverter_nmos.active_height \ - + self.inverter_gap - self.well_enclose_active + + self.inverter_gap - self.nwell_enclose_active # calculate width of the two combined nwells # calculate height to encompass nimplant connected to vdd well_width = 2 * (self.inverter_nmos.active_width + 0.5 * self.inverter_to_inverter_spacing) \ - + 2 * self.well_enclose_active + + 2 * self.nwell_enclose_active well_height = self.vdd_position.y - inverter_well_ypos \ - + self.well_enclose_active + drc["minwidth_tx"] + + self.nwell_enclose_active + drc["minwidth_tx"] offset = [inverter_well_xpos, inverter_well_ypos] self.add_rect(layer="nwell", diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 4527044c..7ed0c9a3 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -333,7 +333,7 @@ class bank(design.design): self.col_addr_bus_width = self.m2_pitch*self.num_col_addr_lines # A space for wells or jogging m2 - self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclose_active"), + self.m2_gap = max(2*drc("pwell_to_nwell") + drc("nwell_enclose_active"), 3*self.m2_pitch) diff --git a/compiler/modules/port_address.py b/compiler/modules/port_address.py index 7f1fdd49..44b0d5a5 100644 --- a/compiler/modules/port_address.py +++ b/compiler/modules/port_address.py @@ -149,7 +149,7 @@ class port_address(design.design): """ # A space for wells or jogging m2 - self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclose_active"), + self.m2_gap = max(2*drc("pwell_to_nwell") + drc("nwell_enclose_active"), 3*self.m2_pitch) row_decoder_offset = vector(0,0) diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 33ecdd01..9e7f4048 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -212,7 +212,7 @@ class port_data(design.design): # A space for wells or jogging m2 between modules - self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclose_active"), + self.m2_gap = max(2*drc("pwell_to_nwell") + drc("nwell_enclose_active"), 3*self.m2_pitch) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index 7e1fc87f..a964cbe4 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -8,7 +8,7 @@ import contact import design import debug -from tech import layer, drc +from tech import layer from vector import vector from globals import OPTS from sram_factory import factory @@ -127,9 +127,10 @@ class pgate(design.design): """ Extend the n/p wells to cover whole cell """ # Add a rail width to extend the well to the top of the rail - max_y_offset = self.height + 0.5 * self.m1_width - self.nwell_position = middle_position - nwell_height = max_y_offset - middle_position.y + nwell_max_offset = max(self.find_highest_layer_coords("nwell").y, + self.height + 0.5 * self.m1_width) + nwell_position = middle_position + nwell_height = nwell_max_offset - middle_position.y if "nwell" in layer: self.add_rect(layer="nwell", offset=middle_position, @@ -137,11 +138,14 @@ class pgate(design.design): height=nwell_height) if "vtg" in layer: self.add_rect(layer="vtg", - offset=self.nwell_position, + offset=nwell_position, width=self.well_width, height=nwell_height) - pwell_position = vector(0, -0.5 * self.m1_width) + # Start this half a rail width below the cell + pwell_min_offset = min(self.find_lowest_layer_coords("pwell").y, + -0.5 * self.m1_width) + pwell_position = vector(0, pwell_min_offset) pwell_height = middle_position.y - pwell_position.y if "pwell" in layer: self.add_rect(layer="pwell", @@ -168,7 +172,7 @@ class pgate(design.design): # OR align the active with the top of PMOS active. max_y_offset = self.height + 0.5 * self.m1_width contact_yoffset = min(pmos_pos.y + pmos.active_height - pmos.active_contact.first_layer_height, - max_y_offset - pmos.active_contact.first_layer_height / 2 - self.well_enclose_active) + max_y_offset - pmos.active_contact.first_layer_height / 2 - self.nwell_enclose_active) contact_offset = vector(contact_xoffset, contact_yoffset) # Offset by half a contact in x and y contact_offset += vector(0.5 * pmos.active_contact.first_layer_width, @@ -220,7 +224,7 @@ class pgate(design.design): # Must be at least an well enclosure of active up # from the bottom of the well contact_yoffset = max(nmos_pos.y, - self.well_enclose_active \ + self.nwell_enclose_active \ - nmos.active_contact.first_layer_height / 2) contact_offset = vector(contact_xoffset, contact_yoffset) diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index ce477a83..8a3a8326 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -153,7 +153,7 @@ class pinv(pgate.pgate): # the well width is determined the multi-finger PMOS device width plus # the well contact width and half well enclosure on both sides self.well_width = self.pmos.active_width + self.pmos.active_contact.width \ - + self.active_space + 2*self.well_enclose_active + + self.active_space + 2*self.nwell_enclose_active self.width = self.well_width # Height is an input parameter, so it is not recomputed. @@ -223,7 +223,7 @@ class pinv(pgate.pgate): self.output_pos = vector(0, 0.5 * (pmos_drain_pos.y + nmos_drain_pos.y)) # This will help with the wells - self.well_pos = vector(0, self.nmos_inst.uy()) + self.well_pos = self.output_pos def route_outputs(self): """ diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index dda736d2..8d3605a2 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -100,7 +100,7 @@ class pnand2(pgate.pgate): # Enclosure space on the sides. self.well_width = 2 * self.pmos.active_width + contact.activem1.width \ + 2 * self.active_space \ - + 2 * self.well_enclose_active + + 2 * self.nwell_enclose_active self.width = self.well_width # Height is an input parameter, so it is not recomputed. @@ -171,7 +171,7 @@ class pnand2(pgate.pgate): 0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos.active_height)) # This will help with the wells - self.well_pos = vector(0, self.nmos1_inst.uy()) + self.well_pos = self.output_pos def add_well_contacts(self): """ diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 8ccbff2c..bb379db7 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -92,14 +92,11 @@ class pnand3(pgate.pgate): # Two PMOS devices and a well contact. Separation between each. # Enclosure space on the sides. self.well_width = 3 * self.pmos.active_width + self.pmos.active_contact.width \ - + 2 * self.active_space + 2 * self.well_enclose_active \ + + 2 * self.active_space + 2 * self.nwell_enclose_active \ - self.overlap_offset.x self.width = self.well_width # Height is an input parameter, so it is not recomputed. - # This will help with the wells and the input/output placement - self.output_pos = vector(0, 0.5*self.height) - # This is the extra space needed to ensure DRC rules # to the active contacts nmos = factory.create(module_type="ptx", tx_type="nmos") @@ -178,9 +175,12 @@ class pnand3(pgate.pgate): self.nmos3_pos = nmos2_pos + self.overlap_offset self.nmos3_inst.place(self.nmos3_pos) - + + # This will help with the wells and the input/output placement + self.output_pos = vector(0, 0.5*self.height) + # This should be placed at the top of the NMOS well - self.well_pos = vector(0, self.nmos1_inst.uy()) + self.well_pos = self.output_pos def add_well_contacts(self): """ Add n/p well taps to the layout and connect to supplies """ diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index d24189ac..9895e9d9 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -98,7 +98,7 @@ class pnor2(pgate.pgate): self.well_width = 2 * self.pmos.active_width \ + self.pmos.active_contact.width \ + 2 * self.active_space \ - + 2 * self.well_enclose_active + + 2 * self.nwell_enclose_active self.width = self.well_width # Height is an input parameter, so it is not recomputed. @@ -136,7 +136,6 @@ class pnor2(pgate.pgate): mod=self.pmos) self.connect_inst(["net1", "B", "Z", "vdd"]) - self.nmos1_inst = self.add_inst(name="pnor2_nmos1", mod=self.nmos) self.connect_inst(["Z", "A", "gnd", "gnd"]) @@ -170,7 +169,7 @@ class pnor2(pgate.pgate): 0.5 * (pmos1_pos.y + nmos1_pos.y + self.nmos.active_height)) # This will help with the wells - self.well_pos = vector(0, self.nmos1_inst.uy()) + self.well_pos = self.output_pos def add_well_contacts(self): """ Add n/p well taps to the layout and connect to supplies """ diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index f9e8ce87..d1e2f3af 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -116,7 +116,7 @@ class precharge(design.design): # adds the lower pmos to layout bl_xoffset = self.bitcell.get_pin(self.bitcell_bl).lx() self.lower_pmos_position = vector(max(bl_xoffset - contact_xdiff, - self.well_enclose_active), + self.nwell_enclose_active), self.pmos.active_offset.y) self.lower_pmos_inst.place(self.lower_pmos_position) @@ -176,7 +176,7 @@ class precharge(design.design): # adds the contact from active to metal1 well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1, 0) \ + vector(0, self.upper_pmos1_inst.uy() + contact.activem1.height / 2 \ - + self.well_extend_active) + + self.nwell_extend_active) self.add_via_center(layers=self.active_stack, offset=well_contact_pos, implant_type="n", diff --git a/compiler/pgates/ptristate_inv.py b/compiler/pgates/ptristate_inv.py index d2965cde..764b87c0 100644 --- a/compiler/pgates/ptristate_inv.py +++ b/compiler/pgates/ptristate_inv.py @@ -44,7 +44,7 @@ class ptristate_inv(pgate.pgate): """ Calls all functions related to the generation of the netlist """ self.add_pins() self.add_ptx() - self.create_ptx() + self.create_ptx() def create_layout(self): """ Calls all functions related to the generation of the layout """ @@ -61,7 +61,6 @@ class ptristate_inv(pgate.pgate): """ Adds pins for spice netlist """ self.add_pin_list(["in", "out", "en", "en_bar", "vdd", "gnd"]) - def setup_layout_constants(self): """ Pre-compute some handy layout parameters. @@ -73,7 +72,7 @@ class ptristate_inv(pgate.pgate): # Two PMOS devices and a well contact. Separation between each. # Enclosure space on the sides. - self.well_width = 2 * self.pmos.active_width + self.well_enclose_active + self.well_width = 2 * self.pmos.active_width + self.nwell_enclose_active # Add an extra space because we route the output on the right of the S/D self.width = self.well_width + 0.5 * self.m1_space @@ -81,7 +80,6 @@ class ptristate_inv(pgate.pgate): # Make sure we can put a well above and below self.top_bottom_space = max(contact.activem1.width, contact.activem1.height) - def add_ptx(self): """ Create the PMOS and NMOS transistors. """ @@ -95,7 +93,6 @@ class ptristate_inv(pgate.pgate): width=self.pmos_width, mults=1, tx_type="pmos") - self.add_mod(self.pmos) def route_supply_rails(self): diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 282e17d8..32bbeefe 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -58,9 +58,9 @@ class ptx(design.design): # some transistor sizes in other netlist depend on pbitcell self.create_layout() - #ll = self.find_lowest_coords() - #ur = self.find_highest_coords() - #self.add_boundary(ll, ur) + ll = self.find_lowest_coords() + ur = self.find_highest_coords() + self.add_boundary(ll, ur) # (0,0) will be the corner of the active area (not the larger well) self.translate_all(self.active_offset) @@ -99,7 +99,7 @@ class ptx(design.design): drc("minwidth_poly")) area_str = "pd={0:.2f}u ps={0:.2f}u as={1:.2f}p ad={1:.2f}p".format(perimeter_sd, area_sd) - self.spice_device= main_str + area_str + self.spice_device = main_str + area_str self.spice.append("\n* ptx " + self.spice_device) # self.spice.append(".ENDS {0}".format(self.name)) @@ -124,30 +124,30 @@ class ptx(design.design): # This is not actually instantiated but used for calculations self.active_contact = factory.create(module_type="contact", layer_stack=self.active_stack, - directions = ("V", "V"), + directions=("V", "V"), dimensions=(1, self.num_contacts)) - # The contacted poly pitch (or uncontacted in an odd technology) + # The contacted poly pitch self.poly_pitch = max(2 * self.contact_to_gate + self.contact_width + self.poly_width, self.poly_space) - # The contacted poly pitch (or uncontacted in an odd technology) - self.contact_pitch = 2 * self.contact_to_gate + \ - self.contact_width + self.poly_width + # The contacted poly pitch + self.contact_spacing = 2 * self.contact_to_gate + \ + self.contact_width + self.poly_width + + # This is measured because of asymmetric enclosure rules + active_enclose_contact = 0.5*(self.active_contact.width - self.contact_width) - # The enclosure of an active contact. Not sure about second term. - active_enclose_contact = max(self.active_enclose_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 + self.contact_to_gate + # This is the distance from the side of + # poly gate to the contacted end of active + # (i.e. the "outside" contacted diffusion sizes) + self.end_to_poly = self.active_contact.width - active_enclose_contact + \ + self.contact_to_gate # 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 + (self.mults - 1) * self.poly_pitch # Active height is just the transistor width self.active_height = self.tx_width @@ -155,32 +155,35 @@ class ptx(design.design): # Poly height must include poly extension over active self.poly_height = self.tx_width + 2 * self.poly_extend_active + well_name = "{}well".format(self.well_type) + # The active offset is due to the well extension - self.active_offset = vector([self.well_enclose_active] * 2) + if well_name in layer: + well_enclose_active = drc(well_name + "_enclose_active") + self.active_offset = vector([well_enclose_active] * 2) + else: + self.active_offset = vector(0, 0) # Well enclosure of active, ensure minwidth as well - well_name = "{}well".format(self.well_type) if well_name in layer: - 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, - self.well_width) + well_width_rule = drc("minwidth_" + well_name) + well_enclose_active = drc(well_name + "_enclose_active") + self.well_width = max(self.active_width + 2 * well_enclose_active, + well_width_rule) + self.well_height = max(self.active_height + 2 * well_enclose_active, + well_width_rule) # We are going to shift the 0,0, so include that in the width and height - self.height = self.cell_well_height - self.active_offset.y - self.width = self.cell_well_width - self.active_offset.x + self.height = self.well_height - self.active_offset.y + self.width = self.well_width - self.active_offset.x else: - # If no well, use the boundary of the active and poly + # The well is not included in the height and width self.height = self.poly_height self.width = self.active_width - # The active offset is due to the well extension - self.active_offset = vector([self.well_enclose_active] * 2) - # 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, + self.contact_offset = self.active_offset + vector(0.5 * self.active_contact.width, 0.5 * self.active_height) - # Min area results are just flagged for now. debug.check(self.active_width * self.active_height >= self.minarea_active, "Minimum active area violated.") @@ -231,8 +234,8 @@ class ptx(design.design): # 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 - + self.m1_space + 0.5 * self.m1_width) + pin_offset = vector(0, + 0.5 * self.active_contact.second_layer_height + self.m1_space + 0.5 * self.m1_width) # This is the width of a m1 extend the ends of the pin end_offset = vector(self.m1_width / 2.0, 0) @@ -328,26 +331,34 @@ class ptx(design.design): Add an (optional) well and implant for the type of transistor. """ well_name = "{}well".format(self.well_type) + if not (well_name in layer or "vtg" in layer): + return + + center_pos = self.active_offset + vector(self.width / 2.0, + self.height / 2.0) + well_ll = center_pos - vector(self.well_width / 2.0, + self.well_height / 2.0) + well_ll = well_ll - vector(0, + self.poly_extend_active) + if well_name in layer: self.add_rect(layer=well_name, - offset=(0,0), - width=self.cell_well_width, - height=self.cell_well_height) + offset=well_ll, + width=self.well_width, + height=self.well_height) if "vtg" in layer: self.add_rect(layer="vtg", - offset=(0,0), - width=self.cell_well_width, - height=self.cell_well_height) - + offset=well_ll, + width=self.well_width, + height=self.well_height) def calculate_num_contacts(self): - """ + """ 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. @@ -361,10 +372,10 @@ class ptx(design.design): for i in range(self.mults): if i%2: # It's a source... so offset from previous drain. - source_positions.append(drain_positions[-1] + vector(self.contact_pitch, 0)) + source_positions.append(drain_positions[-1] + vector(self.contact_spacing, 0)) else: # It's a drain... so offset from previous source. - drain_positions.append(source_positions[-1] + vector(self.contact_pitch, 0)) + drain_positions.append(source_positions[-1] + vector(self.contact_spacing, 0)) return [source_positions,drain_positions] @@ -379,7 +390,7 @@ class ptx(design.design): contact=self.add_via_center(layers=self.active_stack, offset=pos, size=(1, self.num_contacts), - directions=("H","V"), + directions=("V","V"), implant_type=self.implant_type, well_type=self.well_type) self.add_layout_pin_rect_center(text="S", @@ -393,7 +404,7 @@ class ptx(design.design): contact=self.add_via_center(layers=self.active_stack, offset=pos, size=(1, self.num_contacts), - directions=("H","V"), + directions=("V","V"), implant_type=self.implant_type, well_type=self.well_type) self.add_layout_pin_rect_center(text="D", diff --git a/compiler/pgates/pwrite_driver.py b/compiler/pgates/pwrite_driver.py index 2dc356c3..ed970f9b 100644 --- a/compiler/pgates/pwrite_driver.py +++ b/compiler/pgates/pwrite_driver.py @@ -40,12 +40,10 @@ class pwrite_driver(design.design): # Creates the netlist and layout # Since it has variable height, it is not a pgate. self.create_netlist() - if not OPTS.netlist_only: + if not OPTS.netlist_only: self.create_layout() self.DRC_LVS() - - def create_netlist(self): self.add_pins() self.add_modules() @@ -55,8 +53,6 @@ class pwrite_driver(design.design): self.place_modules() self.route_wires() self.route_supplies() - - def add_pins(self): self.add_pin("din", "INPUT") @@ -66,17 +62,19 @@ class pwrite_driver(design.design): self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") - def add_modules(self): # Tristate inverter self.tri = factory.create(module_type="ptristate_inv", height="min") self.add_mod(self.tri) - debug.check(self.tri.width