taps in main array and decoder

This commit is contained in:
Jacob Walker 2023-01-22 18:34:11 -08:00
parent f7aed247fd
commit 559300e5cc
14 changed files with 692 additions and 425 deletions

View File

@ -17,13 +17,14 @@ class pinvbuf(pgate):
This is a simple inverter/buffer used for driving loads. It is
used in the column decoder for 1:2 decoding and as the clock buffer.
"""
def __init__(self, name, size=4, height=None):
def __init__(self, name, size=4, height=None, route_in_cell=False):
debug.info(1, "creating pinvbuf {}".format(name))
self.add_comment("size: {}".format(size))
self.stage_effort = 4
self.row_height = height
self.route_in_cell = route_in_cell
# FIXME: Change the number of stages to support high drives.
# stage effort of 4 or less
@ -132,15 +133,35 @@ class pinvbuf(pgate):
to_layer=a3_pin.layer,
offset=a3_pin.center())
# inv1 Z to inv4 A (up and over)
z1_pin = self.inv1_inst.get_pin("Z")
a4_pin = self.inv4_inst.get_pin("A")
mid_point = vector(z1_pin.cx(), a4_pin.cy())
self.add_wire(route_stack,
[z1_pin.center(), mid_point, a4_pin.center()])
self.add_via_stack_center(from_layer=z1_pin.layer,
to_layer=route_stack[2],
offset=z1_pin.center())
if self.route_in_cell:
# inv1 Z to inv4 A (under and up)
mid_point = vector(a4_pin.cx(), z1_pin.cy())
end_point = a4_pin.center()
# end_point = vector(a4_pin.cx(), a4_pin.by() - self.m1_space - self.contact_space)
self.add_path(route_stack[2],
[z1_pin.center(), mid_point, end_point])
self.add_via_stack_center(from_layer=z1_pin.layer,
to_layer=route_stack[2],
offset=z1_pin.center())
self.add_via_stack_center(from_layer=a4_pin.layer,
to_layer=route_stack[2],
offset=end_point)
self.add_segment_center(a4_pin.layer, end_point, a4_pin.center())
else:
# inv1 Z to inv4 A (up and over)
mid_point = vector(z1_pin.cx(), a4_pin.cy())
self.add_wire(route_stack,
[z1_pin.center(), mid_point, a4_pin.center()])
self.add_via_stack_center(from_layer=z1_pin.layer,
to_layer=route_stack[2],
offset=z1_pin.center())
def add_layout_pins(self):

View File

@ -12,20 +12,25 @@ from .bitcell_base_array import bitcell_base_array
from openram.base import vector
from openram import OPTS
from openram.sram_factory import factory
from openram.tech import drc
from openram.tech import drc, layer
class rom_base_array(bitcell_base_array):
def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0, route_layer="li", output_layer="m2", pitch_match=False):
def __init__(self, rows, cols, strap_spacing, bitmap, tap_spacing = 4, name="", bitline_layer="m1", wordline_layer="m2", tap_direction="row", pitch_match=False):
super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset)
super().__init__(name=name, rows=rows, cols=cols, column_offset=0)
self.data = bitmap
self.tap_direction = tap_direction
self.pitch_match = pitch_match
self.route_layer = route_layer
self.output_layer = output_layer
self.bitline_layer = bitline_layer
self.strap_spacing = strap_spacing
self.wordline_layer = wordline_layer
self.data_col_size = self.column_size
self.tap_spacing = tap_spacing
if strap_spacing != 0:
self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing)
else:
@ -47,20 +52,23 @@ class rom_base_array(bitcell_base_array):
def create_layout(self):
self.create_layout_constants()
self.place_array()
if self.pitch_match:
if self.tap_direction == "row":
self.route_pitch_offsets()
self.place_precharge()
self.place_wordline_contacts()
self.place_bitline_contacts()
self.route_precharge()
self.add_boundary()
self.route_precharge()
self.place_rails()
self.add_label("ARRAY ZERO", self.route_layer)
self.add_label("array height", self.route_layer, [0, self.height])
self.connect_taps()
@ -79,22 +87,32 @@ class rom_base_array(bitcell_base_array):
def add_modules(self):
self.zero_cell = factory.create(module_name="rom_base_zero_cell", module_type="rom_base_cell", bitline_layer=self.route_layer, bit_value=0)
self.one_cell = factory.create(module_name="rom_base_one_cell", module_type="rom_base_cell", bitline_layer=self.route_layer, bit_value=1)
self.zero_cell = factory.create(module_name="rom_base_zero_cell",
module_type="rom_base_cell",
bitline_layer=self.bitline_layer,
bit_value=0)
self.one_cell = factory.create(module_name="rom_base_one_cell",
module_type="rom_base_cell",
bitline_layer=self.bitline_layer,
bit_value=1)
self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing)
self.zero_tap = factory.create(module_type="rom_poly_tap", strap_length=0)
self.precharge_array = factory.create(module_type="rom_precharge_array", cols=self.column_size, strap_spacing=self.strap_spacing, route_layer=self.route_layer)
if self.tap_direction == "row":
self.poly_tap = factory.create(module_type="rom_poly_tap")
else:
self.poly_tap = factory.create(module_type="rom_poly_tap", add_tap=True)
self.precharge_array = factory.create(module_type="rom_precharge_array",
cols=self.column_size,
strap_spacing=self.strap_spacing,
route_layer=self.bitline_layer,
strap_layer=self.wordline_layer,
tap_direction=self.tap_direction)
def create_layout_constants(self):
self.route_width = drc("minwidth_" + self.route_layer)
self.route_width = drc("minwidth_" + self.bitline_layer)
self.route_pitch = drc("{0}_to_{0}".format(self.route_layer))
self.route_pitch = drc("{0}_to_{0}".format(self.bitline_layer))
def add_pins(self):
@ -108,8 +126,10 @@ class rom_base_array(bitcell_base_array):
def create_cell_instances(self):
self.tap_inst = {}
self.tap_list = []
self.cell_inst = {}
self.cell_list = []
self.current_row = 0
#list of current bitline interconnect nets, starts as the same as the bitline list and is updated when new insts of cells are added
self.int_bl_list = self.bitline_names[0].copy()
@ -120,15 +140,10 @@ class rom_base_array(bitcell_base_array):
# for each new strap placed, offset the column index refrenced to get correct bit in the data array
# cols are bit lines
if row % self.strap_spacing == 0 and self.pitch_match:
strap_row = True
if (row + 1) % self.strap_spacing == 0 and self.pitch_match:
pre_strap_row = True
for col in range(self.column_size):
if col % self.strap_spacing == 0:
self.create_tap(row, col)
self.create_poly_tap(row, col)
new_inst = self.create_cell(row, col)
@ -139,7 +154,9 @@ class rom_base_array(bitcell_base_array):
name = "tap_r{0}_c{1}".format(row, self.array_col_size)
self.tap_inst[row, 0]=self.add_inst(name=name, mod=self.zero_tap)
new_tap = self.add_inst(name=name, mod=self.poly_tap)
self.tap_inst[row, self.column_size] = new_tap
self.tap_list.append(new_tap)
self.connect_inst([])
self.cell_list.append(row_list)
@ -147,7 +164,9 @@ class rom_base_array(bitcell_base_array):
def create_poly_tap(self, row, col):
name = "tap_r{0}_c{1}".format(row, col)
self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap)
new_tap = self.add_inst(name=name, mod=self.poly_tap)
self.tap_inst[row, col]=new_tap
self.tap_list.append(new_tap)
self.connect_inst([])
@ -205,33 +224,32 @@ class rom_base_array(bitcell_base_array):
def place_rails(self):
via_width = drc("m2_enclose_via1") * 0.5 + drc("minwidth_via1")
pitch = drc["{0}_to_{0}".format(self.wordline_layer)]
self.route_horizontal_pins("D", insts=self.cell_list[self.row_size - 1])
self.copy_layout_pin(self, "D", "gnd")
for i in range(self.column_size):
drain = self.cell_list[self.row_size - 1][i].get_pin("D")
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.copy_layout_pin(self.precharge_inst, "vdd")
def place_well_tap(self):
tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2
contact_pos = vector(self.via.cx(), tap_y)
self.add_via_center(layers=self.active_stack,
offset=contact_pos,
implant_type="p",
well_type="p")
self.add_power_pin(name="gnd",
loc=contact_pos,
start_layer=self.active_stack[2])
def place_array(self):
self.cell_pos = {}
self.strap_pos = {}
# rows are wordlines
col_offset = 0
pitch_offset = 0
for row in range(self.row_size):
# if row % self.strap_spacing == 0 and row != 0 and self.pitch_match:
# pitch_offset += self.poly_tap.width
if row % self.tap_spacing == 0 and self.pitch_match:
pitch_offset += self.active_contact.width + self.active_space
cell_y = row * (self.zero_cell.height) + pitch_offset
@ -241,7 +259,9 @@ class rom_base_array(bitcell_base_array):
if col % self.strap_spacing == 0:
self.strap_pos[row, col] = vector(cell_x, cell_y)
self.tap_inst[row, col].place(self.strap_pos[row, col])
# cell_x += self.poly_tap.width
if self.tap_direction == "col":
cell_x += self.poly_tap.pitch_offset
self.cell_pos[row, col] = vector(cell_x, cell_y)
self.cell_inst[row, col].place(self.cell_pos[row, col])
@ -249,25 +269,59 @@ class rom_base_array(bitcell_base_array):
self.add_label("debug", "li", self.cell_pos[row, col])
self.strap_pos[row, 0] = vector(0, cell_y)
self.tap_inst[row, 0].place(self.strap_pos[row, 0])
self.strap_pos[row, self.column_size] = vector(cell_x, cell_y)
self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size])
# tap_pin = self.tap_inst[row, 0].get_pin("poly_tap").center()
# self.add_layout_pin_rect_center("wl{}".format(row), "m2", tap_pin)
def route_pitch_offsets(self):
for row in range(0 , self.row_size, self.strap_spacing):
if row != 0:
for col in range(self.column_size):
source = self.cell_inst[row, col].get_pin("S")
drain = self.cell_inst[row - 1, col].get_pin("D")
for row in range(0 , self.row_size, self.tap_spacing):
for col in range(self.column_size):
cell = self.cell_inst[row, col]
source = cell.get_pin("S")
if row != 0:
drain = self.cell_inst[row - 1, col].get_pin("D")
start = vector(drain.cx(), source.cy())
end = drain.center()
self.add_segment_center(self.route_layer, start, end)
self.add_segment_center(self.bitline_layer, start, end)
self.place_well_tap(row, col)
def place_well_tap(self, row, col):
cell = self.cell_inst[row, col]
source = cell.get_pin("S")
if col != self.column_size - 1:
tap_x = (self.cell_inst[row , col + 1].get_pin("S").cx() + source.cx()) * 0.5
else:
tap_x = cell.rx() + self.active_space
if row != 0:
drain = self.cell_inst[row - 1, col].get_pin("D")
tap_y = (source.cy() + drain.cy()) * 0.5
else:
tap_y = source.cy() - self.contact_width - 2 * self.active_enclose_contact - self.active_space
tap_pos = vector(tap_x, tap_y)
self.add_via_center(layers=self.active_stack,
offset=tap_pos,
implant_type="p",
well_type="p",
directions="nonpref")
self.add_via_stack_center(offset=tap_pos,
from_layer=self.active_stack[2],
to_layer=self.wordline_layer)
self.add_layout_pin_rect_center("gnd", self.wordline_layer, tap_pos)
def place_precharge(self):
@ -285,14 +339,14 @@ class rom_base_array(bitcell_base_array):
for wl in range(self.row_size):
self.copy_layout_pin(self.tap_inst[wl, 0], "via", self.wordline_names[0][wl])
self.copy_layout_pin(self.tap_inst[wl, 0], "poly_tap", self.wordline_names[0][wl])
# self.add_via_stack_center(poly_via.center(), "m1", self.output_layer)
# self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.zero_cell.height, length=None)
def place_bitline_contacts(self):
rail_y = self.precharge_inst.get_pin("vdd").cy()
rail_y = self.precharge_inst.get_pins("vdd")[0].cy()
for bl in range(self.column_size):
@ -303,13 +357,12 @@ class rom_base_array(bitcell_base_array):
middle_offset = (src_pin.cy() - pre_pin.cy() ) * 0.5
corrected = vector(src_pin.cx(), src_pin.cy() - middle_offset)
self.add_via_stack_center(corrected, self.route_layer, self.output_layer)
output_pos = vector(corrected.x, rail_y)
self.add_segment_center(self.output_layer, corrected, output_pos)
self.add_segment_center(self.bitline_layer, corrected, output_pos)
self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, output_pos )
self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.bitline_layer, output_pos )
@ -322,7 +375,17 @@ class rom_base_array(bitcell_base_array):
bl_start = bl_pin.center()
bl_end = vector(bl_start.x, pre_out_pin.cy())
self.add_segment_center(self.route_layer, bl_start, bl_end)
self.add_segment_center(self.bitline_layer, bl_start, bl_end)
def connect_taps(self):
array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))]
self.connect_row_pins(layer=self.wordline_layer, pins=array_pins, name=None, round=False)
# self.connect_row_pins(layer="poly", pins=array_pins, name=None, round=False)
if self.tap_direction == "col":
self.route_vertical_pins("active_tap", insts=self.tap_list, layer=self.supply_stack[0], full_width=False)
def get_next_cell_in_bl(self, row_start, col):
for row in range(row_start + 1, self.row_size):

View File

@ -26,14 +26,17 @@ class rom_base_bank(design):
# self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]]
self.strap_spacing = strap_spacing
if "li" in layer:
self.route_layer = "li"
else:
self.route_layer = "m1"
self.bus_layer = "m2"
self.tap_spacing = 8
self.interconnect_layer = "m1"
self.bitline_layer = "m1"
self.wordline_layer = "m2"
super().__init__(name=name)
if "li" in layer:
self.route_stack = self.m1_stack
else:
self.route_stack = self.m2_stack
self.route_layer = self.route_stack[0]
self.setup_layout_constants()
self.create_netlist()
self.create_layout()
@ -81,37 +84,46 @@ class rom_base_bank(design):
def create_netlist(self):
self.add_modules()
# self.add_pins()
print("Creating ROM bank instances")
self.create_instances()
def create_layout(self):
print("Placing ROM bank instances")
self.place_instances()
# self.channel_route()
self.route_decode_outputs()
self.route_control()
print("Routing decoders to array")
self.route_decode_outputs()
print("Routing precharge signal")
self.route_precharge()
print("Routing clock signal")
self.route_clock()
self.route_array_outputs()
# self.route_supplies()
self.height = self.array_inst.height
self.width = self.array_inst.width
self.add_boundary()
print("Rom bank placement complete")
def setup_layout_constants(self):
self.route_layer_width = drc["minwidth_{}".format(self.route_layer)]
self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_layer)]
self.bus_layer_width = drc["minwidth_{}".format(self.bus_layer)]
self.bus_layer_pitch = drc["{0}_to_{0}".format(self.bus_layer)]
self.route_layer_width = drc["minwidth_{}".format(self.route_stack[0])]
self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_stack[0])]
self.interconnect_layer_width = drc["minwidth_{}".format(self.interconnect_layer)]
self.interconnect_layer_pitch = drc["{0}_to_{0}".format(self.interconnect_layer)]
def add_pins(self):
self.add_pin("READ", "INPUT")
self.add_pin("clk", "INPUT")
self.add_pin("CS", "INPUT")
for i in range(self.num_inputs):
self.add_pin("addr_{}".format(i), "INPUT")
out_pins = []
for j in range(self.rows):
out_pins.append("rom_out_{}".format(j))
@ -122,17 +134,54 @@ class rom_base_bank(design):
def add_modules(self):
self.array = factory.create(module_type="rom_base_array", cols=self.cols, rows=self.rows, strap_spacing=self.strap_spacing, bitmap=self.data, route_layer=self.route_layer, pitch_match=True)
self.decode_array = factory.create(module_name="rom_row_decode", module_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer, cols=self.cols)
self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.rows + self.cols) / 2, height=self.decode_array.buf_inst.height)
self.column_mux = factory.create(module_type="rom_column_mux_array", columns=self.cols, word_size=self.word_size, bitline_layer=self.route_layer)
print("Creating bank modules")
self.array = factory.create(module_type="rom_base_array",
cols=self.cols,
rows=self.rows,
strap_spacing=self.strap_spacing,
bitmap=self.data,
bitline_layer=self.bitline_layer,
wordline_layer=self.wordline_layer,
pitch_match=True,
tap_spacing=self.tap_spacing)
self.column_decode = factory.create(module_name="rom_column_decode", module_type="rom_decoder", num_outputs=self.words_per_row, strap_spacing=self.strap_spacing, route_layer=self.route_layer, cols=1)
self.decode_array = factory.create(module_name="rom_row_decode",
module_type="rom_decoder",
num_outputs=self.rows,
strap_spacing=self.strap_spacing,
route_layer=self.route_layer,
cols=self.cols)
self.column_mux = factory.create(module_type="rom_column_mux_array",
columns=self.cols,
word_size=self.word_size,
bitline_layer=self.interconnect_layer)
self.column_decode = factory.create(module_name="rom_column_decode",
module_type="rom_decoder",
num_outputs=self.words_per_row,
strap_spacing=self.strap_spacing,
route_layer=self.route_layer,
cols=1,
invert_outputs=True )
self.control_logic = factory.create(module_type="rom_control_logic",
num_outputs=(self.rows + self.cols + self.words_per_row) * 0.5,
clk_fanout=(self.col_bits + self.row_bits) * 2,
height=self.column_decode.height)
print("Col decode height of {}".format(self.column_decode.height))
def create_instances(self):
gnd = ["gnd"]
vdd = ["vdd"]
prechrg = ["precharge"]
clk = ["clk_int"]
array_pins = []
decode_pins = []
@ -156,6 +205,7 @@ class rom_base_bank(design):
decode_pins.append(name)
decode_pins.append("precharge")
decode_pins.append("clk_int")
decode_pins.append("vdd")
decode_pins.append("gnd")
@ -166,7 +216,7 @@ class rom_base_bank(design):
addr_lsb = ["col_addr_{}".format(addr) for addr in range(self.col_bits)]
col_mux_pins = bitlines + select_lines + bitline_out + gnd
col_decode_pins = addr_lsb + select_lines + prechrg + vdd + gnd
col_decode_pins = addr_lsb + select_lines + prechrg + clk + vdd + gnd
self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array)
self.connect_inst(array_pins)
@ -174,7 +224,7 @@ class rom_base_bank(design):
self.connect_inst(decode_pins)
self.control_inst = self.add_inst(name="rom_control", mod=self.control_logic)
self.connect_inst(["READ", "CS", "precharge", "vdd", "gnd"])
self.connect_inst(["clk", "CS", "precharge", "clk_int", "vdd", "gnd"])
self.mux_inst = self.add_inst(name="rom_column_mux", mod=self.column_mux)
self.connect_inst(col_mux_pins)
@ -187,13 +237,13 @@ class rom_base_bank(design):
def place_instances(self):
self.place_row_decoder()
self.place_data_array()
self.place_control_logic()
self.place_col_decoder()
self.place_col_mux()
self.place_col_decoder()
self.place_control_logic()
def place_row_decoder(self):
self.decode_offset = vector(0, self.control_inst.height)
self.decode_offset = vector(0, self.control_inst.height - self.decode_array.control_array.height)
self.decode_inst.place(offset=self.decode_offset)
def place_data_array(self):
@ -208,53 +258,49 @@ class rom_base_bank(design):
self.array_inst.place(offset=(self.array_offset + vector(0, array_align)))
def place_control_logic(self):
self.control_offset = vector(0,0)
self.control_inst.place(offset=self.control_offset)
self.control_offset = vector(self.control_inst.width + self.decode_array.control_array.width + 2 * (self.route_layer_pitch + self.route_layer_width), self.col_decode_inst.by() + self.control_logic.height)
self.control_inst.place(offset=self.control_offset, mirror="XY")
def place_col_decoder(self):
self.col_decode_offset = vector(self.control_logic.width * 1.3, 0)
col_decode_y = self.mux_inst.get_pin("sel_0").cy() - self.col_decode_inst.get_pin("wl_0").cy()
self.col_decode_offset = vector(self.decode_inst.width - self.col_decode_inst.width, col_decode_y)
self.col_decode_inst.place(offset=self.col_decode_offset)
def place_col_mux(self):
mux_y_offset = self.array_inst.by() - self.mux_inst.height - self.route_layer_pitch
self.mux_offset = vector(self.decode_inst.width, 0)
mux_x_offset = self.array_inst.get_pin("bl_0_0").cx() - self.mux_inst.get_pin("bl_0").cx()
self.mux_offset = vector(mux_x_offset, mux_y_offset)
self.mux_inst.place(offset=self.mux_offset)
# def create_wl_bus(self):
# bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] )
# bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width
# self.wl_interconnects = []
def create_wl_bus(self):
bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] )
bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width
self.wl_interconnects = []
for wl in range(self.rows):
self.wl_interconnects.append("wl_interconnect_{}".format(wl))
# for wl in range(self.rows):
# self.wl_interconnects.append("wl_interconnect_{}".format(wl))
self.wl_bus = self.create_vertical_bus(self.bus_layer, vector(bus_x, bus_y), self.wl_interconnects, self.decode_inst.uy() - self.array_inst.by() )
# self.wl_bus = self.create_vertical_bus(self.bus_layer, vector(bus_x, bus_y), self.wl_interconnects, self.decode_inst.uy() - self.array_inst.by() )
def route_decode_outputs(self):
# for the row decoder
route_pins = [self.array_inst.get_pin("wl_0_{}".format(wl)) for wl in range(self.rows)]
decode_pins = [self.decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.rows)]
route_pins.extend(decode_pins)
self.connect_row_pins(self.interconnect_layer, route_pins, round=True)
# for wl in range(self.rows):
# decode_output = self.decode_array.output_names[wl]
# decode_out_pin = self.decode_inst.get_pin(decode_output)
# array_wl = self.array.wordline_names[0][wl]
# array_wl_pin = self.array_inst.get_pin(array_wl)
# then for the column decoder
col_decode_pins = [self.col_decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.words_per_row)]
sel_pins = [self.mux_inst.get_pin("sel_{}".format(wl)) for wl in range(self.words_per_row)]
sel_pins.extend(col_decode_pins)
self.connect_row_pins(self.array.bitline_layer, sel_pins, round=True)
# # wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]]
# start = decode_out_pin.center()
# end = vector(array_wl_pin.cx(), start.y)
# self.add_segment_center(self.bus_layer, start, end)
# self.add_via_stack_center(array_wl_pin.center(), self.bus_layer, self.interconnect_layer )
def route_array_inputs(self):
@ -270,44 +316,88 @@ class rom_base_bank(design):
self.add_segment_center(self.interconnect_layer, start, end)
self.add_via_stack_center(start, self.route_layer, self.interconnect_layer )
def channel_route(self):
route_nets = []
for wl in range(self.rows):
array_wl = self.array.wordline_names[0][wl]
array_wl_pin = self.array_inst.get_pin(array_wl)
decode_output = self.decode_array.output_names[wl]
decode_out_pin = self.decode_inst.get_pin(decode_output)
route_nets.append([array_wl_pin, decode_out_pin])
array_prechrg = self.array_inst.get_pin("precharge")
decode_prechrg = self.decode_inst.get_pin("precharge")
route_nets.append([array_prechrg, decode_prechrg])
channel_start = vector(decode_out_pin.cx(), self.decode_array.array_inst.by())
channel = self.create_vertical_channel_route(netlist=route_nets, offset=channel_start, layer_stack=self.m1_stack, directions="nonpref")
def route_control(self):
def route_precharge(self):
prechrg_control = self.control_inst.get_pin("prechrg")
decode_prechrg = self.decode_inst.get_pin("precharge")
row_decode_prechrg = self.decode_inst.get_pin("precharge")
col_decode_prechrg = self.col_decode_inst.get_pin("precharge")
array_prechrg = self.array_inst.get_pin("precharge")
end = vector(decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy())
# Route precharge signal to the row decoder
end = vector(row_decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy())
self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end)
start = end + vector(0.5 * self.interconnect_layer_width, 0)
self.add_segment_center(self.interconnect_layer, start, decode_prechrg.center())
self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center())
self.add_via_stack_center(from_layer=self.route_stack[0],
to_layer=prechrg_control.layer,
offset=prechrg_control.center())
# Route precharge to col decoder
start = row_decode_prechrg.center() - vector(0, self.route_layer_pitch + 2 * self.route_layer_width)
mid = vector(col_decode_prechrg.cx(), start.y)
end = vector(col_decode_prechrg.cx(), 0.5 * (self.col_decode_inst.uy() + mid.y) )
self.add_path(self.route_stack[0], [start, mid, end])
self.add_via_stack_center(from_layer=self.route_stack[0],
to_layer=col_decode_prechrg.layer,
offset=end)
self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center())
# Route precharge to main array
end = vector(col_decode_prechrg.cx(), array_prechrg.cy())
self.add_segment_center(self.route_stack[0], array_prechrg.center(), end)
def route_clock(self):
clk_out = self.control_inst.get_pin("clk_out")
row_decode_clk = self.decode_inst.get_pin("clk")
col_decode_clk = self.col_decode_inst.get_pin("clk")
self.add_via_stack_center(from_layer=self.route_stack[2],
to_layer=clk_out.layer,
offset=clk_out.center())
# Route clock to row decoder
end = row_decode_clk.rc() + vector( 2 * self.route_layer_pitch + self.route_layer_width, 0)
self.add_path(self.route_stack[2], [clk_out.center(), end])
self.add_via_stack_center(from_layer=self.route_stack[2],
to_layer=row_decode_clk.layer,
offset=end)
self.add_segment_center(row_decode_clk.layer, end, row_decode_clk.rc())
# Route clock to column decoder
end = col_decode_clk.lc() - vector( 2 * self.route_layer_pitch + self.route_layer_width, 0)
self.add_path(self.route_stack[2], [clk_out.center(), end])
self.add_via_stack_center(from_layer=self.route_stack[2],
to_layer=row_decode_clk.layer,
offset=end)
self.add_segment_center(col_decode_clk.layer, end, col_decode_clk.lc())
def route_array_outputs(self):
for i in range(self.cols):
bl_out = self.array_inst.get_pin("bl_0_{}".format(i)).center()
bl_mux = self.mux_inst.get_pin("bl_{}".format(i)).center()
self.add_path(self.array.bitline_layer, [bl_out, bl_mux])
def route_supplies(self):
for inst in self.insts:
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0)
decode_gnd = self.decode_inst.get_pin("gnd")

View File

@ -15,10 +15,11 @@ from openram.tech import drc
class rom_base_cell(design):
def __init__(self, name="", bitline_layer="li", bit_value=1):
def __init__(self, name="", bitline_layer="li", bit_value=1, add_well=False):
super().__init__(name)
self.bit_value = bit_value
self.bitline_layer = bitline_layer
self.add_well=add_well
self.create_netlist()
self.create_layout()
@ -39,6 +40,7 @@ class rom_base_cell(design):
self.place_poly()
if self.bit_value == 0:
self.short_gate()
@ -150,7 +152,19 @@ class rom_base_cell(design):
self.add_segment_center(self.bitline_layer, self.get_pin("D").center(), self.get_pin("S").center())
# def place_tap(self):
# tap_x = self.poly_contact.width * 0.5
# tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2
# contact_pos = vector(tap_x, tap_y)
# self.add_via_center(layers=self.active_stack,
# offset=contact_pos,
# implant_type="p",
# well_type="p")
# self.add_power_pin(name="gnd",
# loc=contact_pos,
# start_layer=self.active_stack[2])

View File

@ -22,12 +22,12 @@ class rom_column_mux(pgate):
Column-mux transistors driven by the decoder must be sized
for optimal speed
"""
def __init__(self, name, tx_size=8, bitline_layer="li"):
def __init__(self, name, tx_size=8, input_layer="m2", output_layer="m1"):
debug.info(2, "creating single ROM column mux cell: {0}".format(name))
self.tx_size = int(tx_size)
self.bitline_layer = bitline_layer
self.input_layer = input_layer
self.output_layer= output_layer
super().__init__(name)
@ -42,16 +42,19 @@ class rom_column_mux(pgate):
def create_layout(self):
# If li exists, use li and m1 for the mux, otherwise use m1 and m2
if self.bitline_layer == "li" :
self.col_mux_stack = self.li_stack
else:
self.col_mux_stack = self.m1_stack
self.pin_layer = self.bitcell.bitline_layer
self.pin_layer = self.input_layer
self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer))
self.pin_width = getattr(self, "{}_width".format(self.pin_layer))
self.pin_height = 2 * self.pin_width
# If li exists, use li and m1 for the mux, otherwise use m1 and m2
if self.output_layer == "li" :
self.col_mux_stack = self.li_stack
else:
self.col_mux_stack = self.m1_stack
self.place_ptx()
# cell = factory.create(module_type=OPTS.bitcell)
@ -69,7 +72,7 @@ class rom_column_mux(pgate):
# self.add_pn_wells()
def add_ptx(self):
self.bitcell = factory.create(module_type="rom_base_cell", bitline_layer=self.bitline_layer)
self.bitcell = factory.create(module_type="rom_base_cell")
# Adds nmos_lower,nmos_upper to the module
self.ptx_width = self.tx_size * drc("minwidth_tx")
@ -98,7 +101,7 @@ class rom_column_mux(pgate):
# bl_out and br_out
self.add_layout_pin(text="bl_out",
layer=self.col_mux_stack[2],
layer=self.col_mux_stack[0],
offset=bl_pos,
height=self.pin_height)
@ -147,18 +150,8 @@ class rom_column_mux(pgate):
nmos_lower_d_pin = self.nmos_lower.get_pin("D")
# Add vias to bl, br_out, nmos_upper/S, nmos_lower/D
# self.add_via_stack_center(from_layer=bl_pin.layer,
# to_layer=self.col_mux_stack[0],
# offset=bl_pin.bc())
# self.add_via_stack_center(from_layer=br_out_pin.layer,
# to_layer=self.col_mux_stack[0],
# offset=br_out_pin.uc())
# self.add_via_stack_center(from_layer=nmos_upper_s_pin.layer,
# to_layer=self.col_mux_stack[2],
# offset=nmos_upper_s_pin.center())
self.add_via_stack_center(from_layer=nmos_lower_d_pin.layer,
to_layer=self.col_mux_stack[2],
to_layer=self.output_layer,
offset=nmos_lower_d_pin.center())
# bl -> nmos_upper/D on metal1
@ -167,29 +160,17 @@ class rom_column_mux(pgate):
+ nmos_lower_s_pin.uc().scale(0, 0.5)
mid2 = bl_pin.bc().scale(0, 0.4) \
+ nmos_lower_s_pin.uc().scale(1, 0.5)
self.add_path(self.col_mux_stack[0],
self.add_path(self.col_mux_stack[2],
[bl_pin.bc(), mid1, mid2, nmos_lower_s_pin.center()])
# halfway up, move over
mid1 = bl_out_pin.uc().scale(1, 0.4) \
+ nmos_lower_d_pin.bc().scale(0, 0.4)
mid2 = bl_out_pin.uc().scale(0, 0.4) \
+ nmos_lower_d_pin.bc().scale(1, 0.4)
self.add_path(self.col_mux_stack[2],
self.add_path(self.col_mux_stack[0],
[bl_out_pin.uc(), mid1, mid2, nmos_lower_d_pin.center()])
# # br -> nmos_lower/D on metal2
# # br_out -> nmos_lower/S on metal1
# self.add_path(self.col_mux_stack[0],
# [br_out_pin.uc(),
# vector(nmos_lower_s_pin.cx(), br_out_pin.uy()),
# nmos_lower_s_pin.center()])
# # halfway up, move over
# mid1 = br_pin.bc().scale(1, 0.5) \
# + nmos_lower_d_pin.uc().scale(0, 0.5)
# mid2 = br_pin.bc().scale(0, 0.5) \
# + nmos_lower_d_pin.uc().scale(1, 0.5)
# self.add_path(self.col_mux_stack[2],
# [br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()])
def extend_implants(self):
"""

View File

@ -9,7 +9,7 @@ from openram import debug
from openram.base import design
from openram.base import vector
from openram.sram_factory import factory
from openram.tech import layer, preferred_directions
from openram.tech import layer, preferred_directions, drc
from openram.tech import layer_properties as layer_props
from openram import OPTS
@ -20,18 +20,18 @@ class rom_column_mux_array(design):
Array of column mux to read the bitlines from ROM, based on the RAM column mux
"""
def __init__(self, name, columns, word_size, offsets=None, column_offset=0, bitline_layer="m1"):
def __init__(self, name, columns, word_size, input_layer="m2", bitline_layer="m1", sel_layer="m2"):
super().__init__(name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} word_size: {1} ".format(columns, word_size))
self.columns = columns
self.word_size = word_size
self.offsets = offsets
self.words_per_row = int(self.columns / self.word_size)
self.column_offset = column_offset
self.input_layer = input_layer
# self.sel_layer = layer_props.column_mux_array.select_layer
self.sel_layer = sel_layer
self.sel_layer = layer_props.column_mux_array.select_layer
self.sel_pitch = getattr(self, self.sel_layer + "_pitch")
self.bitline_layer = bitline_layer
@ -89,7 +89,9 @@ class rom_column_mux_array(design):
self.width = self.columns * self.mux.width
# one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br
# one extra route pitch is to space from the sense amp
self.route_height = (self.words_per_row + 3) * self.sel_pitch
self.route_height = (self.words_per_row + 3) * self.cell.width
self.route_layer_width = drc["minwidth_{}".format(self.bitline_layer)]
self.route_layer_pitch = drc["{0}_to_{0}".format(self.bitline_layer)]
def create_array(self):
self.mux_inst = []
@ -106,8 +108,7 @@ class rom_column_mux_array(design):
def place_array(self):
# Default to single spaced columns
if not self.offsets:
self.offsets = [n * self.mux.width for n in range(self.columns)]
self.offsets = [n * self.mux.width for n in range(self.columns)]
# For every column, add a pass gate
for col_num, xoffset in enumerate(self.offsets[0:self.columns]):
@ -145,7 +146,7 @@ class rom_column_mux_array(design):
def add_horizontal_input_rail(self):
""" Create address input rails below the mux transistors """
for j in range(self.words_per_row):
offset = vector(0, self.route_height + (j - self.words_per_row) * self.sel_pitch)
offset = vector(0, self.route_height + (j - self.words_per_row) * self.cell.width)
self.add_layout_pin(text="sel_{}".format(j),
layer=self.sel_layer,
offset=offset,
@ -154,6 +155,7 @@ class rom_column_mux_array(design):
def add_vertical_poly_rail(self):
""" Connect the poly to the address rails """
# Offset to the first transistor gate in the pass gate
for col in range(self.columns):
# which select bit should this column connect to depends on the position in the word
@ -165,7 +167,9 @@ class rom_column_mux_array(design):
offset = vector(gate_offset.x,
self.get_pin("sel_{}".format(sel_index)).cy())
bl_offset = offset.scale(0, 1) + vector((self.mux_inst[col].get_pin("bl_out").cx()), 0)
bl_x_offset = self.mux_inst[col].get_pin("bl_out").cx() + 2 * self.route_layer_width + self.route_layer_pitch + 0.5 * self.poly_contact.width
bl_offset = offset.scale(0, 1) + vector(bl_x_offset, 0)
self.add_via_stack_center(from_layer="poly",
to_layer=self.sel_layer,
offset=bl_offset,
@ -178,12 +182,12 @@ class rom_column_mux_array(design):
bl_offset_begin = self.mux_inst[j].get_pin("bl_out").bc()
bl_out_offset_begin = bl_offset_begin - vector(0, (self.words_per_row + 1) * self.sel_pitch)
bl_out_offset_begin = bl_offset_begin - vector(0, (self.words_per_row + 1) * self.cell.width)
# Add the horizontal wires for the first bit
if j % self.words_per_row == 0:
bl_offset_end = self.mux_inst[j + self.words_per_row - 1].get_pin("bl_out").bc()
bl_out_offset_end = bl_offset_end - vector(0, (self.words_per_row + 1) * self.sel_pitch)
bl_out_offset_end = bl_offset_end - vector(0, (self.words_per_row + 1) * self.cell.width)
self.add_path(self.sel_layer, [bl_out_offset_begin, bl_out_offset_end])

View File

@ -8,26 +8,34 @@
from openram.sram_factory import factory
from openram.base import vector, design
from openram.tech import layer, drc
class rom_control_logic(design):
def __init__(self, num_outputs, name="", height=None):
def __init__(self, num_outputs, clk_fanout, name="", height=None):
self.output_size = num_outputs
self.mod_height = height
super().__init__(name, prop=False)
self.height = height
if self.height is not None:
print("got height of {}".format(self.height))
self.driver_height = 0.6 * self.height
self.gate_height = 0.2 * self.height
else:
print("got none height")
self.gate_height = 20 * self.m1_pitch
self.driver_height = self.gate_height
self.clk_fanout = clk_fanout
if "li" in layer:
self.route_layer = "li"
self.route_stack = self.li_stack
else:
self.route_layer = "m1"
self.route_stack = self.m1_stack
# dff = factory.create(module_type="dff")
# if height == None:
# self.mod_height = dff.height * 0.5
# else:
# self.mod_height = height
super().__init__(name)
self.create_netlist()
self.create_layout()
self.add_boundary()
@ -39,29 +47,40 @@ class rom_control_logic(design):
def create_layout(self):
self.create_instances()
self.height=self.nand_inst.height
self.width=self.nand_inst.width + self.inv_inst.width + self.driver_inst.width
self.height=self.driver_inst.height + self.buf_inst.height
self.width= max(self.nand_inst.width + self.buf_inst.width, self.driver_inst.width)
self.place_instances()
self.route_insts()
def add_modules(self):
self.inv_mod = factory.create(module_type="pinv", module_name="rom_control_logic_pinv", height=self.mod_height)
self.nand_mod = factory.create(module_type="pnand2", module_name="rom_control_nand", height=self.mod_height)
self.driver_mod = factory.create(module_type="pdriver", inverting=True, fanout=self.output_size, height=self.mod_height, add_wells=True)
self.buf_mod = factory.create(module_type="pinvbuf",
module_name="rom_control_logic_pinv",
height=self.gate_height,
route_in_cell=True )
self.nand_mod = factory.create(module_type="pnand2",
module_name="rom_control_nand",
height=self.gate_height,
add_wells=False)
self.driver_mod = factory.create(module_type="pdriver",
inverting=True,
fanout=self.output_size,
height=self.driver_height,
add_wells=True)
def add_pins(self):
self.add_pin("clk", "INPUT")
self.add_pin("clk_in", "INPUT")
self.add_pin("CS", "INPUT")
self.add_pin("prechrg", "OUTPUT")
self.add_pin("clk_out", "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def create_instances(self):
self.inv_inst = self.add_inst(name="read_signal_inv", mod=self.inv_mod)
self.connect_inst(["clk", "clk_bar", "vdd", "gnd"])
self.buf_inst = self.add_inst(name="clk_invbuf", mod=self.buf_mod)
self.connect_inst(["clk_in", "clk_bar", "clk_out", "vdd", "gnd"])
self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod)
self.connect_inst(["CS", "clk_bar", "pre_drive", "vdd", "gnd"])
@ -71,16 +90,55 @@ class rom_control_logic(design):
def place_instances(self):
self.nand_inst.place(offset=[self.inv_inst.width, 0])
self.driver_inst.place(offset=[self.nand_inst.width + self.inv_inst.width, 0])
buf_correction = drc["minwidth_{}".format(self.route_stack[0])] * 0.5
# nand_y = self.buf_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy()
self.nand_inst.place(offset=[0, self.nand_inst.height + self.buf_mod.inv2.height + buf_correction], mirror="MX")
self.driver_inst.place(offset=[0, self.buf_inst.height + buf_correction])
def route_insts(self):
route_width = drc["minwidth_{}".format(self.route_stack[2])]
self.copy_layout_pin(self.inv_inst, "A", "READ")
self.copy_layout_pin(self.buf_inst, "A", "clk_in")
self.copy_layout_pin(self.buf_inst, "Zb", "clkb_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.nand_inst, "B", "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_layout_pin(self.buf_inst, "vdd")
self.add_path(self.route_layer, [self.inv_inst.get_pin("Z").center(), self.nand_inst.get_pin("A").center()])
clk_bar = self.buf_inst.get_pin("Zb")
self.add_path(self.route_layer, [self.nand_inst.get_pin("Z").center(), self.driver_inst.get_pin("A").center()])
nand_B = self.nand_inst.get_pin("B")
# Connect buffered clock bar to nand input
mid = vector(clk_bar.lx() - route_width - 2 * self.m1_space)
self.add_path(self.route_stack[2], [clk_bar.center(), mid, nand_B.center()])
self.add_via_stack_center(from_layer=clk_bar.layer,
to_layer=self.route_stack[2],
offset=clk_bar.center())
self.add_via_stack_center(from_layer=nand_B.layer,
to_layer=self.route_stack[2],
offset=nand_B.center())
# Connect nand output to precharge driver
nand_Z = self.nand_inst.get_pin("Z")
nand_output = vector(nand_Z.cx(), nand_B.cy() + 3 * route_width)
driver_A = self.driver_inst.get_pin("A")
self.add_path(self.route_stack[2], [nand_output, driver_A.center()])
self.add_via_stack_center(from_layer=nand_Z.layer,
to_layer=self.route_stack[2],
offset=nand_output)
self.add_via_stack_center(from_layer=driver_A.layer,
to_layer=self.route_stack[2],
offset=driver_A.center())

View File

@ -14,7 +14,7 @@ from openram.tech import drc
class rom_decoder(design):
def __init__(self, num_outputs, cols, strap_spacing, name="", route_layer="m1", output_layer="m2"):
def __init__(self, num_outputs, cols, strap_spacing, name="", route_layer="m1", output_layer="m1", invert_outputs=False):
# word lines/ rows / inputs in the base array become the address lines / cols / inputs in the decoder
# bit lines / cols / outputs in the base array become the word lines / rows / outputs in the decoder
@ -34,7 +34,11 @@ class rom_decoder(design):
self.output_layer = output_layer
self.inv_route_layer = "m2"
self.cols=cols
self.invert_outputs=invert_outputs
self.create_netlist()
self.width = self.array_mod.height + self.wordline_buf.width
self.height = self.array_mod.width + self.control_array.height
self.create_layout()
def create_netlist(self):
@ -49,10 +53,9 @@ class rom_decoder(design):
self.place_input_buffer()
self.place_driver()
self.route_outputs()
self.width = self.array_inst.height + self.wordline_buf_inst.width
self.height = self.array_inst.width + self.buf_inst.height
self.connect_inputs()
# self.route_supplies()
self.route_supplies()
self.add_boundary()
def setup_layout_constants(self):
@ -97,18 +100,24 @@ class rom_decoder(design):
for j in range(self.num_outputs):
self.add_pin("wl_{0}".format(j), "OUTPUT")
self.add_pin("precharge_gate", "INPUT")
self.add_pin("precharge", "INPUT")
self.add_pin("clk", "INPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
def add_modules(self):
self.control_array = factory.create(module_type="rom_address_control_array", cols=self.num_inputs)
self.control_array = factory.create(module_type="rom_address_control_array",
cols=self.num_inputs)
self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), \
rows=self.num_outputs, \
cols=self.cols)
rows=self.num_outputs, \
cols=self.cols,
invert_outputs=self.invert_outputs,
tap_spacing=self.strap_spacing)
self.array_mod = factory.create(module_type="rom_base_array", \
module_name="{}_array".format(self.name), \
@ -116,8 +125,8 @@ class rom_decoder(design):
rows=2 * self.num_inputs, \
bitmap=self.decode_map,
strap_spacing = self.strap_spacing,
route_layer=self.route_layer,
output_layer=self.output_layer)
bitline_layer=self.output_layer,
tap_direction="col")
def create_instances(self):
@ -135,8 +144,8 @@ class rom_decoder(design):
for i in range(self.num_inputs):
control_pins.append("A{0}".format(i))
control_pins.append("A{0}_int".format(i))
control_pins.append("Abar{0}_int".format(i))
control_pins.append("in_{0}".format(i))
control_pins.append("inbar_{0}".format(i))
control_pins.append("clk")
control_pins.append("vdd")
control_pins.append("gnd")
@ -156,7 +165,7 @@ class rom_decoder(design):
for i in reversed(range(self.num_inputs)):
array_pins.append("inbar_{0}".format(i))
array_pins.append("in_{0}".format(i))
array_pins.append("precharge_gate")
array_pins.append("precharge")
array_pins.append("vdd")
array_pins.append("gnd")
self.connect_inst(array_pins)
@ -173,10 +182,11 @@ class rom_decoder(design):
def place_input_buffer(self):
wl = self.array_mod.row_size - 1
align = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl]).cx() - self.buf_inst.get_pin("A0_out").cx()
print("align: {}".format(align))
self.buf_inst.place(vector(align, 0))
self.copy_layout_pin(self.buf_inst, "clk")
def place_array(self):
@ -196,6 +206,9 @@ class rom_decoder(design):
for j in range(self.num_outputs):
self.copy_layout_pin(self.wordline_buf_inst, "out_{}".format(j), "wl_{}".format(j))
offset = self.wordline_buf_inst.get_pin("out_{}".format(j)).center()
# self.add_via_stack_center(offset, self.output_layer, self.wordline_buf.route_layer)
array_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.num_outputs)]
driver_pins = [self.wordline_buf_inst.get_pin("in_{}".format(bl)) for bl in range(self.num_outputs)]
@ -229,44 +242,50 @@ class rom_decoder(design):
def route_supplies(self):
minwidth = drc["minwidth_{}".format(self.inv_route_layer)]
pitch = drc["{0}_to_{0}".format(self.inv_route_layer)]
self.copy_layout_pin(self.array_inst, "vdd")
self.copy_layout_pin(self.wordline_buf_inst, "vdd")
self.copy_layout_pin(self.buf_inst, "vdd")
self.copy_layout_pin(self.array_inst, "gnd")
self.copy_layout_pin(self.wordline_buf_inst, "gnd")
self.copy_layout_pin(self.buf_inst, "gnd")
# route decode array vdd and inv array vdd together
array_vdd = self.array_inst.get_pin("vdd")
inv_vdd = self.buf_inst.get_pins("vdd")[-1]
# array_vdd = self.array_inst.get_pin("vdd")
# inv_vdd = self.buf_inst.get_pins("vdd")[-1]
end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth)
self.add_segment_center("m1", array_vdd.center(), end)
end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy())
self.add_segment_center(self.route_layer, inv_vdd.center(), end)
# end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth)
# self.add_segment_center("m1", array_vdd.center(), end)
# end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy())
# self.add_segment_center(self.route_layer, inv_vdd.center(), end)
end = vector(array_vdd.cx(), inv_vdd.cy())
self.add_via_stack_center(end, self.route_layer, "m1")
self.add_layout_pin_rect_center("vdd", "m1", end)
# end = vector(array_vdd.cx(), inv_vdd.cy())
# self.add_via_stack_center(end, self.route_layer, "m1")
# self.add_layout_pin_rect_center("vdd", "m1", end)
# route pin on inv gnd
# # route pin on inv gnd
inv_gnd = self.buf_inst.get_pins("gnd")[0]
array_gnd = self.array_inst.get_pins("gnd")
# inv_gnd = self.buf_inst.get_pins("gnd")[0]
# array_gnd = self.array_inst.get_pins("gnd")
# add x jog
# # add x jog
start = vector(array_gnd[0].cx(), inv_gnd.cy())
self.add_via_stack_center(start, self.route_layer, "m1")
self.add_layout_pin_rect_center("gnd", "m1", start)
# start = vector(array_gnd[0].cx(), inv_gnd.cy())
# self.add_via_stack_center(start, self.route_layer, "m1")
# self.add_layout_pin_rect_center("gnd", "m1", start)
end = array_gnd[0].center()
self.add_segment_center("m1", start, end)
# add y jog
# end = array_gnd[0].center()
# self.add_segment_center("m1", start, end)
# # add y jog
width = minwidth
height = array_gnd[0].uy() - array_gnd[-1].uy() + minwidth
# width = minwidth
# height = array_gnd[0].uy() - array_gnd[-1].uy() + minwidth
offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy()))
# offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy()))
start = end - vector(0, 0.5 * minwidth)
end = vector(start.x, array_gnd[1].uy())
# start = end - vector(0, 0.5 * minwidth)
# end = vector(start.x, array_gnd[1].uy())

