mirror of https://github.com/VLSIDA/OpenRAM.git
Improvements to power routing.
Improved the route horizontal and vertical pin functions to create a single pin at the end. Swapped A and B on wordline driver input for cleaner routing in most technologies. Fixed vertical supply routing in port_address.
This commit is contained in:
parent
10bec414e8
commit
8b3c10ae79
|
|
@ -74,24 +74,30 @@ class layout():
|
||||||
############################################################
|
############################################################
|
||||||
# GDS layout
|
# GDS layout
|
||||||
############################################################
|
############################################################
|
||||||
def offset_all_coordinates(self):
|
def offset_all_coordinates(self, offset=None):
|
||||||
"""
|
"""
|
||||||
This function is called after everything is placed to
|
This function is called after everything is placed to
|
||||||
shift the origin in the lowest left corner
|
shift the origin in the lowest left corner
|
||||||
"""
|
"""
|
||||||
offset = self.find_lowest_coords()
|
if not offset:
|
||||||
self.translate_all(offset)
|
offset = vector(0, 0)
|
||||||
return offset
|
ll = self.find_lowest_coords()
|
||||||
|
real_offset = ll + offset
|
||||||
|
self.translate_all(real_offset)
|
||||||
|
return real_offset
|
||||||
|
|
||||||
def offset_x_coordinates(self):
|
def offset_x_coordinates(self, offset=None):
|
||||||
"""
|
"""
|
||||||
This function is called after everything is placed to
|
This function is called after everything is placed to
|
||||||
shift the origin to the furthest left point.
|
shift the origin to the furthest left point.
|
||||||
Y offset is unchanged.
|
Y offset is unchanged.
|
||||||
"""
|
"""
|
||||||
offset = self.find_lowest_coords()
|
if not offset:
|
||||||
self.translate_all(offset.scale(1, 0))
|
offset = vector(0, 0)
|
||||||
return offset
|
ll = self.find_lowest_coords()
|
||||||
|
real_offset = ll.scale(1, 0) + offset
|
||||||
|
self.translate_all(real_offset)
|
||||||
|
return real_offset
|
||||||
|
|
||||||
def get_gate_offset(self, x_offset, height, inv_num):
|
def get_gate_offset(self, x_offset, height, inv_num):
|
||||||
"""
|
"""
|
||||||
|
|
@ -422,7 +428,7 @@ class layout():
|
||||||
for pin_name in self.pin_map.keys():
|
for pin_name in self.pin_map.keys():
|
||||||
self.copy_layout_pin(instance, pin_name, prefix + pin_name)
|
self.copy_layout_pin(instance, pin_name, prefix + pin_name)
|
||||||
|
|
||||||
def route_vertical_pins(self, name, insts=None, layer=None, side=None):
|
def route_vertical_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"):
|
||||||
"""
|
"""
|
||||||
Route together all of the pins of a given name that vertically align.
|
Route together all of the pins of a given name that vertically align.
|
||||||
Uses local_insts if insts not specified.
|
Uses local_insts if insts not specified.
|
||||||
|
|
@ -437,19 +443,17 @@ class layout():
|
||||||
for inst in insts:
|
for inst in insts:
|
||||||
for pin in inst.get_pins(name):
|
for pin in inst.get_pins(name):
|
||||||
|
|
||||||
if side == "right":
|
x = getattr(pin, xside)()
|
||||||
x = pin.rx()
|
|
||||||
elif side == "left":
|
|
||||||
x = pin.lx()
|
|
||||||
else:
|
|
||||||
x = pin.cx()
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
bins[x].append((inst,pin))
|
bins[x].append((inst,pin))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
bins[x] = [(inst,pin)]
|
bins[x] = [(inst,pin)]
|
||||||
|
|
||||||
for x, v in bins.items():
|
for x, v in bins.items():
|
||||||
|
# Not enough to route a pin
|
||||||
|
if len(v) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
bot_y = min([inst.by() for (inst,pin) in v])
|
bot_y = min([inst.by() for (inst,pin) in v])
|
||||||
top_y = max([inst.uy() for (inst,pin) in v])
|
top_y = max([inst.uy() for (inst,pin) in v])
|
||||||
|
|
||||||
|
|
@ -459,9 +463,12 @@ class layout():
|
||||||
pin_layer = layer
|
pin_layer = layer
|
||||||
else:
|
else:
|
||||||
pin_layer = self.supply_stack[2]
|
pin_layer = self.supply_stack[2]
|
||||||
|
|
||||||
|
y = getattr(pin, yside)()
|
||||||
|
|
||||||
last_via = self.add_via_stack_center(from_layer=pin.layer,
|
last_via = self.add_via_stack_center(from_layer=pin.layer,
|
||||||
to_layer=pin_layer,
|
to_layer=pin_layer,
|
||||||
offset=vector(x, pin.cy()),
|
offset=vector(x, y),
|
||||||
min_area=True)
|
min_area=True)
|
||||||
|
|
||||||
if last_via:
|
if last_via:
|
||||||
|
|
@ -469,13 +476,22 @@ class layout():
|
||||||
else:
|
else:
|
||||||
via_width=None
|
via_width=None
|
||||||
|
|
||||||
self.add_layout_pin_segment_center(text=name,
|
top_pos = vector(x, top_y)
|
||||||
layer=pin_layer,
|
bot_pos = vector(x, bot_y)
|
||||||
start=vector(x, bot_y),
|
self.add_segment_center(layer=pin_layer,
|
||||||
end=vector(x, top_y),
|
start=bot_pos,
|
||||||
width=via_width)
|
end=top_pos,
|
||||||
|
width=via_width)
|
||||||
|
|
||||||
def route_horizontal_pins(self, name, insts=None, layer=None, side=None):
|
self.add_layout_pin_rect_center(text=name,
|
||||||
|
layer=pin_layer,
|
||||||
|
offset=top_pos)
|
||||||
|
# self.add_layout_pin_rect_center(text=name,
|
||||||
|
# layer=pin_layer,
|
||||||
|
# offset=bot_pos)
|
||||||
|
|
||||||
|
|
||||||
|
def route_horizontal_pins(self, name, insts=None, layer=None, xside="cx", yside="cy"):
|
||||||
"""
|
"""
|
||||||
Route together all of the pins of a given name that horizontally align.
|
Route together all of the pins of a given name that horizontally align.
|
||||||
Uses local_insts if insts not specified.
|
Uses local_insts if insts not specified.
|
||||||
|
|
@ -489,19 +505,20 @@ class layout():
|
||||||
|
|
||||||
for inst in insts:
|
for inst in insts:
|
||||||
for pin in inst.get_pins(name):
|
for pin in inst.get_pins(name):
|
||||||
if side == "top":
|
|
||||||
y = pin.uy()
|
|
||||||
elif side == "bottom":
|
|
||||||
y = pin.by()
|
|
||||||
else:
|
|
||||||
y = pin.cy()
|
|
||||||
|
|
||||||
|
y = getattr(pin, yside)()
|
||||||
try:
|
try:
|
||||||
bins[y].append((inst,pin))
|
bins[y].append((inst,pin))
|
||||||
except KeyError:
|
except KeyError:
|
||||||
bins[y] = [(inst,pin)]
|
bins[y] = [(inst,pin)]
|
||||||
|
|
||||||
|
# Filter the small bins
|
||||||
|
|
||||||
for y, v in bins.items():
|
for y, v in bins.items():
|
||||||
|
# Not enough to route a pin
|
||||||
|
if len(v) < 2:
|
||||||
|
continue
|
||||||
|
|
||||||
left_x = min([inst.lx() for (inst,pin) in v])
|
left_x = min([inst.lx() for (inst,pin) in v])
|
||||||
right_x = max([inst.rx() for (inst,pin) in v])
|
right_x = max([inst.rx() for (inst,pin) in v])
|
||||||
|
|
||||||
|
|
@ -511,6 +528,9 @@ class layout():
|
||||||
pin_layer = layer
|
pin_layer = layer
|
||||||
else:
|
else:
|
||||||
pin_layer = self.supply_stack[0]
|
pin_layer = self.supply_stack[0]
|
||||||
|
|
||||||
|
x = getattr(pin, xside)()
|
||||||
|
|
||||||
last_via = self.add_via_stack_center(from_layer=pin.layer,
|
last_via = self.add_via_stack_center(from_layer=pin.layer,
|
||||||
to_layer=pin_layer,
|
to_layer=pin_layer,
|
||||||
offset=vector(pin.cx(), y),
|
offset=vector(pin.cx(), y),
|
||||||
|
|
@ -521,11 +541,19 @@ class layout():
|
||||||
else:
|
else:
|
||||||
via_height=None
|
via_height=None
|
||||||
|
|
||||||
self.add_layout_pin_segment_center(text=name,
|
left_pos = vector(left_x, y)
|
||||||
layer=pin_layer,
|
right_pos = vector(right_x, y)
|
||||||
start=vector(left_x, y),
|
self.add_segment_center(layer=pin_layer,
|
||||||
end=vector(right_x, y),
|
start=left_pos,
|
||||||
width=via_height)
|
end=right_pos,
|
||||||
|
width=via_height)
|
||||||
|
|
||||||
|
self.add_layout_pin_rect_center(text=name,
|
||||||
|
layer=pin_layer,
|
||||||
|
offset=left_pos)
|
||||||
|
# self.add_layout_pin_rect_center(text=name,
|
||||||
|
# layer=pin_layer,
|
||||||
|
# offset=right_pos)
|
||||||
|
|
||||||
def add_layout_pin_segment_center(self, text, layer, start, end, width=None):
|
def add_layout_pin_segment_center(self, text, layer, start, end, width=None):
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -596,10 +596,10 @@ class hierarchical_decoder(design.design):
|
||||||
"""
|
"""
|
||||||
if layer_props.hierarchical_decoder.vertical_supply:
|
if layer_props.hierarchical_decoder.vertical_supply:
|
||||||
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
||||||
self.route_vertical_pins("vdd", insts=pre_insts)
|
self.route_vertical_pins("vdd", insts=pre_insts, yside="by")
|
||||||
self.route_vertical_pins("gnd", insts=pre_insts)
|
self.route_vertical_pins("gnd", insts=pre_insts, yside="by")
|
||||||
self.route_vertical_pins("vdd", insts=self.and_inst)
|
self.route_vertical_pins("vdd", insts=self.and_inst, yside="by")
|
||||||
self.route_vertical_pins("gnd", insts=self.and_inst)
|
self.route_vertical_pins("gnd", insts=self.and_inst, yside="by")
|
||||||
return
|
return
|
||||||
for n in ["vdd", "gnd"]:
|
for n in ["vdd", "gnd"]:
|
||||||
pins = self.and_inst[0].get_pins(n)
|
pins = self.and_inst[0].get_pins(n)
|
||||||
|
|
@ -622,8 +622,8 @@ class hierarchical_decoder(design.design):
|
||||||
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
pre_insts = self.pre2x4_inst + self.pre3x8_inst + self.pre4x16_inst
|
||||||
self.route_vertical_pins("vdd", insts=pre_insts)
|
self.route_vertical_pins("vdd", insts=pre_insts)
|
||||||
self.route_vertical_pins("gnd", insts=pre_insts)
|
self.route_vertical_pins("gnd", insts=pre_insts)
|
||||||
self.route_vertical_pins("vdd", insts=self.and_inst, side="right")
|
self.route_vertical_pins("vdd", insts=self.and_inst, xside="rx")
|
||||||
self.route_vertical_pins("gnd", insts=self.and_inst, side="left")
|
self.route_vertical_pins("gnd", insts=self.and_inst, xside="lx")
|
||||||
|
|
||||||
# Widen the rails to cover any gap
|
# Widen the rails to cover any gap
|
||||||
for inst in self.and_inst:
|
for inst in self.and_inst:
|
||||||
|
|
|
||||||
|
|
@ -228,17 +228,15 @@ class port_address(design.design):
|
||||||
wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0)
|
wordline_driver_array_offset = vector(self.row_decoder_inst.rx(), 0)
|
||||||
self.wordline_driver_array_inst.place(wordline_driver_array_offset)
|
self.wordline_driver_array_inst.place(wordline_driver_array_offset)
|
||||||
|
|
||||||
# The wordline driver also had an extra gap on the right, so use this offset
|
# This m4_pitch corresponds to the offset space for jog routing in the
|
||||||
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active")
|
# wordline_driver_array
|
||||||
x_offset = self.wordline_driver_array_inst.rx() - well_gap - self.rbl_driver.width
|
rbl_driver_offset = wordline_driver_array_offset + vector(self.m4_pitch, 0)
|
||||||
|
|
||||||
if self.port == 0:
|
if self.port == 0:
|
||||||
rbl_driver_offset = vector(x_offset,
|
|
||||||
0)
|
|
||||||
self.rbl_driver_inst.place(rbl_driver_offset, "MX")
|
self.rbl_driver_inst.place(rbl_driver_offset, "MX")
|
||||||
else:
|
else:
|
||||||
rbl_driver_offset = vector(x_offset,
|
rbl_driver_offset += vector(0,
|
||||||
self.wordline_driver_array.height)
|
self.wordline_driver_array.height)
|
||||||
self.rbl_driver_inst.place(rbl_driver_offset)
|
self.rbl_driver_inst.place(rbl_driver_offset)
|
||||||
|
|
||||||
# Pass this up
|
# Pass this up
|
||||||
|
|
|
||||||
|
|
@ -463,6 +463,11 @@ class replica_bitcell_array(bitcell_base_array):
|
||||||
supply_insts = self.dummy_col_insts + self.dummy_row_insts
|
supply_insts = self.dummy_col_insts + self.dummy_row_insts
|
||||||
|
|
||||||
for pin_name in self.supplies:
|
for pin_name in self.supplies:
|
||||||
|
#self.route_vertical_pins(name=pin_name, insts=supply_insts)
|
||||||
|
self.route_horizontal_pins(name=pin_name, insts=supply_insts)
|
||||||
|
|
||||||
|
#self.route_vertical_pins(name=pin_name, insts=self.replica_col_insts)
|
||||||
|
#self.route_horizontal_pins(name=pin_name, insts=self.replica_col_insts)
|
||||||
for inst in supply_insts:
|
for inst in supply_insts:
|
||||||
pin_list = inst.get_pins(pin_name)
|
pin_list = inst.get_pins(pin_name)
|
||||||
for pin in pin_list:
|
for pin in pin_list:
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,16 @@ class wordline_driver_array(design.design):
|
||||||
self.route_layer = "li"
|
self.route_layer = "li"
|
||||||
else:
|
else:
|
||||||
self.route_layer = "m1"
|
self.route_layer = "m1"
|
||||||
|
|
||||||
self.place_drivers()
|
self.place_drivers()
|
||||||
self.route_layout()
|
self.route_layout()
|
||||||
self.offset_x_coordinates()
|
self.offset_x_coordinates(vector(-self.m4_pitch, 0))
|
||||||
|
|
||||||
|
# Leave a well gap to separate the bitcell array well from this well
|
||||||
|
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active")
|
||||||
|
self.width = self.wld_inst[-1].rx() + well_gap
|
||||||
|
self.height = self.wld_inst[-1].uy()
|
||||||
|
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
self.route_vdd_gnd()
|
self.route_vdd_gnd()
|
||||||
self.DRC_LVS()
|
self.DRC_LVS()
|
||||||
|
|
@ -73,8 +80,8 @@ class wordline_driver_array(design.design):
|
||||||
self.route_vertical_pins("vdd", insts=self.wld_inst)
|
self.route_vertical_pins("vdd", insts=self.wld_inst)
|
||||||
self.route_vertical_pins("gnd", insts=self.wld_inst)
|
self.route_vertical_pins("gnd", insts=self.wld_inst)
|
||||||
else:
|
else:
|
||||||
self.route_vertical_pins("vdd", insts=self.wld_inst, side="left")
|
self.route_vertical_pins("vdd", insts=self.wld_inst, xside="lx")
|
||||||
self.route_vertical_pins("gnd", insts=self.wld_inst, side="right")
|
self.route_vertical_pins("gnd", insts=self.wld_inst, xside="rx")
|
||||||
|
|
||||||
# Widen the rails to cover any gap
|
# Widen the rails to cover any gap
|
||||||
for num in range(self.rows):
|
for num in range(self.rows):
|
||||||
|
|
@ -93,8 +100,8 @@ class wordline_driver_array(design.design):
|
||||||
# add and2
|
# add and2
|
||||||
self.wld_inst.append(self.add_inst(name=name_and,
|
self.wld_inst.append(self.add_inst(name=name_and,
|
||||||
mod=self.wl_driver))
|
mod=self.wl_driver))
|
||||||
self.connect_inst(["en",
|
self.connect_inst(["in_{0}".format(row),
|
||||||
"in_{0}".format(row),
|
"en",
|
||||||
"wl_{0}".format(row),
|
"wl_{0}".format(row),
|
||||||
"vdd", "gnd"])
|
"vdd", "gnd"])
|
||||||
|
|
||||||
|
|
@ -114,18 +121,13 @@ class wordline_driver_array(design.design):
|
||||||
self.wld_inst[row].place(offset=and2_offset,
|
self.wld_inst[row].place(offset=and2_offset,
|
||||||
mirror=inst_mirror)
|
mirror=inst_mirror)
|
||||||
|
|
||||||
# Leave a well gap to separate the bitcell array well from this well
|
|
||||||
well_gap = 2 * drc("pwell_to_nwell") + drc("nwell_enclose_active")
|
|
||||||
self.width = self.wl_driver.width + well_gap
|
|
||||||
self.height = self.wl_driver.height * self.rows
|
|
||||||
|
|
||||||
def route_layout(self):
|
def route_layout(self):
|
||||||
""" Route all of the signals """
|
""" Route all of the signals """
|
||||||
|
|
||||||
# Wordline enable connection
|
# Wordline enable connection
|
||||||
en_pin = self.wld_inst[0].get_pin("B")
|
en_pin = self.wld_inst[0].get_pin("B")
|
||||||
en_bottom_pos = vector(en_pin.cx(), 0)
|
en_bottom_pos = vector(en_pin.cx(), 0)
|
||||||
en_top_pos = vector(en_pin.cx(), self.height)
|
en_top_pos = vector(en_pin.cx(), self.wld_inst[-1].uy())
|
||||||
en_pin = self.add_layout_pin_segment_center(text="en",
|
en_pin = self.add_layout_pin_segment_center(text="en",
|
||||||
layer="m2",
|
layer="m2",
|
||||||
start=en_bottom_pos,
|
start=en_bottom_pos,
|
||||||
|
|
@ -135,7 +137,7 @@ class wordline_driver_array(design.design):
|
||||||
and_inst = self.wld_inst[row]
|
and_inst = self.wld_inst[row]
|
||||||
|
|
||||||
# Drop a via
|
# Drop a via
|
||||||
b_pin = and_inst.get_pin("A")
|
b_pin = and_inst.get_pin("B")
|
||||||
self.add_via_stack_center(from_layer=b_pin.layer,
|
self.add_via_stack_center(from_layer=b_pin.layer,
|
||||||
to_layer="m2",
|
to_layer="m2",
|
||||||
offset=b_pin.center())
|
offset=b_pin.center())
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue