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 self.second_layer_name = second_layer
def setup_layout_constants(self): def setup_layout_constants(self):
self.contact_width = drc["minwidth_{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)] contact_to_contact = drc("{0}_to_{0}".format(self.via_layer_name))
self.contact_pitch = self.contact_width + contact_to_contact 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_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 self.contact_array_height = self.contact_width + (self.dimensions[1] - 1) * self.contact_pitch
# DRC rules # DRC rules
first_layer_minwidth = drc["minwidth_{0}".format(self.first_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_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_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)] 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_minwidth = drc("minwidth_{0}".format(self.second_layer_name))
second_layer_minarea = drc["minarea_{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_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)] 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, self.first_layer_horizontal_enclosure = max((first_layer_minwidth - self.contact_array_width) / 2,
first_layer_enclosure) first_layer_enclosure)
@ -145,16 +145,16 @@ class contact(hierarchy_design.hierarchy_design):
height=self.second_layer_height) height=self.second_layer_height)
def create_implant_well_enclosures(self): def create_implant_well_enclosures(self):
implant_position = self.first_layer_position - [drc["implant_enclosure_active"]]*2 implant_position = self.first_layer_position - [drc("implant_enclosure_active")]*2
implant_width = self.first_layer_width + 2*drc["implant_enclosure_active"] implant_width = self.first_layer_width + 2*drc("implant_enclosure_active")
implant_height = self.first_layer_height + 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), self.add_rect(layer="{}implant".format(self.implant_type),
offset=implant_position, offset=implant_position,
width=implant_width, width=implant_width,
height=implant_height) height=implant_height)
well_position = self.first_layer_position - [drc["well_enclosure_active"]]*2 well_position = self.first_layer_position - [drc("well_enclosure_active")]*2
well_width = self.first_layer_width + 2*drc["well_enclosure_active"] well_width = self.first_layer_width + 2*drc("well_enclosure_active")
well_height = self.first_layer_height + 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), self.add_rect(layer="{}well".format(self.well_type),
offset=well_position, offset=well_position,
width=well_width, width=well_width,

View File

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

View File

@ -63,7 +63,7 @@ class pin_layout:
and return the new rectangle. and return the new rectangle.
""" """
if not spacing: 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 (ll,ur) = self.rect
spacing = vector(spacing, spacing) 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 (self.horiz_layer_width, self.num_vias, self.vert_layer_width) = self.layer_widths
if not self.vert_layer_width: 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: 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 # offset this by 1/2 the via size
self.c=contact(self.layer_stack, (self.num_vias, self.num_vias)) 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.via_layer_name = via_layer
self.vert_layer_name = vert_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_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, via_connect = contact(self.layer_stack,
(1, 1)) (1, 1))
self.node_to_node = [drc["minwidth_" + str(self.horiz_layer_name)] + via_connect.width, self.node_to_node = [drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.width,
drc["minwidth_" + str(self.horiz_layer_name)] + via_connect.height] drc("minwidth_" + str(self.horiz_layer_name)) + via_connect.height]
# create a 1x1 contact # create a 1x1 contact
def create_vias(self): def create_vias(self):

View File

@ -1,3 +1,4 @@
import debug
from drc_value import * from drc_value import *
from drc_lut import * from drc_lut import *
@ -13,7 +14,11 @@ class design_rules():
self.rules[name] = value self.rules[name] = value
def __call__(self, name, *args): 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): def __setitem__(self, b, c):
""" """
@ -26,10 +31,10 @@ class design_rules():
For backward compatibility with existing rules. For backward compatibility with existing rules.
""" """
rule = self.rules[b] rule = self.rules[b]
if callable(rule): if not callable(rule):
return rule()
else:
return 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): def __init__(self, table):
self.table = table self.table = table
def __call__(self, *args): def __call__(self, *key):
""" """
Lookup a given tuple in the table. Lookup a given tuple in the table.
""" """
if len(*key)==0:
key_tuple = args
if not key_tuple:
key_size = len(list(self.table.keys())[0]) key_size = len(list(self.table.keys())[0])
key_tuple = tuple(0 for i in range(key_size)) key = tuple(0 for i in range(key_size))
for key in sorted(self.table.keys(), reverse=True): for table_key in sorted(self.table.keys(), reverse=True):
if self.match(key_tuple, key): if self.match(key, table_key):
return self.table[key] return self.table[table_key]
def match(self, t1, t2): 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 self.central_bus_width = self.m2_pitch * self.num_control_lines + 2*self.m2_width
# A space for wells or jogging m2 # 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) 2*self.m2_pitch)
@ -530,7 +530,7 @@ class bank(design.design):
# Place the col decoder right aligned with row decoder # Place the col decoder right aligned with row decoder
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width) 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)) 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()) y_off = min(self.col_decoder_inst[port].by(), self.col_mux_array_inst[port].by())
else: else:
y_off = self.row_decoder_inst[port].by() 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_pos = vector(x_off,y_off)
self.bank_select_inst[port].place(self.bank_select_pos) 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.mod_bitcell = getattr(c, OPTS.bitcell)
self.bitcell = self.mod_bitcell() self.bitcell = self.mod_bitcell()
height = self.bitcell.height + drc["poly_to_active"] height = self.bitcell.height + drc("poly_to_active")
# 1x Inverter # 1x Inverter
self.inv_sel = pinv(height=height) self.inv_sel = pinv(height=height)
@ -88,8 +88,8 @@ class bank_select(design.design):
def calculate_module_offsets(self): def calculate_module_offsets(self):
self.xoffset_nand = 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_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_inv = max(self.xoffset_nand + self.nand2.width, self.xoffset_nor + self.nor2.width)
self.xoffset_bank_sel_inv = 0 self.xoffset_bank_sel_inv = 0
self.xoffset_inputs = 0 self.xoffset_inputs = 0

View File

@ -39,7 +39,7 @@ class bitcell_array(design.design):
def create_layout(self): def create_layout(self):
# We increase it by a well enclosure so the precharges don't overlap our wells # 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 self.width = self.column_size*self.cell.width + self.m1_width
xoffset = 0.0 xoffset = 0.0
@ -199,13 +199,13 @@ class bitcell_array(design.design):
return total_power return total_power
def gen_wl_wire(self): 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 wl_wire.wire_c = 2*spice["min_tx_gate_c"] + wl_wire.wire_c # 2 access tx gate per cell
return wl_wire return wl_wire
def gen_bl_wire(self): def gen_bl_wire(self):
bl_pos = 0 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 bl_wire.wire_c =spice["min_tx_drain_c"] + bl_wire.wire_c # 1 access tx d/s per cell
return bl_wire 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 self.central_bus_width = self.m2_pitch * self.num_control_lines + 2*self.m2_width
# A space for wells or jogging m2 # 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) 2*self.m2_pitch)
@ -382,7 +382,7 @@ class multibank(design.design):
""" """
# Place the col decoder right aligned with row decoder # Place the col decoder right aligned with row decoder
x_off = -(self.central_bus_width + self.wordline_driver.width + self.col_decoder.width) 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", self.col_decoder_inst=self.add_inst(name="col_address_decoder",
mod=self.col_decoder, mod=self.col_decoder,
offset=vector(x_off,y_off)) 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()) y_off = min(self.col_decoder_inst.by(), self.col_mux_array_inst.by())
else: else:
y_off = self.row_decoder_inst.by() 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_pos = vector(x_off,y_off)
self.bank_select_inst = self.add_inst(name="bank_select", self.bank_select_inst = self.add_inst(name="bank_select",
mod=self.bank_select, mod=self.bank_select,

View File

@ -63,7 +63,7 @@ class precharge_array(design.design):
layer="metal1", layer="metal1",
offset=self.pc_cell.get_pin("en").ll(), offset=self.pc_cell.get_pin("en").ll(),
width=self.width, width=self.width,
height=drc["minwidth_metal1"]) height=drc("minwidth_metal1"))
for inst in self.local_insts: for inst in self.local_insts:
self.copy_layout_pin(inst, "vdd") self.copy_layout_pin(inst, "vdd")
@ -74,13 +74,13 @@ class precharge_array(design.design):
self.add_layout_pin(text="bl_{0}".format(i), self.add_layout_pin(text="bl_{0}".format(i),
layer="metal2", layer="metal2",
offset=bl_pin.ll(), offset=bl_pin.ll(),
width=drc["minwidth_metal2"], width=drc("minwidth_metal2"),
height=bl_pin.height()) height=bl_pin.height())
br_pin = inst.get_pin("br") br_pin = inst.get_pin("br")
self.add_layout_pin(text="br_{0}".format(i), self.add_layout_pin(text="br_{0}".format(i),
layer="metal2", layer="metal2",
offset=br_pin.ll(), offset=br_pin.ll(),
width=drc["minwidth_metal2"], width=drc("minwidth_metal2"),
height=bl_pin.height()) 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 # 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 # Wordlines may be close to each other when tiled, so gnd connections are routed in opposite directions
if row % 2 == 0: 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: 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_right = pin.rc()
pin_extension1 = pin_right + vector(self.m3_pitch,0) 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) wl_last = self.wl_list[self.total_ports-1]+"_{}".format(row)
pin_last = self.rbl_inst.get_pin(wl_last) 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]) self.add_path("metal1", [pin.rc()-correct, pin_last.rc()-correct])
def route_supplies(self): def route_supplies(self):
@ -261,7 +261,7 @@ class replica_bitline(design.design):
# 3. Route the contact of previous route to the bitcell WL # 3. Route the contact of previous route to the bitcell WL
# route bend of previous net to bitcell WL # route bend of previous net to bitcell WL
wl_offset = self.rbc_inst.get_pin(self.wl_list[0]).lc() 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) wl_mid2 = vector(wl_mid1.x, contact_offset.y)
#xmid_point= 0.5*(wl_offset.x+contact_offset.x) #xmid_point= 0.5*(wl_offset.x+contact_offset.x)
#wl_mid1 = vector(xmid_point,contact_offset.y) #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 = self.rbc_inst.get_pin(wl)
pin_last = self.rbc_inst.get_pin(wl_last) 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]) self.add_path("metal1", [pin.lc()+correct, pin_last.lc()+correct])
# DRAIN ROUTE # DRAIN ROUTE

