OpenRAM/compiler/pgates/pdriver.py

180 lines
6.6 KiB
Python
Raw Normal View History

2018-12-03 18:11:12 +01:00
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())