pitch match decoder and array

This commit is contained in:
Jacob Walker 2022-12-30 00:35:15 -08:00
parent e697efa5f6
commit ce8197d206
13 changed files with 361 additions and 115 deletions

View File

@ -16,11 +16,12 @@ from openram.tech import drc
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"):
def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0, route_layer="li", output_layer="m2", pitch_match=False):
super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset)
self.data = bitmap
self.pitch_match = pitch_match
self.route_layer = route_layer
self.output_layer = output_layer
self.strap_spacing = strap_spacing
@ -44,14 +45,18 @@ class rom_base_array(bitcell_base_array):
def create_layout(self):
self.create_layout_constants()
self.place_array()
if self.pitch_match:
self.route_pitch_offsets()
self.place_precharge()
self.place_wordline_contacts()
self.place_bitline_contacts()
self.place_precharge()
self.place_rails()
self.route_precharge()
self.add_boundary()
self.add_label("ARRAY ZERO", self.route_layer)
self.add_label("array height", self.route_layer, [0, self.height])
@ -95,6 +100,12 @@ class rom_base_array(bitcell_base_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)
def create_layout_constants(self):
self.route_width = drc("minwidth_" + self.route_layer)
self.route_pitch = drc("{0}_to_{0}".format(self.route_layer))
def add_pins(self):
for bl_name in self.get_bitline_names():
self.add_pin(bl_name, "INOUT")
@ -116,9 +127,13 @@ class rom_base_array(bitcell_base_array):
row_list = []
# for each new strap placed, offset the column index refrenced to get correct bit in the data array
strap_offset = 0
first_in_col = True
# cols are bit lines
strap_row = False
pre_strap_row = False
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:
@ -127,7 +142,6 @@ class rom_base_array(bitcell_base_array):
#print("tap instance added at c{0}, r{1}".format(col, row))
self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap)
self.connect_inst([])
strap_offset += 1
name = "bit_r{0}_c{1}".format(row, col)
@ -137,19 +151,23 @@ class rom_base_array(bitcell_base_array):
# if the last row and 0 below add both contacts
if (row < self.row_size - 1 and row > 0 and self.data[row + 1][col] == 0 and self.data[row - 1][col] == 0) or \
(row == self.row_size - 1 and self.data[row - 1][col] == 0) or \
(row == 0 and self.data[row + 1][col] == 0):
(row == 0 and self.data[row + 1][col] == 0) or \
(row < self.row_size - 1 and self.data[row + 1][col] == 0 and strap_row) or \
(row > 0 and self.data[row - 1][col] == 0 and pre_strap_row):
new_inst = self.add_inst(name=name, mod=self.cell_ac)
# if dummy/0 is below and not above, add a source contact
# if in the first row, add a source contact
elif (row > 0 and self.data[row - 1][col] == 0) or \
(row == 0):
(row == 0) or \
(strap_row):
new_inst=self.add_inst(name=name, mod=self.cell_sc)
elif (row < self.row_size - 1 and self.data[row + 1][col] == 0) or \
(row == self.row_size - 1):
(row == self.row_size - 1) or \
(pre_strap_row):
new_inst=self.add_inst(name=name, mod=self.cell_dc)
else:
@ -187,7 +205,6 @@ class rom_base_array(bitcell_base_array):
row_list.append(new_inst)
name = "tap_r{0}_c{1}".format(row, self.array_col_size)
#print(*row_list)
self.tap_inst[row, self.column_size]=self.add_inst(name=name, mod=self.zero_tap)
@ -222,9 +239,7 @@ class rom_base_array(bitcell_base_array):
def place_rails(self):
width = drc("minwidth_" + self.route_layer)
drc_rule = "{0}_to_{0}".format(self.route_layer)
spacing = drc(drc_rule)
spacing = self.route_pitch
rail_y = self.cell_list[self.row_size - 1][0].offset.y + self.dummy.base_width + spacing
# self.dummy.height * (self.row_size)
@ -237,7 +252,7 @@ class rom_base_array(bitcell_base_array):
rail_start = vector(start_x , rail_y)
rail_end = vector(end_x, rail_y)
self.gnd = self.add_layout_pin_rect_ends( name="gnd",
self.gnd = self.add_layout_pin_rect_ends(name="gnd",
layer="m1",
start=rail_start,
end=rail_end)
@ -249,22 +264,22 @@ class rom_base_array(bitcell_base_array):
self.add_via_stack_center(via_pos, self.route_layer, "m1", ["H", "V"])
prechrg_vdd = self.precharge_inst.get_pin("vdd")
def place_array(self):
self.cell_pos = {}
self.strap_pos = {}
# rows are wordlines
pitch_offset = 0
for row in range(self.row_size):
# strap_cols = -1
if row % self.strap_spacing == 0 and row != 0 and self.pitch_match:
pitch_offset += self.poly_tap.width
cell_y = row * (self.dummy.height)
cell_y = row * (self.dummy.height) + pitch_offset
cell_x = 0
for col in range(self.column_size):
if col % self.strap_spacing == 0:
@ -286,6 +301,19 @@ class rom_base_array(bitcell_base_array):
# 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")
start = vector(drain.cx(), source.cy())
end = drain.center()
self.add_segment_center(self.route_layer, start, end)
def place_precharge(self):
self.precharge_offset = vector(0, - self.precharge_inst.height - self.dummy.nmos.end_to_contact - 2 * drc["nwell_enclose_active"])
@ -293,14 +321,15 @@ class rom_base_array(bitcell_base_array):
self.precharge_inst.place(offset=self.precharge_offset)
self.copy_layout_pin(self.precharge_inst, "vdd")
self.copy_layout_pin(self.precharge_inst, "gate", "precharge")
def place_wordline_contacts(self):
width = drc["minwidth_{}".format(self.route_layer)]
width = self.route_width
height = drc["minwidth_{}".format(self.route_layer)]
height = self.route_width
offset = vector(self.poly_contact.width * 0.5, self.dummy.poly.offset.y)
@ -308,36 +337,31 @@ class rom_base_array(bitcell_base_array):
poly_via = self.tap_inst[wl, 0].get_pin("via")
self.copy_layout_pin(self.tap_inst[wl, 0], "via", 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)
corrected_offset = offset - vector(0.5 * width, 0.5 * height)
# self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.dummy.height, length=None)
def place_bitline_contacts(self):
src_pin = self.cell_nc.source_pos
rail_y = self.precharge_inst.get_pin("vdd").cy()
for bl in range(self.column_size):
# self.copy_layout_pin(self.cell_list[0][bl], "S", self.bitline_names[0][bl])
src_pin = self.cell_list[0][bl].get_pin("S")
prechg_pin_name = "pre_bl{0}_out".format(bl)
pre_pin = self.precharge_inst.get_pin(prechg_pin_name)
# offset = src_pin_offset + vector(src_pin.x, 0)
middle_offset = (pre_pin.cy() - src_pin.cy()) * 0.5
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)
self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, corrected )
output_pos = vector(corrected.x, rail_y)
self.add_segment_center(self.output_layer, corrected, output_pos)
# self.gnd[0].y()
self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, output_pos )
def route_precharge(self):

