rom base passing tests with top level routing

This commit is contained in:
Jacob Walker 2023-03-20 14:35:06 -07:00
parent 7c453e80be
commit fef9902c45
11 changed files with 176 additions and 83 deletions

View File

@ -1897,7 +1897,7 @@ class layout():
elif add_vias: elif add_vias:
self.copy_power_pin(pin, new_name=new_name) self.copy_power_pin(pin, new_name=new_name)
def add_io_pin(self, instance, pin_name, new_name, start_layer=None): def add_io_pin(self, instance, pin_name, new_name, start_layer=None, directions=None):
""" """
Add a signle input or output pin up to metal 3. Add a signle input or output pin up to metal 3.
""" """
@ -1907,7 +1907,7 @@ class layout():
start_layer = pin.layer start_layer = pin.layer
# Just use the power pin function for now to save code # Just use the power pin function for now to save code
self.add_power_pin(new_name, pin.center(), start_layer=start_layer) self.add_power_pin(new_name, pin.center(), start_layer=start_layer, directions=directions)
def add_power_pin(self, name, loc, directions=None, start_layer="m1"): def add_power_pin(self, name, loc, directions=None, start_layer="m1"):
# Hack for min area # Hack for min area

View File

@ -108,3 +108,15 @@ class rom_address_control_array(design):
self.route_horizontal_pins("vdd", insts=self.buf_insts, layer=self.route_layer) self.route_horizontal_pins("vdd", insts=self.buf_insts, layer=self.route_layer)
self.route_horizontal_pins("gnd", insts=self.buf_insts, layer=self.route_layer) self.route_horizontal_pins("gnd", insts=self.buf_insts, layer=self.route_layer)
tmp_pins = []
for pin in self.get_pins("vdd"):
edge = vector(pin.lx() + 0.5 * self.route_width, pin.cy())
tmp_pins.append(self.add_layout_pin_rect_center("vdd_edge", layer=self.route_layer, offset=edge))
self.copy_layout_pin_shapes("vdd")
self.remove_layout_pin("vdd")
for pin in tmp_pins:
print("copying pin")
self.copy_layout_pin(self, "vdd_edge", "vdd")
self.remove_layout_pin("vdd_edge")

View File