View File

@ -14,36 +14,43 @@ from openram.tech import drc
class rom_poly_tap(design):
def __init__(self, name="", strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m2"):
super().__init__(name, cell_name, prop)
def __init__(self, name="", cell_name=None, tx_type="nmos", strap_layer="m2", add_tap=False):
super().__init__(name, cell_name)
self.strap_layer=strap_layer
self.length = strap_length
self.tx_type = tx_type
self.add_tap = add_tap
self.pitch_offset = 0
self.create_netlist()
self.create_layout()
def create_netlist(self):
#for layout constants
self.dummy = factory.create(module_type="rom_base_cell")
if self.tx_type == "nmos":
self.dummy = factory.create(module_type="rom_base_cell")
else:
self.dummy = factory.create(module_type="rom_precharge_cell")
self.pmos = factory.create(module_type="ptx", tx_type="pmos")
def create_layout(self):
self.place_via()
# if self.tx_type == "pmos":
self.extend_poly()
self.place_ptap()
if self.add_tap:
self.place_active_tap()
self.extend_poly()
self.add_boundary()
# if self.length != 0:
# self.place_strap()
def add_boundary(self):
contact_width = self.poly_contact.width + 2 * self.contact_x_offset
contact_width = self.poly_contact.width
offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact)
# offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact)
self.height = self.dummy.height
self.width = contact_width + self.pitch_offset
self.width = contact_width + self.pitch_offset
super().add_boundary()
@ -59,59 +66,66 @@ class rom_poly_tap(design):
else:
assert(False)
contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact
if self.tx_type == "nmos":
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
# contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5)
# self.contact_x_offset = 0
else:
contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x
self.contact_x_offset = 0
# else:
# contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x
# contact_x = - contact_width * 0.5 - self.contact_x_offset
contact_x = contact_width * 0.5 + self.contact_x_offset
contact_x = contact_width * 0.5 + self.contact_x_offset
self.contact_offset = vector(contact_x, contact_y)
self.via = self.add_via_stack_center(from_layer="poly",
to_layer=self.strap_layer,
offset=self.contact_offset)
self.add_layout_pin_rect_center("via", self.strap_layer, self.contact_offset)
self.add_layout_pin_rect_center("poly_tap", self.strap_layer, self.contact_offset)
def place_strap(self):
# def place_strap(self):
strap_start = vector(self.via.lx() , self.via.cy())
# strap_start = vector(self.via.lx() , self.via.cy())
strap_end = vector( self.dummy.width * (self.length + 1), self.via.cy())
# strap_end = vector( self.dummy.width * (self.length + 1), self.via.cy())
self.strap = self.add_path(self.strap_layer, (strap_start, strap_end))
# self.strap = self.add_path(self.strap_layer, (strap_start, strap_end))
def extend_poly(self):
base_contact_width = self.poly_contact.width + 2 * self.contact_x_offset
self.pitch_offset = (base_contact_width - self.active_enclose_contact - self.active_extend_contact) - self.active_space
self.add_segment_center("poly", self.via.center(), vector(self.via.cx() + self.pitch_offset, self.via.cy()))
self.add_segment_center("poly", self.via.center(), vector(0, self.via.cy()))
poly_x = self.poly_contact.width + self.contact_x_offset
poly_y = self.contact_offset.y - self.poly_width * 0.5
extend_offset = vector(poly_x, poly_y)
self.add_rect("poly", extend_offset, self.contact_x_offset + self.pitch_offset, self.poly_width)
poly_x = 0
extend_offset = vector(poly_x, poly_y)
self.add_rect("poly", extend_offset, self.contact_x_offset , self.poly_width)
def place_ptap(self):
tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2
def place_active_tap(self):
gap = self.poly_extend_active - 0.5 * ( self.active_contact.height - self.poly_contact.width )
offset = self.active_space - gap
# tap_x = self.via.cx() + self.contact_width + self.active_enclose_contact + self.poly_enclose_contact
tap_x = self.via.cx() + offset
tap_y = self.via.cy() + self.dummy.width * 0.5
contact_pos = vector(tap_x, tap_y)
# edge of the next nmos
active_edge = self.dummy.width - self.dummy.cell_inst.height - self.poly_extend_active
# edge of the active contact
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
if self.tx_type == "nmos":
self.add_via_center(layers=self.active_stack,
offset=contact_pos,
implant_type="p",
well_type="p",
directions="nonpref")
self.add_power_pin(name="gnd",
loc=contact_pos,
start_layer=self.active_stack[2])
self.add_layout_pin_rect_center("active_tap", self.supply_stack[0], contact_pos)
contact_pos = vector(self.via.cx(), tap_y)
self.add_via_center(layers=self.active_stack,
offset=contact_pos,
implant_type="p",
well_type="p")
self.add_power_pin(name="gnd",
loc=contact_pos,
start_layer=self.active_stack[2])

View File

@ -19,25 +19,25 @@ class rom_precharge_array(design):
"""
An array of inverters to create the inverted address lines for the rom decoder
"""
def __init__(self, cols, pmos_size=None, name="", route_layer="li", strap_spacing=None):
def __init__(self, cols, name="", route_layer="li", strap_spacing=None, strap_layer="m2", tap_direction="row"):
self.cols = cols
self.route_layer = route_layer
self.strap_layer = strap_layer
self.tap_direction = tap_direction
if self.route_layer == "m1" :
self.supply_layer = "li"
else:
self.supply_layer = "m1"
if name=="":
name = "rom_inv_array_{0}".format(cols)
# if pmos_size == None:
# self.pmos_size = dff.height * 0.5
# else:
# self.pmos_size = inv_size
if strap_spacing != None:
self.strap_spacing = strap_spacing
else:
self.strap_spacing = 0
if "li" in layer:
self.inv_layer = "li"
else:
self.inv_layer = "m1"
if strap_spacing != 0:
self.num_straps = ceil(self.cols / self.strap_spacing)
@ -62,28 +62,30 @@ class rom_precharge_array(design):
self.height = self.pmos.width
self.place_instances()
self.create_layout_pins()
self.add_well_tap()
self.route_supply()
self.connect_taps()
self.add_boundary()
self.extend_well()
def add_boundary(self):
# self.translate_all(self.well_ll)
ur = self.find_highest_coords()
self.add_label(layer="nwell", text="upper right",offset=ur)
# ur = vector(ur.x, ur.y - self.well_ll.y)
super().add_boundary(vector(0, 0), ur)
self.width = self.cols * self.pmos.width
self.height = ur.y
self.width = ur.x
def create_modules(self):
self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", route_layer=self.route_layer)
self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", route_layer=self.route_layer, supply_layer=self.supply_layer)
# For layout constants
self.dummy = factory.create(module_type="rom_base_cell")
self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing)
self.poly_tap = factory.create(module_type="rom_poly_tap", tx_type="pmos", add_tap=(self.tap_direction == "col"))
def add_pins(self):
for col in range(self.cols):
@ -96,33 +98,34 @@ class rom_precharge_array(design):
self.pmos_insts = []
self.tap_insts = []
self.tap_insts.append(self.add_inst(name="tap_0", mod=self.poly_tap))
self.connect_inst([])
self.create_poly_tap(-1)
for col in range(self.cols):
if col % self.strap_spacing == 0:
self.create_poly_tap(col)
self.create_precharge_tx(col)
# if col % self.strap_spacing == 0:
# name = "tap_c{}".format(col)
# tap = self.add_inst(name=name, mod=self.poly_tap)
# self.array_insts.append(tap)
# self.tap_insts.append(tap)
# self.connect_inst([])
name = "Xpmos_c{0}".format(col)
pmos = self.add_inst(name=name, mod=self.pmos)
self.array_insts.append(pmos)
self.pmos_insts.append(pmos)
bl = "pre_bl{0}_out".format(col)
self.connect_inst(["vdd", "gate", bl, "vdd"])
print(self.array_insts)
def create_precharge_tx(self, col):
name = "Xpmos_c{0}".format(col)
pmos = self.add_inst(name=name, mod=self.pmos)
self.array_insts.append(pmos)
self.pmos_insts.append(pmos)
bl = "pre_bl{0}_out".format(col)
self.connect_inst(["vdd", "gate", bl])
def create_poly_tap(self, col):
name = "tap_c{}".format( col)
new_tap = self.add_inst(name=name, mod=self.poly_tap)
self.tap_insts.append(new_tap)
self.connect_inst([])
def place_instances(self):
self.add_label("ZERO", self.route_layer)
self.array_pos = []
strap_num = 0
strap_num = 1
cell_y = 0
# columns are bit lines4
cell_x = 0
@ -130,12 +133,19 @@ class rom_precharge_array(design):
self.tap_insts[0].place(vector(cell_x, cell_y))
for col in range(self.cols):
if col % self.strap_spacing == 0:
self.tap_insts[strap_num].place(vector(cell_x, cell_y))
strap_num += 1
if self.tap_direction == "col":
cell_x += self.poly_tap.pitch_offset
# if col % self.strap_spacing == 0 :
# self.tap_insts[strap_num].place(vector(cell_x, cell_y))
# self.add_label("debug", "li", vector(cell_x, cell_y))
# cell_x += self.poly_tap.width
# strap_num += 1
self.pmos_insts[col].place(vector(cell_x, cell_y))
self.add_label("debug", "li", vector(cell_x, cell_y))
@ -143,51 +153,31 @@ class rom_precharge_array(design):
def create_layout_pins(self):
self.copy_layout_pin(self.tap_insts[0], "via", "gate")
self.copy_layout_pin(self.tap_insts[0], "poly_tap", "gate")
for col in range(self.cols):
source_pin = self.pmos_insts[col].get_pin("D")
bl = "pre_bl{0}_out".format(col)
self.add_layout_pin_rect_center(bl, self.route_layer, source_pin.center())
def add_well_tap(self):
layer_stack = self.active_stack
contact_x = self.pmos_insts[self.cols - 1].rx() + self.active_space
contact_offset = vector(contact_x, self.pmos.height * 0.5)
self.nwell_contact = self.add_via_center(layers=layer_stack,
offset=contact_offset,
implant_type="n",
well_type="n",
directions=("V", "V"))
def route_supply(self):
start_pin = self.pmos_insts[0].get_pin("S").lx()
end_pin = self.pmos_insts[-1].get_pin("S").rx()
spacing = drc["{0}_to_{0}".format(self.route_layer)]
start = vector(start_pin, -2*spacing)
end = vector(end_pin, -2*spacing)
self.vdd = self.add_layout_pin_segment_center("vdd", "m1", start, end)
for i in range(self.cols):
start = self.pmos_insts[i].get_pin("S").center()
end = vector(start.x, self.vdd.cy())
self.add_segment_center(self.route_layer, start, end)
self.add_via_stack_center(end, self.route_layer, "m1")
# self.vdd = self.add_layout_pin_segment_center("vdd", self.supply_layer, start, end)
# vdd = [self.pmos_insts[i].get_pin("vdd") for i in range(self.cols)]routeroute_horizon_horizon
self.route_horizontal_pins("vdd", insts=self.pmos_insts)
# connect nwell tap to vdd
start = end
end = vector(self.nwell_contact.cx(), start.y)
self.add_segment_center(self.route_layer, start, end)
start = end - vector(0, 0.5 * self.mcon_width)
end = self.nwell_contact.center()
self.add_segment_center(self.route_layer, start, end)
def connect_taps(self):
array_pins = [self.tap_insts[i].get_pin("poly_tap") for i in range(len(self.tap_insts))]
self.connect_row_pins(layer=self.strap_layer, pins=array_pins, name=None, round=False)
def extend_well(self):
well_y = self.pmos_insts[0].get_pin("vdd").cy() - 0.5 * self.nwell_width
well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width
well_ll = vector(0, well_y)
self.add_rect("nwell", well_ll, self.width , self.height - well_y)

View File

@ -15,20 +15,16 @@ from openram.tech import drc
class rom_precharge_cell(rom_base_cell):
def __init__(self, name="", route_layer="m1"):
def __init__(self, name="", route_layer="m1", supply_layer="li"):
self.supply_layer = supply_layer
super().__init__(name=name, bitline_layer=route_layer)
# def create_netlist(self):
# self.add_pins()
# self.add_modules()
# self.create_tx()
def create_layout(self):
super().create_layout()
self.place_tap()
self.extend_well()
@ -37,19 +33,21 @@ class rom_precharge_cell(rom_base_cell):
self.pmos = factory.create(module_type="ptx",
module_name="pre_pmos_mod",
tx_type="pmos"
tx_type="pmos",
add_source_contact=self.supply_layer,
add_drain_contact=self.bitline_layer
)
def create_tx(self):
self.cell_inst = self.add_inst( name="precharge_pmos",
mod=self.pmos,
)
self.connect_inst(["bitline", "gate", "vdd", "body"])
self.connect_inst(["bitline", "gate", "vdd", "vdd"])
def add_pins(self):
pin_list = ["vdd", "gate", "bitline", "body"]
dir_list = ["POWER", "INPUT", "OUTPUT", "POWER"]
pin_list = ["vdd", "gate", "bitline"]
dir_list = ["POWER", "INPUT", "OUTPUT"]
self.add_pin_list(pin_list, dir_list)
@ -57,8 +55,6 @@ class rom_precharge_cell(rom_base_cell):
self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active)
#contact to contact distance, minimum cell width before drc offsets
self.base_width = self.pmos.width - 2 * self.active_enclose_contact - self.pmos.contact_width
@ -70,37 +66,34 @@ class rom_precharge_cell(rom_base_cell):
def extend_well(self):
self.pmos
well_y = - (0.5 * self.nwell_width)
well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width
well_ll = vector(0, well_y)
# height = self.active_width + 2 * self.well_enclose_active
height = self.height + 0.5 * self.nwell_width
height = self.get_pin("D").cy() + 0.5 * self.nwell_width - well_y
self.add_rect("nwell", well_ll, self.width , height)
# def place_tx(self):
# pmos_offset = vector(self.pmos.poly_extend_active + self.pmos.height, 0)
def place_tap(self):
source = self.cell_inst.get_pin("S")
tap_y = source.cy() - self.contact_width - 2 * self.active_enclose_contact - self.active_space
pos = vector(source.cx(), tap_y )
self.add_via_center(layers=self.active_stack,
offset=pos,
implant_type="n",
well_type="n",
directions="nonpref")
self.add_via_stack_center(offset=pos,
from_layer=self.active_stack[2],
to_layer=self.supply_layer)
# self.cell_inst.place(pmos_offset, rotate=90)
# self.add_label("inst_zero", self.bitline_layer)
# self.add_layout_pin_rect_center("S", self.bitline_layer, self.cell_inst.get_pin("S").center())
# self.add_layout_pin_rect_center("D", self.bitline_layer, self.cell_inst.get_pin("D").center())
# def place_poly(self):
# poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.rx() + self.poly_extend_active)
# poly_offset = vector(self.cell_inst.rx() + self.poly_extend_active, self.cell_inst.width * 0.5 )
# start = poly_offset
# end = poly_offset + vector(poly_size, 0)
# self.add_segment_center("poly", start, end)
# def add_boundary(self):
# #cell width with offsets applied, height becomes width when the cells are rotated
# self.width = self.pmos.height + self.poly_extend_active_spacing + 2 * self.pmos.poly_extend_active
# # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied
# # self.height = self.base_width - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0)
# super().add_boundary()
bitline_offset = vector( 2 * (drc("minwidth_{}".format(self.bitline_layer)) + drc("{0}_to_{0}".format(self.bitline_layer))) ,0)
self.add_layout_pin_rect_center("vdd", self.supply_layer, pos - bitline_offset)
self.add_path(self.supply_layer, [self.get_pin("vdd").center(), pos, self.get_pin("S").center()])
self.remove_layout_pin("S")