View File

@ -1,40 +1,82 @@
import math
from math import ceil, log, sqrt
from openram.base import vector
from openram.base import design
from openram import OPTS
from openram.sram_factory import factory
import tech
from openram.tech import drc
class rom_base_bank(design):
def __init__(self, strap_spacing=0, data_file=None, name="") -> None:
self.rows = 4
self.cols = 4
self.num_inputs = 2
self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]]
def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2) -> None:
# self.cols = word_size * 8
self.read_binary(word_size=word_size, data_file=data_file)
self.num_outputs = self.rows
self.num_inputs = ceil(log(self.rows, 2))
# self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]]
self.strap_spacing = strap_spacing
self.route_layer = "li"
self.bus_layer = "m1"
self.interconnect_layer = "m2"
self.bus_layer = "m2"
self.interconnect_layer = "m1"
super().__init__(name=name)
self.setup_layout_constants()
self.create_netlist()
self.create_layout()
"""
Reads a hexadecimal file from a given directory to be used as the data written to the ROM
endian is either "big" or "little"
word_size is the number of bytes per word
sets the row and column size based on the size of binary input, tries to keep array as square as possible,
"""
def read_binary(self, data_file, word_size=2, endian="big"):
hex_file = open(data_file, 'r')
hex_data = hex_file.read()
bin_data = list("{0:08b}".format(int(hex_data, 16)))
bin_data = [int(x) for x in bin_data]
# data size in bytes
data_size = len(bin_data) / 8
num_words = int(data_size / word_size)
bytes_per_col = sqrt(num_words)
self.words_per_row = int(ceil(bytes_per_col /(2*word_size)))
bits_per_row = self.words_per_row * word_size * 8
chunked_data = []
for i in range(0, len(bin_data), bits_per_row):
word = bin_data[i:i + bits_per_row]
if len(word) < bits_per_row:
word = [0] * (bits_per_row - len(word)) + word
chunked_data.append(word)
if endian == "big":
chunked_data.reverse()
self.data = chunked_data
self.cols = bits_per_row
self.rows = int(num_words / (self.words_per_row))
# print("hex: {0}, binary: {1}, chunked: {2}".format(hex_data, bin_data, chunked_data))
def create_netlist(self):
self.add_modules()
# self.add_pins()
self.create_instances()
def create_layout(self):
self.place_instances()
self.create_wl_bus()
# self.channel_route()
self.route_decode_outputs()
self.route_array_inputs()
self.route_control()
self.route_supplies()
self.height = self.array_inst.height
@ -47,12 +89,31 @@ class rom_base_bank(design):
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.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("CS", "INPUT")
for i in range(self.num_inputs):
self.add_pin("addr_{}".format(i), "INPUT")
out_pins = []
for j in range(self.num_outputs):
out_pins.append("rom_out_{}".format(j))
self.add_pin_list(out_pins, "OUTPUT")
self.add_pin("vdd", "POWER")
self.add_pin("gnd", "GROUND")
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)
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_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer)
self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.rows + self.cols) / 2, height=self.decode_array.inv_inst.height)
def create_instances(self):
@ -66,7 +127,7 @@ class rom_base_bank(design):
name = "wl_{}".format(wl)
array_pins.append(wl)
array_pins.append("array_precharge")
array_pins.append("precharge")
array_pins.append("vdd")
array_pins.append("gnd")
@ -78,7 +139,7 @@ class rom_base_bank(design):
name = "wl_{}".format(wl)
decode_pins.append(name)
decode_pins.append("decode_precharge")
decode_pins.append("precharge")
decode_pins.append("vdd")
decode_pins.append("gnd")
@ -89,20 +150,26 @@ class rom_base_bank(design):
self.decode_inst = self.add_inst(name="rom_decoder", mod=self.decode_array)
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"])
def place_instances(self):
array_x = self.decode_inst.width + (self.rows + 2) * ( self.route_layer_width + self.route_layer_pitch )
array_y = self.array.height
array_x = self.decode_inst.width + (2) * ( self.route_layer_width + self.route_layer_pitch )
array_y = self.decode_array.inv_inst.height - self.array.precharge_inst.cy() - self.array.dummy.height * 0.5
self.array_offset = vector(array_x ,array_y)
self.decode_offset = vector(0, 0)
self.array_inst.place(offset=self.array_offset, mirror="MX")
self.control_offset = vector(0,0)
self.array_inst.place(offset=self.array_offset)
self.decode_inst.place(offset=self.decode_offset)
self.control_inst.place(offset=self.control_offset, mirror="MX")
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
@ -119,13 +186,17 @@ class rom_base_bank(design):
decode_output = self.decode_array.output_names[wl]
decode_out_pin = self.decode_inst.get_pin(decode_output)
wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]]
array_wl = self.array.wordline_names[0][wl]
array_wl_pin = self.array_inst.get_pin(array_wl)
# wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]]
start = decode_out_pin.center()
end = vector(wl_bus_wire.cx(), start.y)
end = vector(array_wl_pin.cx(), start.y)
self.add_segment_center(self.interconnect_layer, start, end)
self.add_via_stack_center(end, self.route_layer, self.interconnect_layer )
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):
@ -142,18 +213,52 @@ 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):
prechrg_control = self.control_inst.get_pin("prechrg")
decode_prechrg = self.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())
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())
def route_supplies(self):
gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0)
print()
print(self.decode_inst.get_pin("gnd").center())
decode_gnd = self.decode_inst.get_pin("gnd")
decode_vdd = self.decode_inst.get_pin("vdd")
array_vdd = self.array_inst.get_pin("vdd")
self.add_segment_center("m1", gnd_start, decode_gnd.center())
# self.add_segment_center("m1", gnd_start, decode_gnd.center())
self.add_power_pin("gnd", decode_vdd.center())
self.add_power_pin("vdd", decode_gnd.center())