@ -1,3 +1,4 @@
# See LICENSE for licensing information. # See LICENSE for licensing information.
# #
# Copyright (c) 2016-2023 Regents of the University of California and The Board # Copyright (c) 2016-2023 Regents of the University of California and The Board
@ -108,13 +109,12 @@ class rom_bank(design):
self.route_clock() self.route_clock()
self.route_array_outputs() self.route_array_outputs()
self.place_top_level_pins() self.place_top_level_pins()
self.route_supplies()
self.route_output_buffers() self.route_output_buffers()
rt = router_tech(self.supply_stack, 1) rt = router_tech(self.supply_stack, 1)
init_bbox = self.get_bbox(side="ring", init_bbox = self.get_bbox(side="ring",
margin=rt.track_width) margin=rt.track_width)
self.route_supplies(init_bbox)
# We need the initial bbox for the supply rings later # We need the initial bbox for the supply rings later
# because the perimeter pins will change the bbox # because the perimeter pins will change the bbox
# Route the pins to the perimeter # Route the pins to the perimeter
@ -125,7 +125,7 @@ class rom_bank(design):
margin=11*rt.track_width) margin=11*rt.track_width)
self.route_escape_pins(bbox) self.route_escape_pins(bbox)
self.route_supplies()
def setup_layout_constants(self): def setup_layout_constants(self):
@ -221,6 +221,7 @@ class rom_bank(design):
module_name="rom_output_buffer", module_name="rom_output_buffer",
rows=self.word_size, rows=self.word_size,
fanout=4, fanout=4,
tap_spacing=1,
invert_outputs=True) invert_outputs=True)
@ -373,8 +374,8 @@ class rom_bank(design):
# Route precharge to col decoder # Route precharge to col decoder
start = prechrg_control.center() start = prechrg_control.center()
mid1 = vector(self.control_inst.rx(), prechrg_control.cy()) mid1 = vector(self.control_inst.rx() + self.interconnect_layer_pitch, prechrg_control.cy())
mid2 = vector(self.control_inst.rx(), col_decode_prechrg.cy()) mid2 = vector(self.control_inst.rx() + self.interconnect_layer_pitch, col_decode_prechrg.cy())
end = col_decode_prechrg.center() end = col_decode_prechrg.center()
self.add_path(self.route_stack[0], [start, mid1, mid2, end]) self.add_path(self.route_stack[0], [start, mid1, mid2, end])
@ -383,7 +384,7 @@ class rom_bank(design):
offset=end) offset=end)
start = mid1 start = mid1
mid1 = vector(self.control_inst.rx(), start.y) mid1 = vector(self.control_inst.rx() + self.interconnect_layer_pitch, start.y)
mid2 = vector(mid1.x, col_decode_clk.cy()) mid2 = vector(mid1.x, col_decode_clk.cy())
end = col_decode_clk.center() end = col_decode_clk.center()
self.add_path(self.route_stack[0], [start, mid1, mid2, end]) self.add_path(self.route_stack[0], [start, mid1, mid2, end])
@ -438,7 +439,7 @@ class rom_bank(design):
self.add_io_pin(self.control_inst, "clk_in", "clk") self.add_io_pin(self.control_inst, "clk_in", "clk")
for i in range(self.word_size): for i in range(self.word_size):
self.add_io_pin(self.output_inv_inst, "out_{}".format(i), "dout[{}]".format(i)) self.add_io_pin(self.output_inv_inst, "out_{}".format(i), "dout[{}]".format(i), directions="nonpref")
for lsb in range(self.col_bits): for lsb in range(self.col_bits):
name = "addr[{}]".format(lsb) name = "addr[{}]".format(lsb)
@ -449,15 +450,49 @@ class rom_bank(design):
pin_num = msb - self.col_bits pin_num = msb - self.col_bits
self.add_io_pin(self.decode_inst, "A{}".format(pin_num), name) self.add_io_pin(self.decode_inst, "A{}".format(pin_num), name)
def route_supplies(self): def route_supplies(self, bbox=None):
for pin_name in ["vdd", "gnd"]:
for inst in self.insts: for inst in self.insts:
if not inst.mod.name.__contains__("contact"): self.copy_power_pins(inst, pin_name)
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd") if not OPTS.route_supplies:
# Do not route the power supply (leave as must-connect pins)
return
elif OPTS.route_supplies == "grid":
from openram.router import supply_grid_router as router
else:
from openram.router import supply_tree_router as router
rtr=router(layers=self.supply_stack,
design=self,
bbox=bbox,
pin_type=OPTS.supply_pin_type)
rtr.route()
if OPTS.supply_pin_type in ["left", "right", "top", "bottom", "ring"]:
# Find the lowest leftest pin for vdd and gnd
for pin_name in ["vdd", "gnd"]:
# Copy the pin shape(s) to rectangles
for pin in self.get_pins(pin_name):
self.add_rect(pin.layer,
pin.ll(),
pin.width(),
pin.height())
# Remove the pin shape(s)
self.remove_layout_pin(pin_name)
# Get new pins
pins = rtr.get_new_pins(pin_name)
for pin in pins:
self.add_layout_pin(pin_name,
pin.layer,
pin.ll(),
pin.width(),
pin.height())
def route_escape_pins(self, bbox): def route_escape_pins(self, bbox):
pins_to_route = [] pins_to_route = []
for bit in range(self.col_bits): for bit in range(self.col_bits):

View File

