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 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. 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)) debug.info(1, "creating pinvbuf {}".format(name))
self.add_comment("size: {}".format(size)) self.add_comment("size: {}".format(size))
self.stage_effort = 4 self.stage_effort = 4
self.row_height = height self.row_height = height
self.route_in_cell = route_in_cell
# FIXME: Change the number of stages to support high drives. # FIXME: Change the number of stages to support high drives.
# stage effort of 4 or less # stage effort of 4 or less
@ -132,15 +133,35 @@ class pinvbuf(pgate):
to_layer=a3_pin.layer, to_layer=a3_pin.layer,
offset=a3_pin.center()) offset=a3_pin.center())
# inv1 Z to inv4 A (up and over)
z1_pin = self.inv1_inst.get_pin("Z") z1_pin = self.inv1_inst.get_pin("Z")
a4_pin = self.inv4_inst.get_pin("A") a4_pin = self.inv4_inst.get_pin("A")
mid_point = vector(z1_pin.cx(), a4_pin.cy()) if self.route_in_cell:
self.add_wire(route_stack, # inv1 Z to inv4 A (under and up)
[z1_pin.center(), mid_point, a4_pin.center()]) mid_point = vector(a4_pin.cx(), z1_pin.cy())
self.add_via_stack_center(from_layer=z1_pin.layer, end_point = a4_pin.center()
to_layer=route_stack[2], # end_point = vector(a4_pin.cx(), a4_pin.by() - self.m1_space - self.contact_space)
offset=z1_pin.center()) 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): 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.base import vector
from openram import OPTS from openram import OPTS
from openram.sram_factory import factory from openram.sram_factory import factory
from openram.tech import drc from openram.tech import drc, layer
class rom_base_array(bitcell_base_array): 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.data = bitmap
self.tap_direction = tap_direction
self.pitch_match = pitch_match self.pitch_match = pitch_match
self.route_layer = route_layer self.bitline_layer = bitline_layer
self.output_layer = output_layer
self.strap_spacing = strap_spacing self.strap_spacing = strap_spacing
self.wordline_layer = wordline_layer
self.data_col_size = self.column_size self.data_col_size = self.column_size
self.tap_spacing = tap_spacing
if strap_spacing != 0: if strap_spacing != 0:
self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing) self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing)
else: else:
@ -47,20 +52,23 @@ class rom_base_array(bitcell_base_array):
def create_layout(self): def create_layout(self):
self.create_layout_constants() self.create_layout_constants()
self.place_array() self.place_array()
if self.pitch_match: if self.tap_direction == "row":
self.route_pitch_offsets() self.route_pitch_offsets()
self.place_precharge() self.place_precharge()
self.place_wordline_contacts() self.place_wordline_contacts()
self.place_bitline_contacts() self.place_bitline_contacts()
self.route_precharge()
self.add_boundary() self.add_boundary()
self.route_precharge()
self.place_rails() self.place_rails()
self.add_label("ARRAY ZERO", self.route_layer) self.connect_taps()
self.add_label("array height", self.route_layer, [0, self.height])
@ -79,22 +87,32 @@ class rom_base_array(bitcell_base_array):
def add_modules(self): 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.zero_cell = factory.create(module_name="rom_base_zero_cell",
self.one_cell = factory.create(module_name="rom_base_one_cell", module_type="rom_base_cell", bitline_layer=self.route_layer, bit_value=1) 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) if self.tap_direction == "row":
self.poly_tap = factory.create(module_type="rom_poly_tap")
self.zero_tap = factory.create(module_type="rom_poly_tap", strap_length=0) else:
self.poly_tap = factory.create(module_type="rom_poly_tap", add_tap=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, strap_spacing=self.strap_spacing, route_layer=self.route_layer) 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): 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): def add_pins(self):
@ -108,8 +126,10 @@ 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.cell_inst = {} self.cell_inst = {}
self.cell_list = [] self.cell_list = []
self.current_row = 0 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 #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() 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 # for each new strap placed, offset the column index refrenced to get correct bit in the data array
# cols are bit lines # 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): for col in range(self.column_size):
if col % self.strap_spacing == 0: if col % self.strap_spacing == 0:
self.create_tap(row, col) self.create_poly_tap(row, col)
new_inst = self.create_cell(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) 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.connect_inst([])
self.cell_list.append(row_list) self.cell_list.append(row_list)
@ -147,7 +164,9 @@ class rom_base_array(bitcell_base_array):
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)
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([]) self.connect_inst([])
@ -205,33 +224,32 @@ class rom_base_array(bitcell_base_array):
def place_rails(self): 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]) for i in range(self.column_size):
self.copy_layout_pin(self, "D", "gnd") 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): def place_array(self):
self.cell_pos = {} self.cell_pos = {}
self.strap_pos = {} self.strap_pos = {}
# rows are wordlines # rows are wordlines
col_offset = 0
pitch_offset = 0 pitch_offset = 0
for row in range(self.row_size): for row in range(self.row_size):
# if row % self.strap_spacing == 0 and row != 0 and self.pitch_match: if row % self.tap_spacing == 0 and self.pitch_match:
# pitch_offset += self.poly_tap.width pitch_offset += self.active_contact.width + self.active_space
cell_y = row * (self.zero_cell.height) + pitch_offset 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: if col % self.strap_spacing == 0:
self.strap_pos[row, col] = vector(cell_x, cell_y) self.strap_pos[row, col] = vector(cell_x, cell_y)
self.tap_inst[row, col].place(self.strap_pos[row, col]) 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_pos[row, col] = vector(cell_x, cell_y)
self.cell_inst[row, col].place(self.cell_pos[row, col]) 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.add_label("debug", "li", self.cell_pos[row, col])
self.strap_pos[row, 0] = vector(0, cell_y) self.strap_pos[row, self.column_size] = vector(cell_x, cell_y)
self.tap_inst[row, 0].place(self.strap_pos[row, 0]) 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): def route_pitch_offsets(self):
for row in range(0 , self.row_size, self.strap_spacing): for row in range(0 , self.row_size, self.tap_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 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()) start = vector(drain.cx(), source.cy())
end = drain.center() 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): def place_precharge(self):
@ -285,14 +339,14 @@ class rom_base_array(bitcell_base_array):
for wl in range(self.row_size): 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.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) # 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): 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): 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 middle_offset = (src_pin.cy() - pre_pin.cy() ) * 0.5
corrected = vector(src_pin.cx(), src_pin.cy() - middle_offset) 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) 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_start = bl_pin.center()
bl_end = vector(bl_start.x, pre_out_pin.cy()) 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): def get_next_cell_in_bl(self, row_start, col):
for row in range(row_start + 1, self.row_size): 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.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]]
self.strap_spacing = strap_spacing self.strap_spacing = strap_spacing
if "li" in layer: self.tap_spacing = 8
self.route_layer = "li"
else:
self.route_layer = "m1"
self.bus_layer = "m2"
self.interconnect_layer = "m1" self.interconnect_layer = "m1"
self.bitline_layer = "m1"
self.wordline_layer = "m2"
super().__init__(name=name) 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.setup_layout_constants()
self.create_netlist() self.create_netlist()
self.create_layout() self.create_layout()
@ -81,37 +84,46 @@ class rom_base_bank(design):
def create_netlist(self): def create_netlist(self):
self.add_modules() self.add_modules()
# self.add_pins() # self.add_pins()
print("Creating ROM bank instances")
self.create_instances() self.create_instances()
def create_layout(self): def create_layout(self):
print("Placing ROM bank instances")
self.place_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.route_supplies()
self.height = self.array_inst.height self.height = self.array_inst.height
self.width = self.array_inst.width self.width = self.array_inst.width
self.add_boundary() self.add_boundary()
print("Rom bank placement complete")
def setup_layout_constants(self): def setup_layout_constants(self):
self.route_layer_width = drc["minwidth_{}".format(self.route_layer)] self.route_layer_width = drc["minwidth_{}".format(self.route_stack[0])]
self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_layer)] self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_stack[0])]
self.bus_layer_width = drc["minwidth_{}".format(self.bus_layer)]
self.bus_layer_pitch = drc["{0}_to_{0}".format(self.bus_layer)]
self.interconnect_layer_width = drc["minwidth_{}".format(self.interconnect_layer)] self.interconnect_layer_width = drc["minwidth_{}".format(self.interconnect_layer)]
self.interconnect_layer_pitch = drc["{0}_to_{0}".format(self.interconnect_layer)] self.interconnect_layer_pitch = drc["{0}_to_{0}".format(self.interconnect_layer)]
def add_pins(self): def add_pins(self):
self.add_pin("READ", "INPUT") self.add_pin("clk", "INPUT")
self.add_pin("CS", "INPUT") self.add_pin("CS", "INPUT")
for i in range(self.num_inputs): for i in range(self.num_inputs):
self.add_pin("addr_{}".format(i), "INPUT") self.add_pin("addr_{}".format(i), "INPUT")
out_pins = [] out_pins = []
for j in range(self.rows): for j in range(self.rows):
out_pins.append("rom_out_{}".format(j)) out_pins.append("rom_out_{}".format(j))
@ -122,17 +134,54 @@ class rom_base_bank(design):
def add_modules(self): 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)
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) 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.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): def create_instances(self):
gnd = ["gnd"] gnd = ["gnd"]
vdd = ["vdd"] vdd = ["vdd"]
prechrg = ["precharge"] prechrg = ["precharge"]
clk = ["clk_int"]
array_pins = [] array_pins = []
decode_pins = [] decode_pins = []
@ -156,6 +205,7 @@ class rom_base_bank(design):
decode_pins.append(name) decode_pins.append(name)
decode_pins.append("precharge") decode_pins.append("precharge")
decode_pins.append("clk_int")
decode_pins.append("vdd") decode_pins.append("vdd")
decode_pins.append("gnd") 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)] addr_lsb = ["col_addr_{}".format(addr) for addr in range(self.col_bits)]
col_mux_pins = bitlines + select_lines + bitline_out + gnd 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.array_inst = self.add_inst(name="rom_bit_array", mod=self.array)
self.connect_inst(array_pins) self.connect_inst(array_pins)
@ -174,7 +224,7 @@ class rom_base_bank(design):
self.connect_inst(decode_pins) self.connect_inst(decode_pins)
self.control_inst = self.add_inst(name="rom_control", mod=self.control_logic) 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.mux_inst = self.add_inst(name="rom_column_mux", mod=self.column_mux)
self.connect_inst(col_mux_pins) self.connect_inst(col_mux_pins)
@ -187,13 +237,13 @@ class rom_base_bank(design):
def place_instances(self): def place_instances(self):
self.place_row_decoder() self.place_row_decoder()
self.place_data_array() self.place_data_array()
self.place_control_logic()
self.place_col_decoder()
self.place_col_mux() self.place_col_mux()
self.place_col_decoder()
self.place_control_logic()
def place_row_decoder(self): 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) self.decode_inst.place(offset=self.decode_offset)
def place_data_array(self): 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))) self.array_inst.place(offset=(self.array_offset + vector(0, array_align)))
def place_control_logic(self): 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): 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) self.col_decode_inst.place(offset=self.col_decode_offset)
def place_col_mux(self): 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) 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): # for wl in range(self.rows):
bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) # self.wl_interconnects.append("wl_interconnect_{}".format(wl))
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_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_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() )
def route_decode_outputs(self): 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)] 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)] decode_pins = [self.decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.rows)]
route_pins.extend(decode_pins) route_pins.extend(decode_pins)
self.connect_row_pins(self.interconnect_layer, route_pins, round=True) 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] # then for the column decoder
# array_wl_pin = self.array_inst.get_pin(array_wl) 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): 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_segment_center(self.interconnect_layer, start, end)
self.add_via_stack_center(start, self.route_layer, self.interconnect_layer ) 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) def route_precharge(self):
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):
prechrg_control = self.control_inst.get_pin("prechrg") 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") 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) self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end)
start = end + vector(0.5 * self.interconnect_layer_width, 0) 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): 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) gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0)
decode_gnd = self.decode_inst.get_pin("gnd") decode_gnd = self.decode_inst.get_pin("gnd")

