mirror of https://github.com/VLSIDA/OpenRAM.git
taps in main array and decoder
This commit is contained in:
parent
f7aed247fd
commit
559300e5cc
|
|
@ -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):
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
@ -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())
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue