mirror of https://github.com/VLSIDA/OpenRAM.git
225 lines
10 KiB
Python
225 lines
10 KiB
Python
|
|
import design
|
||
|
|
import debug
|
||
|
|
from tech import drc, cell
|
||
|
|
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]
|