OpenRAM/compiler/wordline_driver.py

214 lines
8.8 KiB
Python

from tech import drc, parameter, cell
import debug
import design
from math import log
from math import sqrt
import math
from pinv import pinv
from nand_2 import nand_2
from vector import vector
from globals import OPTS
class wordline_driver(design.design):
"""
Creates a Wordline Driver
Generates the wordline-driver to drive the bitcell
"""
def __init__(self, name, rows):
design.design.__init__(self, name)
self.rows = rows
self.add_pins()
self.design_layout()
self.DRC_LVS()
def add_pins(self):
# inputs to wordline_driver.
for i in range(self.rows):
self.add_pin("decode_out[{0}]".format(i))
# Outputs from wordline_driver.
for i in range(self.rows):
self.add_pin("wl[{0}]".format(i))
self.add_pin("clk")
self.add_pin("vdd")
self.add_pin("gnd")
def design_layout(self):
self.add_layout()
self.offsets_of_gates()
self.create_layout()
def add_layout(self):
self.inv = pinv(name="pinverter",
nmos_width=drc["minwidth_tx"],
beta=parameter["pinv_beta"])
self.add_mod(self.inv)
self.NAND2 = nand_2(name="pnand2",
nmos_width=2*drc["minwidth_tx"])
self.add_mod(self.NAND2)
def offsets_of_gates(self):
self.x_offset0 = 2 * drc["minwidth_metal1"] + 5 * drc["metal1_to_metal1"]
self.x_offset1 = self.x_offset0 + self.inv.width
self.x_offset2 = self.x_offset1 + self.NAND2.width
self.width = self.x_offset2 + self.inv.width
self.height = self.inv.height * self.rows
# Defining offset postions
self.decode_out_positions = []
self.clk_positions = []
self.WL_positions = []
self.vdd_positions = []
self.gnd_positions = []
def create_layout(self):
# Clk connection
self.add_rect(layer="metal1",
offset=[drc["minwidth_metal1"] + 2 * drc["metal1_to_metal1"],
2 * drc["minwidth_metal1"]],
width=drc["minwidth_metal1"],
height=self.height + 4*drc["minwidth_metal1"])
self.clk_positions.append([drc["minwidth_metal1"] + 2*drc["metal1_to_metal1"],
self.height])
self.add_label(text="clk",
layer="metal1",
offset=self.clk_positions[0])
for row in range(self.rows):
name_inv1 = "Wordline_driver_inv_clk%d" % (row)
name_nand = "Wordline_driver_nand%d" % (row)
name_inv2 = "Wordline_driver_inv%d" % (row)
# Extend vdd and gnd of Wordline_driver
yoffset = (row + 1) * self.inv.height - 0.5 * drc["minwidth_metal2"]
self.add_rect(layer="metal2",
offset=[0, yoffset],
width=self.x_offset0,
height=drc["minwidth_metal2"])
self.add_via(layers=("metal1", "via1", "metal2"),
offset=[drc["minwidth_metal1"], yoffset],
mirror="R90")
self.add_via(layers=("metal1", "via1", "metal2"),
offset=[self.x_offset0 + drc["minwidth_metal1"],
yoffset],
mirror="R90")
inv_nand2B_connection_height = (abs(self.inv.Z_position.y
- self.NAND2.B_position.y)
+ drc["minwidth_metal1"])
if (row % 2):
y_offset = self.inv.height*(row + 1)
name_inv1_offset = [self.x_offset0, y_offset]
nand2_offset=[self.x_offset1, y_offset]
inv2_offset=[self.x_offset2, y_offset]
inst_mirror = "MX"
cell_dir = vector(0,-1)
m1tm2_rotate=270
m1tm2_mirror="R0"
else:
y_offset = self.inv.height*row
name_inv1_offset = [self.x_offset0, y_offset]
nand2_offset=[self.x_offset1, y_offset]
inv2_offset=[self.x_offset2, y_offset]
inst_mirror = "R0"
cell_dir = vector(0,1)
m1tm2_rotate=90
m1tm2_mirror="MX"
# add inv1 based on the info above
self.add_inst(name=name_inv1,
mod=self.inv,
offset=name_inv1_offset,
mirror=inst_mirror )
self.connect_inst(["clk", "clk_bar[{0}]".format(row),
"vdd", "gnd"])
# add nand 2
self.add_inst(name=name_nand,
mod=self.NAND2,
offset=nand2_offset,
mirror=inst_mirror)
self.connect_inst(["decode_out[{0}]".format(row),
"clk_bar[{0}]".format(row),
"net[{0}]".format(row),
"vdd", "gnd"])
# add inv2
self.add_inst(name=name_inv2,
mod=self.inv,
offset=inv2_offset,
mirror=inst_mirror)
self.connect_inst(["net[{0}]".format(row),
"wl[{0}]".format(row),
"vdd", "gnd"])
# clk connection
clk_offset= [drc["minwidth_metal1"] + 2 * drc["metal1_to_metal1"],
y_offset + cell_dir.y * self.inv.A_position.y]
self.add_rect(layer="metal1",
offset=clk_offset,
width=self.x_offset0 - 2*drc["metal1_to_metal1"],
height=cell_dir.y *drc["minwidth_metal1"])
# first inv to nand2 B
inv_to_nand2B_offset = [self.x_offset1 - drc["minwidth_metal1"],
y_offset + cell_dir.y * self.NAND2.B_position.y]
self.add_rect(layer="metal1",
offset=inv_to_nand2B_offset,
width=drc["minwidth_metal1"],
height=cell_dir.y*inv_nand2B_connection_height)
# Nand2 out to 2nd inv
nand2_to_2ndinv_offset =[self.x_offset2,
y_offset + cell_dir.y * self.NAND2.Z_position.y]
self.add_rect(layer="metal1",
offset=nand2_to_2ndinv_offset,
width=drc["minwidth_metal1"],
height=cell_dir.y * drc["minwidth_metal1"])
# nand2 A connection
self.add_rect(layer="metal2",
offset=[0, y_offset + cell_dir.y * self.NAND2.A_position.y],
width=self.x_offset1,
height=cell_dir.y*drc["minwidth_metal2"])
self.add_via(layers=("metal1", "via1", "metal2"),
offset=[self.x_offset1,
y_offset + cell_dir.y * self.NAND2.A_position.y],
rotate=m1tm2_rotate,
mirror=m1tm2_mirror)
self.add_via(layers=("metal1", "via1", "metal2"),
offset=[0,
y_offset +cell_dir.y*self.NAND2.A_position.y],
mirror=inst_mirror)
base_offset = vector(self.width, y_offset)
decode_out_offset = base_offset.scale(0,1)+self.NAND2.A_position.scale(cell_dir)
wl_offset = base_offset + self.inv.Z_position.scale(cell_dir)
vdd_offset = base_offset + self.inv.vdd_position.scale(cell_dir)
gnd_offset = base_offset + self.inv.gnd_position.scale(cell_dir)
self.add_label(text="decode_out[{0}]".format(row),
layer="metal2",
offset=decode_out_offset)
self.add_rect(layer="metal1",
offset=wl_offset,
width=drc["minwidth_metal1"]*cell_dir.y,
height=drc["minwidth_metal1"]*cell_dir.y)
self.add_label(text="wl[{0}]".format(row),
layer="metal1",
offset=wl_offset)
self.add_label(text="gnd",
layer="metal1",
offset=gnd_offset)
self.add_label(text="vdd",
layer="metal1",
offset=vdd_offset)
self.decode_out_positions.append(decode_out_offset)
self.WL_positions.append(wl_offset)
self.vdd_positions.append(vdd_offset)
self.gnd_positions.append(gnd_offset)