View File

@ -17,9 +17,7 @@ class rom_base_cell(rom_dummy_cell):
def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"):
super().__init__(name, cell_name, add_source_contact, add_drain_contact, route_layer)
#self.route_layer= route_layer
#self.create_netlist()
#self.create_layout()
def create_netlist(self):
@ -27,7 +25,6 @@ class rom_base_cell(rom_dummy_cell):
self.add_nmos()
self.create_nmos()
def create_layout(self):
self.setup_drc_offsets()
self.place_nmos()
@ -64,15 +61,7 @@ class rom_base_cell(rom_dummy_cell):
self.copy_layout_pin(self.cell_inst, "S", "S")
self.copy_layout_pin(self.cell_inst, "D", "D")
self.source_pos = self.cell_inst.get_pin("S").center()
# if self.add_source_contact != False:
# # drain_x = 0
# # drain_y = 0.5 * (self.width - self.poly_extend_active_spacing)
# print("drained")
# print(drain_pos)
# self.add_layout_pin_rect_center("S", self.route_layer, drain_pos)
# self.add_label("S", self.route_layer, self.cell_inst.get_pin("S").center())

View File

@ -0,0 +1,81 @@
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2022 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from openram.sram_factory import factory
from openram.base import vector, design
class rom_control_logic(design):
def __init__(self, num_outputs, name="", height=None):
self.output_size = num_outputs
self.mod_height = height
# 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()
def create_netlist(self):
self.add_modules()
self.add_pins()
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.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=False)
def add_pins(self):
self.add_pin("READ", "INPUT")
self.add_pin("CS", "INPUT")
self.add_pin("prechrg", "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(["READ", "READ_BAR", "vdd", "gnd"])
self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod)
self.connect_inst(["CS", "READ_BAR", "pre_drive", "vdd", "gnd"])
self.driver_inst = self.add_inst(name="driver_inst", mod=self.driver_mod)
self.connect_inst(["pre_drive", "prechrg", "vdd", "gnd"])
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])
def route_insts(self):
self.copy_layout_pin(self.inv_inst, "A", "READ")
self.copy_layout_pin(self.driver_inst, "Z", "prechrg")
self.copy_layout_pin(self.nand_inst, "B", "CS")
self.add_path("li", [self.inv_inst.get_pin("Z").center(), self.nand_inst.get_pin("A").center()])
self.add_path("li", [self.nand_inst.get_pin("Z").center(), self.driver_inst.get_pin("A").center()])

