mirror of https://github.com/VLSIDA/OpenRAM.git
rom base passing tests with top level routing
This commit is contained in:
parent
7c453e80be
commit
fef9902c45
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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")
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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))
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue