OpenRAM/compiler/single_level_column_mux.py

225 lines
10 KiB
Python

import design
import debug
from tech import drc
from vector import vector
from contact 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, name, tx_size):
design.design.__init__(self, name)
debug.info(2, "create single columnmux cell: {0}".format(name))
c = reload(__import__(OPTS.config.bitcell))
self.mod_bitcell = getattr(c, OPTS.config.bitcell)
self.bitcell_chars = self.mod_bitcell.chars
self.tx_size = tx_size
self.ptx_width = self.tx_size * drc["minwidth_tx"]
self.add_pins()
self.create_layout()
def add_pins(self):
self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"])
def create_layout(self):
# This is not instantiated and used for calculations only.
self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2"))
self.pwell_contact = contact(layer_stack=("active", "contact", "metal1"))
self.create_ptx()
self.add_ptx()
self.connect_poly()
self.connect_to_bitlines()
self.add_gnd_rail()
self.add_well_contacts()
self.setup_layout_constants()
def create_ptx(self):
"""Initializes the nmos1 and nmos2 transistors"""
self.nmos1 = ptx(name="nmos1",
width=self.ptx_width,
mults=1,
tx_type="nmos")
self.add_mod(self.nmos1)
self.nmos2 = ptx(name="nmos2",
width=self.ptx_width,
mults=1,
tx_type="nmos")
self.nmos2 = self.nmos2
self.add_mod(self.nmos2)
def add_ptx(self):
# Adds nmos1,nmos2 to the module
self.nmos1_position = (vector(drc["minwidth_metal1"],
drc["poly_extend_active"])
- vector([drc["well_enclosure_active"]]*2))
self.add_inst(name="M_1",
mod=self.nmos1,
offset=self.nmos1_position)
self.connect_inst(["bl", "sel", "bl_out", "gnd"])
nmos2_to_nmos1 = vector(self.nmos1.active_width,
self.nmos1.active_height + drc["minwidth_poly"]
+ 2* drc["poly_extend_active"])
self.nmos2_position = self.nmos1_position + nmos2_to_nmos1
self.add_inst(name="M_2",
mod=self.nmos2,
offset=self.nmos2_position)
self.connect_inst(["br", "sel", "br_out", "gnd"])
def connect_poly(self):
self.poly_offset = (self.nmos1_position
+ self.nmos1.poly_positions[0]
+ vector(0,self.nmos1.poly_height))
width=self.nmos2_position[0] - self.nmos1_position[0] + drc["minwidth_poly"]
self.poly = self.add_rect(layer="poly",
offset=self.poly_offset,
width=width,
height=drc["minwidth_poly"])
self.add_label(text="col_addr",
layer="poly",
offset=self.poly_offset)
def connect_to_bitlines(self):
offset = [self.nmos1.active_contact_positions[0].x + self.m1m2_via.contact_width / 2
+ 3 * (self.m1m2_via.second_layer_width - self.m1m2_via.first_layer_width) / 2,
self.nmos1.active_position[1] + self.nmos1.active_height]
offset = self.nmos1_position + offset
connection = vector(0,
self.nmos2.active_height+ 2 * drc["poly_extend_active"] \
+ drc["minwidth_poly"] + drc["minwidth_metal2"])
self.add_rect(layer="metal2",
offset=offset,
width=drc["minwidth_metal2"],
height=connection.y - drc["minwidth_metal2"])
self.BL_position = (vector(self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width,
offset.y)
+ connection)
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset,
mirror="MX")
self.add_label(text="bl",
layer="metal2",
offset=self.BL_position)
self.add_rect(layer="metal2",
offset=self.BL_position - vector(0, 2 * drc["minwidth_metal2"]),
width=drc["minwidth_metal2"],
height=2 * drc["minwidth_metal2"])
width = self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width - offset[0] + drc["minwidth_metal2"]
self.add_rect(layer="metal2",
offset=[offset[0],
self.BL_position[1] - 2*drc["minwidth_metal2"]],
width=width,
height=drc["minwidth_metal2"])
offset = self.nmos1_position + self.nmos1.active_contact_positions[1]
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset)
self.add_rect(layer="metal2",
offset=[self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width,
0],
width=drc["minwidth_metal2"],
height=(drc["minwidth_metal2"] + offset[1]))
self.add_rect(layer="metal2",
offset=[self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width,
offset[1]],
width=(offset[0] - self.bitcell_chars["BL"][0] - 0.5 * self.m1m2_via.width
+ 2 * drc["minwidth_metal2"]),
height=drc["minwidth_metal2"])
self.BL_out_position = vector(self.bitcell_chars["BL"][0] - 0.5* self.m1m2_via.width,
0)
self.add_label(text="bl_out",
layer="metal2",
offset=self.BL_out_position)
offset = [self.nmos2.active_contact_positions[1].x - self.m1m2_via.contact_width / 2,
self.nmos2.active_position[1] + self.nmos2.active_height]
offset = self.nmos2_position + offset
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset,
mirror="MX")
mid = offset + vector(drc["minwidth_metal2"],0)
self.add_rect(layer="metal2",
offset= mid,
width= (self.bitcell_chars["BR"][0] - mid[0] + 0.5*self.m1m2_via.width),
height=-drc["minwidth_metal2"])
self.add_rect(layer="metal2",
offset=[self.bitcell_chars["BR"][0] - 0.5*self.m1m2_via.width,
offset[1] - drc["metal1_to_metal1"]],
width=drc["minwidth_metal2"],
height=2*drc["minwidth_metal2"])
self.BR_position = vector(self.bitcell_chars["BR"][0] - 0.5 * self.m1m2_via.width,
self.BL_position.y)
self.add_label(text="br",
layer="metal2",
offset=self.BR_position)
offset = self.nmos2_position + self.nmos2.active_contact_positions[0]
self.BR_out_position = vector(self.bitcell_chars["BR"][0] - 0.5 * self.m1m2_via.width,
0)
self.add_label(text="br_out",
layer="metal2",
offset=self.BR_out_position)
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset)
self.add_rect(layer="metal2",
offset=offset,
width=self.BR_out_position.x - offset[0],
height=drc["minwidth_metal2"])
self.add_rect(layer="metal2",
offset=[self.BR_out_position.x,
offset[1] + drc["minwidth_metal2"]],
width=drc["minwidth_metal2"],
height=-(offset[1] + drc["minwidth_metal2"]))
def add_gnd_rail(self):
self.gnd_position = vector(self.bitcell_chars["gnd"][0] - 0.5 * self.m1m2_via.width,
0)
self.add_layout_pin(text="gnd",
layer="metal2",
offset=self.gnd_position,
width=drc["minwidth_metal2"],
height=self.BL_position[1])
def add_well_contacts(self):
offset = vector(self.gnd_position[0] + drc["minwidth_metal2"],
self.nmos1.poly_height / 2)
self.add_via(layers=("metal1", "via1", "metal2"),
offset=offset - vector(self.m1m2_via.width / 2, 0),
mirror="MY")
self.add_contact(layers=("active", "contact", "metal1"),
offset=offset - vector(self.m1m2_via.width, 0),
mirror="MY")
temp = vector(self.m1m2_via.width,
(self.pwell_contact.first_layer_height - self.pwell_contact.second_layer_height) / 2)
offset_implant = offset - temp + vector([drc["implant_to_contact"]]*2).scale(1,-1)
self.add_rect(layer="pimplant",
offset=offset_implant,
width=-(2*drc["implant_to_contact"] + self.pwell_contact.first_layer_width),
height=2*drc["implant_to_contact"] + self.pwell_contact.width)
offset_well = self.nmos1_position + vector(self.nmos1.width, 0)
self.add_rect(layer="pwell",
offset=offset_well,
width=self.gnd_position[0] + drc["minwidth_metal2"] - offset_well[0],
height=self.nmos1.height + drc["minwidth_poly"])
self.add_rect(layer="vtg",
offset=offset_well,
width=self.gnd_position[0] + drc["minwidth_metal2"] - offset_well[0],
height=self.nmos1.height + drc["minwidth_poly"])
def setup_layout_constants(self):
self.width = self.width = self.bitcell_chars["width"]
self.height = self.height = self.BL_position[1]