Merging branch with PrivateRAM dev

This commit is contained in:
Michael Timothy Grimes
2018-05-18 15:15:31 -07:00
84 changed files with 14871 additions and 13447 deletions
+2 -2
View File
@@ -76,11 +76,11 @@ class pgate(design.design):
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=contact_offset,
rotate=rotate)
# self.add_layout_pin_center_segment(text=name,
# self.add_layout_pin_segment_center(text=name,
# layer="metal1",
# start=left_gate_offset.scale(0,1),
# end=left_gate_offset)
self.add_layout_pin_center_rect(text=name,
self.add_layout_pin_rect_center(text=name,
layer="metal1",
offset=contact_offset,
width=contact_m1_width,
+5 -5
View File
@@ -148,12 +148,12 @@ class pinv(pgate.pgate):
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_center_rect(text="gnd",
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
offset=vector(0.5*self.width,0),
width=self.width)
self.add_layout_pin_center_rect(text="vdd",
self.add_layout_pin_rect_center(text="vdd",
layer="metal1",
offset=vector(0.5*self.width,self.height),
width=self.width)
@@ -208,13 +208,13 @@ class pinv(pgate.pgate):
if self.route_output == True:
# This extends the output to the edge of the cell
output_offset = mid_drain_offset.scale(0,1) + vector(self.width,0)
self.add_layout_pin_center_segment(text="Z",
self.add_layout_pin_segment_center(text="Z",
layer="metal1",
start=mid_drain_offset,
end=output_offset)
else:
# This leaves the output as an internal pin (min sized)
self.add_layout_pin_center_rect(text="Z",
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid_drain_offset + vector(0.5*self.m1_width,0))
@@ -257,4 +257,4 @@ class pinv(pgate.pgate):
c_load = load
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
transistion_prob = spice["inv_transisition_prob"]
return transistion_prob*(c_load + c_para)
return transistion_prob*(c_load + c_para)
+161
View File
@@ -0,0 +1,161 @@
import debug
import design
from tech import drc
from math import log
from vector import vector
from globals import OPTS
from pinv import pinv
class pinvbuf(design.design):
"""
This is a simple inverter/buffer used for driving loads. It is
used in the column decoder for 1:2 decoding and as the clock buffer.
"""
c = reload(__import__(OPTS.bitcell))
bitcell = getattr(c, OPTS.bitcell)
def __init__(self, inv1_size=2, inv2_size=4, height=bitcell.height, name=""):
if name=="":
name = "pinvbuf_{0}_{1}".format(inv1_size, inv2_size)
design.design.__init__(self, name)
debug.info(1, "Creating {}".format(self.name))
self.inv = pinv(size=1, height=height)
self.add_mod(self.inv)
self.inv1 = pinv(size=inv1_size, height=height)
self.add_mod(self.inv1)
self.inv2 = pinv(size=inv2_size, height=height)
self.add_mod(self.inv2)
self.width = 2*self.inv1.width + self.inv2.width
self.height = 2*self.inv1.height
self.create_layout()
self.offset_all_coordinates()
self.DRC_LVS()
def create_layout(self):
self.add_pins()
self.add_insts()
self.add_wires()
self.add_layout_pins()
def add_pins(self):
self.add_pin("A")
self.add_pin("Zb")
self.add_pin("Z")
self.add_pin("vdd")
self.add_pin("gnd")
def add_insts(self):
# Add INV1 to the right (capacitance shield)
self.inv1_inst=self.add_inst(name="buf_inv1",
mod=self.inv,
offset=vector(0,0))
self.connect_inst(["A", "zb_int", "vdd", "gnd"])
# Add INV2 to the right
self.inv2_inst=self.add_inst(name="buf_inv2",
mod=self.inv1,
offset=vector(self.inv1_inst.rx(),0))
self.connect_inst(["zb_int", "z_int", "vdd", "gnd"])
# Add INV3 to the right
self.inv3_inst=self.add_inst(name="buf_inv3",
mod=self.inv2,
offset=vector(self.inv2_inst.rx(),0))
self.connect_inst(["z_int", "Zb", "vdd", "gnd"])
# Add INV4 to the bottom
self.inv4_inst=self.add_inst(name="buf_inv4",
mod=self.inv2,
offset=vector(self.inv2_inst.rx(),2*self.inv2.height),
mirror = "MX")
self.connect_inst(["zb_int", "Z", "vdd", "gnd"])
def add_wires(self):
# inv1 Z to inv2 A
z1_pin = self.inv1_inst.get_pin("Z")
a2_pin = self.inv2_inst.get_pin("A")
mid_point = vector(z1_pin.cx(), a2_pin.cy())
self.add_path("metal1", [z1_pin.center(), mid_point, a2_pin.center()])
# inv2 Z to inv3 A
z2_pin = self.inv2_inst.get_pin("Z")
a3_pin = self.inv3_inst.get_pin("A")
mid_point = vector(z2_pin.cx(), a3_pin.cy())
self.add_path("metal1", [z2_pin.center(), mid_point, a3_pin.center()])
# inv1 Z to inv4 A (up and over)
z1_pin = self.inv1_inst.get_pin("Z")
a4_pin = self.inv4_inst.get_pin("A")
mid_point = vector(z1_pin.cx(), a4_pin.cy())
self.add_wire(("metal1","via1","metal2"), [z1_pin.center(), mid_point, a4_pin.center()])
self.add_via_center(layers=("metal1","via1","metal2"),
offset=z1_pin.center())
def add_layout_pins(self):
# Continous vdd rail along with label.
vdd_pin=self.inv1_inst.get_pin("vdd")
self.add_layout_pin(text="vdd",
layer="metal1",
offset=vdd_pin.ll().scale(0,1),
width=self.width,
height=vdd_pin.height())
# Continous vdd rail along with label.
gnd_pin=self.inv4_inst.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll().scale(0,1),
width=self.width,
height=gnd_pin.height())
# Continous gnd rail along with label.
gnd_pin=self.inv1_inst.get_pin("gnd")
self.add_layout_pin(text="gnd",
layer="metal1",
offset=gnd_pin.ll().scale(0,1),
width=self.width,
height=vdd_pin.height())
z_pin = self.inv4_inst.get_pin("Z")
self.add_layout_pin_rect_center(text="Z",
layer="metal2",
offset=z_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=z_pin.center())
zb_pin = self.inv3_inst.get_pin("Z")
self.add_layout_pin_rect_center(text="Zb",
layer="metal2",
offset=zb_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=zb_pin.center())
a_pin = self.inv1_inst.get_pin("A")
self.add_layout_pin_rect_center(text="A",
layer="metal2",
offset=a_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=a_pin.center())
def analytical_delay(self, slew, load=0.0):
""" Calculate the analytical delay of DFF-> INV -> INV """
inv1_delay = self.inv1.analytical_delay(slew=slew, load=self.inv2.input_load())
inv2_delay = self.inv2.analytical_delay(slew=inv1_delay.slew, load=load)
return inv1_delay + inv2_delay
+3 -3
View File
@@ -102,12 +102,12 @@ class pnand2(pgate.pgate):
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_center_rect(text="gnd",
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
offset=vector(0.5*self.width,0),
width=self.width)
self.add_layout_pin_center_rect(text="vdd",
self.add_layout_pin_rect_center(text="vdd",
layer="metal1",
offset=vector(0.5*self.width,self.height),
width=self.width)
@@ -197,7 +197,7 @@ class pnand2(pgate.pgate):
self.add_path("metal2",[pmos_pin.bc(), mid_offset, nmos_pin.uc()])
# This extends the output to the edge of the cell
self.add_layout_pin_center_rect(text="Z",
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid_offset,
width=contact.m1m2.first_layer_height,
+3 -3
View File
@@ -100,12 +100,12 @@ class pnand3(pgate.pgate):
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_center_rect(text="gnd",
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
offset=vector(0.5*self.width,0),
width=self.width)
self.add_layout_pin_center_rect(text="vdd",
self.add_layout_pin_rect_center(text="vdd",
layer="metal1",
offset=vector(0.5*self.width,self.height),
width=self.width)
@@ -218,7 +218,7 @@ class pnand3(pgate.pgate):
# This extends the output to the edge of the cell
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=mid_offset)
self.add_layout_pin_center_rect(text="Z",
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid_offset,
width=contact.m1m2.first_layer_width,
+4 -4
View File
@@ -106,12 +106,12 @@ class pnor2(pgate.pgate):
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
self.add_layout_pin_center_rect(text="gnd",
self.add_layout_pin_rect_center(text="gnd",
layer="metal1",
offset=vector(0.5*self.width,0),
width=self.width)
self.add_layout_pin_center_rect(text="vdd",
self.add_layout_pin_rect_center(text="vdd",
layer="metal1",
offset=vector(0.5*self.width,self.height),
width=self.width)
@@ -208,7 +208,7 @@ class pnor2(pgate.pgate):
self.add_contact_center(layers=("metal1", "via1", "metal2"),
offset=mid3_offset,
rotate=90)
self.add_layout_pin_center_rect(text="Z",
self.add_layout_pin_rect_center(text="Z",
layer="metal1",
offset=mid3_offset,
width=contact.m1m2.first_layer_height,
@@ -240,4 +240,4 @@ class pnor2(pgate.pgate):
c_para = spice["min_tx_drain_c"]*(self.nmos_size/parameter["min_tx_size"])#ff
transistion_prob = spice["nor2_transisition_prob"]
return transistion_prob*(c_load + c_para)
+213
View File
@@ -0,0 +1,213 @@
import contact
import pgate
import debug
from tech import drc, parameter
from ptx import ptx
from vector import vector
from globals import OPTS
class precharge(pgate.pgate):
"""
Creates a single precharge cell
This module implements the precharge bitline cell used in the design.
"""
def __init__(self, name, size=1):
pgate.pgate.__init__(self, name)
debug.info(2, "create single precharge cell: {0}".format(name))
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.beta = parameter["beta"]
self.ptx_width = self.beta*parameter["min_tx_size"]
self.width = self.bitcell.width
self.add_pins()
self.create_layout()
self.DRC_LVS()
def add_pins(self):
self.add_pin_list(["bl", "br", "en", "vdd"])
def create_layout(self):
self.create_ptx()
self.add_ptx()
self.connect_poly()
self.add_en()
self.add_nwell_and_contact()
self.add_vdd_rail()
self.add_bitlines()
self.connect_to_bitlines()
def create_ptx(self):
"""Initializes the upper and lower pmos"""
self.pmos = ptx(width=self.ptx_width,
tx_type="pmos")
self.add_mod(self.pmos)
# Compute the other pmos2 location, but determining offset to overlap the
# source and drain pins
self.overlap_offset = self.pmos.get_pin("D").ll() - self.pmos.get_pin("S").ll()
def add_vdd_rail(self):
"""Adds a vdd rail at the top of the cell"""
# adds the rail across the width of the cell
vdd_position = vector(0, self.height - self.m1_width)
self.add_rect(layer="metal1",
offset=vdd_position,
width=self.width,
height=self.m1_width)
pmos_pin = self.upper_pmos2_inst.get_pin("S")
# center of vdd rail
vdd_pos = vector(pmos_pin.cx(), vdd_position.y + 0.5*self.m1_width)
self.add_path("metal1", [pmos_pin.uc(), vdd_pos])
# Add the M1->M2->M3 stack at the left edge
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=vdd_pos.scale(0,1))
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=vdd_pos.scale(0,1))
self.add_layout_pin_rect_center(text="vdd",
layer="metal3",
offset=vdd_pos.scale(0,1))
def add_ptx(self):
"""Adds both the upper_pmos and lower_pmos to the module"""
# adds the lower pmos to layout
#base = vector(self.width - 2*self.pmos.width + self.overlap_offset.x, 0)
self.lower_pmos_position = vector(self.bitcell.get_pin("BL").lx(),
self.pmos.active_offset.y)
self.lower_pmos_inst=self.add_inst(name="lower_pmos",
mod=self.pmos,
offset=self.lower_pmos_position)
self.connect_inst(["bl", "en", "BR", "vdd"])
# adds the upper pmos(s) to layout
ydiff = self.pmos.height + 2*self.m1_space + contact.poly.width
self.upper_pmos1_pos = self.lower_pmos_position + vector(0, ydiff)
self.upper_pmos1_inst=self.add_inst(name="upper_pmos1",
mod=self.pmos,
offset=self.upper_pmos1_pos)
self.connect_inst(["bl", "en", "vdd", "vdd"])
upper_pmos2_pos = self.upper_pmos1_pos + self.overlap_offset
self.upper_pmos2_inst=self.add_inst(name="upper_pmos2",
mod=self.pmos,
offset=upper_pmos2_pos)
self.connect_inst(["br", "en", "vdd", "vdd"])
def connect_poly(self):
"""Connects the upper and lower pmos together"""
offset = self.lower_pmos_inst.get_pin("G").ll()
# connects the top and bottom pmos' gates together
ylength = self.upper_pmos1_inst.get_pin("G").ll().y - offset.y
self.add_rect(layer="poly",
offset=offset,
width=self.poly_width,
height=ylength)
# connects the two poly for the two upper pmos(s)
offset = offset + vector(0, ylength - self.poly_width)
xlength = self.upper_pmos2_inst.get_pin("G").lx() - self.upper_pmos1_inst.get_pin("G").lx() + self.poly_width
self.add_rect(layer="poly",
offset=offset,
width=xlength,
height=self.poly_width)
def add_en(self):
"""Adds the en input rail, en contact/vias, and connects to the pmos"""
# adds the en contact to connect the gates to the en rail on metal1
offset = self.lower_pmos_inst.get_pin("G").ul() + vector(0,0.5*self.poly_space)
self.add_contact_center(layers=("poly", "contact", "metal1"),
offset=offset,
rotate=90)
# adds the en rail on metal1
self.add_layout_pin_segment_center(text="en",
layer="metal1",
start=offset.scale(0,1),
end=offset.scale(0,1)+vector(self.width,0))
def add_nwell_and_contact(self):
"""Adds a nwell tap to connect to the vdd rail"""
# 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.well.height/2 + drc["well_extend_active"])
self.add_contact_center(layers=("active", "contact", "metal1"),
offset=well_contact_pos,
implant_type="n",
well_type="n")
self.height = well_contact_pos.y + contact.well.height
self.add_rect(layer="nwell",
offset=vector(0,0),
width=self.width,
height=self.height)
def add_bitlines(self):
"""Adds both bit-line and bit-line-bar to the module"""
# adds the BL on metal 2
offset = vector(self.bitcell.get_pin("BL").cx(),0) - vector(0.5 * self.m2_width,0)
self.add_layout_pin(text="bl",
layer="metal2",
offset=offset,
width=drc['minwidth_metal2'],
height=self.height)
# adds the BR on metal 2
offset = vector(self.bitcell.get_pin("BR").cx(),0) - vector(0.5 * self.m2_width,0)
self.add_layout_pin(text="br",
layer="metal2",
offset=offset,
width=drc['minwidth_metal2'],
height=self.height)
def connect_to_bitlines(self):
self.add_bitline_contacts()
self.connect_pmos(self.lower_pmos_inst.get_pin("S"),self.get_pin("bl"))
self.connect_pmos(self.lower_pmos_inst.get_pin("D"),self.get_pin("br"))
self.connect_pmos(self.upper_pmos1_inst.get_pin("S"),self.get_pin("bl"))
self.connect_pmos(self.upper_pmos2_inst.get_pin("D"),self.get_pin("br"))
def add_bitline_contacts(self):
"""Adds contacts/via from metal1 to metal2 for bit-lines"""
stack=("metal1", "via1", "metal2")
pos = self.lower_pmos_inst.get_pin("S").center()
self.add_contact_center(layers=stack,
offset=pos)
pos = self.lower_pmos_inst.get_pin("D").center()
self.add_contact_center(layers=stack,
offset=pos)
pos = self.upper_pmos1_inst.get_pin("S").center()
self.add_contact_center(layers=stack,
offset=pos)
pos = self.upper_pmos2_inst.get_pin("D").center()
self.add_contact_center(layers=stack,
offset=pos)
def connect_pmos(self, pmos_pin, bit_pin):
""" Connect pmos pin to bitline pin """
ll_pos = vector(min(pmos_pin.lx(),bit_pin.lx()), pmos_pin.by())
ur_pos = vector(max(pmos_pin.rx(),bit_pin.rx()), pmos_pin.uy())
width = ur_pos.x-ll_pos.x
height = ur_pos.y-ll_pos.y
self.add_rect(layer="metal2",
offset=ll_pos,
width=width,
height=height)
+5 -5
View File
@@ -210,7 +210,7 @@ class ptx(design.design):
for a in source_positions:
self.add_path(("metal1"), [a,a+pin_offset.scale(source_dir,source_dir)])
# Add a single horizontal pin
self.add_layout_pin_center_segment(text="S",
self.add_layout_pin_segment_center(text="S",
layer="metal1",
start=source_positions[0]+source_offset-end_offset,
end=source_positions[-1]+source_offset+end_offset)
@@ -222,7 +222,7 @@ class ptx(design.design):
for a in drain_positions:
self.add_path(("metal1"), [a,a+drain_offset])
# Add a single horizontal pin
self.add_layout_pin_center_segment(text="D",
self.add_layout_pin_segment_center(text="D",
layer="metal1",
start=drain_positions[0]+drain_offset-end_offset,
end=drain_positions[-1]+drain_offset+end_offset)
@@ -246,7 +246,7 @@ class ptx(design.design):
offset=poly_offset,
height=self.poly_height,
width=self.poly_width)
self.add_layout_pin_center_rect(text="G",
self.add_layout_pin_rect_center(text="G",
layer="poly",
offset=poly_offset,
height=self.poly_height,
@@ -329,7 +329,7 @@ class ptx(design.design):
size=(1, self.num_contacts),
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_center_rect(text="S",
self.add_layout_pin_rect_center(text="S",
layer="metal1",
offset=pos,
width=contact.mod.second_layer_width,
@@ -342,7 +342,7 @@ class ptx(design.design):
size=(1, self.num_contacts),
implant_type=self.implant_type,
well_type=self.well_type)
self.add_layout_pin_center_rect(text="D",
self.add_layout_pin_rect_center(text="D",
layer="metal1",
offset=pos,
width=contact.mod.second_layer_width,
+163
View File
@@ -0,0 +1,163 @@
import design
import debug
from tech import drc, info
from vector import vector
import contact
from ptx import ptx
from globals import OPTS
class single_level_column_mux(design.design):
"""
This module implements the columnmux bitline cell used in the design.
Creates a single columnmux cell.
"""
def __init__(self, tx_size):
name="single_level_column_mux_{}".format(tx_size)
design.design.__init__(self, name)
debug.info(2, "create single column mux cell: {0}".format(name))
c = reload(__import__(OPTS.bitcell))
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
self.ptx_width = tx_size * drc["minwidth_tx"]
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
self.create_layout()
def create_layout(self):
self.add_ptx()
self.pin_height = 2*self.m2_width
self.width = self.bitcell.width
self.height = self.nmos2.uy() + self.pin_height
self.connect_poly()
self.add_bitline_pins()
self.connect_bitlines()
self.add_wells()
def add_bitline_pins(self):
""" Add the top and bottom pins to this cell """
bl_pos = vector(self.bitcell.get_pin("BL").lx(), 0)
br_pos = vector(self.bitcell.get_pin("BR").lx(), 0)
# bl and br
self.add_layout_pin(text="bl",
layer="metal2",
offset=bl_pos + vector(0,self.height - self.pin_height),
height=self.pin_height)
self.add_layout_pin(text="br",
layer="metal2",
offset=br_pos + vector(0,self.height - self.pin_height),
height=self.pin_height)
# bl_out and br_out
self.add_layout_pin(text="bl_out",
layer="metal2",
offset=bl_pos,
height=self.pin_height)
self.add_layout_pin(text="br_out",
layer="metal2",
offset=br_pos,
height=self.pin_height)
def add_ptx(self):
""" Create the two pass gate NMOS transistors to switch the bitlines"""
# Adds nmos1,nmos2 to the module
self.nmos = ptx(width=self.ptx_width)
self.add_mod(self.nmos)
# Space it in the center
nmos1_position = self.nmos.active_offset.scale(0,1) + vector(0.5*self.bitcell.width-0.5*self.nmos.active_width,0)
self.nmos1=self.add_inst(name="mux_tx1",
mod=self.nmos,
offset=nmos1_position)
self.connect_inst(["bl", "sel", "bl_out", "gnd"])
# This aligns it directly above the other tx with gates abutting
nmos2_position = nmos1_position + vector(0,self.nmos.active_height + self.poly_space)
self.nmos2=self.add_inst(name="mux_tx2",
mod=self.nmos,
offset=nmos2_position)
self.connect_inst(["br", "sel", "br_out", "gnd"])
def connect_poly(self):
""" Connect the poly gate of the two pass transistors """
height=self.nmos2.get_pin("G").uy() - self.nmos1.get_pin("G").by()
self.add_layout_pin(text="sel",
layer="poly",
offset=self.nmos1.get_pin("G").ll(),
height=height)
def connect_bitlines(self):
""" Connect the bitlines to the mux transistors """
# These are on metal2
bl_pin = self.get_pin("bl")
br_pin = self.get_pin("br")
bl_out_pin = self.get_pin("bl_out")
br_out_pin = self.get_pin("br_out")
# These are on metal1
nmos1_s_pin = self.nmos1.get_pin("S")
nmos1_d_pin = self.nmos1.get_pin("D")
nmos2_s_pin = self.nmos2.get_pin("S")
nmos2_d_pin = self.nmos2.get_pin("D")
# Add vias to bl, br_out, nmos2/S, nmos1/D
self.add_via_center(layers=("metal1","via1","metal2"),
offset=bl_pin.bc())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=br_out_pin.uc())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=nmos2_s_pin.center())
self.add_via_center(layers=("metal1","via1","metal2"),
offset=nmos1_d_pin.center())
# bl -> nmos2/D on metal1
# bl_out -> nmos2/S on metal2
self.add_path("metal1",[bl_pin.ll(), vector(nmos2_d_pin.cx(),bl_pin.by()), nmos2_d_pin.center()])
# halfway up, move over
mid1 = bl_out_pin.uc().scale(1,0.5)+nmos2_s_pin.bc().scale(0,0.5)
mid2 = bl_out_pin.uc().scale(0,0.5)+nmos2_s_pin.bc().scale(1,0.5)
self.add_path("metal2",[bl_out_pin.uc(), mid1, mid2, nmos2_s_pin.bc()])
# br -> nmos1/D on metal2
# br_out -> nmos1/S on metal1
self.add_path("metal1",[br_out_pin.uc(), vector(nmos1_s_pin.cx(),br_out_pin.uy()), nmos1_s_pin.center()])
# halfway up, move over
mid1 = br_pin.bc().scale(1,0.5)+nmos1_d_pin.uc().scale(0,0.5)
mid2 = br_pin.bc().scale(0,0.5)+nmos1_d_pin.uc().scale(1,0.5)
self.add_path("metal2",[br_pin.bc(), mid1, mid2, nmos1_d_pin.uc()])
def add_wells(self):
"""
Add a well and implant over the whole cell. Also, add the
pwell contact (if it exists)
"""
# Add it to the right, aligned in between the two tx
active_pos = self.nmos2.lr().scale(0,0.5) + self.nmos1.ur().scale(1,0.5)
self.add_via_center(layers=("active", "contact", "metal1"),
offset=active_pos,
implant_type="p",
well_type="p")
# Add the M1->M2->M3 stack
self.add_via_center(layers=("metal1", "via1", "metal2"),
offset=active_pos)
self.add_via_center(layers=("metal2", "via2", "metal3"),
offset=active_pos)
self.add_layout_pin_rect_center(text="gnd",
layer="metal3",
offset=active_pos)