Update all drc usages to call function type

This commit is contained in:
Matt Guthaus 2018-10-12 14:37:51 -07:00
parent 4932d83afc
commit ce8c2d983d
27 changed files with 194 additions and 185 deletions

View File

@ -73,21 +73,21 @@ class contact(hierarchy_design.hierarchy_design):
self.second_layer_name = second_layer
def setup_layout_constants(self):
self.contact_width = drc["minwidth_{0}". format(self.via_layer_name)]
contact_to_contact = drc["{0}_to_{0}".format(self.via_layer_name)]
self.contact_width = drc("minwidth_{0}". format(self.via_layer_name))
contact_to_contact = drc("{0}_to_{0}".format(self.via_layer_name))
self.contact_pitch = self.contact_width + contact_to_contact
self.contact_array_width = self.contact_width + (self.dimensions[0] - 1) * self.contact_pitch
self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch
# DRC rules
first_layer_minwidth = drc["minwidth_{0}".format(self.first_layer_name)]
first_layer_minarea = drc["minarea_{0}".format(self.first_layer_name)]
first_layer_enclosure = drc["{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name)]
first_layer_extend = drc["{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name)]
second_layer_minwidth = drc["minwidth_{0}".format(self.second_layer_name)]
second_layer_minarea = drc["minarea_{0}".format(self.second_layer_name)]
second_layer_enclosure = drc["{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name)]
second_layer_extend = drc["{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name)]
first_layer_minwidth = drc("minwidth_{0}".format(self.first_layer_name))
first_layer_minarea = drc("minarea_{0}".format(self.first_layer_name))
first_layer_enclosure = drc("{0}_enclosure_{1}".format(self.first_layer_name, self.via_layer_name))
first_layer_extend = drc("{0}_extend_{1}".format(self.first_layer_name, self.via_layer_name))
second_layer_minwidth = drc("minwidth_{0}".format(self.second_layer_name))
second_layer_minarea = drc("minarea_{0}".format(self.second_layer_name))
second_layer_enclosure = drc("{0}_enclosure_{1}".format(self.second_layer_name, self.via_layer_name))
second_layer_extend = drc("{0}_extend_{1}".format(self.second_layer_name, self.via_layer_name))
self.first_layer_horizontal_enclosure = max((first_layer_minwidth - self.contact_array_width) / 2,
first_layer_enclosure)
@ -145,16 +145,16 @@ class contact(hierarchy_design.hierarchy_design):
height=self.second_layer_height)
def create_implant_well_enclosures(self):
implant_position = self.first_layer_position - [drc["implant_enclosure_active"]]*2
implant_width = self.first_layer_width + 2*drc["implant_enclosure_active"]
implant_height = self.first_layer_height + 2*drc["implant_enclosure_active"]
implant_position = self.first_layer_position - [drc("implant_enclosure_active")]*2
implant_width = self.first_layer_width + 2*drc("implant_enclosure_active")
implant_height = self.first_layer_height + 2*drc("implant_enclosure_active")
self.add_rect(layer="{}implant".format(self.implant_type),
offset=implant_position,
width=implant_width,
height=implant_height)
well_position = self.first_layer_position - [drc["well_enclosure_active"]]*2
well_width = self.first_layer_width + 2*drc["well_enclosure_active"]
well_height = self.first_layer_height + 2*drc["well_enclosure_active"]
well_position = self.first_layer_position - [drc("well_enclosure_active")]*2
well_width = self.first_layer_width + 2*drc("well_enclosure_active")
well_height = self.first_layer_height + 2*drc("well_enclosure_active")
self.add_rect(layer="{}well".format(self.well_type),
offset=well_position,
width=well_width,

View File

@ -29,24 +29,24 @@ class design(hierarchy_design):
def setup_drc_constants(self):
""" These are some DRC constants used in many places in the compiler."""
from tech import drc
self.well_width = drc["minwidth_well"]
self.poly_width = drc["minwidth_poly"]
self.poly_space = drc["poly_to_poly"]
self.m1_width = drc["minwidth_metal1"]
self.m1_space = drc["metal1_to_metal1"]
self.m2_width = drc["minwidth_metal2"]
self.m2_space = drc["metal2_to_metal2"]
self.m3_width = drc["minwidth_metal3"]
self.m3_space = drc["metal3_to_metal3"]
self.active_width = drc["minwidth_active"]
self.contact_width = drc["minwidth_contact"]
self.well_width = drc("minwidth_well")
self.poly_width = drc("minwidth_poly")
self.poly_space = drc("poly_to_poly")
self.m1_width = drc("minwidth_metal1")
self.m1_space = drc("metal1_to_metal1")
self.m2_width = drc("minwidth_metal2")
self.m2_space = drc("metal2_to_metal2")
self.m3_width = drc("minwidth_metal3")
self.m3_space = drc("metal3_to_metal3")
self.active_width = drc("minwidth_active")
self.contact_width = drc("minwidth_contact")
self.poly_to_active = drc["poly_to_active"]
self.poly_extend_active = drc["poly_extend_active"]
self.contact_to_gate = drc["contact_to_gate"]
self.well_enclose_active = drc["well_enclosure_active"]
self.implant_enclose_active = drc["implant_enclosure_active"]
self.implant_space = drc["implant_to_implant"]
self.poly_to_active = drc("poly_to_active")
self.poly_extend_active = drc("poly_extend_active")
self.contact_to_gate = drc("contact_to_gate")
self.well_enclose_active = drc("well_enclosure_active")
self.implant_enclose_active = drc("implant_enclosure_active")
self.implant_space = drc("implant_to_implant")
def setup_multiport_constants(self):
""" These are contants and lists that aid multiport design """

View File

@ -63,7 +63,7 @@ class pin_layout:
and return the new rectangle.
"""
if not spacing:
spacing = 0.5*drc["{0}_to_{0}".format(self.layer)]
spacing = 0.5*drc("{0}_to_{0}".format(self.layer))
(ll,ur) = self.rect
spacing = vector(spacing, spacing)

View File

@ -40,9 +40,9 @@ class route(design):
(self.horiz_layer_width, self.num_vias, self.vert_layer_width) = self.layer_widths
if not self.vert_layer_width:
self.vert_layer_width = drc["minwidth_{0}".format(self.vert_layer_name)]
self.vert_layer_width = drc("minwidth_{0}".format(self.vert_layer_name))
if not self.horiz_layer_width:
self.horiz_layer_width = drc["minwidth_{0}".format(self.horiz_layer_name)]
self.horiz_layer_width = drc("minwidth_{0}".format(self.horiz_layer_name))
# offset this by 1/2 the via size
self.c=contact(self.layer_stack, (self.num_vias, self.num_vias))

View File

@ -33,14 +33,14 @@ class wire(path):
self.via_layer_name = via_layer
self.vert_layer_name = vert_layer
self.vert_layer_width = drc["minwidth_{0}".format(vert_layer)]
self.vert_layer_width = drc("minwidth_{0}".format(vert_layer))
self.horiz_layer_name = horiz_layer
self.horiz_layer_width = drc["minwidth_{0}".format(horiz_layer)]
self.horiz_layer_width = drc("minwidth_{0}".format(horiz_layer))
via_connect = contact(self.layer_stack,
(1, 1))
self.node_to_node = [drc["minwidth_" + str(self.horiz_layer_name)] + via_connect.width,
drc["minwidth_" + str(self.horiz_layer_name)] + via_connect.height]
self.node_to_node = [drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.width,
drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.height]
# create a 1x1 contact
def create_vias(self):

View File

@ -1,3 +1,4 @@
import debug
from drc_value import *
from drc_lut import *
@ -13,7 +14,11 @@ class design_rules():
self.rules[name] = value
def __call__(self, name, *args):
return self.rules[name](args)
rule = self.rules[name]
if callable(rule):
return rule(args)
else:
return rule
def __setitem__(self, b, c):
"""
@ -26,10 +31,10 @@ class design_rules():
For backward compatibility with existing rules.
"""
rule = self.rules[b]
if callable(rule):
return rule()
else:
if not callable(rule):
return rule
else:
debug.error("Must call complex DRC rule {} with arguments.".format(b),-1)

View File

@ -12,18 +12,16 @@ class drc_lut():
def __init__(self, table):
self.table = table
def __call__(self, *args):
def __call__(self, *key):
"""
Lookup a given tuple in the table.
"""
key_tuple = args
if not key_tuple:
if len(*key)==0:
key_size = len(list(self.table.keys())[0])
key_tuple = tuple(0 for i in range(key_size))
for key in sorted(self.table.keys(), reverse=True):
if self.match(key_tuple, key):
return self.table[key]
key = tuple(0 for i in range(key_size))
for table_key in sorted(self.table.keys(), reverse=True):
if self.match(key, table_key):
return self.table[table_key]
def match(self, t1, t2):
"""

View File

@ -200,7 +200,7 @@ class bank(design.design):
self.central_bus_width = self.m2_pitch * self.num_control_lines + 2*self.m2_width
# A space for wells or jogging m2
self.m2_gap = max(2*drc["pwell_to_nwell"] + drc["well_enclosure_active"],
self.m2_gap = max(2*drc("pwell_to_nwell") + drc("well_enclosure_active"),
2*self.m2_pitch)
@ -530,7 +530,7 @@ class bank(design.design):
# Place the col decoder right aligned with row decoder
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width)
y_off = -(self.col_decoder.height + 2*drc["well_to_well"])
y_off = -(self.col_decoder.height + 2*drc("well_to_well"))
col_decoder_inst.place(vector(x_off,y_off))
@ -567,7 +567,7 @@ class bank(design.design):
y_off = min(self.col_decoder_inst[port].by(), self.col_mux_array_inst[port].by())
else:
y_off = self.row_decoder_inst[port].by()
y_off -= (self.bank_select.height + drc["well_to_well"])
y_off -= (self.bank_select.height + drc("well_to_well"))
self.bank_select_pos = vector(x_off,y_off)
self.bank_select_inst[port].place(self.bank_select_pos)

View File

@ -67,7 +67,7 @@ class bank_select(design.design):
self.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell()
height = self.bitcell.height + drc["poly_to_active"]
height = self.bitcell.height + drc("poly_to_active")
# 1x Inverter
self.inv_sel = pinv(height=height)
@ -88,8 +88,8 @@ class bank_select(design.design):
def calculate_module_offsets(self):
self.xoffset_nand = self.inv4x.width + 2*self.m2_pitch + drc["pwell_to_nwell"]
self.xoffset_nor = self.inv4x.width + 2*self.m2_pitch + drc["pwell_to_nwell"]
self.xoffset_nand = self.inv4x.width + 2*self.m2_pitch + drc("pwell_to_nwell")
self.xoffset_nor = self.inv4x.width + 2*self.m2_pitch + drc("pwell_to_nwell")
self.xoffset_inv = max(self.xoffset_nand + self.nand2.width, self.xoffset_nor + self.nor2.width)
self.xoffset_bank_sel_inv = 0
self.xoffset_inputs = 0

View File

@ -39,7 +39,7 @@ class bitcell_array(design.design):
def create_layout(self):
# We increase it by a well enclosure so the precharges don't overlap our wells
self.height = self.row_size*self.cell.height + drc["well_enclosure_active"] + self.m1_width
self.height = self.row_size*self.cell.height + drc("well_enclosure_active") + self.m1_width
self.width = self.column_size*self.cell.width + self.m1_width
xoffset = 0.0
@ -199,13 +199,13 @@ class bitcell_array(design.design):
return total_power
def gen_wl_wire(self):
wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc["minwidth_metal1"])
wl_wire = self.generate_rc_net(int(self.column_size), self.width, drc("minwidth_metal1"))
wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
return wl_wire
def gen_bl_wire(self):
bl_pos = 0
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), self.height, drc["minwidth_metal1"])
bl_wire = self.generate_rc_net(int(self.row_size-bl_pos), self.height, drc("minwidth_metal1"))
bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire

View File

@ -170,7 +170,7 @@ class multibank(design.design):
self.central_bus_width = self.m2_pitch * self.num_control_lines + 2*self.m2_width
# A space for wells or jogging m2
self.m2_gap = max(2*drc["pwell_to_nwell"] + drc["well_enclosure_active"],
self.m2_gap = max(2*drc("pwell_to_nwell"] + drc["well_enclosure_active"),
2*self.m2_pitch)
@ -382,7 +382,7 @@ class multibank(design.design):
"""
# Place the col decoder right aligned with row decoder
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width)
y_off = -(self.col_decoder.height + 2*drc["well_to_well"])
y_off = -(self.col_decoder.height + 2*drc("well_to_well"))
self.col_decoder_inst=self.add_inst(name="col_address_decoder",
mod=self.col_decoder,
offset=vector(x_off,y_off))
@ -427,7 +427,7 @@ class multibank(design.design):
y_off = min(self.col_decoder_inst.by(), self.col_mux_array_inst.by())
else:
y_off = self.row_decoder_inst.by()
y_off -= (self.bank_select.height + drc["well_to_well"])
y_off -= (self.bank_select.height + drc("well_to_well"))
self.bank_select_pos = vector(x_off,y_off)
self.bank_select_inst = self.add_inst(name="bank_select",
mod=self.bank_select,

View File

@ -63,7 +63,7 @@ class precharge_array(design.design):
layer="metal1",
offset=self.pc_cell.get_pin("en").ll(),
width=self.width,
height=drc["minwidth_metal1"])
height=drc("minwidth_metal1"))
for inst in self.local_insts:
self.copy_layout_pin(inst, "vdd")
@ -74,13 +74,13 @@ class precharge_array(design.design):
self.add_layout_pin(text="bl_{0}".format(i),
layer="metal2",
offset=bl_pin.ll(),
width=drc["minwidth_metal2"],
width=drc("minwidth_metal2"),
height=bl_pin.height())
br_pin = inst.get_pin("br")
self.add_layout_pin(text="br_{0}".format(i),
layer="metal2",
offset=br_pin.ll(),
width=drc["minwidth_metal2"],
width=drc("minwidth_metal2"),
height=bl_pin.height())

View File

@ -186,9 +186,9 @@ class replica_bitline(design.design):
# Route the connection to the right so that it doesn't interfere with the cells
# Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions
if row % 2 == 0:
vertical_extension = vector(0, 1.5*drc["minwidth_metal1"] + 0.5*contact.m1m2.height)
vertical_extension = vector(0, 1.5*drc("minwidth_metal1") + 0.5*contact.m1m2.height)
else:
vertical_extension = vector(0, -1.5*drc["minwidth_metal1"] - 1.5*contact.m1m2.height)
vertical_extension = vector(0, -1.5*drc("minwidth_metal1") - 1.5*contact.m1m2.height)
pin_right = pin.rc()
pin_extension1 = pin_right + vector(self.m3_pitch,0)
@ -202,7 +202,7 @@ class replica_bitline(design.design):
wl_last = self.wl_list[self.total_ports-1]+"_{}".format(row)
pin_last = self.rbl_inst.get_pin(wl_last)
correct = vector(0.5*drc["minwidth_metal1"], 0)
correct = vector(0.5*drc("minwidth_metal1"), 0)
self.add_path("metal1", [pin.rc()-correct, pin_last.rc()-correct])
def route_supplies(self):
@ -261,7 +261,7 @@ class replica_bitline(design.design):
# 3. Route the contact of previous route to the bitcell WL
# route bend of previous net to bitcell WL
wl_offset = self.rbc_inst.get_pin(self.wl_list[0]).lc()
wl_mid1 = wl_offset - vector(1.5*drc["minwidth_metal1"], 0)
wl_mid1 = wl_offset - vector(1.5*drc("minwidth_metal1"), 0)
wl_mid2 = vector(wl_mid1.x, contact_offset.y)
#xmid_point= 0.5*(wl_offset.x+contact_offset.x)
#wl_mid1 = vector(xmid_point,contact_offset.y)
@ -274,7 +274,7 @@ class replica_bitline(design.design):
pin = self.rbc_inst.get_pin(wl)
pin_last = self.rbc_inst.get_pin(wl_last)
correct = vector(0.5*drc["minwidth_metal1"], 0)
correct = vector(0.5*drc("minwidth_metal1"), 0)
self.add_path("metal1", [pin.lc()+correct, pin_last.lc()+correct])
# DRAIN ROUTE

View File

@ -132,7 +132,7 @@ class sense_amp_array(design.design):
layer="metal1",
offset=sclk_offset,
width=self.width,
height=drc["minwidth_metal1"])
height=drc("minwidth_metal1"))
def analytical_delay(self, slew, load=0.0):
return self.amp.analytical_delay(slew=slew, load=load)

View File

@ -170,23 +170,23 @@ class single_level_column_mux_array(design.design):
self.add_rect(layer="metal1",
offset=bl_out_offset,
width=width,
height=drc["minwidth_metal2"])
height=drc("minwidth_metal2"))
self.add_rect(layer="metal1",
offset=br_out_offset,
width=width,
height=drc["minwidth_metal2"])
height=drc("minwidth_metal2"))
# Extend the bitline output rails and gnd downward on the first bit of each n-way mux
self.add_layout_pin(text="bl_out_{}".format(int(j/self.words_per_row)),
layer="metal2",
offset=bl_out_offset.scale(1,0),
width=drc['minwidth_metal2'],
width=drc('minwidth_metal2'),
height=self.route_height)
self.add_layout_pin(text="br_out_{}".format(int(j/self.words_per_row)),
layer="metal2",
offset=br_out_offset.scale(1,0),
width=drc['minwidth_metal2'],
width=drc('minwidth_metal2'),
height=self.route_height)
# This via is on the right of the wire
@ -202,7 +202,7 @@ class single_level_column_mux_array(design.design):
self.add_rect(layer="metal2",
offset=bl_out_offset,
width=drc['minwidth_metal2'],
width=drc('minwidth_metal2'),
height=self.route_height-bl_out_offset.y)
# This via is on the right of the wire
self.add_via(layers=("metal1", "via1", "metal2"),
@ -210,7 +210,7 @@ class single_level_column_mux_array(design.design):
rotate=90)
self.add_rect(layer="metal2",
offset=br_out_offset,
width=drc['minwidth_metal2'],
width=drc('minwidth_metal2'),
height=self.route_height-br_out_offset.y)
# This via is on the left of the wire
self.add_via(layers=("metal1", "via1", "metal2"),

View File

@ -107,14 +107,14 @@ class tri_gate_array(design.design):
layer="metal1",
offset=en_pin.ll().scale(0, 1),
width=width,
height=drc["minwidth_metal1"])
height=drc("minwidth_metal1"))
enbar_pin = self.tri_inst[0].get_pin("en_bar")
self.add_layout_pin(text="en_bar",
layer="metal1",
offset=enbar_pin.ll().scale(0, 1),
width=width,
height=drc["minwidth_metal1"])
height=drc("minwidth_metal1"))

View File

@ -130,7 +130,7 @@ class write_driver_array(design.design):
layer="metal1",
offset=self.driver_insts[0].get_pin("en").ll().scale(0,1),
width=self.width,
height=drc['minwidth_metal1'])
height=drc('minwidth_metal1'))

View File

@ -110,7 +110,7 @@ class pgate(design.design):
max_y_offset = self.height + 0.5*self.m1_width
self.nwell_position = middle_position
nwell_height = max_y_offset - middle_position.y
if drc["has_nwell"]:
if drc("has_nwell"):
self.add_rect(layer="nwell",
offset=middle_position,
width=self.well_width,
@ -122,7 +122,7 @@ class pgate(design.design):
pwell_position = vector(0,-0.5*self.m1_width)
pwell_height = middle_position.y-pwell_position.y
if drc["has_pwell"]:
if drc("has_pwell"):
self.add_rect(layer="pwell",
offset=pwell_position,
width=self.well_width,
@ -138,7 +138,7 @@ class pgate(design.design):
layer_stack = ("active", "contact", "metal1")
# To the right a spacing away from the pmos right active edge
contact_xoffset = pmos_pos.x + pmos.active_width + drc["active_to_body_active"]
contact_xoffset = pmos_pos.x + pmos.active_width + drc("active_to_body_active")
# Must be at least an well enclosure of active down from the top of the well
# OR align the active with the top of PMOS active.
max_y_offset = self.height + 0.5*self.m1_width
@ -185,7 +185,7 @@ class pgate(design.design):
pwell_position = vector(0,-0.5*self.m1_width)
# To the right a spacing away from the nmos right active edge
contact_xoffset = nmos_pos.x + nmos.active_width + drc["active_to_body_active"]
contact_xoffset = nmos_pos.x + nmos.active_width + drc("active_to_body_active")
# Must be at least an well enclosure of active up from the bottom of the well
contact_yoffset = max(nmos_pos.y,
self.well_enclose_active - nmos.active_contact.first_layer_height/2)

View File

@ -76,8 +76,8 @@ class pinv(pgate.pgate):
# This may make the result differ when the layout is created...
if OPTS.netlist_only:
self.tx_mults = 1
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_size*drc("minwidth_tx")
return
# Do a quick sanity check and bail if unlikely feasible height
@ -85,16 +85,16 @@ class pinv(pgate.pgate):
# Assume we need 3 metal 1 pitches (2 power rails, one between the tx for the drain)
# plus the tx height
nmos = ptx(tx_type="nmos")
pmos = ptx(width=drc["minwidth_tx"], tx_type="pmos")
pmos = ptx(width=drc("minwidth_tx"), tx_type="pmos")
tx_height = nmos.poly_height + pmos.poly_height
# rotated m1 pitch or poly to active spacing
min_channel = max(contact.poly.width + self.m1_space,
contact.poly.width + 2*drc["poly_to_active"])
contact.poly.width + 2*drc("poly_to_active"))
# This is the extra space needed to ensure DRC rules to the active contacts
extra_contact_space = max(-nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc["poly_extend_active"], self.poly_space)
drc("poly_extend_active"), self.poly_space)
total_height = tx_height + min_channel + 2*self.top_bottom_space
debug.check(self.height> total_height,"Cell height {0} too small for simple min height {1}.".format(self.height,total_height))
@ -103,16 +103,16 @@ class pinv(pgate.pgate):
# Divide the height in half. Could divide proportional to beta, but this makes
# connecting wells of multiple cells easier.
# Subtract the poly space under the rail of the tx
nmos_height_available = 0.5 * tx_height_available - 0.5*drc["poly_to_poly"]
pmos_height_available = 0.5 * tx_height_available - 0.5*drc["poly_to_poly"]
nmos_height_available = 0.5 * tx_height_available - 0.5*drc("poly_to_poly")
pmos_height_available = 0.5 * tx_height_available - 0.5*drc("poly_to_poly")
debug.info(2,"Height avail {0:.4f} PMOS {1:.4f} NMOS {2:.4f}".format(tx_height_available,
nmos_height_available,
pmos_height_available))
# Determine the number of mults for each to fit width into available space
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_size*drc("minwidth_tx")
nmos_required_mults = max(int(ceil(self.nmos_width/nmos_height_available)),1)
pmos_required_mults = max(int(ceil(self.pmos_width/pmos_height_available)),1)
# The mults must be the same for easy connection of poly
@ -124,9 +124,9 @@ class pinv(pgate.pgate):
# We also need to round the width to the grid or we will end up with LVS property
# mismatch errors when fingers are not a grid length and get rounded in the offset geometry.
self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults)
debug.check(self.nmos_width>=drc["minwidth_tx"],"Cannot finger NMOS transistors to fit cell height.")
debug.check(self.nmos_width>=drc("minwidth_tx"),"Cannot finger NMOS transistors to fit cell height.")
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
debug.check(self.pmos_width>=drc["minwidth_tx"],"Cannot finger PMOS transistors to fit cell height.")
debug.check(self.pmos_width>=drc("minwidth_tx"),"Cannot finger PMOS transistors to fit cell height.")
def setup_layout_constants(self):
@ -137,7 +137,7 @@ class pinv(pgate.pgate):
# the well width is determined the multi-finger PMOS device width plus
# the well contact width and half well enclosure on both sides
self.well_width = self.pmos.active_width + self.pmos.active_contact.width \
+ drc["active_to_body_active"] + 2*drc["well_enclosure_active"]
+ drc("active_to_body_active") + 2*drc("well_enclosure_active")
self.width = self.well_width
# Height is an input parameter, so it is not recomputed.

View File

@ -23,8 +23,8 @@ class pnand2(pgate.pgate):
self.nmos_size = 2*size
self.pmos_size = parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_size*drc("minwidth_tx")
# FIXME: Allow these to be sized
debug.check(size==1,"Size 1 pnand2 is only supported now.")
@ -91,7 +91,7 @@ class pnand2(pgate.pgate):
# Two PMOS devices and a well contact. Separation between each.
# Enclosure space on the sides.
self.well_width = 2*self.pmos.active_width + contact.active.width \
+ 2*drc["active_to_body_active"] + 2*drc["well_enclosure_active"]
+ 2*drc("active_to_body_active") + 2*drc("well_enclosure_active")
self.width = self.well_width
# Height is an input parameter, so it is not recomputed.
@ -100,7 +100,7 @@ class pnand2(pgate.pgate):
extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc["poly_extend_active"], self.poly_space)
drc("poly_extend_active"), self.poly_space)
def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """

View File

@ -25,8 +25,8 @@ class pnand3(pgate.pgate):
# If we relax this, we could size this better.
self.nmos_size = 2*size
self.pmos_size = parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_size*drc("minwidth_tx")
# FIXME: Allow these to be sized
debug.check(size==1,"Size 1 pnand3 is only supported now.")
@ -83,7 +83,7 @@ class pnand3(pgate.pgate):
# Two PMOS devices and a well contact. Separation between each.
# Enclosure space on the sides.
self.well_width = 3*self.pmos.active_width + self.pmos.active_contact.width \
+ 2*drc["active_to_body_active"] + 2*drc["well_enclosure_active"] \
+ 2*drc("active_to_body_active") + 2*drc("well_enclosure_active") \
- self.overlap_offset.x
self.width = self.well_width
# Height is an input parameter, so it is not recomputed.
@ -96,7 +96,7 @@ class pnand3(pgate.pgate):
extra_contact_space = max(-nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc["poly_extend_active"], self.poly_space)
drc("poly_extend_active"), self.poly_space)
def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """
@ -191,7 +191,7 @@ class pnand3(pgate.pgate):
metal_spacing = max(self.m1_space + self.m1_width, self.m2_space + self.m2_width,
self.m1_space + 0.5*contact.poly.width + 0.5*self.m1_width)
active_spacing = max(self.m1_space, 0.5*contact.poly.first_layer_width + drc["poly_to_active"])
active_spacing = max(self.m1_space, 0.5*contact.poly.first_layer_width + drc("poly_to_active"))
inputC_yoffset = self.nmos3_pos.y + self.nmos.active_height + active_spacing
self.route_input_gate(self.pmos3_inst, self.nmos3_inst, inputC_yoffset, "C", position="center")

View File

@ -24,8 +24,8 @@ class pnor2(pgate.pgate):
self.nmos_size = size
# We will just make this 1.5 times for now. NORs are not ideal anyhow.
self.pmos_size = 1.5*parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_size*drc("minwidth_tx")
# FIXME: Allow these to be sized
debug.check(size==1,"Size 1 pnor2 is only supported now.")
@ -92,7 +92,7 @@ class pnor2(pgate.pgate):
# Two PMOS devices and a well contact. Separation between each.
# Enclosure space on the sides.
self.well_width = 2*self.pmos.active_width + self.pmos.active_contact.width \
+ 2*drc["active_to_body_active"] + 2*drc["well_enclosure_active"]
+ 2*drc("active_to_body_active") + 2*drc("well_enclosure_active")
self.width = self.well_width
# Height is an input parameter, so it is not recomputed.
@ -101,7 +101,7 @@ class pnor2(pgate.pgate):
extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
drc["poly_extend_active"], self.poly_space)
drc("poly_extend_active"), self.poly_space)
def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """

View File

@ -162,7 +162,7 @@ class precharge(pgate.pgate):
"""Adds a nwell tap to connect to the vdd rail"""
# adds the contact from active to metal1
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \
+ vector(0, self.upper_pmos1_inst.uy() + contact.well.height/2 + drc["well_extend_active"])
+ vector(0, self.upper_pmos1_inst.uy() + contact.well.height/2 + drc("well_extend_active"))
self.add_contact_center(layers=("active", "contact", "metal1"),
offset=well_contact_pos,
implant_type="n",
@ -184,7 +184,7 @@ class precharge(pgate.pgate):
self.add_layout_pin(text="bl",
layer="metal2",
offset=offset,
width=drc['minwidth_metal2'],
width=drc("minwidth_metal2"),
height=self.height)
# adds the BR on metal 2
@ -192,7 +192,7 @@ class precharge(pgate.pgate):
self.add_layout_pin(text="br",
layer="metal2",
offset=offset,
width=drc['minwidth_metal2'],
width=drc("minwidth_metal2"),
height=self.height)
def connect_to_bitlines(self):

View File

@ -15,7 +15,7 @@ class ptx(design.design):
you to connect the fingered gates and active for parallel devices.
"""
def __init__(self, width=drc["minwidth_tx"], mults=1, tx_type="nmos", connect_active=False, connect_poly=False, num_contacts=None):
def __init__(self, width=drc("minwidth_tx"), mults=1, tx_type="nmos", connect_active=False, connect_poly=False, num_contacts=None):
# We need to keep unique names because outputting to GDSII
# will use the last record with a given name. I.e., you will
# over-write a design in GDS if one has and the other doesn't
@ -66,12 +66,12 @@ class ptx(design.design):
# self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
# " ".join(self.pins)))
# Just make a guess since these will actually be decided in the layout later.
area_sd = 2.5*drc["minwidth_poly"]*self.tx_width
perimeter_sd = 2*drc["minwidth_poly"] + 2*self.tx_width
area_sd = 2.5*drc("minwidth_poly")*self.tx_width
perimeter_sd = 2*drc("minwidth_poly") + 2*self.tx_width
self.spice_device="M{{0}} {{1}} {0} m={1} w={2}u l={3}u pd={4}u ps={4}u as={5}p ad={5}p".format(spice[self.tx_type],
self.mults,
self.tx_width,
drc["minwidth_poly"],
drc("minwidth_poly"),
perimeter_sd,
area_sd)
self.spice.append("\n* ptx " + self.spice_device)
@ -109,7 +109,7 @@ class ptx(design.design):
self.contact_pitch = 2*self.contact_to_gate + self.contact_width + self.poly_width
# The enclosure of an active contact. Not sure about second term.
active_enclose_contact = max(drc["active_enclosure_contact"],
active_enclose_contact = max(drc("active_enclosure_contact"),
(self.active_width - self.contact_width)/2)
# This is the distance from the edge of poly to the contacted end of active
self.end_to_poly = active_enclose_contact + self.contact_width + self.contact_to_gate
@ -129,7 +129,7 @@ class ptx(design.design):
self.active_offset = vector([self.well_enclose_active]*2)
# Well enclosure of active, ensure minwidth as well
if drc["has_{}well".format(self.well_type)]:
if drc("has_{}well".format(self.well_type)):
self.cell_well_width = max(self.active_width + 2*self.well_enclose_active,
self.well_width)
self.cell_well_height = max(self.tx_width + 2*self.well_enclose_active,
@ -151,9 +151,9 @@ class ptx(design.design):
# Min area results are just flagged for now.
debug.check(self.active_width*self.active_height>=drc["minarea_active"],"Minimum active area violated.")
debug.check(self.active_width*self.active_height>=drc("minarea_active"),"Minimum active area violated.")
# We do not want to increase the poly dimensions to fix an area problem as it would cause an LVS issue.
debug.check(self.poly_width*self.poly_height>=drc["minarea_poly"],"Minimum poly area violated.")
debug.check(self.poly_width*self.poly_height>=drc("minarea_poly"),"Minimum poly area violated.")
def connect_fingered_poly(self, poly_positions):
"""
@ -181,7 +181,7 @@ class ptx(design.design):
layer="poly",
offset=poly_offset,
width=poly_width,
height=drc["minwidth_poly"])
height=drc("minwidth_poly"))
def connect_fingered_active(self, drain_positions, source_positions):
@ -269,7 +269,7 @@ class ptx(design.design):
height=self.active_height)
# If the implant must enclose the active, shift offset
# and increase width/height
enclose_width = drc["implant_enclosure_active"]
enclose_width = drc("implant_enclosure_active")
enclose_offset = [enclose_width]*2
self.add_rect(layer="{}implant".format(self.implant_type),
offset=self.active_offset - enclose_offset,
@ -280,7 +280,7 @@ class ptx(design.design):
"""
Add an (optional) well and implant for the type of transistor.
"""
if drc["has_{}well".format(self.well_type)]:
if drc("has_{}well".format(self.well_type)):
self.add_rect(layer="{}well".format(self.well_type),
offset=(0,0),
width=self.cell_well_width,

View File

@ -52,7 +52,7 @@ class single_level_column_mux(design.design):
self.bitcell = self.mod_bitcell()
# Adds nmos_lower,nmos_upper to the module
self.ptx_width = self.tx_size * drc["minwidth_tx"]
self.ptx_width = self.tx_size * drc("minwidth_tx")
self.nmos = ptx(width=self.ptx_width)
self.add_mod(self.nmos)

View File

@ -1,6 +1,6 @@
import sys
import gdsMill
import tech
from tech import drc,GDS,layer
from contact import contact
import math
import debug
@ -31,7 +31,7 @@ class router:
self.cell.gds_write(gds_filename)
# Load the gds file and read in all the shapes
self.layout = gdsMill.VlsiLayout(units=tech.GDS["unit"])
self.layout = gdsMill.VlsiLayout(units=GDS["unit"])
self.reader = gdsMill.Gds2reader(self.layout)
self.reader.loadFromFile(gds_filename)
self.top_name = self.layout.rootStructureName
@ -118,17 +118,18 @@ class router:
self.layers = layers
(self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.layers
self.vert_layer_minwidth = tech.drc["minwidth_{0}".format(self.vert_layer_name)]
self.vert_layer_spacing = tech.drc[str(self.vert_layer_name)+"_to_"+str(self.vert_layer_name)]
self.vert_layer_number = tech.layer[self.vert_layer_name]
self.horiz_layer_minwidth = tech.drc["minwidth_{0}".format(self.horiz_layer_name)]
self.horiz_layer_spacing = tech.drc[str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name)]
self.horiz_layer_number = tech.layer[self.horiz_layer_name]
# Contacted track spacing.
# This is the minimum routed track spacing
via_connect = contact(self.layers, (1, 1))
self.max_via_size = max(via_connect.width,via_connect.height)
self.vert_layer_minwidth = drc("minwidth_{0}".format(self.vert_layer_name))
self.vert_layer_spacing = drc(str(self.vert_layer_name)+"_to_"+str(self.vert_layer_name))
self.vert_layer_number = layer[self.vert_layer_name]
self.horiz_layer_minwidth = drc("minwidth_{0}".format(self.horiz_layer_name))
self.horiz_layer_spacing = drc(str(self.horiz_layer_name)+"_to_"+str(self.horiz_layer_name))
self.horiz_layer_number = layer[self.horiz_layer_name]
self.horiz_track_width = self.max_via_size + self.horiz_layer_spacing
self.vert_track_width = self.max_via_size + self.vert_layer_spacing
@ -263,7 +264,7 @@ class router:
"""
Scale a shape (two vector list) to user units
"""
unit_factor = [tech.GDS["unit"][0]] * 2
unit_factor = [GDS["unit"][0]] * 2
ll=shape[0].scale(unit_factor)
ur=shape[1].scale(unit_factor)
return [ll,ur]
@ -470,19 +471,21 @@ class router:
return set([best_coord])
def get_layer_width_space(self, zindex):
def get_layer_width_space(self, zindex, width=0, length=0):
"""
Return the width and spacing of a given layer.
Return the width and spacing of a given layer
and wire of a given width and length.
"""
if zindex==1:
width = self.vert_layer_minwidth
spacing = self.vert_layer_spacing
layer_name = self.vert_layer_name
elif zindex==0:
width = self.horiz_layer_minwidth
spacing = self.horiz_layer_spacing
layer_name = self.horiz_layer_name
else:
debug.error("Invalid zindex for track", -1)
width = drc("minwidth_{0}".format(layer_name), width, length)
spacing = drc(str(layer_name)+"_to_"+str(layer_name), width, length)
return (width,spacing)
def convert_pin_coord_to_tracks(self, pin, coord):
@ -1022,31 +1025,6 @@ class router:
self.rg.add_target(pin_in_tracks)
def add_supply_rail_target(self, pin_name):
"""
Add the supply rails of given name as a routing target.
"""
debug.info(2,"Add supply rail target {}".format(pin_name))
for rail in self.supply_rails:
if rail.name != pin_name:
continue
for wave_index in range(len(rail)):
pin_in_tracks = rail[wave_index]
#debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.set_target(pin_in_tracks)
self.rg.set_blocked(pin_in_tracks,False)
def set_supply_rail_blocked(self, value=True):
"""
Add the supply rails of given name as a routing target.
"""
debug.info(3,"Blocking supply rail")
for rail in self.supply_rails:
for wave_index in range(len(rail)):
pin_in_tracks = rail[wave_index]
#debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.set_blocked(pin_in_tracks,value)
def set_component_blockages(self, pin_name, value=True):
"""
Block all of the pin components.
@ -1126,7 +1104,8 @@ class router:
def add_wavepath(self, name, path):
"""
Add the current wave to the given design instance.
This is a single layer path that is multiple tracks wide.
This is a single rectangle that is multiple tracks wide.
It must pay attention to wide metal spacing rules.
"""
path=self.prepare_path(path)
@ -1149,17 +1128,25 @@ class router:
If name is supplied, it is added as a pin and not just a rectangle.
"""
# Find the pin enclosure of the whole track shape (ignoring DRCs)
(abs_ll,unused) = self.convert_track_to_shape(ll)
(unused,abs_ur) = self.convert_track_to_shape(ur)
# Get the layer information
(width, space) = self.get_layer_width_space(zindex)
x_distance = abs(abs_ll.x-abs_ur.x)
y_distance = abs(abs_ll.y-abs_ur.y)
shape_width = min(x_distance, y_distance)
shape_length = max(x_distance, y_distance)
# Get the DRC rule for the grid dimensions
(width, space) = self.get_layer_width_space(zindex, shape_width, shape_length)
layer = self.get_layer(zindex)
# This finds the pin shape enclosed by the track with DRC spacing on the sides
(abs_ll,unused) = self.convert_track_to_pin(ll)
(unused,abs_ur) = self.convert_track_to_pin(ur)
#print("enclose ll={0} ur={1}".format(ll,ur))
#print("enclose ll={0} ur={1}".format(abs_ll,abs_ur))
pin = pin_layout(name, [abs_ll, abs_ur], layer)
# Compute the shape offsets with correct spacing
new_ll = abs_ll + vector(0.5*space, 0.5*space)
new_ur = abs_ur - vector(0.5*space, 0.5*space)
pin = pin_layout(name, [new_ll, new_ur], layer)
return pin
@ -1319,7 +1306,7 @@ def snap_to_grid(offset):
return vector(xoff, yoff)
def snap_val_to_grid(x):
grid = tech.drc["grid"]
grid = drc("grid")
xgrid = int(round(round((x / grid), 2), 0))
xoff = xgrid * grid
return xoff

View File

@ -244,10 +244,29 @@ class supply_router(router):
recent_paths.append(self.paths[-1])
def add_supply_rail_target(self, pin_name):
"""
Add the supply rails of given name as a routing target.
"""
debug.info(2,"Add supply rail target {}".format(pin_name))
for rail in self.supply_rails:
if rail.name != pin_name:
continue
for wave_index in range(len(rail)):
pin_in_tracks = rail[wave_index]
#debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.set_target(pin_in_tracks)
self.rg.set_blocked(pin_in_tracks,False)
def set_supply_rail_blocked(self, value=True):
"""
Add the supply rails of given name as a routing target.
"""
debug.info(3,"Blocking supply rail")
for rail in self.supply_rails:
for wave_index in range(len(rail)):
pin_in_tracks = rail[wave_index]
#debug.info(1,"Set target: " + str(pin_name) + " " + str(pin_in_tracks))
self.rg.set_blocked(pin_in_tracks,value)