View File

@ -15,10 +15,11 @@ from openram.tech import drc
class rom_base_cell(design): 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) super().__init__(name)
self.bit_value = bit_value self.bit_value = bit_value
self.bitline_layer = bitline_layer self.bitline_layer = bitline_layer
self.add_well=add_well
self.create_netlist() self.create_netlist()
self.create_layout() self.create_layout()
@ -42,6 +43,7 @@ class rom_base_cell(design):
# Calculates offsets of cell width and height so that tiling of cells does not violate any drc rules # Calculates offsets of cell width and height so that tiling of cells does not violate any drc rules
def setup_drc_offsets(self): def setup_drc_offsets(self):
@ -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()) 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 Column-mux transistors driven by the decoder must be sized
for optimal speed 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)) debug.info(2, "creating single ROM column mux cell: {0}".format(name))
self.tx_size = int(tx_size) self.tx_size = int(tx_size)
self.bitline_layer = bitline_layer self.input_layer = input_layer
self.output_layer= output_layer
super().__init__(name) super().__init__(name)
@ -42,16 +42,19 @@ class rom_column_mux(pgate):
def create_layout(self): 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.pin_layer = self.input_layer
self.col_mux_stack = self.li_stack
else:
self.col_mux_stack = self.m1_stack
self.pin_layer = self.bitcell.bitline_layer
self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer)) self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer))
self.pin_width = getattr(self, "{}_width".format(self.pin_layer)) self.pin_width = getattr(self, "{}_width".format(self.pin_layer))
self.pin_height = 2 * self.pin_width 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() self.place_ptx()
# cell = factory.create(module_type=OPTS.bitcell) # cell = factory.create(module_type=OPTS.bitcell)
@ -69,7 +72,7 @@ class rom_column_mux(pgate):
# self.add_pn_wells() # self.add_pn_wells()
def add_ptx(self): 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 # Adds nmos_lower,nmos_upper to the module
self.ptx_width = self.tx_size * drc("minwidth_tx") self.ptx_width = self.tx_size * drc("minwidth_tx")
@ -98,7 +101,7 @@ class rom_column_mux(pgate):
# bl_out and br_out # bl_out and br_out
self.add_layout_pin(text="bl_out", self.add_layout_pin(text="bl_out",
layer=self.col_mux_stack[2], layer=self.col_mux_stack[0],
offset=bl_pos, offset=bl_pos,
height=self.pin_height) height=self.pin_height)
@ -147,18 +150,8 @@ class rom_column_mux(pgate):
nmos_lower_d_pin = self.nmos_lower.get_pin("D") 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, 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()) offset=nmos_lower_d_pin.center())
# bl -> nmos_upper/D on metal1 # bl -> nmos_upper/D on metal1
@ -167,29 +160,17 @@ class rom_column_mux(pgate):
+ nmos_lower_s_pin.uc().scale(0, 0.5) + nmos_lower_s_pin.uc().scale(0, 0.5)
mid2 = bl_pin.bc().scale(0, 0.4) \ mid2 = bl_pin.bc().scale(0, 0.4) \
+ nmos_lower_s_pin.uc().scale(1, 0.5) + 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()]) [bl_pin.bc(), mid1, mid2, nmos_lower_s_pin.center()])
# halfway up, move over # halfway up, move over
mid1 = bl_out_pin.uc().scale(1, 0.4) \ mid1 = bl_out_pin.uc().scale(1, 0.4) \
+ nmos_lower_d_pin.bc().scale(0, 0.4) + nmos_lower_d_pin.bc().scale(0, 0.4)
mid2 = bl_out_pin.uc().scale(0, 0.4) \ mid2 = bl_out_pin.uc().scale(0, 0.4) \
+ nmos_lower_d_pin.bc().scale(1, 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()]) [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): def extend_implants(self):
""" """

View File

@ -9,7 +9,7 @@ from openram import debug
from openram.base import design from openram.base import design
from openram.base import vector from openram.base import vector
from openram.sram_factory import factory 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.tech import layer_properties as layer_props
from openram import OPTS 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 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) 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))
self.columns = columns self.columns = columns
self.word_size = word_size self.word_size = word_size
self.offsets = offsets
self.words_per_row = int(self.columns / self.word_size) 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.sel_pitch = getattr(self, self.sel_layer + "_pitch")
self.bitline_layer = bitline_layer self.bitline_layer = bitline_layer
@ -89,7 +89,9 @@ class rom_column_mux_array(design):
self.width = self.columns * self.mux.width 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 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 # 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): def create_array(self):
self.mux_inst = [] self.mux_inst = []
@ -106,8 +108,7 @@ class rom_column_mux_array(design):
def place_array(self): def place_array(self):
# Default to single spaced columns # 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 every column, add a pass gate
for col_num, xoffset in enumerate(self.offsets[0:self.columns]): 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): def add_horizontal_input_rail(self):
""" Create address input rails below the mux transistors """ """ Create address input rails below the mux transistors """
for j in range(self.words_per_row): 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), self.add_layout_pin(text="sel_{}".format(j),
layer=self.sel_layer, layer=self.sel_layer,
offset=offset, offset=offset,
@ -154,6 +155,7 @@ class rom_column_mux_array(design):
def add_vertical_poly_rail(self): def add_vertical_poly_rail(self):
""" Connect the poly to the address rails """ """ Connect the poly to the address rails """
# Offset to the first transistor gate in the pass gate # Offset to the first transistor gate in the pass gate
for col in range(self.columns): for col in range(self.columns):
# which select bit should this column connect to depends on the position in the word # 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, offset = vector(gate_offset.x,
self.get_pin("sel_{}".format(sel_index)).cy()) 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", self.add_via_stack_center(from_layer="poly",
to_layer=self.sel_layer, to_layer=self.sel_layer,
offset=bl_offset, 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_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 # Add the horizontal wires for the first bit
if j % self.words_per_row == 0: 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_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]) 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.sram_factory import factory
from openram.base import vector, design from openram.base import vector, design
from openram.tech import layer, drc
class rom_control_logic(design): 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.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: if "li" in layer:
self.route_layer = "li" self.route_stack = self.li_stack
else: 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_netlist()
self.create_layout() self.create_layout()
self.add_boundary() self.add_boundary()
@ -39,29 +47,40 @@ class rom_control_logic(design):
def create_layout(self): def create_layout(self):
self.create_instances() self.create_instances()
self.height=self.nand_inst.height self.height=self.driver_inst.height + self.buf_inst.height
self.width=self.nand_inst.width + self.inv_inst.width + self.driver_inst.width self.width= max(self.nand_inst.width + self.buf_inst.width, self.driver_inst.width)
self.place_instances() self.place_instances()
self.route_insts() self.route_insts()
def add_modules(self): def add_modules(self):
self.inv_mod = factory.create(module_type="pinv", module_name="rom_control_logic_pinv", height=self.mod_height) self.buf_mod = factory.create(module_type="pinvbuf",
self.nand_mod = factory.create(module_type="pnand2", module_name="rom_control_nand", height=self.mod_height) module_name="rom_control_logic_pinv",
self.driver_mod = factory.create(module_type="pdriver", inverting=True, fanout=self.output_size, height=self.mod_height, add_wells=True) 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): def add_pins(self):
self.add_pin("clk", "INPUT") self.add_pin("clk_in", "INPUT")
self.add_pin("CS", "INPUT") self.add_pin("CS", "INPUT")
self.add_pin("prechrg", "OUTPUT") self.add_pin("prechrg", "OUTPUT")
self.add_pin("clk_out", "OUTPUT")
self.add_pin("vdd", "POWER") self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def create_instances(self): def create_instances(self):
self.inv_inst = self.add_inst(name="read_signal_inv", mod=self.inv_mod) self.buf_inst = self.add_inst(name="clk_invbuf", mod=self.buf_mod)
self.connect_inst(["clk", "clk_bar", "vdd", "gnd"]) 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.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod)
self.connect_inst(["CS", "clk_bar", "pre_drive", "vdd", "gnd"]) self.connect_inst(["CS", "clk_bar", "pre_drive", "vdd", "gnd"])
@ -71,16 +90,55 @@ class rom_control_logic(design):
def place_instances(self): def place_instances(self):
self.nand_inst.place(offset=[self.inv_inst.width, 0]) buf_correction = drc["minwidth_{}".format(self.route_stack[0])] * 0.5
self.driver_inst.place(offset=[self.nand_inst.width + self.inv_inst.width, 0]) # 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): def route_insts(self):
self.copy_layout_pin(self.inv_inst, "A", "READ") route_width = drc["minwidth_{}".format(self.route_stack[2])]
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.driver_inst, "Z", "prechrg")
self.copy_layout_pin(self.nand_inst, "B", "CS") 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): 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 # 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 # 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.output_layer = output_layer
self.inv_route_layer = "m2" self.inv_route_layer = "m2"
self.cols=cols self.cols=cols
self.invert_outputs=invert_outputs
self.create_netlist() 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() self.create_layout()
def create_netlist(self): def create_netlist(self):
@ -49,10 +53,9 @@ class rom_decoder(design):
self.place_input_buffer() self.place_input_buffer()
self.place_driver() self.place_driver()
self.route_outputs() 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.connect_inputs()
# self.route_supplies() self.route_supplies()
self.add_boundary() self.add_boundary()
def setup_layout_constants(self): def setup_layout_constants(self):
@ -97,18 +100,24 @@ class rom_decoder(design):
for j in range(self.num_outputs): for j in range(self.num_outputs):
self.add_pin("wl_{0}".format(j), "OUTPUT") 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("vdd", "POWER")
self.add_pin("gnd", "GROUND") self.add_pin("gnd", "GROUND")
def add_modules(self): 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), \ self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), \
rows=self.num_outputs, \ rows=self.num_outputs, \
cols=self.cols) cols=self.cols,
invert_outputs=self.invert_outputs,
tap_spacing=self.strap_spacing)
self.array_mod = factory.create(module_type="rom_base_array", \ self.array_mod = factory.create(module_type="rom_base_array", \
module_name="{}_array".format(self.name), \ module_name="{}_array".format(self.name), \
@ -116,8 +125,8 @@ class rom_decoder(design):
rows=2 * self.num_inputs, \ rows=2 * self.num_inputs, \
bitmap=self.decode_map, bitmap=self.decode_map,
strap_spacing = self.strap_spacing, strap_spacing = self.strap_spacing,
route_layer=self.route_layer, bitline_layer=self.output_layer,
output_layer=self.output_layer) tap_direction="col")
def create_instances(self): def create_instances(self):
@ -135,8 +144,8 @@ class rom_decoder(design):
for i in range(self.num_inputs): for i in range(self.num_inputs):
control_pins.append("A{0}".format(i)) control_pins.append("A{0}".format(i))
control_pins.append("A{0}_int".format(i)) control_pins.append("in_{0}".format(i))
control_pins.append("Abar{0}_int".format(i)) control_pins.append("inbar_{0}".format(i))
control_pins.append("clk") control_pins.append("clk")
control_pins.append("vdd") control_pins.append("vdd")
control_pins.append("gnd") control_pins.append("gnd")
@ -156,7 +165,7 @@ class rom_decoder(design):
for i in reversed(range(self.num_inputs)): for i in reversed(range(self.num_inputs)):
array_pins.append("inbar_{0}".format(i)) array_pins.append("inbar_{0}".format(i))
array_pins.append("in_{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("vdd")
array_pins.append("gnd") array_pins.append("gnd")
self.connect_inst(array_pins) self.connect_inst(array_pins)
@ -173,10 +182,11 @@ class rom_decoder(design):
def place_input_buffer(self): def place_input_buffer(self):
wl = self.array_mod.row_size - 1 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() 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.buf_inst.place(vector(align, 0))
self.copy_layout_pin(self.buf_inst, "clk")
def place_array(self): def place_array(self):
@ -196,6 +206,9 @@ class rom_decoder(design):
for j in range(self.num_outputs): for j in range(self.num_outputs):
self.copy_layout_pin(self.wordline_buf_inst, "out_{}".format(j), "wl_{}".format(j)) 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)] 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)] 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): def route_supplies(self):
minwidth = drc["minwidth_{}".format(self.inv_route_layer)] minwidth = drc["minwidth_{}".format(self.inv_route_layer)]
pitch = drc["{0}_to_{0}".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 # route decode array vdd and inv array vdd together
array_vdd = self.array_inst.get_pin("vdd") # array_vdd = self.array_inst.get_pin("vdd")
inv_vdd = self.buf_inst.get_pins("vdd")[-1] # inv_vdd = self.buf_inst.get_pins("vdd")[-1]
end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth) # end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth)
self.add_segment_center("m1", array_vdd.center(), end) # self.add_segment_center("m1", array_vdd.center(), end)
end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy()) # end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy())
self.add_segment_center(self.route_layer, inv_vdd.center(), end) # self.add_segment_center(self.route_layer, inv_vdd.center(), end)
end = vector(array_vdd.cx(), inv_vdd.cy()) # end = vector(array_vdd.cx(), inv_vdd.cy())
self.add_via_stack_center(end, self.route_layer, "m1") # self.add_via_stack_center(end, self.route_layer, "m1")
self.add_layout_pin_rect_center("vdd", "m1", end) # 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] # inv_gnd = self.buf_inst.get_pins("gnd")[0]
array_gnd = self.array_inst.get_pins("gnd") # array_gnd = self.array_inst.get_pins("gnd")
# add x jog # # add x jog
start = vector(array_gnd[0].cx(), inv_gnd.cy()) # start = vector(array_gnd[0].cx(), inv_gnd.cy())
self.add_via_stack_center(start, self.route_layer, "m1") # self.add_via_stack_center(start, self.route_layer, "m1")
self.add_layout_pin_rect_center("gnd", "m1", start) # self.add_layout_pin_rect_center("gnd", "m1", start)
end = array_gnd[0].center() # end = array_gnd[0].center()
self.add_segment_center("m1", start, end) # self.add_segment_center("m1", start, end)
# add y jog # # add y jog
width = minwidth # width = minwidth
height = array_gnd[0].uy() - array_gnd[-1].uy() + 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) # start = end - vector(0, 0.5 * minwidth)
end = vector(start.x, array_gnd[1].uy()) # end = vector(start.x, array_gnd[1].uy())

View File

@ -14,34 +14,41 @@ from openram.tech import drc
class rom_poly_tap(design): class rom_poly_tap(design):
def __init__(self, name="", strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m2"): def __init__(self, name="", cell_name=None, tx_type="nmos", strap_layer="m2", add_tap=False):
super().__init__(name, cell_name, prop) super().__init__(name, cell_name)
self.strap_layer=strap_layer self.strap_layer=strap_layer
self.length = strap_length
self.tx_type = tx_type self.tx_type = tx_type
self.add_tap = add_tap
self.pitch_offset = 0
self.create_netlist() self.create_netlist()
self.create_layout() self.create_layout()
def create_netlist(self): def create_netlist(self):
#for layout constants #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") self.pmos = factory.create(module_type="ptx", tx_type="pmos")
def create_layout(self): def create_layout(self):
self.place_via() self.place_via()
# if self.tx_type == "pmos":
self.extend_poly() if self.add_tap:
self.place_ptap() self.place_active_tap()
self.extend_poly()
self.add_boundary() self.add_boundary()
# if self.length != 0: # if self.length != 0:
# self.place_strap() # self.place_strap()
def add_boundary(self): 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.height = self.dummy.height
self.width = contact_width + self.pitch_offset self.width = contact_width + self.pitch_offset
@ -59,59 +66,66 @@ class rom_poly_tap(design):
else: else:
assert(False) 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": 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) # contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5)
# self.contact_x_offset = 0 self.contact_x_offset = 0
else: # else:
contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x # 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.contact_offset = vector(contact_x, contact_y)
self.via = self.add_via_stack_center(from_layer="poly", self.via = self.add_via_stack_center(from_layer="poly",
to_layer=self.strap_layer, to_layer=self.strap_layer,
offset=self.contact_offset) 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): def extend_poly(self):
base_contact_width = self.poly_contact.width + 2 * self.contact_x_offset 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()))
self.pitch_offset = (base_contact_width - self.active_enclose_contact - self.active_extend_contact) - self.active_space
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) 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)
poly_x = 0
extend_offset = vector(poly_x, poly_y)
self.add_rect("poly", extend_offset, self.contact_x_offset , self.poly_width) # edge of the next nmos
active_edge = self.dummy.width - self.dummy.cell_inst.height - self.poly_extend_active
def place_ptap(self): # edge of the active contact
tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 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 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.cols = cols
self.route_layer = route_layer 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=="": if name=="":
name = "rom_inv_array_{0}".format(cols) 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: if strap_spacing != None:
self.strap_spacing = strap_spacing self.strap_spacing = strap_spacing
else: else:
self.strap_spacing = 0 self.strap_spacing = 0
if "li" in layer:
self.inv_layer = "li"
else:
self.inv_layer = "m1"
if strap_spacing != 0: if strap_spacing != 0:
self.num_straps = ceil(self.cols / self.strap_spacing) self.num_straps = ceil(self.cols / self.strap_spacing)
@ -62,28 +62,30 @@ class rom_precharge_array(design):
self.height = self.pmos.width self.height = self.pmos.width
self.place_instances() self.place_instances()
self.create_layout_pins() self.create_layout_pins()
self.add_well_tap()
self.route_supply() self.route_supply()
self.connect_taps()
self.add_boundary() self.add_boundary()
self.extend_well()
def add_boundary(self): def add_boundary(self):
# self.translate_all(self.well_ll) # self.translate_all(self.well_ll)
ur = self.find_highest_coords() 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) # ur = vector(ur.x, ur.y - self.well_ll.y)
super().add_boundary(vector(0, 0), ur) super().add_boundary(vector(0, 0), ur)
self.width = self.cols * self.pmos.width
self.height = ur.y self.height = ur.y
self.width = ur.x
def create_modules(self): 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 # 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", 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): def add_pins(self):
for col in range(self.cols): for col in range(self.cols):
@ -96,33 +98,34 @@ class rom_precharge_array(design):
self.pmos_insts = [] self.pmos_insts = []
self.tap_insts = [] self.tap_insts = []
self.tap_insts.append(self.add_inst(name="tap_0", mod=self.poly_tap)) self.create_poly_tap(-1)
self.connect_inst([])
for col in range(self.cols): for col in range(self.cols):
if col % self.strap_spacing == 0:
# if col % self.strap_spacing == 0: self.create_poly_tap(col)
# name = "tap_c{}".format(col) self.create_precharge_tx(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): def place_instances(self):
self.add_label("ZERO", self.route_layer) self.add_label("ZERO", self.route_layer)
self.array_pos = [] self.array_pos = []
strap_num = 0 strap_num = 1
cell_y = 0 cell_y = 0
# columns are bit lines4 # columns are bit lines4
cell_x = 0 cell_x = 0
@ -131,11 +134,18 @@ class rom_precharge_array(design):
for col in range(self.cols): 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 : # if col % self.strap_spacing == 0 :
# self.tap_insts[strap_num].place(vector(cell_x, cell_y)) # self.tap_insts[strap_num].place(vector(cell_x, cell_y))
# self.add_label("debug", "li", vector(cell_x, cell_y)) # self.add_label("debug", "li", vector(cell_x, cell_y))
# cell_x += self.poly_tap.width # cell_x += self.poly_tap.width
# strap_num += 1
self.pmos_insts[col].place(vector(cell_x, cell_y)) self.pmos_insts[col].place(vector(cell_x, cell_y))
self.add_label("debug", "li", 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): 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): for col in range(self.cols):
source_pin = self.pmos_insts[col].get_pin("D") source_pin = self.pmos_insts[col].get_pin("D")
bl = "pre_bl{0}_out".format(col) bl = "pre_bl{0}_out".format(col)
self.add_layout_pin_rect_center(bl, self.route_layer, source_pin.center()) 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): def route_supply(self):
# self.vdd = self.add_layout_pin_segment_center("vdd", self.supply_layer, start, end)
start_pin = self.pmos_insts[0].get_pin("S").lx() # vdd = [self.pmos_insts[i].get_pin("vdd") for i in range(self.cols)]routeroute_horizon_horizon
end_pin = self.pmos_insts[-1].get_pin("S").rx() self.route_horizontal_pins("vdd", insts=self.pmos_insts)
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")
# 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) def connect_taps(self):
end = self.nwell_contact.center() array_pins = [self.tap_insts[i].get_pin("poly_tap") for i in range(len(self.tap_insts))]
self.add_segment_center(self.route_layer, start, end)
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): 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) 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): def create_layout(self):
super().create_layout() super().create_layout()
self.place_tap()
self.extend_well() self.extend_well()
@ -37,19 +33,21 @@ class rom_precharge_cell(rom_base_cell):
self.pmos = factory.create(module_type="ptx", self.pmos = factory.create(module_type="ptx",
module_name="pre_pmos_mod", 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): def create_tx(self):
self.cell_inst = self.add_inst( name="precharge_pmos", self.cell_inst = self.add_inst( name="precharge_pmos",
mod=self.pmos, mod=self.pmos,
) )
self.connect_inst(["bitline", "gate", "vdd", "body"]) self.connect_inst(["bitline", "gate", "vdd", "vdd"])
def add_pins(self): def add_pins(self):
pin_list = ["vdd", "gate", "bitline", "body"] pin_list = ["vdd", "gate", "bitline"]
dir_list = ["POWER", "INPUT", "OUTPUT", "POWER"] dir_list = ["POWER", "INPUT", "OUTPUT"]
self.add_pin_list(pin_list, dir_list) 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) 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 #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 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): 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) well_ll = vector(0, well_y)
# height = self.active_width + 2 * self.well_enclose_active # 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) 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)
# 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): def place_tap(self):
# poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.rx() + self.poly_extend_active) source = self.cell_inst.get_pin("S")
# poly_offset = vector(self.cell_inst.rx() + self.poly_extend_active, self.cell_inst.width * 0.5 )
# start = poly_offset tap_y = source.cy() - self.contact_width - 2 * self.active_enclose_contact - self.active_space
# 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 pos = vector(source.cx(), tap_y )
# 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.add_via_center(layers=self.active_stack,
# # self.height = self.base_width - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) 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)
# 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 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) design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name)) debug.info(1, "Creating {0}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.rows = rows self.rows = rows
self.cols = cols self.cols = cols
self.invert_outputs=invert_outputs
self.tap_spacing = tap_spacing
self.create_netlist() self.create_netlist()
if not OPTS.netlist_only: if not OPTS.netlist_only:
self.create_layout() self.create_layout()
@ -60,10 +61,25 @@ 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.wl_driver = factory.create(module_type="pbuf_dec", if self.invert_outputs:
size=self.cols, self.wl_driver = factory.create(module_type="pinv_dec",
height=b.height, size=self.cols,
add_wells=False) 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): def route_supplies(self):
""" """
@ -80,21 +96,25 @@ class rom_wordline_driver_array(design):
def create_drivers(self): def create_drivers(self):
self.wld_inst = [] self.wld_inst = []
for row in range(self.rows): for row in range(self.rows):
self.wld_inst.append(self.add_inst(name="wld{0}".format(row), if row % self.tap_spacing == 0:
mod=self.wl_driver)) 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), self.connect_inst(["in_{0}".format(row),
"out_{0}".format(row), "out_{0}".format(row),
"vdd", "gnd"]) "vdd", "gnd"])
def place_drivers(self): def place_drivers(self):
y_offset = 0
for row in range(self.rows): for row in range(self.rows):
# These are flipped since we always start with an RBL on the bottom # These are flipped since we always start with an RBL on the bottom
y_offset = self.wl_driver.height * row
offset = [0, y_offset] offset = [0, y_offset]
self.wld_inst[row].place(offset=offset) self.wld_inst[row].place(offset=offset)
y_offset += self.wld_inst[row].height
self.width = self.wl_driver.width self.width = self.wl_driver.width
self.height = self.wl_driver.height * self.rows 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") 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) self.local_check(a)
openram.end_openram() openram.end_openram()

View File

@ -25,7 +25,7 @@ class rom_decoder_test(openram_test):
debug.info(2, "Testing control logic for rom cell") 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) self.local_check(a)
openram.end_openram() openram.end_openram()