View File

@ -5,15 +5,14 @@
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
from math import ceil, log
from openram.base import design
from openram.sram_factory import factory
from openram.base import vector
from openram.base import vector, design
from openram import OPTS
from openram.tech import drc
class rom_decoder(design):
def __init__(self, num_outputs, strap_spacing, name="", route_layer="li", output_layer="m2"):
@ -25,7 +24,7 @@ class rom_decoder(design):
self.num_inputs = ceil(log(num_outputs, 2))
self.create_decode_map()
for i in range(2 * self.num_inputs): print(self.decode_map[i])
# for i in range(2 * self.num_inputs): print(self.decode_map[i])
super().__init__(name)
@ -152,7 +151,6 @@ class rom_decoder(design):
def place_input_inverters(self):
print(self.array_inst.ll().x)
self.inv_inst.place(vector(self.array_inst.ll().x, 0))
@ -163,7 +161,6 @@ class rom_decoder(design):
def create_outputs(self):
self.output_names = []
self.outputs = []
for j in range(self.num_outputs):
name = "out_{0}".format(j)
self.output_names.append(name)
@ -179,6 +176,8 @@ class rom_decoder(design):
def connect_inputs(self):
self.copy_layout_pin(self.array_inst, "precharge")
for i in range(self.num_inputs):
wl = self.num_inputs * 2 - i * 2 - 1
wl_bar = wl - 1
@ -235,14 +234,8 @@ class rom_decoder(design):
offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy()))
# self.add_rect_center(self.route_layer, offset, width, height)
start = end - vector(0, 0.5 * minwidth)
end = vector(start.x, array_gnd[1].uy())
# self.add_segment_center("m1", start, end)

View File

@ -18,8 +18,8 @@ class rom_dummy_cell(design):
def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"):
super().__init__(name, cell_name)
self.route_layer = route_layer
self.add_source_contact=add_source_contact
self.add_drain_contact=add_drain_contact
self.add_source_contact="li"
self.add_drain_contact="li"
self.create_netlist()
self.create_layout()
@ -70,12 +70,22 @@ class rom_dummy_cell(design):
def add_boundary(self):
#cell width with offsets applied, height becomes width when the cells are rotated
# self.width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active
self.width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.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.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0)
width = self.nmos.width + self.active_space
#cell width with offsets applied, height becomes width when the cells are rotated
# width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.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
height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0)
# make the cells square so the pitch of wordlines will match bitlines
print("height: {0} width: {1}".format(height, width))
if width > height:
self.width = width
self.height = width
else:
self.width = height
self.height = height
super().add_boundary()

View File

