2016-11-08 18:57:35 +01:00
|
|
|
import design
|
|
|
|
|
import debug
|
2017-12-12 23:53:19 +01:00
|
|
|
from tech import drc, info
|
2016-11-08 18:57:35 +01:00
|
|
|
from vector import vector
|
2017-12-12 23:53:19 +01:00
|
|
|
import contact
|
2016-11-08 18:57:35 +01:00
|
|
|
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.
|
|
|
|
|
"""
|
|
|
|
|
|
2018-02-02 23:26:39 +01:00
|
|
|
def __init__(self, tx_size):
|
|
|
|
|
name="single_level_column_mux_{}".format(tx_size)
|
2016-11-08 18:57:35 +01:00
|
|
|
design.design.__init__(self, name)
|
2018-02-02 23:26:39 +01:00
|
|
|
debug.info(2, "create single column mux cell: {0}".format(name))
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2018-08-28 19:24:09 +02:00
|
|
|
self.tx_size = tx_size
|
2018-08-27 23:18:32 +02:00
|
|
|
|
|
|
|
|
self.create_netlist()
|
2018-08-28 19:24:09 +02:00
|
|
|
if not OPTS.netlist_only:
|
|
|
|
|
self.create_layout()
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2018-08-27 23:18:32 +02:00
|
|
|
def create_netlist(self):
|
2018-08-28 19:24:09 +02:00
|
|
|
self.add_modules()
|
|
|
|
|
self.add_pins()
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_ptx()
|
2018-08-27 23:18:32 +02:00
|
|
|
|
|
|
|
|
def create_layout(self):
|
2018-08-28 19:24:09 +02:00
|
|
|
|
2018-02-03 00:17:21 +01:00
|
|
|
self.pin_height = 2*self.m2_width
|
2017-08-24 00:02:15 +02:00
|
|
|
self.width = self.bitcell.width
|
2018-06-29 20:35:29 +02:00
|
|
|
self.height = self.nmos_upper.uy() + self.pin_height
|
2016-11-08 18:57:35 +01:00
|
|
|
self.connect_poly()
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_bitline_pins()
|
|
|
|
|
self.connect_bitlines()
|
|
|
|
|
self.add_wells()
|
2018-08-28 19:24:09 +02:00
|
|
|
|
|
|
|
|
def add_modules(self):
|
2018-09-04 20:55:22 +02:00
|
|
|
# This is just used for measurements,
|
|
|
|
|
# so don't add the module
|
2018-08-28 19:24:09 +02:00
|
|
|
from importlib import reload
|
|
|
|
|
c = reload(__import__(OPTS.bitcell))
|
|
|
|
|
self.mod_bitcell = getattr(c, OPTS.bitcell)
|
|
|
|
|
self.bitcell = self.mod_bitcell()
|
|
|
|
|
|
|
|
|
|
# Adds nmos_lower,nmos_upper to the module
|
|
|
|
|
self.ptx_width = self.tx_size * drc["minwidth_tx"]
|
|
|
|
|
self.nmos = ptx(width=self.ptx_width)
|
|
|
|
|
self.add_mod(self.nmos)
|
|
|
|
|
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2018-08-28 19:24:09 +02:00
|
|
|
def add_pins(self):
|
|
|
|
|
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
|
|
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
def add_bitline_pins(self):
|
|
|
|
|
""" Add the top and bottom pins to this cell """
|
|
|
|
|
|
2018-05-22 23:16:51 +02:00
|
|
|
bl_pos = vector(self.bitcell.get_pin("bl").lx(), 0)
|
|
|
|
|
br_pos = vector(self.bitcell.get_pin("br").lx(), 0)
|
2017-12-12 23:53:19 +01:00
|
|
|
|
|
|
|
|
# bl and br
|
|
|
|
|
self.add_layout_pin(text="bl",
|
|
|
|
|
layer="metal2",
|
2018-02-03 00:17:21 +01:00
|
|
|
offset=bl_pos + vector(0,self.height - self.pin_height),
|
|
|
|
|
height=self.pin_height)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_layout_pin(text="br",
|
|
|
|
|
layer="metal2",
|
2018-02-03 00:17:21 +01:00
|
|
|
offset=br_pos + vector(0,self.height - self.pin_height),
|
|
|
|
|
height=self.pin_height)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
# bl_out and br_out
|
|
|
|
|
self.add_layout_pin(text="bl_out",
|
|
|
|
|
layer="metal2",
|
|
|
|
|
offset=bl_pos,
|
2018-02-03 00:17:21 +01:00
|
|
|
height=self.pin_height)
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_layout_pin(text="br_out",
|
|
|
|
|
layer="metal2",
|
|
|
|
|
offset=br_pos,
|
2018-02-03 00:17:21 +01:00
|
|
|
height=self.pin_height)
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
def add_ptx(self):
|
2017-08-24 00:02:15 +02:00
|
|
|
""" Create the two pass gate NMOS transistors to switch the bitlines"""
|
|
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
# Space it in the center
|
2018-06-29 20:35:29 +02:00
|
|
|
nmos_lower_position = self.nmos.active_offset.scale(0,1) + vector(0.5*self.bitcell.width-0.5*self.nmos.active_width,0)
|
|
|
|
|
self.nmos_lower=self.add_inst(name="mux_tx1",
|
2017-12-12 23:53:19 +01:00
|
|
|
mod=self.nmos,
|
2018-06-29 20:35:29 +02:00
|
|
|
offset=nmos_lower_position)
|
2016-11-08 18:57:35 +01:00
|
|
|
self.connect_inst(["bl", "sel", "bl_out", "gnd"])
|
|
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
# This aligns it directly above the other tx with gates abutting
|
2018-06-29 20:35:29 +02:00
|
|
|
nmos_upper_position = nmos_lower_position + vector(0,self.nmos.active_height + self.poly_space)
|
|
|
|
|
self.nmos_upper=self.add_inst(name="mux_tx2",
|
2017-12-12 23:53:19 +01:00
|
|
|
mod=self.nmos,
|
2018-06-29 20:35:29 +02:00
|
|
|
offset=nmos_upper_position)
|
2016-11-08 18:57:35 +01:00
|
|
|
self.connect_inst(["br", "sel", "br_out", "gnd"])
|
|
|
|
|
|
2017-08-24 00:02:15 +02:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
def connect_poly(self):
|
2017-08-24 00:02:15 +02:00
|
|
|
""" Connect the poly gate of the two pass transistors """
|
|
|
|
|
|
2018-06-29 20:35:29 +02:00
|
|
|
height=self.nmos_upper.get_pin("G").uy() - self.nmos_lower.get_pin("G").by()
|
2017-12-19 18:01:24 +01:00
|
|
|
self.add_layout_pin(text="sel",
|
2017-08-24 00:02:15 +02:00
|
|
|
layer="poly",
|
2018-06-29 20:35:29 +02:00
|
|
|
offset=self.nmos_lower.get_pin("G").ll(),
|
2017-12-12 23:53:19 +01:00
|
|
|
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
|
2018-06-29 20:35:29 +02:00
|
|
|
nmos_lower_s_pin = self.nmos_lower.get_pin("S")
|
|
|
|
|
nmos_lower_d_pin = self.nmos_lower.get_pin("D")
|
|
|
|
|
nmos_upper_s_pin = self.nmos_upper.get_pin("S")
|
|
|
|
|
nmos_upper_d_pin = self.nmos_upper.get_pin("D")
|
2017-12-12 23:53:19 +01:00
|
|
|
|
2018-06-29 20:35:29 +02:00
|
|
|
# Add vias to bl, br_out, nmos_upper/S, nmos_lower/D
|
2017-12-12 23:53:19 +01:00
|
|
|
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"),
|
2018-06-29 20:35:29 +02:00
|
|
|
offset=nmos_upper_s_pin.center())
|
2017-12-12 23:53:19 +01:00
|
|
|
self.add_via_center(layers=("metal1","via1","metal2"),
|
2018-06-29 20:35:29 +02:00
|
|
|
offset=nmos_lower_d_pin.center())
|
2017-12-12 23:53:19 +01:00
|
|
|
|
2018-06-29 20:35:29 +02:00
|
|
|
# bl -> nmos_upper/D on metal1
|
|
|
|
|
# bl_out -> nmos_upper/S on metal2
|
|
|
|
|
self.add_path("metal1",[bl_pin.ll(), vector(nmos_upper_d_pin.cx(),bl_pin.by()), nmos_upper_d_pin.center()])
|
2017-12-12 23:53:19 +01:00
|
|
|
# halfway up, move over
|
2018-06-29 20:35:29 +02:00
|
|
|
mid1 = bl_out_pin.uc().scale(1,0.5)+nmos_upper_s_pin.bc().scale(0,0.5)
|
|
|
|
|
mid2 = bl_out_pin.uc().scale(0,0.5)+nmos_upper_s_pin.bc().scale(1,0.5)
|
|
|
|
|
self.add_path("metal2",[bl_out_pin.uc(), mid1, mid2, nmos_upper_s_pin.bc()])
|
2017-12-12 23:53:19 +01:00
|
|
|
|
2018-06-29 20:35:29 +02:00
|
|
|
# br -> nmos_lower/D on metal2
|
|
|
|
|
# br_out -> nmos_lower/S on metal1
|
|
|
|
|
self.add_path("metal1",[br_out_pin.uc(), vector(nmos_lower_s_pin.cx(),br_out_pin.uy()), nmos_lower_s_pin.center()])
|
2017-12-12 23:53:19 +01:00
|
|
|
# halfway up, move over
|
2018-06-29 20:35:29 +02:00
|
|
|
mid1 = br_pin.bc().scale(1,0.5)+nmos_lower_d_pin.uc().scale(0,0.5)
|
|
|
|
|
mid2 = br_pin.bc().scale(0,0.5)+nmos_lower_d_pin.uc().scale(1,0.5)
|
|
|
|
|
self.add_path("metal2",[br_pin.bc(), mid1, mid2, nmos_lower_d_pin.uc()])
|
2017-12-12 23:53:19 +01:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2017-12-12 23:53:19 +01:00
|
|
|
def add_wells(self):
|
2018-04-06 18:50:13 +02:00
|
|
|
"""
|
|
|
|
|
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
|
2018-06-29 20:35:29 +02:00
|
|
|
active_pos = vector(self.bitcell.width,self.nmos_upper.by())
|
|
|
|
|
active_via = self.add_via_center(layers=("active", "contact", "metal1"),
|
|
|
|
|
offset=active_pos,
|
|
|
|
|
implant_type="p",
|
|
|
|
|
well_type="p")
|
2018-01-30 00:53:22 +01:00
|
|
|
|
2016-11-08 18:57:35 +01:00
|
|
|
|
2018-04-06 18:50:13 +02:00
|
|
|
# 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)
|
2018-06-29 20:35:29 +02:00
|
|
|
|
|
|
|
|
# Add well enclosure over all the tx and contact
|
|
|
|
|
self.add_rect(layer="pwell",
|
|
|
|
|
offset=vector(0,0),
|
|
|
|
|
width=self.bitcell.width,
|
|
|
|
|
height=self.height)
|
2018-04-06 18:50:13 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|