View File

@ -132,7 +132,7 @@ class sense_amp_array(design.design):
layer="metal1", layer="metal1",
offset=sclk_offset, offset=sclk_offset,
width=self.width, width=self.width,
height=drc["minwidth_metal1"]) height=drc("minwidth_metal1"))
def analytical_delay(self, slew, load=0.0): def analytical_delay(self, slew, load=0.0):
return self.amp.analytical_delay(slew=slew, load=load) 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", self.add_rect(layer="metal1",
offset=bl_out_offset, offset=bl_out_offset,
width=width, width=width,
height=drc["minwidth_metal2"]) height=drc("minwidth_metal2"))
self.add_rect(layer="metal1", self.add_rect(layer="metal1",
offset=br_out_offset, offset=br_out_offset,
width=width, 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 # 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)), self.add_layout_pin(text="bl_out_{}".format(int(j/self.words_per_row)),
layer="metal2", layer="metal2",
offset=bl_out_offset.scale(1,0), offset=bl_out_offset.scale(1,0),
width=drc['minwidth_metal2'], width=drc('minwidth_metal2'),
height=self.route_height) height=self.route_height)
self.add_layout_pin(text="br_out_{}".format(int(j/self.words_per_row)), self.add_layout_pin(text="br_out_{}".format(int(j/self.words_per_row)),
layer="metal2", layer="metal2",
offset=br_out_offset.scale(1,0), offset=br_out_offset.scale(1,0),
width=drc['minwidth_metal2'], width=drc('minwidth_metal2'),
height=self.route_height) height=self.route_height)
# This via is on the right of the wire # 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", self.add_rect(layer="metal2",
offset=bl_out_offset, offset=bl_out_offset,
width=drc['minwidth_metal2'], width=drc('minwidth_metal2'),
height=self.route_height-bl_out_offset.y) height=self.route_height-bl_out_offset.y)
# This via is on the right of the wire # This via is on the right of the wire
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via(layers=("metal1", "via1", "metal2"),
@ -210,7 +210,7 @@ class single_level_column_mux_array(design.design):
rotate=90) rotate=90)
self.add_rect(layer="metal2", self.add_rect(layer="metal2",
offset=br_out_offset, offset=br_out_offset,
width=drc['minwidth_metal2'], width=drc('minwidth_metal2'),
height=self.route_height-br_out_offset.y) height=self.route_height-br_out_offset.y)
# This via is on the left of the wire # This via is on the left of the wire
self.add_via(layers=("metal1", "via1", "metal2"), self.add_via(layers=("metal1", "via1", "metal2"),

View File

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

View File

@ -130,7 +130,7 @@ class write_driver_array(design.design):
layer="metal1", layer="metal1",
offset=self.driver_insts[0].get_pin("en").ll().scale(0,1), offset=self.driver_insts[0].get_pin("en").ll().scale(0,1),
width=self.width, 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 max_y_offset = self.height + 0.5*self.m1_width
self.nwell_position = middle_position self.nwell_position = middle_position
nwell_height = max_y_offset - middle_position.y nwell_height = max_y_offset - middle_position.y
if drc["has_nwell"]: if drc("has_nwell"):
self.add_rect(layer="nwell", self.add_rect(layer="nwell",
offset=middle_position, offset=middle_position,
width=self.well_width, width=self.well_width,
@ -122,7 +122,7 @@ class pgate(design.design):
pwell_position = vector(0,-0.5*self.m1_width) pwell_position = vector(0,-0.5*self.m1_width)
pwell_height = middle_position.y-pwell_position.y pwell_height = middle_position.y-pwell_position.y
if drc["has_pwell"]: if drc("has_pwell"):
self.add_rect(layer="pwell", self.add_rect(layer="pwell",
offset=pwell_position, offset=pwell_position,
width=self.well_width, width=self.well_width,
@ -138,7 +138,7 @@ class pgate(design.design):
layer_stack = ("active", "contact", "metal1") layer_stack = ("active", "contact", "metal1")
# To the right a spacing away from the pmos right active edge # 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 # 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. # OR align the active with the top of PMOS active.
max_y_offset = self.height + 0.5*self.m1_width 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) pwell_position = vector(0,-0.5*self.m1_width)
# To the right a spacing away from the nmos right active edge # 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 # Must be at least an well enclosure of active up from the bottom of the well
contact_yoffset = max(nmos_pos.y, contact_yoffset = max(nmos_pos.y,
self.well_enclose_active - nmos.active_contact.first_layer_height/2) 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... # This may make the result differ when the layout is created...
if OPTS.netlist_only: if OPTS.netlist_only:
self.tx_mults = 1 self.tx_mults = 1
self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc("minwidth_tx")
return return
# Do a quick sanity check and bail if unlikely feasible height # 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) # Assume we need 3 metal 1 pitches (2 power rails, one between the tx for the drain)
# plus the tx height # plus the tx height
nmos = ptx(tx_type="nmos") 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 tx_height = nmos.poly_height + pmos.poly_height
# rotated m1 pitch or poly to active spacing # rotated m1 pitch or poly to active spacing
min_channel = max(contact.poly.width + self.m1_space, 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 # This is the extra space needed to ensure DRC rules to the active contacts
extra_contact_space = max(-nmos.get_pin("D").by(),0) extra_contact_space = max(-nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell # 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, 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 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)) 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 # Divide the height in half. Could divide proportional to beta, but this makes
# connecting wells of multiple cells easier. # connecting wells of multiple cells easier.
# Subtract the poly space under the rail of the tx # Subtract the poly space under the rail of the tx
nmos_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"] 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, debug.info(2,"Height avail {0:.4f} PMOS {1:.4f} NMOS {2:.4f}".format(tx_height_available,
nmos_height_available, nmos_height_available,
pmos_height_available)) pmos_height_available))
# Determine the number of mults for each to fit width into available space # Determine the number of mults for each to fit width into available space
self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_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) 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) pmos_required_mults = max(int(ceil(self.pmos_width/pmos_height_available)),1)
# The mults must be the same for easy connection of poly # 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 # 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. # 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) 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) 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): 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 width is determined the multi-finger PMOS device width plus
# the well contact width and half well enclosure on both sides # the well contact width and half well enclosure on both sides
self.well_width = self.pmos.active_width + self.pmos.active_contact.width \ 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 self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # 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.nmos_size = 2*size
self.pmos_size = parameter["beta"]*size self.pmos_size = parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc("minwidth_tx")
# FIXME: Allow these to be sized # FIXME: Allow these to be sized
debug.check(size==1,"Size 1 pnand2 is only supported now.") 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. # Two PMOS devices and a well contact. Separation between each.
# Enclosure space on the sides. # Enclosure space on the sides.
self.well_width = 2*self.pmos.active_width + contact.active.width \ 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 self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # 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) extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell # 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, 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): def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """ """ 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. # If we relax this, we could size this better.
self.nmos_size = 2*size self.nmos_size = 2*size
self.pmos_size = parameter["beta"]*size self.pmos_size = parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc("minwidth_tx")
# FIXME: Allow these to be sized # FIXME: Allow these to be sized
debug.check(size==1,"Size 1 pnand3 is only supported now.") 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. # Two PMOS devices and a well contact. Separation between each.
# Enclosure space on the sides. # Enclosure space on the sides.
self.well_width = 3*self.pmos.active_width + self.pmos.active_contact.width \ 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.overlap_offset.x
self.width = self.well_width self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # 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) extra_contact_space = max(-nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell # 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, 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): def route_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """ """ 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, 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) 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 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") 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 self.nmos_size = size
# We will just make this 1.5 times for now. NORs are not ideal anyhow. # We will just make this 1.5 times for now. NORs are not ideal anyhow.
self.pmos_size = 1.5*parameter["beta"]*size self.pmos_size = 1.5*parameter["beta"]*size
self.nmos_width = self.nmos_size*drc["minwidth_tx"] self.nmos_width = self.nmos_size*drc("minwidth_tx")
self.pmos_width = self.pmos_size*drc["minwidth_tx"] self.pmos_width = self.pmos_size*drc("minwidth_tx")
# FIXME: Allow these to be sized # FIXME: Allow these to be sized
debug.check(size==1,"Size 1 pnor2 is only supported now.") 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. # Two PMOS devices and a well contact. Separation between each.
# Enclosure space on the sides. # Enclosure space on the sides.
self.well_width = 2*self.pmos.active_width + self.pmos.active_contact.width \ 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 self.width = self.well_width
# Height is an input parameter, so it is not recomputed. # 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) extra_contact_space = max(-self.nmos.get_pin("D").by(),0)
# This is a poly-to-poly of a flipped cell # 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, 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): def add_supply_rails(self):
""" Add vdd/gnd rails to the top and bottom. """ """ 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 a nwell tap to connect to the vdd rail"""
# adds the contact from active to metal1 # adds the contact from active to metal1
well_contact_pos = self.upper_pmos1_inst.get_pin("D").center().scale(1,0) \ 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"), self.add_contact_center(layers=("active", "contact", "metal1"),
offset=well_contact_pos, offset=well_contact_pos,
implant_type="n", implant_type="n",
@ -184,7 +184,7 @@ class precharge(pgate.pgate):
self.add_layout_pin(text="bl", self.add_layout_pin(text="bl",
layer="metal2", layer="metal2",
offset=offset, offset=offset,
width=drc['minwidth_metal2'], width=drc("minwidth_metal2"),
height=self.height) height=self.height)
# adds the BR on metal 2 # adds the BR on metal 2
@ -192,7 +192,7 @@ class precharge(pgate.pgate):
self.add_layout_pin(text="br", self.add_layout_pin(text="br",
layer="metal2", layer="metal2",
offset=offset, offset=offset,
width=drc['minwidth_metal2'], width=drc("minwidth_metal2"),
height=self.height) height=self.height)
def connect_to_bitlines(self): 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. 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 # We need to keep unique names because outputting to GDSII
# will use the last record with a given name. I.e., you will # 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 # 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, # self.spice.append("\n.SUBCKT {0} {1}".format(self.name,
# " ".join(self.pins))) # " ".join(self.pins)))
# Just make a guess since these will actually be decided in the layout later. # Just make a guess since these will actually be decided in the layout later.
area_sd = 2.5*drc["minwidth_poly"]*self.tx_width area_sd = 2.5*drc("minwidth_poly")*self.tx_width
perimeter_sd = 2*drc["minwidth_poly"] + 2*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.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.mults,
self.tx_width, self.tx_width,
drc["minwidth_poly"], drc("minwidth_poly"),
perimeter_sd, perimeter_sd,
area_sd) area_sd)
self.spice.append("\n* ptx " + self.spice_device) 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 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. # 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) (self.active_width - self.contact_width)/2)
# This is the distance from the edge of poly to the contacted end of active # 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 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) self.active_offset = vector([self.well_enclose_active]*2)
# Well enclosure of active, ensure minwidth as well # 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.cell_well_width = max(self.active_width + 2*self.well_enclose_active,
self.well_width) self.well_width)
self.cell_well_height = max(self.tx_width + 2*self.well_enclose_active, 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. # 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. # 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): def connect_fingered_poly(self, poly_positions):
""" """
@ -181,7 +181,7 @@ class ptx(design.design):
layer="poly", layer="poly",
offset=poly_offset, offset=poly_offset,
width=poly_width, width=poly_width,
height=drc["minwidth_poly"]) height=drc("minwidth_poly"))
def connect_fingered_active(self, drain_positions, source_positions): def connect_fingered_active(self, drain_positions, source_positions):
@ -269,7 +269,7 @@ class ptx(design.design):
height=self.active_height) height=self.active_height)
# If the implant must enclose the active, shift offset # If the implant must enclose the active, shift offset
# and increase width/height # and increase width/height
enclose_width = drc["implant_enclosure_active"] enclose_width = drc("implant_enclosure_active")
enclose_offset = [enclose_width]*2 enclose_offset = [enclose_width]*2
self.add_rect(layer="{}implant".format(self.implant_type), self.add_rect(layer="{}implant".format(self.implant_type),
offset=self.active_offset - enclose_offset, 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. 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), self.add_rect(layer="{}well".format(self.well_type),
offset=(0,0), offset=(0,0),
width=self.cell_well_width, width=self.cell_well_width,

View File

@ -52,7 +52,7 @@ class single_level_column_mux(design.design):
self.bitcell = self.mod_bitcell() self.bitcell = self.mod_bitcell()
# Adds nmos_lower,nmos_upper to the module # 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.nmos = ptx(width=self.ptx_width)
self.add_mod(self.nmos) self.add_mod(self.nmos)

View File

@ -1,6 +1,6 @@
import sys import sys
import gdsMill import gdsMill
import tech from tech import drc,GDS,layer
from contact import contact from contact import contact
import math import math
import debug import debug
@ -31,7 +31,7 @@ class router:
self.cell.gds_write(gds_filename) self.cell.gds_write(gds_filename)
# Load the gds file and read in all the shapes # 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 = gdsMill.Gds2reader(self.layout)
self.reader.loadFromFile(gds_filename) self.reader.loadFromFile(gds_filename)
self.top_name = self.layout.rootStructureName self.top_name = self.layout.rootStructureName
@ -118,17 +118,18 @@ class router:
self.layers = layers self.layers = layers
(self.horiz_layer_name, self.via_layer_name, self.vert_layer_name) = self.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)] # This is the minimum routed track spacing
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.
via_connect = contact(self.layers, (1, 1)) via_connect = contact(self.layers, (1, 1))
self.max_via_size = max(via_connect.width,via_connect.height) 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.horiz_track_width = self.max_via_size + self.horiz_layer_spacing
self.vert_track_width = self.max_via_size + self.vert_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 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) ll=shape[0].scale(unit_factor)
ur=shape[1].scale(unit_factor) ur=shape[1].scale(unit_factor)
return [ll,ur] return [ll,ur]
@ -470,19 +471,21 @@ class router:
return set([best_coord]) 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: if zindex==1:
width = self.vert_layer_minwidth layer_name = self.vert_layer_name
spacing = self.vert_layer_spacing
elif zindex==0: elif zindex==0:
width = self.horiz_layer_minwidth layer_name = self.horiz_layer_name
spacing = self.horiz_layer_spacing
else: else:
debug.error("Invalid zindex for track", -1) 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) return (width,spacing)
def convert_pin_coord_to_tracks(self, pin, coord): def convert_pin_coord_to_tracks(self, pin, coord):
@ -1022,31 +1025,6 @@ class router:
self.rg.add_target(pin_in_tracks) 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): def set_component_blockages(self, pin_name, value=True):
""" """
Block all of the pin components. Block all of the pin components.
@ -1126,7 +1104,8 @@ class router:
def add_wavepath(self, name, path): def add_wavepath(self, name, path):
""" """
Add the current wave to the given design instance. 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) 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. 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 # 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) layer = self.get_layer(zindex)
# This finds the pin shape enclosed by the track with DRC spacing on the sides # Compute the shape offsets with correct spacing
(abs_ll,unused) = self.convert_track_to_pin(ll) new_ll = abs_ll + vector(0.5*space, 0.5*space)
(unused,abs_ur) = self.convert_track_to_pin(ur) new_ur = abs_ur - vector(0.5*space, 0.5*space)
#print("enclose ll={0} ur={1}".format(ll,ur)) pin = pin_layout(name, [new_ll, new_ur], layer)
#print("enclose ll={0} ur={1}".format(abs_ll,abs_ur))
pin = pin_layout(name, [abs_ll, abs_ur], layer)
return pin return pin
@ -1319,7 +1306,7 @@ def snap_to_grid(offset):
return vector(xoff, yoff) return vector(xoff, yoff)
def snap_val_to_grid(x): def snap_val_to_grid(x):
grid = tech.drc["grid"] grid = drc("grid")
xgrid = int(round(round((x / grid), 2), 0)) xgrid = int(round(round((x / grid), 2), 0))
xoff = xgrid * grid xoff = xgrid * grid
return xoff return xoff

View File

@ -244,10 +244,29 @@ class supply_router(router):
recent_paths.append(self.paths[-1]) 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)