mirror of https://github.com/VLSIDA/OpenRAM.git
Update all drc usages to call function type
This commit is contained in:
parent
4932d83afc
commit
ce8c2d983d
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 """
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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"),
|
||||
|
|
|
|||
|
|
@ -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"))
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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'))
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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. """
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
||||
|
|
|
|||
|
|
@ -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. """
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue