mirror of https://github.com/VLSIDA/OpenRAM.git
180 lines
6.6 KiB
Python
180 lines
6.6 KiB
Python
import debug
|
|
import design
|
|
import math
|
|
from tech import drc
|
|
from math import log
|
|
from vector import vector
|
|
from globals import OPTS
|
|
from pinv import pinv
|
|
|
|
class pdriver(design.design):
|
|
"""
|
|
This instantiates an even or odd number of inverters sized for driving a load.
|
|
"""
|
|
unique_id = 1
|
|
|
|
def __init__(self, driver_size=4, height=None, name="", neg_polarity=False, c_load=8, electrical_effort=1, size_list):
|
|
|
|
self.stage_effort = 4
|
|
self.row_height = height
|
|
# FIXME: Change the number of stages to support high drives.
|
|
|
|
# stage effort of 4 or less
|
|
self.driver_size = driver_size
|
|
self.neg_polarity = neg_polarity
|
|
self.size_list = size_list
|
|
self.c_load = c_load
|
|
self.electrical_effort = electrical_effort
|
|
|
|
if length(self.size_list) > 0 and (self.c_load != 8 or self.neg_polarity):
|
|
raise Exception("Cannot specify both neg_polarity or c_load and size_list.")
|
|
|
|
# size_list specified
|
|
if length(self.size_list) > 0:
|
|
if not length(self.size_list) % 2:
|
|
neg_polarity = True
|
|
self.inv_num = length(self.size_list)
|
|
else:
|
|
c_in = c_load/electrical_effort
|
|
N = max(1, math.loglp(electrical_effort) / math.loglp(3.6))
|
|
if self.neg_polarity:
|
|
if (int(N) % 2 == 0): # if N is even
|
|
self.inv_num = int(N)+1
|
|
else: # if N is odd
|
|
self.inv_num = int(N)
|
|
else: # positive polarity
|
|
if (int(N) % 2 == 0): # if N is even
|
|
self.inv_num = int(N)
|
|
else:
|
|
self.inv_num = int(N)+1
|
|
|
|
if name=="":
|
|
name = "pdriver_{0}_{1}_{2}".format(self.driver_size, self.inv_num,
|
|
pdriver.unique_id)
|
|
pdriver.unique_id += 1
|
|
|
|
design.design.__init__(self, name)
|
|
debug.info(1, "Creating {}".format(self.name))
|
|
|
|
self.create_netlist()
|
|
if not OPTS.netlist_only:
|
|
self.create_layout()
|
|
|
|
|
|
def create_netlist(self):
|
|
self.add_pins()
|
|
self.add_modules()
|
|
self.create_insts()
|
|
|
|
def create_layout(self):
|
|
|
|
self.width = self.inv_num * self.inv_list[0].width
|
|
self.height = self.inv_list[0].height
|
|
|
|
self.place_modules()
|
|
self.route_wires()
|
|
self.add_layout_pins()
|
|
|
|
self.DRC_LVS()
|
|
|
|
def add_pins(self):
|
|
self.add_pin("A")
|
|
self.add_pin("Z")
|
|
self.add_pin("vdd")
|
|
self.add_pin("gnd")
|
|
|
|
def add_modules(self):
|
|
inv_list = []
|
|
|
|
if length(self.size_list) > 0: # size list specified
|
|
for x in length(self.size_list):
|
|
inv_list.append.=(pinv(size=size_list[x], height=self.row_height))
|
|
self.add_mod(inv_list[x])
|
|
else:
|
|
# Shield the cap, but have at least a stage effort of 4
|
|
input_size = max(1,int(self.driver_size/self.stage_effort))
|
|
for x in inv_num:
|
|
inv_list.append(pinv(size=input_size, height=self.row_height))
|
|
self.add_mod(inv_list[x])
|
|
|
|
def create_insts(self):
|
|
inv_inst_list = []
|
|
|
|
for x in range(1,self.inv_num+1):
|
|
# Create first inverter
|
|
if x == 1:
|
|
zbx_int = "Zb{}_int".format(x);
|
|
inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
|
|
mod=self.inv_list[x]))
|
|
if self.inv_num == 1:
|
|
self.connect_inst(["A", "Z", "vdd", "gnd"])
|
|
else:
|
|
self.connect_inst(["A", zbx_int, "vdd", "gnd"])
|
|
# Create last inverter
|
|
else if x == inv_num:
|
|
zbn_int = "Zb{}_int".format(x-1);
|
|
inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
|
|
mod=self.inv_list[x]))
|
|
self.connect_inst([zbn_int, "Z", "vdd", "gnd"])
|
|
|
|
# Create middle inverters
|
|
else:
|
|
zbx_int = "Zb{}_int".format(x-1);
|
|
zbn_int = "Zb{}_int".format(x);
|
|
inv_inst_list.append(self.add_inst(name="buf_inv{}".format(x),
|
|
mod=self.inv_list[x]))
|
|
self.connect_inst([zbx_int, zbn_int, "vdd", "gnd"])
|
|
|
|
|
|
def place_modules(self):
|
|
# Add INV1 to the left
|
|
inv_inst_list[0].place(vector(0,0))
|
|
|
|
# Add inverters to the right of INV1
|
|
for x in range(1,len(inv_inst_list)):
|
|
inv_inst_list[x].place(vector(inv_inst_list[x-1].rx(),0))
|
|
|
|
|
|
def route_wires(self):
|
|
z_inst_list = []
|
|
a_inst_list = []
|
|
# inv_current Z to inv_next A
|
|
for x in range(0,len(inv_inst_list)-1):
|
|
z_inst_list.append(self.inv_inst_list[x].get_pin("Z"))
|
|
a_inst_list.append(self.inv_inst_list[x+1].get_pin("A"))
|
|
mid_point = vector(z_inst_list[x].cx(), a_inst_list[x].cy())
|
|
self.add_path("metal1", [z_inst_list[x].center(), mid_point, a_inst_list[x].center()])
|
|
|
|
|
|
def add_layout_pins(self):
|
|
# Continous vdd rail along with label.
|
|
vdd_pin=inv_inst_list[0].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 gnd rail along with label.
|
|
gnd_pin=inv_inst_list[0].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 = inv_inst_list[len(inv_inst_list)-1].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())
|
|
|
|
a_pin = inv_inst_list[0].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())
|
|
|
|
|