@ -58,7 +58,7 @@ class rom_base_array(bitcell_base_array):
self.route_precharge() self.route_precharge()
self.add_boundary() self.add_boundary()
self.place_rails() self.route_supplies()
self.connect_taps() self.connect_taps()
def add_boundary(self): def add_boundary(self):
@ -86,7 +86,8 @@ class rom_base_array(bitcell_base_array):
if self.tap_direction == "row": if self.tap_direction == "row":
self.poly_tap = factory.create(module_type="rom_poly_tap") self.poly_tap = factory.create(module_type="rom_poly_tap")
else: else:
self.poly_tap = factory.create(module_type="rom_poly_tap", add_tap=True) self.poly_tap = factory.create(module_type="rom_poly_tap", add_active_tap=True)
self.end_poly_tap = factory.create(module_type="rom_poly_tap", place_poly=True)
self.precharge_array = factory.create(module_type="rom_precharge_array", self.precharge_array = factory.create(module_type="rom_precharge_array",
cols=self.column_size, cols=self.column_size,
strap_spacing=self.strap_spacing, strap_spacing=self.strap_spacing,
@ -109,7 +110,8 @@ class rom_base_array(bitcell_base_array):
def create_cell_instances(self): def create_cell_instances(self):
self.tap_inst = {} self.tap_inst = {}
self.tap_list = [] self.active_tap_list = []
self.poly_tap_list = []
self.cell_inst = {} self.cell_inst = {}
self.cell_list = [] self.cell_list = []
self.current_row = 0 self.current_row = 0
@ -129,19 +131,25 @@ class rom_base_array(bitcell_base_array):
self.cell_inst[row, col] = new_inst self.cell_inst[row, col] = new_inst
row_list.append(new_inst) row_list.append(new_inst)
name = "tap_r{0}_c{1}".format(row, self.array_col_size) self.create_poly_tap(row, self.column_size)
new_tap = self.add_inst(name=name, mod=self.poly_tap) # name = "tap_r{0}_c{1}".format(row, self.array_col_size)
self.tap_inst[row, self.column_size] = new_tap # new_tap = self.add_inst(name=name, mod=self.poly_tap)
self.tap_list.append(new_tap) # self.tap_inst[row, self.column_size] = new_tap
self.connect_inst([]) # self.tap_list.append(new_tap)
# self.connect_inst([])
self.cell_list.append(row_list) self.cell_list.append(row_list)
def create_poly_tap(self, row, col): def create_poly_tap(self, row, col):
name = "tap_r{0}_c{1}".format(row, col) name = "tap_r{0}_c{1}".format(row, col)
if row == self.row_size and self.tap_direction == "col":
new_tap = self.add_inst(name=name, mod=self.end_poly_tap)
else:
new_tap = self.add_inst(name=name, mod=self.poly_tap) new_tap = self.add_inst(name=name, mod=self.poly_tap)
self.active_tap_list.append(new_tap)
self.tap_inst[row, col]=new_tap self.tap_inst[row, col]=new_tap
self.tap_list.append(new_tap) self.poly_tap_list.append(new_tap)
self.connect_inst([]) self.connect_inst([])
def create_cell(self, row, col): def create_cell(self, row, col):
@ -189,15 +197,32 @@ class rom_base_array(bitcell_base_array):
# Make a flat list too # Make a flat list too
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl]
def place_rails(self): def route_supplies(self):
via_width = drc("m2_enclose_via1") * 0.5 + drc("minwidth_via1") via_width = drc("m2_enclose_via1") * 0.5 + drc("minwidth_via1")
pitch = drc["{0}_to_{0}".format(self.wordline_layer)] pitch = drc["{0}_to_{0}".format(self.wordline_layer)]
drain_l = self.cell_list[self.row_size][0].get_pin("D")
drain_r = self.cell_list[self.row_size][self.column_size - 1].get_pin("D")
gnd_l = drain_l.center() + vector(-0.5 * self.route_width, pitch + via_width + self.route_pitch)
gnd_r = drain_r.center() + vector(0.5 * self.route_width, pitch + via_width + self.route_pitch)
self.add_layout_pin_segment_center(text="gnd", layer=self.bitline_layer, start=gnd_l, end=gnd_r)
for i in range(self.column_size):
drain = self.cell_list[self.row_size][i].get_pin("D") if self.tap_direction == "row":
gnd_pos = drain.center() + vector(0, pitch + via_width + self.route_pitch)
self.add_layout_pin_rect_center(text="gnd", layer=self.bitline_layer, offset=gnd_pos)
self.route_horizontal_pins("gnd", insts=[self], yside="cy") self.route_horizontal_pins("gnd", insts=[self], yside="cy")
self.connect_row_pins(layer=self.wordline_layer, pins=self.gnd_taps, name="gnd")
self.remove_layout_pin("gnd_tap")
if self.tap_direction == "col":
active_tap_pins = [self.active_tap_list[i].get_pin("active_tap") for i in range(len(self.active_tap_list))]
self.connect_col_pins(layer=self.supply_stack[0], pins=active_tap_pins, name="gnd_tmp")
for pin in self.get_pins("gnd_tmp"):
bottom = vector(pin.cx(), pin.by())
top = vector(pin.cx(), pin.uy())
self.add_layout_pin_rect_ends(layer=self.supply_stack[0], start=bottom, end=top, name="gnd")
self.remove_layout_pin("gnd_tmp")
self.copy_layout_pin(self.precharge_inst, "vdd") self.copy_layout_pin(self.precharge_inst, "vdd")
@ -231,7 +256,7 @@ class rom_base_array(bitcell_base_array):
self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size]) self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size])
def route_pitch_offsets(self): def route_pitch_offsets(self):
self.gnd_taps = []
for row in range(0 , self.row_size, self.tap_spacing): for row in range(0 , self.row_size, self.tap_spacing):
for col in range(self.column_size): for col in range(self.column_size):
@ -270,12 +295,11 @@ class rom_base_array(bitcell_base_array):
self.add_via_stack_center(offset=tap_pos, self.add_via_stack_center(offset=tap_pos,
from_layer=self.active_stack[2], from_layer=self.active_stack[2],
to_layer=self.wordline_layer) to_layer=self.wordline_layer)
self.add_layout_pin_rect_center("gnd", self.wordline_layer, tap_pos) self.gnd_taps.append(self.add_layout_pin_rect_center("gnd_tap", self.wordline_layer, tap_pos))
def place_precharge(self): def place_precharge(self):
self.precharge_offset = vector(0, - self.precharge_inst.height - self.zero_cell.nmos.end_to_contact - 2 * drc["nwell_enclose_active"] - 3 * self.m1_pitch) self.precharge_offset = vector(0, - self.precharge_inst.height - self.zero_cell.nmos.end_to_contact - 2 * drc["nwell_enclose_active"] - 3 * self.m1_pitch)
self.precharge_inst.place(offset=self.precharge_offset) self.precharge_inst.place(offset=self.precharge_offset)
self.copy_layout_pin(self.precharge_inst, "vdd")
self.copy_layout_pin(self.precharge_inst, "gate", "precharge") self.copy_layout_pin(self.precharge_inst, "gate", "precharge")
def place_wordline_contacts(self): def place_wordline_contacts(self):
@ -332,9 +356,6 @@ class rom_base_array(bitcell_base_array):
self.add_layout_pin_rect_center(text="precharge_r", layer="m1", offset=mid1) self.add_layout_pin_rect_center(text="precharge_r", layer="m1", offset=mid1)
def connect_taps(self): def connect_taps(self):
array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))] poly_tap_pins = [self.poly_tap_list[i].get_pin("poly_tap") for i in range(len(self.poly_tap_list))]
self.connect_row_pins(layer=self.wordline_layer, pins=array_pins, name=None, round=False) self.connect_row_pins(layer=self.wordline_layer, pins=poly_tap_pins)
if self.tap_direction == "col":
self.route_vertical_pins("active_tap", insts=self.tap_list, layer=self.supply_stack[0], full_width=False)

View File

@ -165,9 +165,9 @@ class rom_column_mux(pgate):
# If there is a li layer, include it in the power stack # If there is a li layer, include it in the power stack
self.add_via_stack_center(from_layer=self.active_stack[2], self.add_via_stack_center(from_layer=self.active_stack[2],
to_layer=self.supply_stack[0], to_layer=self.pin_layer,
offset=active_pos) offset=active_pos)
self.add_layout_pin_rect_center(text="gnd", self.add_layout_pin_rect_center(text="gnd",
layer=self.supply_stack[0], layer=self.pin_layer,
offset=active_pos) offset=active_pos)

View File

@ -20,7 +20,7 @@ class rom_column_mux_array(design):
Array of column mux to read the bitlines from ROM, based on the RAM column mux Array of column mux to read the bitlines from ROM, based on the RAM column mux
""" """
def __init__(self, name, columns, word_size, tap_spacing=4, input_layer="m2", bitline_layer="m1", sel_layer="m2"): def __init__(self, name, columns, word_size, tap_spacing=4, input_layer="m1", bitline_layer="m1", sel_layer="m2"):
super().__init__(name) super().__init__(name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} word_size: {1} ".format(columns, word_size)) self.add_comment("cols: {0} word_size: {1} ".format(columns, word_size))
@ -31,7 +31,7 @@ class rom_column_mux_array(design):
self.input_layer = input_layer self.input_layer = input_layer
self.tap_spacing = tap_spacing self.tap_spacing = tap_spacing
self.sel_layer = sel_layer self.sel_layer = sel_layer
self.supply_layer = "m2"
self.sel_pitch = getattr(self, self.sel_layer + "_pitch") self.sel_pitch = getattr(self, self.sel_layer + "_pitch")
self.bitline_layer = bitline_layer self.bitline_layer = bitline_layer
@ -75,7 +75,7 @@ class rom_column_mux_array(design):
def add_modules(self): def add_modules(self):
self.mux = factory.create(module_type="rom_column_mux", input_layer=self.input_layer, output_layer=self.bitline_layer) self.mux = factory.create(module_type="rom_column_mux", input_layer=self.input_layer, output_layer=self.bitline_layer)
self.tap = factory.create(module_type="rom_poly_tap", add_tap=True) self.tap = factory.create(module_type="rom_poly_tap", add_active_tap=True)
self.cell = factory.create(module_type="rom_base_cell") self.cell = factory.create(module_type="rom_base_cell")
def setup_layout_constants(self): def setup_layout_constants(self):
@ -123,7 +123,7 @@ class rom_column_mux_array(design):
def route_supplies(self): def route_supplies(self):
self.route_horizontal_pins("gnd", self.insts) self.route_horizontal_pins("gnd", self.insts, layer=self.supply_layer)
def add_routing(self): def add_routing(self):
self.add_horizontal_input_rail() self.add_horizontal_input_rail()

View File

@ -101,10 +101,10 @@ class rom_control_logic(design):
self.copy_layout_pin(self.buf_inst, "Z", "clk_out") self.copy_layout_pin(self.buf_inst, "Z", "clk_out")
self.copy_layout_pin(self.driver_inst, "Z", "prechrg") self.copy_layout_pin(self.driver_inst, "Z", "prechrg")
self.copy_layout_pin(self.nand_inst, "A", "CS") self.copy_layout_pin(self.nand_inst, "A", "CS")
self.copy_layout_pin(self.buf_inst, "gnd")
self.copy_layout_pin(self.driver_inst, "vdd")
self.copy_layout_pin(self.buf_inst, "vdd")
self.copy_power_pin(self.buf_inst.get_pin("gnd"), directions="nonpref")
self.copy_power_pin(self.driver_inst.get_pin("gnd"), directions="nonpref")
self.copy_power_pin(self.buf_inst.get_pin("vdd"), directions="nonpref")
clk = self.buf_inst.get_pin("Z") clk = self.buf_inst.get_pin("Z")
nand_B = self.nand_inst.get_pin("B") nand_B = self.nand_inst.get_pin("B")

View File

@ -13,11 +13,15 @@ from openram.tech import drc
class rom_poly_tap(design): class rom_poly_tap(design):
def __init__(self, name="", cell_name=None, tx_type="nmos", strap_layer="m2", add_tap=False): def __init__(self, name="", cell_name=None, tx_type="nmos", strap_layer="m2", add_active_tap=False, place_poly=None):
super().__init__(name, cell_name) super().__init__(name, cell_name)
self.strap_layer=strap_layer self.strap_layer=strap_layer
self.tx_type = tx_type self.tx_type = tx_type
self.add_tap = add_tap self.add_tap = add_active_tap
if place_poly is None:
self.place_poly = add_active_tap
else:
self.place_poly = place_poly
self.pitch_offset = 0 self.pitch_offset = 0
self.create_netlist() self.create_netlist()
self.create_layout() self.create_layout()
@ -32,7 +36,7 @@ class rom_poly_tap(design):
self.place_via() self.place_via()
self.add_boundary() self.add_boundary()
if self.add_tap: if self.add_tap or self.place_poly:
self.place_active_tap() self.place_active_tap()
self.extend_poly() self.extend_poly()
@ -47,14 +51,6 @@ class rom_poly_tap(design):
contact_width = self.poly_contact.width contact_width = self.poly_contact.width
# DRC rule here is hard coded since licon.9 isnt included in skywater130 tech file
# poly contact spacing to P-diffusion < 0.235um (licon.9 + psdm.5a)
# if OPTS.tech_name == "sky130":
# self.contact_x_offset = 0.235 - (contact_width - self.pmos.contact_width) * 0.5 - self.poly_extend_active
# else:
# assert(False)
contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact
self.contact_x_offset = 0 self.contact_x_offset = 0
@ -91,13 +87,10 @@ class rom_poly_tap(design):
tap_edge = tap_x + 0.5 * self.active_contact.height tap_edge = tap_x + 0.5 * self.active_contact.height
self.pitch_offset += (self.active_space * 2) - (tap_edge - active_edge) + self.contact_x_offset self.pitch_offset += (self.active_space * 2) - (tap_edge - active_edge) + self.contact_x_offset
if self.tx_type == "nmos": if self.tx_type == "nmos" and self.add_tap:
self.add_via_center(layers=self.active_stack, self.add_via_center(layers=self.active_stack,
offset=contact_pos, offset=contact_pos,
implant_type="p", implant_type="p",
well_type="p", well_type="p",
directions="nonpref") directions="nonpref")
self.add_power_pin(name="gnd", self.add_layout_pin_rect_center("active_tap", self.active_stack[2], contact_pos)
loc=contact_pos,
start_layer=self.active_stack[2])
self.add_layout_pin_rect_center("active_tap", self.supply_stack[0], contact_pos)

View File

@ -83,7 +83,7 @@ class rom_precharge_array(design):
# For layout constants # For layout constants
self.dummy = factory.create(module_type="rom_base_cell") self.dummy = factory.create(module_type="rom_base_cell")
self.poly_tap = factory.create(module_type="rom_poly_tap", tx_type="pmos", add_tap=(self.tap_direction == "col")) self.poly_tap = factory.create(module_type="rom_poly_tap", tx_type="pmos", add_active_tap=(self.tap_direction == "col"))
def add_pins(self): def add_pins(self):
for col in range(self.cols): for col in range(self.cols):

View File

@ -49,11 +49,13 @@ class rom_wordline_driver_array(design):
self.route_layer = "m1" self.route_layer = "m1"
self.place_drivers() self.place_drivers()
self.route_layout() self.route_layout()
self.route_supplies()
if self.tap_spacing != 0: if self.tap_spacing != 0:
self.place_taps() self.place_taps()
self.route_supplies()
self.add_boundary() self.add_boundary()
def add_pins(self): def add_pins(self):
# inputs to wordline_driver. # inputs to wordline_driver.
for i in range(self.rows): for i in range(self.rows):
@ -66,7 +68,7 @@ class rom_wordline_driver_array(design):
def add_modules(self): def add_modules(self):
b = factory.create(module_type="rom_base_cell") b = factory.create(module_type="rom_base_cell")
self.tap = factory.create(module_type="rom_poly_tap", add_tap = True) self.tap = factory.create(module_type="rom_poly_tap", add_active_tap = True)
if self.invert_outputs: if self.invert_outputs:
self.wl_driver = factory.create(module_type="pinv_dec", self.wl_driver = factory.create(module_type="pinv_dec",
@ -86,13 +88,41 @@ class rom_wordline_driver_array(design):
Add a pin for each row of vdd/gnd which Add a pin for each row of vdd/gnd which
are must-connects next level up. are must-connects next level up.
""" """
# self.route_vertical_pins("vdd", self.wld_inst, xside="cx", layer=self.supply_layer)
if layer_props.wordline_driver.vertical_supply: # self.route_vertical_pins("gnd", self.wld_inst, xside="cx", layer=self.supply_layer)
self.route_vertical_pins("vdd", [self], layer=self.supply_layer) if not self.invert_outputs:
self.route_vertical_pins("gnd", [self], layer=self.supply_layer) vdd_pins = [pin for inst in self.wld_inst for pin in inst.get_pins("vdd")]
gnd_pins = [pin for inst in self.wld_inst for pin in inst.get_pins("gnd")]
else: else:
self.route_vertical_pins("vdd", self.wld_inst, xside="rx",) vdd_pins = [inst.get_pin("vdd") for inst in self.wld_inst]
self.route_vertical_pins("gnd", self.wld_inst, xside="lx",) gnd_pins = [inst.get_pin("gnd") for inst in self.wld_inst]
if self.tap_spacing != 0:
vdd_pins = vdd_pins + self.vdd_taps
gnd_pins = gnd_pins + self.gnd_taps
supply_width = drc["minwidth_{}".format(self.supply_layer)]
# Route together all internal supply pins
self.connect_col_pins(layer=self.supply_layer, pins=vdd_pins, name="vdd_tmp")
self.connect_col_pins(layer=self.supply_layer, pins=gnd_pins, name="gnd_tmp")
self.remove_layout_pin("gnd_tap")
self.remove_layout_pin("vdd_tap")
# Place the top level supply pins on the edge of the module
for pin in self.get_pins("gnd_tmp"):
bottom = vector(pin.cx(), pin.by() - 0.5 * supply_width)
top = vector(pin.cx(), pin.uy() + 0.5 * supply_width)
self.add_layout_pin_rect_ends(layer=self.supply_layer, start=bottom, end=top, name="gnd")
for pin in self.get_pins("vdd_tmp"):
bottom = vector(pin.cx(), pin.by() - 0.5 * supply_width)
top = vector(pin.cx(), pin.uy() + 0.5 * supply_width)
self.add_layout_pin_rect_ends(layer=self.supply_layer, start=bottom, end=top, name="vdd")
self.remove_layout_pin("gnd_tmp")
self.remove_layout_pin("vdd_tmp")
def create_drivers(self): def create_drivers(self):
self.wld_inst = [] self.wld_inst = []
@ -125,8 +155,7 @@ class rom_wordline_driver_array(design):
else: else:
row_num = row row_num = row
inst = self.wld_inst[row_num] inst = self.wld_inst[row_num]
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
self.copy_layout_pin(inst, "A", "in_{0}".format(row)) self.copy_layout_pin(inst, "A", "in_{0}".format(row))
@ -151,7 +180,8 @@ class rom_wordline_driver_array(design):
self.add_layout_pin_rect_center(text="out_{}".format(row), layer=self.route_layer, offset=end - vector(0, 0.5 * route_width)) self.add_layout_pin_rect_center(text="out_{}".format(row), layer=self.route_layer, offset=end - vector(0, 0.5 * route_width))
def place_taps(self): def place_taps(self):
self.vdd_taps = []
self.gnd_taps = []
for wl in range(0 , self.rows, self.tap_spacing): for wl in range(0 , self.rows, self.tap_spacing):
driver = self.wld_inst[wl] driver = self.wld_inst[wl]
@ -176,6 +206,7 @@ class rom_wordline_driver_array(design):
self.place_tap(contact_pos, "p") self.place_tap(contact_pos, "p")
def place_tap(self, offset, well_type): def place_tap(self, offset, well_type):
self.add_via_center(layers=self.active_stack, self.add_via_center(layers=self.active_stack,
offset=offset, offset=offset,
implant_type=well_type, implant_type=well_type,
@ -185,7 +216,8 @@ class rom_wordline_driver_array(design):
from_layer=self.active_stack[2], from_layer=self.active_stack[2],
to_layer=self.supply_layer) to_layer=self.supply_layer)
if well_type == "p": if well_type == "p":
pin = "gnd" pin = "gnd_tap"
self.gnd_taps.append(self.add_layout_pin_rect_center(text=pin, layer=self.supply_layer, offset=offset))
else: else:
pin = "vdd" pin = "vdd_tap"
self.add_layout_pin_rect_center(text=pin, layer=self.supply_layer, offset=offset) self.vdd_taps.append(self.add_layout_pin_rect_center(text=pin, layer=self.supply_layer, offset=offset))

View File

@ -2,7 +2,7 @@
tech_name = "sky130" tech_name = "sky130"
nominal_corner_only = True nominal_corner_only = True
#route_supplies = "ring" route_supplies = "ring"
#check_lvsdrc = True check_lvsdrc = True
check_lvsdrc = False # check_lvsdrc = False