View File

@ -19,14 +19,15 @@ class rom_wordline_driver_array(design):
Creates a Wordline Buffer/Inverter array
"""
def __init__(self, name, rows, cols):
def __init__(self, name, rows, cols, invert_outputs=False, tap_spacing=4):
design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.rows = rows
self.cols = cols
self.invert_outputs=invert_outputs
self.tap_spacing = tap_spacing
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
@ -60,10 +61,25 @@ class rom_wordline_driver_array(design):
def add_modules(self):
b = factory.create(module_type="rom_base_cell")
self.wl_driver = factory.create(module_type="pbuf_dec",
size=self.cols,
height=b.height,
add_wells=False)
if self.invert_outputs:
self.wl_driver = factory.create(module_type="pinv_dec",
size=self.cols,
height=b.height,
add_wells=False)
self.wl_driver_tap = factory.create(module_type="pinv_dec",
size=self.cols,
add_wells=True)
else:
self.wl_driver = factory.create(module_type="pbuf_dec",
size=self.cols,
height=b.height,
add_wells=False)
self.wl_driver_tap = factory.create(module_type="pbuf_dec",
size=self.cols,
add_wells=True)
print(self.wl_driver.height)
print(self.wl_driver_tap.height)
def route_supplies(self):
"""
@ -80,21 +96,25 @@ class rom_wordline_driver_array(design):
def create_drivers(self):
self.wld_inst = []
for row in range(self.rows):
self.wld_inst.append(self.add_inst(name="wld{0}".format(row),
mod=self.wl_driver))
if row % self.tap_spacing == 0:
self.wld_inst.append(self.add_inst(name="wld{0}".format(row),
mod=self.wl_driver_tap))
else:
self.wld_inst.append(self.add_inst(name="wld{0}".format(row),
mod=self.wl_driver))
self.connect_inst(["in_{0}".format(row),
"out_{0}".format(row),
"vdd", "gnd"])
def place_drivers(self):
y_offset = 0
for row in range(self.rows):
# These are flipped since we always start with an RBL on the bottom
y_offset = self.wl_driver.height * row
offset = [0, y_offset]
self.wld_inst[row].place(offset=offset)
y_offset += self.wld_inst[row].height
self.width = self.wl_driver.width
self.height = self.wl_driver.height * self.rows

View File

@ -24,7 +24,7 @@ class rom_bank_test(openram_test):
debug.info(2, "Testing 4x4 array for rom cell")
a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data", word_size=1)
a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_1kB", word_size=1)
self.local_check(a)
openram.end_openram()

View File

@ -25,7 +25,7 @@ class rom_decoder_test(openram_test):
debug.info(2, "Testing control logic for rom cell")
a = factory.create(module_type="rom_control_logic", num_outputs=4)
a = factory.create(module_type="rom_control_logic", num_outputs=4, clk_fanout=4, height=40)
self.local_check(a)
openram.end_openram()