@ -56,7 +56,7 @@ class rom_inv_array(design):
def create_modules(self):
self.inv_mod = factory.create(module_type="pinv", module_name="inv_array_mod", height=self.inv_size, add_wells=False)
self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size)
self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size, add_wells=True)
# For layout constants
self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=0)
@ -73,7 +73,6 @@ class rom_inv_array(design):
for col in range(self.cols):
name = "Xinv_c{0}".format(col)
if col == self.cols - 1:
print("TAP ME DOWN")
self.inv_insts.append(self.add_inst(name=name, mod=self.end_inv))
else:
self.inv_insts.append(self.add_inst(name=name, mod=self.inv_mod))

View File

@ -13,7 +13,7 @@ from openram.sram_factory import factory
class rom_poly_tap(design):
def __init__(self, name, strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m1"):
def __init__(self, name="", strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m1"):
super().__init__(name, cell_name, prop)
self.strap_layer=strap_layer
self.length = strap_length
@ -37,13 +37,20 @@ class rom_poly_tap(design):
def add_boundary(self):
contact_width = self.poly_contact.width + 2 * self.contact_x_offset
offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact)
print("THINGY {}".format(offset))
self.height = self.dummy.height
self.width = self.poly_contact.width + 2 * self.contact_x_offset
self.width = contact_width + self.pitch_offset
print("poly height: {0}, width: {1}".format(self.height, self.width))
super().add_boundary()
def place_via(self):
contact_width = self.poly_contact.width
# DRC rule here is hard coded since licon.9 isnt included in skywater130 tech file
# poly contact spacing to P-diffusion < 0.235um (licon.9 + psdm.5a)
@ -59,23 +66,16 @@ class rom_poly_tap(design):
# self.contact_x_offset = 0
else:
contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x
print(self.tx_type)
print(contact_y)
# 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)
print("polycule")
print(self.contact_offset)
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)
# if self.length == 0:
# self.add_layout_pin_rect_center(text="poly_tap",
# layer=self.strap_layer,
# offset=print()contact_offset,
# )
@ -88,14 +88,21 @@ class rom_poly_tap(design):
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
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.poly_width)
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)
self.add_rect("poly", extend_offset, self.contact_x_offset , self.poly_width)

View File

@ -139,6 +139,7 @@ class rom_precharge_array(design):
def create_layout_pins(self):
self.copy_layout_pin(self.tap_insts[0], "via", "gate")
for col in range(self.cols):
source_pin = self.pmos_insts[col].get_pin("D")
bl = "pre_bl{0}_out".format(col)

View File

@ -50,12 +50,12 @@ class rom_precharge_cell(design):
self.cell_inst = self.add_inst( name="precharge_pmos",
mod=self.pmos,
)
self.connect_inst(["bitline", "gate", "vdd", "vdd"])
self.connect_inst(["bitline", "gate", "vdd", "body"])
def add_pins(self):
pin_list = ["vdd", "gate", "bitline", "vdd"]
dir_list = ["OUTPUT", "INPUT", "OUTPUT", "POWER"]
pin_list = ["vdd", "gate", "bitline", "body"]
dir_list = ["POWER", "INPUT", "OUTPUT", "INPUT"]
self.add_pin_list(pin_list, dir_list)

View File

@ -27,7 +27,7 @@ class rom_array_test(openram_test):
data = [[1, 0, 0, 0, 0, 1, 0, 0, 1], [0, 1, 1, 1, 0, 1, 0, 0, 1], [1, 0, 1, 1, 0, 1, 0, 0, 1], [1, 1, 0, 1, 1, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 0, 0, 1], [0, 1, 1, 1, 1, 0, 0, 0, 1], [1, 0, 1, 1, 1, 0, 0, 0, 1], [1, 1, 0, 0, 1, 1, 0, 0, 1]]
a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4)
a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4, pitch_match=True)
self.local_check(a)
openram.end_openram()

View File

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

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python3
# See LICENSE for licensing information.
#
# Copyright (c) 2016-2021 Regents of the University of California and The Board
# of Regents for the Oklahoma Agricultural and Mechanical College
# (acting for and on behalf of Oklahoma State University)
# All rights reserved.
#
import unittest
from testutils import *
import sys, os
import openram
from openram import OPTS
from openram.sram_factory import factory
from openram import debug
class rom_decoder_test(openram_test):
def runTest(self):
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
openram.init_openram(config_file, is_unit_test=True)
debug.info(2, "Testing control logic for rom cell")
a = factory.create(module_type="rom_control_logic", num_outputs=4)
self.local_check(a)
openram.end_openram()
# run the test from the command line
if __name__ == "__main__":
(OPTS, args) = openram.parse_args()
del sys.argv[1:]
header(__file__, OPTS.tech_name)
unittest.main(testRunner=debugTestRunner())