mirror of https://github.com/VLSIDA/OpenRAM.git
Decoder array and start of rom bank
This commit is contained in:
parent
bc8d564dbf
commit
63925bd48e
|
|
@ -12,25 +12,27 @@ from .bitcell_base_array import bitcell_base_array
|
|||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import tech
|
||||
from tech import drc
|
||||
|
||||
class rom_base_array(bitcell_base_array):
|
||||
|
||||
def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0):
|
||||
|
||||
def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0, route_layer="li", output_layer="m2"):
|
||||
|
||||
super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset)
|
||||
|
||||
#TODO: data is input in col-major order for ease of parsing, create a function to convert a row-major input to col-major
|
||||
self.data = bitmap
|
||||
self.route_layer = 'm1'
|
||||
self.strap_spacing = strap_spacing
|
||||
self.data_col_size = self.column_size
|
||||
self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing)
|
||||
|
||||
self.data = bitmap
|
||||
self.route_layer = route_layer
|
||||
self.output_layer = output_layer
|
||||
self.strap_spacing = strap_spacing
|
||||
self.data_col_size = self.column_size
|
||||
if strap_spacing != 0:
|
||||
self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing)
|
||||
else:
|
||||
self.array_col_size = self.column_size
|
||||
self.create_all_bitline_names()
|
||||
self.create_all_wordline_names()
|
||||
self.create_netlist()
|
||||
|
||||
self.create_layout()
|
||||
|
||||
|
||||
|
|
@ -38,31 +40,44 @@ class rom_base_array(bitcell_base_array):
|
|||
self.add_modules()
|
||||
self.add_pins()
|
||||
|
||||
self.create_instances()
|
||||
self.create_cell_instances()
|
||||
self.create_precharge_inst()
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
self.place_array()
|
||||
self.place_wordline_contacts()
|
||||
self.place_bitline_contacts()
|
||||
self.place_precharge()
|
||||
self.place_rails()
|
||||
#self.route_bitlines()
|
||||
#self.route_wordlines()
|
||||
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])
|
||||
|
||||
|
||||
|
||||
#def add_pins(self):
|
||||
def add_boundary(self):
|
||||
self.width = self.dummy.width * self.column_size
|
||||
self.height = self.dummy.height * self.row_size
|
||||
super().add_boundary()
|
||||
|
||||
def add_modules(self):
|
||||
|
||||
# dummy cell, # "dummy" cells represent 0
|
||||
self.dummy = factory.create(module_type="rom_dummy_cell", route_layer=self.route_layer)
|
||||
ll = self.find_lowest_coords()
|
||||
bottom_offset = - self.dummy.nmos.end_to_contact + self.precharge_inst.offset.y
|
||||
m1_offset = self.m1_width
|
||||
self.translate_all(vector(0, ll.y + 0.5 * m1_offset))
|
||||
ur = self.find_highest_coords()
|
||||
|
||||
ur = vector(ur.x, ur.y - self.m1_width)
|
||||
#super().add_boundary(ll=vector(lowerx, lowery), ur=vector(upperx, uppery))
|
||||
super().add_boundary(vector(0, 0), ur)
|
||||
self.width = ur.x
|
||||
self.height = ur.y
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
|
||||
# dummy cell, "dummy" cells represent 0
|
||||
self.dummy = factory.create(module_type="rom_dummy_cell", route_layer=self.route_layer)
|
||||
|
||||
#base cell with no contacts
|
||||
self.cell_nc = factory.create(module_name="base_mod_0_contact", module_type="rom_base_cell")
|
||||
|
|
@ -77,14 +92,24 @@ class rom_base_array(bitcell_base_array):
|
|||
|
||||
self.zero_tap = factory.create(module_type="rom_poly_tap", strap_length=0)
|
||||
|
||||
self.gnd_rail = factory.create(module_type="rom_array_gnd_tap", length=self.row_size)
|
||||
|
||||
def create_instances(self):
|
||||
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 add_pins(self):
|
||||
for bl_name in self.get_bitline_names():
|
||||
self.add_pin(bl_name, "INOUT")
|
||||
for wl_name in self.get_wordline_names():
|
||||
self.add_pin(wl_name, "INPUT")
|
||||
self.add_pin("precharge_gate", "INPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
|
||||
def create_cell_instances(self):
|
||||
self.tap_inst = {}
|
||||
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
|
||||
int_bl_list = self.bitline_names[0]
|
||||
#When rotated correctly rows are word lines
|
||||
|
|
@ -93,62 +118,61 @@ 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
|
||||
strap_offset = 0
|
||||
#when rotated correctly cols are bit lines
|
||||
for col in range(self.array_col_size):
|
||||
# when rotated correctly cols are bit lines
|
||||
for col in range(self.column_size):
|
||||
|
||||
name = "bit_r{0}_c{1}".format(row, col)
|
||||
|
||||
data_col = col - strap_offset
|
||||
if col % self.strap_spacing == 0:
|
||||
|
||||
name = "tap_r{0}_c{1}".format(row, col)
|
||||
print("tap instance added at c{0}, r{1}".format(col, row))
|
||||
self.cell_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap)
|
||||
#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
|
||||
continue
|
||||
|
||||
name = "bit_r{0}_c{1}".format(row, col)
|
||||
|
||||
if self.data[row][data_col] == 1:
|
||||
if self.data[row][col] == 1:
|
||||
# if dummy/0 cell above and below a 1, add a tx with contacts on both drain and source
|
||||
# if the first row and a 0 above, add both contacts
|
||||
# if the last row and 0 below add both contacts
|
||||
#(row == 0 and self.data[row + 1][col] == 0):
|
||||
if (row < self.row_size - 1 and row > 0 and self.data[row + 1][data_col] == 0 and self.data[row - 1][data_col] == 0) or \
|
||||
(row == self.row_size - 1 and self.data[row - 1][data_col] == 0):
|
||||
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):
|
||||
|
||||
new_inst = self.add_inst(name=name, mod=self.cell_ac)
|
||||
|
||||
self.cell_inst[row, col]=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][data_col] == 0):
|
||||
self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_sc)
|
||||
elif (row > 0 and self.data[row - 1][col] == 0) or \
|
||||
(row == 0):
|
||||
|
||||
elif (row < self.row_size - 1 and self.data[row + 1][data_col] == 0) or \
|
||||
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):
|
||||
self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_dc)
|
||||
new_inst=self.add_inst(name=name, mod=self.cell_dc)
|
||||
|
||||
else:
|
||||
self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_nc)
|
||||
new_inst=self.add_inst(name=name, mod=self.cell_nc)
|
||||
|
||||
|
||||
if row == self.row_size - 1 or self.get_next_cell_in_bl(row, data_col) == -1:
|
||||
if row == self.row_size - 1 or self.get_next_cell_in_bl(row, col) == -1:
|
||||
|
||||
bl_l = int_bl_list[data_col]
|
||||
bl_l = int_bl_list[col]
|
||||
bl_h = "gnd"
|
||||
else:
|
||||
bl_l = int_bl_list[data_col]
|
||||
int_bl_list[data_col] = "bl_int_{0}_{1}".format(row, data_col)
|
||||
bl_h = int_bl_list[data_col]
|
||||
bl_l = int_bl_list[col]
|
||||
int_bl_list[col] = "bl_int_{0}_{1}".format(row, col)
|
||||
bl_h = int_bl_list[col]
|
||||
|
||||
|
||||
|
||||
self.cell_inst[row, col] = new_inst
|
||||
self.connect_inst([bl_h, bl_l, self.wordline_names[0][row], "gnd"])
|
||||
|
||||
|
||||
else:
|
||||
|
||||
self.cell_inst[row, col]=self.add_inst(name=name,
|
||||
mod=self.dummy)
|
||||
new_inst = self.add_inst(name=name, mod=self.dummy)
|
||||
self.cell_inst[row, col] = new_inst
|
||||
self.connect_inst([])
|
||||
|
||||
# when col = 0 bl_h is connected to vdd, otherwise connect to previous bl connection
|
||||
|
|
@ -156,18 +180,30 @@ class rom_base_array(bitcell_base_array):
|
|||
#
|
||||
|
||||
|
||||
row_list.append(self.cell_inst[row, col])
|
||||
row_list.append(new_inst)
|
||||
|
||||
|
||||
|
||||
name = "tap_r{0}_c{1}".format(row, self.array_col_size)
|
||||
#print(*row_list)
|
||||
self.cell_inst[row, self.array_col_size]=self.add_inst(name=name, mod=self.zero_tap)
|
||||
self.tap_inst[row, self.column_size]=self.add_inst(name=name, mod=self.zero_tap)
|
||||
self.connect_inst([])
|
||||
|
||||
self.cell_list.append(row_list)
|
||||
|
||||
|
||||
def create_precharge_inst(self):
|
||||
prechrg_pins = []
|
||||
|
||||
for bl in range(self.column_size):
|
||||
prechrg_pins.append(self.bitline_names[0][bl])
|
||||
|
||||
prechrg_pins.append("precharge_gate")
|
||||
prechrg_pins.append("vdd")
|
||||
self.precharge_inst = self.add_inst(name="decode_array_precharge", mod=self.precharge_array)
|
||||
self.connect_inst(prechrg_pins)
|
||||
|
||||
|
||||
|
||||
def create_all_bitline_names(self):
|
||||
for col in range(self.column_size):
|
||||
|
|
@ -176,110 +212,138 @@ class rom_base_array(bitcell_base_array):
|
|||
# Make a flat list too
|
||||
self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl]
|
||||
|
||||
def place_taps(self):
|
||||
|
||||
self.tap_pos = {}
|
||||
for row in range(self.row_size):
|
||||
for col in range(0, self.column_size, self.strap_spacing):
|
||||
|
||||
|
||||
tap_x = self.dummy.width * col
|
||||
tap_y = self.dummy.height * row
|
||||
|
||||
self.tap_pos[row, col] = vector(tap_x, tap_y)
|
||||
self.tap_inst[row, col].place(self.tap_pos[row, col])
|
||||
tap_x = self.dummy.width * self.column_size + self.poly_tap.width
|
||||
tap_y = self.dummy.height * row
|
||||
|
||||
self.tap_pos[row, self.column_size] = vector(tap_x, tap_y)
|
||||
self.tap_inst[row, self.column_size].place(self.tap_pos[row, self.column_size])
|
||||
|
||||
|
||||
|
||||
def place_rails(self):
|
||||
|
||||
width = drc("minwidth_" + self.route_layer)
|
||||
drc_rule = "{0}_to_{0}".format(self.route_layer)
|
||||
spacing = drc(drc_rule)
|
||||
|
||||
rail_y = self.dummy.height * (self.row_size) + self.mcon_width * 0.5
|
||||
start_x = self.cell_inst[self.row_size - 1, 0].rx()
|
||||
end_x = self.cell_inst[self.row_size - 1, self.array_col_size - 1].cx()
|
||||
rail_y = self.cell_list[self.row_size - 1][0].offset.y + self.dummy.base_width + spacing
|
||||
# self.dummy.height * (self.row_size)
|
||||
start_x = self.get_pin(self.bitline_names[0][0]).cx()
|
||||
# self.cell_list[self.row_size - 1][0].offset.x
|
||||
end_x = self.get_pin(self.bitline_names[0][self.column_size - 1]).cx()
|
||||
# self.cell_list[self.row_size - 1][self.column_size - 1].offset.x
|
||||
#self.dummy.height * self.row_size
|
||||
#self.cell_inst[self.row_size - 1,0].uy()
|
||||
rail_start = vector(start_x , rail_y)
|
||||
rail_end = vector(end_x, rail_y)
|
||||
|
||||
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)
|
||||
|
||||
for bl in range(self.column_size):
|
||||
drain_pin = self.cell_list[self.row_size - 1][bl].get_pin("D")
|
||||
via_pos = vector(drain_pin.cx(), rail_y)
|
||||
self.add_segment_center(self.route_layer, drain_pin.center(), via_pos)
|
||||
|
||||
|
||||
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
|
||||
for row in range(self.row_size):
|
||||
|
||||
strap_cols = -1
|
||||
# strap_cols = -1
|
||||
|
||||
cell_y = row * (self.dummy.height)
|
||||
|
||||
# columns are bit lines
|
||||
for col in range(self.array_col_size):
|
||||
|
||||
cell_x = 0
|
||||
|
||||
for col in range(self.column_size):
|
||||
|
||||
if col % self.strap_spacing == 0:
|
||||
strap_cols += 1
|
||||
rot = 0
|
||||
else:
|
||||
rot = 90
|
||||
|
||||
bit_cols = col - strap_cols
|
||||
|
||||
if col == 0:
|
||||
cell_x = 0
|
||||
else:
|
||||
cell_x = (self.dummy.width * bit_cols) + (self.poly_tap.width * strap_cols)
|
||||
|
||||
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
|
||||
|
||||
self.cell_pos[row, col] = vector(cell_x, cell_y)
|
||||
self.cell_inst[row, col].place(self.cell_pos[row, col], rotate=rot)
|
||||
self.cell_inst[row, col].place(self.cell_pos[row, col])
|
||||
cell_x += self.dummy.width
|
||||
self.add_label("debug", "li", self.cell_pos[row, col])
|
||||
|
||||
strap_cols += 1
|
||||
bit_cols = self.array_col_size - strap_cols
|
||||
cell_x = (self.dummy.width * bit_cols) + (self.poly_tap.width * strap_cols)
|
||||
self.cell_pos[row, self.array_col_size] = vector(cell_x, cell_y)
|
||||
self.cell_inst[row, self.array_col_size].place(self.cell_pos[row, self.array_col_size])
|
||||
|
||||
|
||||
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.cell_inst[row, self.array_col_size].get_pin("poly_tap").center()
|
||||
# self.add_layout_pin_rect_center("wl{}".format(row), "m2", tap_pin)
|
||||
|
||||
|
||||
def place_precharge(self):
|
||||
|
||||
self.precharge_offset = vector(0, - self.precharge_inst.height - self.dummy.nmos.end_to_contact - 2 * drc["nwell_enclose_active"])
|
||||
|
||||
self.precharge_inst.place(offset=self.precharge_offset)
|
||||
|
||||
self.copy_layout_pin(self.precharge_inst, "vdd")
|
||||
|
||||
|
||||
|
||||
def place_wordline_contacts(self):
|
||||
|
||||
width = drc["minwidth_{}".format(self.route_layer)]
|
||||
|
||||
height = drc["minwidth_{}".format(self.route_layer)]
|
||||
|
||||
offset = vector(self.poly_contact.width * 0.5, self.dummy.poly.offset.y)
|
||||
|
||||
for wl in range(self.row_size):
|
||||
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
for bl in range(self.column_size):
|
||||
|
||||
|
||||
def route_bitlines(self):
|
||||
# self.copy_layout_pin(self.cell_list[0][bl], "S", self.bitline_names[0][bl])
|
||||
|
||||
#get first nmos in col
|
||||
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)
|
||||
|
||||
#connect to main bitline wire
|
||||
|
||||
# offset = src_pin_offset + vector(src_pin.x, 0)
|
||||
|
||||
|
||||
#get next nmos in col
|
||||
middle_offset = (pre_pin.cy() - src_pin.cy()) * 0.5
|
||||
|
||||
#route source to drain
|
||||
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 )
|
||||
|
||||
#loop
|
||||
|
||||
# self.gnd[0].y()
|
||||
|
||||
|
||||
for col in range(self.column_size):
|
||||
for row in range(self.row_size ):
|
||||
|
||||
#nmos at this position and another nmos further down
|
||||
if self.data[row][col] == 1 :
|
||||
|
||||
next_row = self.get_next_cell_in_bl(row, col)
|
||||
if next_row != -1:
|
||||
|
||||
drain_pin = self.cell_inst[row, col].get_pin("D")
|
||||
source_pin = self.cell_inst[next_row, col].get_pin("S")
|
||||
|
||||
source_pos = source_pin.bc()
|
||||
drain_pos = drain_pin.bc()
|
||||
self.add_path(self.route_layer, [drain_pos, source_pos])
|
||||
|
||||
|
||||
def route_precharge(self):
|
||||
for bl in range(self.column_size):
|
||||
bl_pin = self.cell_list[0][bl].get_pin("S")
|
||||
prechg_pin = "pre_bl{0}_out".format(bl)
|
||||
pre_out_pin = self.precharge_inst.get_pin(prechg_pin)
|
||||
|
||||
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)
|
||||
|
||||
def get_next_cell_in_bl(self, row_start, col):
|
||||
for row in range(row_start + 1, self.row_size):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,177 @@
|
|||
|
||||
import math
|
||||
from base import vector
|
||||
from base import design
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import tech
|
||||
from 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]]
|
||||
self.strap_spacing = strap_spacing
|
||||
self.route_layer = "li"
|
||||
self.bus_layer = "m1"
|
||||
self.interconnect_layer = "m2"
|
||||
|
||||
|
||||
|
||||
super().__init__(name=name)
|
||||
self.setup_layout_constants()
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.create_instances()
|
||||
|
||||
def create_layout(self):
|
||||
self.place_instances()
|
||||
self.create_wl_bus()
|
||||
self.route_decode_outputs()
|
||||
self.route_array_inputs()
|
||||
|
||||
self.route_supplies()
|
||||
self.height = self.array_inst.height
|
||||
self.width = self.array_inst.width
|
||||
self.add_boundary()
|
||||
|
||||
|
||||
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)]
|
||||
|
||||
|
||||
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.decode_array = factory.create(module_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer)
|
||||
|
||||
|
||||
|
||||
def create_instances(self):
|
||||
array_pins = []
|
||||
decode_pins = []
|
||||
|
||||
for bl in range(self.cols):
|
||||
name = "bl_{}".format(bl)
|
||||
array_pins.append(name)
|
||||
for wl in range(self.rows):
|
||||
name = "wl_{}".format(wl)
|
||||
array_pins.append(wl)
|
||||
|
||||
array_pins.append("array_precharge")
|
||||
array_pins.append("vdd")
|
||||
array_pins.append("gnd")
|
||||
|
||||
|
||||
for addr in range(self.num_inputs):
|
||||
name = "addr_{}".format(addr)
|
||||
decode_pins.append(name)
|
||||
for wl in range(self.rows):
|
||||
name = "wl_{}".format(wl)
|
||||
decode_pins.append(name)
|
||||
|
||||
decode_pins.append("decode_precharge")
|
||||
decode_pins.append("vdd")
|
||||
decode_pins.append("gnd")
|
||||
|
||||
|
||||
self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array)
|
||||
self.connect_inst(array_pins)
|
||||
|
||||
self.decode_inst = self.add_inst(name="rom_decoder", mod=self.decode_array)
|
||||
self.connect_inst(decode_pins)
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
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.decode_inst.place(offset=self.decode_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 = []
|
||||
|
||||
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() )
|
||||
|
||||
def route_decode_outputs(self):
|
||||
|
||||
for wl in range(self.rows):
|
||||
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]]
|
||||
|
||||
start = decode_out_pin.center()
|
||||
end = vector(wl_bus_wire.cx(), start.y)
|
||||
|
||||
self.add_segment_center(self.interconnect_layer, start, end)
|
||||
self.add_via_stack_center(end, self.route_layer, self.interconnect_layer )
|
||||
|
||||
|
||||
def route_array_inputs(self):
|
||||
|
||||
for wl in range(self.rows):
|
||||
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]]
|
||||
|
||||
end = array_wl_pin.center()
|
||||
start = vector(wl_bus_wire.cx(), end.y)
|
||||
|
||||
self.add_segment_center(self.interconnect_layer, start, end)
|
||||
self.add_via_stack_center(start, self.route_layer, self.interconnect_layer )
|
||||
|
||||
|
||||
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_power_pin("gnd", decode_vdd.center())
|
||||
self.add_power_pin("vdd", decode_gnd.center())
|
||||
|
||||
vdd_start = vector(array_vdd.lx() + 0.5 * self.via1_space, array_vdd.cy())
|
||||
end = vector(decode_vdd.lx(), vdd_start.y)
|
||||
|
||||
self.add_segment_center(self.interconnect_layer, vdd_start, end)
|
||||
self.add_via_stack_center(vdd_start, "m1", self.interconnect_layer)
|
||||
|
||||
vdd_start = vector(decode_vdd.cx(), vdd_start.y)
|
||||
|
||||
self.add_segment_center(self.interconnect_layer, vdd_start, decode_vdd.center())
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -6,10 +6,7 @@
|
|||
# All rights reserved.
|
||||
#
|
||||
|
||||
|
||||
import math
|
||||
from .rom_dummy_cell import rom_dummy_cell
|
||||
from base import design
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
|
@ -26,9 +23,7 @@ class rom_base_cell(rom_dummy_cell):
|
|||
#self.create_layout()
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
print("using base cell netlist creation")
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_nmos()
|
||||
self.create_nmos()
|
||||
|
|
@ -39,9 +34,6 @@ class rom_base_cell(rom_dummy_cell):
|
|||
self.place_nmos()
|
||||
self.add_boundary()
|
||||
|
||||
print(self.height)
|
||||
print(self.width)
|
||||
|
||||
|
||||
def create_nmos(self):
|
||||
self.cell_inst = self.add_inst( name=self.name + "_nmos",
|
||||
|
|
@ -58,19 +50,30 @@ class rom_base_cell(rom_dummy_cell):
|
|||
|
||||
def place_nmos(self):
|
||||
|
||||
|
||||
poly_offset = vector(0.5 * self.nmos.active_contact.width + self.nmos.active_contact_to_gate,
|
||||
self.nmos.poly_height)
|
||||
# 0.5 * self.nmos.active_contact.width + self.nmos.active_contact_to_gate
|
||||
poly_offset = vector(self.poly_extend_active_spacing * 0.5 + self.nmos.height + 2 * self.poly_extend_active, self.nmos.width * 0.5 - 0.5 * self.nmos.contact_width - self.active_enclose_contact)
|
||||
|
||||
nmos_offset = vector(- 0.5 * self.nmos.contact_width - self.active_enclose_contact, self.nmos.poly_extend_active)
|
||||
# nmos_offset = vector(- 0.5 * self.nmos.contact_width - self.active_enclose_contact, self.nmos.poly_extend_active)
|
||||
print("{} poly spacing".format(self.poly_extend_active_spacing))
|
||||
|
||||
nmos_offset = vector(self.nmos.poly_extend_active + self.nmos.height ,- 0.5 * self.nmos.contact_width - self.active_enclose_contact)
|
||||
# add rect of poly to account for offset from drc spacing
|
||||
self.add_rect("poly", poly_offset, self.nmos.poly_width, self.poly_extend_active_spacing )
|
||||
self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.nmos.poly_width)
|
||||
|
||||
self.cell_inst.place(nmos_offset)
|
||||
self.add_label("CELL ZERO", self.route_layer)
|
||||
self.add_label("S", self.route_layer, self.cell_inst.get_pin("S").center())
|
||||
self.add_label("D", self.route_layer, self.cell_inst.get_pin("D").center())
|
||||
self.cell_inst.place(nmos_offset, rotate=90)
|
||||
# self.add_label("CELL ZERO", self.route_layer)
|
||||
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())
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,249 @@
|
|||
# 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 math
|
||||
from base import design
|
||||
from sram_factory import factory
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
import tech
|
||||
from tech import drc
|
||||
|
||||
|
||||
class rom_decoder(design):
|
||||
def __init__(self, num_outputs, strap_spacing, name="", route_layer="li", output_layer="m2"):
|
||||
|
||||
# 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
|
||||
# array gets rotated 90deg so that rows/cols switch
|
||||
self.strap_spacing=strap_spacing
|
||||
self.num_outputs = num_outputs
|
||||
self.num_inputs = math.ceil(math.log(num_outputs, 2))
|
||||
self.create_decode_map()
|
||||
|
||||
for i in range(2 * self.num_inputs): print(self.decode_map[i])
|
||||
|
||||
super().__init__(name)
|
||||
|
||||
b = factory.create(module_type=OPTS.bitcell)
|
||||
self.cell_height = b.height
|
||||
self.route_layer = route_layer
|
||||
self.output_layer = output_layer
|
||||
self.inv_route_layer = "m1"
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_modules()
|
||||
self.add_pins()
|
||||
self.create_instances()
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
self.place_array()
|
||||
self.place_input_inverters()
|
||||
self.create_outputs()
|
||||
self.width = self.array_inst.height
|
||||
self.height = self.array_inst.width + self.inv_inst.height
|
||||
self.connect_inputs()
|
||||
self.route_supplies()
|
||||
self.add_boundary()
|
||||
|
||||
def create_decode_map(self):
|
||||
self.decode_map = []
|
||||
# create decoding map that will be the bitmap for the rom decoder
|
||||
# row/col order in the map will be switched in the placed decoder/
|
||||
for col in range(self.num_inputs):
|
||||
|
||||
# odd cols are address
|
||||
# even cols are address bar
|
||||
col_array = []
|
||||
inv_col_array = []
|
||||
for row in range(self.num_outputs):
|
||||
|
||||
addr_idx = -col - 1
|
||||
|
||||
addr = format(row, 'b')
|
||||
if col >= len(addr) :
|
||||
bin_digit = 0
|
||||
else:
|
||||
bin_digit = int(addr[addr_idx])
|
||||
|
||||
col_array.append(bin_digit)
|
||||
# print("addr {0}, at indx {1}, digit {2}".format(addr, addr_idx, bin_digit))
|
||||
|
||||
if bin_digit == 0 : inv_col_array.append(1)
|
||||
else : inv_col_array.append(0)
|
||||
|
||||
|
||||
|
||||
self.decode_map.append(col_array)
|
||||
self.decode_map.append(inv_col_array)
|
||||
self.decode_map.reverse()
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
for i in range(self.num_inputs):
|
||||
self.add_pin("in_{0}".format(i), "INPUT")
|
||||
|
||||
for j in range(self.num_outputs):
|
||||
self.add_pin("out_{0}".format(j), "OUTPUT")
|
||||
self.add_pin("precharge_gate", "INPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
|
||||
|
||||
def add_modules(self):
|
||||
|
||||
self.inv_array = factory.create(module_type="rom_inv_array", cols=self.num_inputs)
|
||||
|
||||
self.array_mod = factory.create(module_type="rom_base_array", \
|
||||
module_name="rom_decode_array", \
|
||||
cols=self.num_outputs, \
|
||||
rows=2 * self.num_inputs, \
|
||||
bitmap=self.decode_map,
|
||||
strap_spacing = self.strap_spacing,
|
||||
route_layer=self.route_layer,
|
||||
output_layer=self.output_layer)
|
||||
|
||||
|
||||
def create_instances(self):
|
||||
|
||||
self.create_input_inverters()
|
||||
self.create_array_inst()
|
||||
|
||||
|
||||
def create_input_inverters(self):
|
||||
name = "pre_inv_array"
|
||||
self.inv_inst = self.add_inst(name=name, mod=self.inv_array)
|
||||
|
||||
inv_pins = []
|
||||
|
||||
for i in range(self.num_inputs):
|
||||
inv_pins.append("in_{0}".format(i))
|
||||
inv_pins.append("inbar_{0}".format(i))
|
||||
|
||||
inv_pins.append("vdd")
|
||||
inv_pins.append("gnd")
|
||||
self.connect_inst(inv_pins)
|
||||
|
||||
|
||||
def create_array_inst(self):
|
||||
self.array_inst = self.add_inst(name="decode_array_inst", mod=self.array_mod)
|
||||
|
||||
array_pins = []
|
||||
|
||||
for j in range(self.num_outputs):
|
||||
name = "out_{0}".format(j)
|
||||
array_pins.append(name)
|
||||
|
||||
|
||||
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("vdd")
|
||||
array_pins.append("gnd")
|
||||
self.connect_inst(array_pins)
|
||||
|
||||
|
||||
def place_input_inverters(self):
|
||||
print(self.array_inst.ll().x)
|
||||
self.inv_inst.place(vector(self.array_inst.ll().x, 0))
|
||||
|
||||
|
||||
def place_array(self):
|
||||
offset = vector(self.array_mod.height, self.inv_array.height + self.m1_width + self.poly_contact.width)
|
||||
self.array_inst.place(offset, rotate=90)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
for bl in range(self.num_outputs):
|
||||
self.copy_layout_pin(self.array_inst, self.array_mod.bitline_names[0][bl], self.output_names[bl])
|
||||
# prechg_pin = self.array_mod.bitline_names[0][bl]
|
||||
# src_pin = self.array_inst.get_pin(prechg_pin)
|
||||
# offset = src_pin.center()
|
||||
# self.add_via_stack_center(offset, self.route_layer, self.output_layer)
|
||||
# self.outputs.append(self.add_layout_pin_rect_center(self.output_names[bl], self.output_layer, offset ))
|
||||
|
||||
def connect_inputs(self):
|
||||
|
||||
for i in range(self.num_inputs):
|
||||
wl = self.num_inputs * 2 - i * 2 - 1
|
||||
wl_bar = wl - 1
|
||||
addr_pin = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl])
|
||||
addr_bar_pin = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl_bar])
|
||||
|
||||
inv_in_pin = self.inv_inst.get_pin("inv{}_in".format(i))
|
||||
inv_out_pin = self.inv_inst.get_pin("inv{}_out".format(i))
|
||||
|
||||
addr_start = inv_in_pin.center()
|
||||
addr_end = vector(addr_start.x, addr_pin.cy())
|
||||
|
||||
addr_bar_start = inv_out_pin.center()
|
||||
addr_bar_end = vector(addr_bar_start.x, addr_bar_pin.cy())
|
||||
self.add_segment_center(self.inv_route_layer, addr_start, addr_end)
|
||||
self.add_segment_center(self.inv_route_layer, addr_bar_start, addr_bar_end)
|
||||
|
||||
def route_supplies(self):
|
||||
minwidth = drc["minwidth_{}".format(self.inv_route_layer)]
|
||||
pitch = drc["{0}_to_{0}".format(self.inv_route_layer)]
|
||||
|
||||
|
||||
# route decode array vdd and inv array vdd together
|
||||
array_vdd = self.array_inst.get_pin("vdd")
|
||||
inv_vdd = self.inv_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())
|
||||
self.add_via_stack_center(end, self.route_layer, "m1")
|
||||
self.add_layout_pin_rect_center("vdd", "m1", end)
|
||||
|
||||
# route pin on inv gnd
|
||||
|
||||
inv_gnd = self.inv_inst.get_pins("gnd")[0]
|
||||
array_gnd = self.array_inst.get_pins("gnd")
|
||||
|
||||
# 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)
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
|
|
@ -41,9 +41,7 @@ class rom_dummy_cell(design):
|
|||
self.add_boundary()
|
||||
self.add_poly()
|
||||
self.add_metal()
|
||||
print(self.height)
|
||||
print(self.width)
|
||||
self.add_label("0,0", self.route_layer)
|
||||
#self.add_label("0,0", self.route_layer)
|
||||
|
||||
|
||||
|
||||
|
|
@ -65,8 +63,6 @@ class rom_dummy_cell(design):
|
|||
#this is calculated as a negative value
|
||||
self.cell_diffusion_offset = ((self.base_width - 2 * self.active_enclose_contact - self.nmos.contact_width) - drc("active_to_active")) * 0.5
|
||||
|
||||
|
||||
|
||||
# width offset to account for poly-active spacing between base and dummy cells on the same bitline
|
||||
self.poly_active_offset = 0.5 * (self.base_width - 2 * self.cell_diffusion_offset - (self.poly_width + 2 * self.active_enclose_contact + self.nmos.contact_width)) - self.poly_to_active
|
||||
|
||||
|
|
@ -77,8 +73,8 @@ 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)
|
||||
|
||||
|
|
@ -88,18 +84,22 @@ class rom_dummy_cell(design):
|
|||
|
||||
def add_poly(self):
|
||||
|
||||
poly_x = 0.5 * self.nmos.contact_width + self.contact_to_gate
|
||||
poly_x = 0.5 * (self.nmos.poly_height + self.poly_extend_active_spacing)
|
||||
# 0.5 * self.nmos.contact_width + self.contact_to_gate
|
||||
|
||||
self.poly = self.add_rect("poly", vector(poly_x, 0), self.poly_width, self.nmos.poly_height + self.poly_extend_active_spacing)
|
||||
print(self.poly_width, self.height)
|
||||
self.poly = self.add_rect_center("poly", vector(poly_x, self.base_width * 0.5), 2 * poly_x, self.poly_width)
|
||||
|
||||
def add_metal(self):
|
||||
|
||||
wire_x = min(self.cell_diffusion_offset, 0) + min(self.poly_active_offset, 0) - self.mcon_width * 0.5
|
||||
wire_y = 0.5 * (self.width - self.poly_extend_active_spacing)
|
||||
if self.route_layer == "li":
|
||||
via = "mcon"
|
||||
else:
|
||||
via = "via{}".format(self.route_layer[len(self.route_layer) - 1])
|
||||
wire_y = self.height + drc["minwidth_{}".format(via)] * 0.5
|
||||
wire_x = 0.5 * (self.width - self.poly_extend_active_spacing)
|
||||
|
||||
wire_start = vector( wire_x, wire_y )
|
||||
wire_end = vector(self.height + self.mcon_width * 0.5, wire_y)
|
||||
wire_start = vector( wire_x, 0)
|
||||
wire_end = vector(wire_x, wire_y)
|
||||
|
||||
# if self.route_layer == 'm1':
|
||||
|
||||
|
|
@ -109,11 +109,18 @@ class rom_dummy_cell(design):
|
|||
# self.add_via_center(self.li_stack, [self.width, wire_y])
|
||||
|
||||
self.add_path(self.route_layer, [wire_start, wire_end])
|
||||
|
||||
# drain_x = 0
|
||||
# drain_y = 0.5 * (self.width)
|
||||
source_x = 0.5 * (self.width - self.poly_extend_active_spacing)
|
||||
source_y = 0
|
||||
source_pos = vector(source_x, source_y)
|
||||
self.add_layout_pin_rect_center("S", self.route_layer, source_pos)
|
||||
|
||||
drain_pos = vector(source_x, self.height)
|
||||
self.add_layout_pin_rect_center("D", self.route_layer, drain_pos)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def add_nmos(self):
|
||||
#used only for layout constants
|
||||
# if not self.source_contact:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
# 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.
|
||||
#
|
||||
|
||||
from base import design
|
||||
from sram_factory import factory
|
||||
from base import vector
|
||||
from tech import layer, drc
|
||||
|
||||
|
||||
|
||||
class rom_inv_array(design):
|
||||
"""
|
||||
An array of inverters to create the inverted address lines for the rom decoder
|
||||
"""
|
||||
def __init__(self, cols, inv_size=None, name="", route_layer="m1"):
|
||||
self.cols = cols
|
||||
self.route_layer = route_layer
|
||||
dff = factory.create(module_type="dff")
|
||||
if name=="":
|
||||
name = "rom_inv_array_{0}".format(cols)
|
||||
if inv_size == None:
|
||||
self.inv_size = dff.height * 0.5
|
||||
else:
|
||||
self.inv_size = inv_size
|
||||
|
||||
|
||||
if "li" in layer:
|
||||
self.inv_layer = "li"
|
||||
else:
|
||||
self.inv_layer = "m1"
|
||||
super().__init__(name)
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.create_modules()
|
||||
self.add_pins()
|
||||
self.create_instances()
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.cols * self.poly_tap.height * 2
|
||||
self.height = self.inv_mod.height
|
||||
self.setup_layout_constants()
|
||||
self.place_instances()
|
||||
self.place_vias()
|
||||
self.route_sources()
|
||||
self.add_boundary()
|
||||
|
||||
|
||||
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)
|
||||
# For layout constants
|
||||
self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=0)
|
||||
|
||||
def add_pins(self):
|
||||
for col in range(self.cols):
|
||||
self.add_pin("inv{0}_in".format(col), "INPUT")
|
||||
self.add_pin("inv{0}_out".format(col), "OUTPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gnd", "GROUND")
|
||||
|
||||
def create_instances(self):
|
||||
self.inv_insts = []
|
||||
|
||||
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))
|
||||
inst_A = "inv{0}_in".format(col)
|
||||
inst_Z = "inv{0}_out".format(col)
|
||||
self.connect_inst([inst_A, inst_Z, "vdd", "gnd"])
|
||||
|
||||
def setup_layout_constants(self):
|
||||
input_pin = self.inv_insts[0].get_pin("A")
|
||||
output_pin = self.inv_insts[0].get_pin("Z")
|
||||
|
||||
# NEED TO OFFSET OUTPUT VIA IN ORDER TO ALIGN WITH PITCH OF ADDRESS INPUTS TO ARRAY
|
||||
|
||||
# print(self.poly_tap.get_pin("poly_tap").center())
|
||||
|
||||
# distance between input and output pins of inverter
|
||||
in_out_distance = output_pin.cx() - input_pin.cx()
|
||||
# distance from left edge of inverter to input plus right edge to output
|
||||
edge_to_pins_distance = input_pin.cx() - self.inv_insts[0].lx() + self.inv_insts[0].rx() - output_pin.cx()
|
||||
|
||||
self.alignment_offset = edge_to_pins_distance - in_out_distance
|
||||
|
||||
def place_instances(self):
|
||||
self.add_label("ZERO", self.route_layer)
|
||||
for col in range(self.cols):
|
||||
# base = vector(col*(self.inv_mod.width - self.alignment_offset), 0)
|
||||
base = vector(col*(self.poly_tap.height * 2), 0)
|
||||
self.inv_insts[col].place(offset=base)
|
||||
#vdd_pin = self.inv_insts[0].get_pin("vdd").center()
|
||||
#self.add_layout_pin_rect_center("vdd_align", self.inv_layer, vdd_pin, 0, 0)
|
||||
|
||||
def place_vias(self):
|
||||
for i in range(self.cols):
|
||||
input_pin = self.inv_insts[i].get_pin("A")
|
||||
output_pin = self.inv_insts[i].get_pin("Z")
|
||||
|
||||
self.add_via_stack_center(input_pin.center(), self.inv_mod.route_layer, self.route_layer)
|
||||
self.add_via_stack_center(output_pin.center(), self.inv_mod.route_layer, self.route_layer)
|
||||
self.add_layout_pin_rect_center("inv{}_in".format(i), offset=input_pin.center(), layer=self.route_layer)
|
||||
self.add_layout_pin_rect_center("inv{}_out".format(i), offset=output_pin.center(), layer=self.route_layer)
|
||||
|
||||
def route_sources(self):
|
||||
|
||||
vdd_start = self.inv_insts[0].get_pin("vdd")
|
||||
vdd_end = self.inv_insts[-1].get_pin("vdd")
|
||||
|
||||
gnd_start = self.inv_insts[0].get_pin("gnd")
|
||||
gnd_end = self.inv_insts[-1].get_pin("gnd")
|
||||
|
||||
self.copy_layout_pin(self.inv_insts[0], "vdd")
|
||||
self.copy_layout_pin(self.inv_insts[0], "gnd")
|
||||
# self.vdd = self.add_layout_pin_rect_ends("vdd", self.inv_layer, vdd_start.center(), vdd_end.center())[-1]
|
||||
# self.gnd = self.add_layout_pin_rect_ends("gnd", self.inv_layer, gnd_start.center(), gnd_end.center())[-1]
|
||||
|
||||
|
|
@ -2,54 +2,94 @@
|
|||
|
||||
from base import design
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
class rom_poly_tap(design):
|
||||
|
||||
def __init__(self, name, strap_length=0, cell_name=None, prop=None, strap_layer="m2"):
|
||||
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
|
||||
self.tx_type = tx_type
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
|
||||
|
||||
#for layout constants
|
||||
self.dummy = factory.create(module_type="rom_dummy_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.add_boundary()
|
||||
if self.length != 0:
|
||||
self.place_strap(self.length)
|
||||
self.place_strap()
|
||||
|
||||
|
||||
def add_boundary(self):
|
||||
self.height = self.dummy.height
|
||||
self.width = self.poly_contact.width
|
||||
self.width = self.poly_contact.width + 2 * self.contact_x_offset
|
||||
super().add_boundary()
|
||||
|
||||
def place_via(self):
|
||||
|
||||
contact_width = self.poly_contact.width
|
||||
|
||||
contact_x = - contact_width * 0.5
|
||||
contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5)
|
||||
contact_width = self.poly_contact.width
|
||||
# DRC rule here is hard coded since licon.9 isnt included in skywater130 tech file
|
||||
|
||||
contact_offset = vector(contact_x, contact_y)
|
||||
# poly contact spacing to P-diffusion < 0.235um (licon.9 + psdm.5a)
|
||||
if OPTS.tech_name == "sky130":
|
||||
self.contact_x_offset = 0.235 - (contact_width - self.pmos.contact_width) * 0.5 - self.poly_extend_active
|
||||
else:
|
||||
assert(False)
|
||||
|
||||
if self.tx_type == "nmos":
|
||||
|
||||
contact_y = self.dummy.poly.cy()
|
||||
# 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
|
||||
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=contact_offset)
|
||||
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,
|
||||
# )
|
||||
|
||||
self.add_label("ZERO", "poly")
|
||||
|
||||
def place_strap(self, length):
|
||||
|
||||
strap_start = vector(self.via.cx(), self.via.cy())
|
||||
def place_strap(self):
|
||||
|
||||
strap_end = vector( self.dummy.width * (length - 1) + self.m2_width, self.via.cy())
|
||||
strap_start = vector(self.via.lx() , 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))
|
||||
|
||||
def extend_poly(self):
|
||||
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)
|
||||
|
||||
poly_x = 0
|
||||
extend_offset = vector(poly_x, poly_y)
|
||||
|
||||
self.add_rect("poly", extend_offset, self.contact_x_offset, self.poly_width)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,201 @@
|
|||
# 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 math
|
||||
from base import geometry
|
||||
from base import design
|
||||
from sram_factory import factory
|
||||
from base import vector
|
||||
from tech import layer, drc
|
||||
|
||||
|
||||
|
||||
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):
|
||||
self.cols = cols
|
||||
self.route_layer = route_layer
|
||||
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 = math.ceil(self.cols / self.strap_spacing)
|
||||
self.array_col_size = self.cols + self.num_straps
|
||||
else:
|
||||
self.num_straps = 0
|
||||
self.array_col_size = self.cols
|
||||
|
||||
super().__init__(name)
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
def create_netlist(self):
|
||||
self.create_modules()
|
||||
self.add_pins()
|
||||
self.create_instances()
|
||||
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
self.width = self.cols * self.pmos.width + self.num_straps * self.poly_tap.width
|
||||
self.height = self.pmos.width
|
||||
self.place_instances()
|
||||
self.create_layout_pins()
|
||||
self.add_well_tap()
|
||||
self.route_supply()
|
||||
self.extend_implant()
|
||||
|
||||
self.add_boundary()
|
||||
|
||||
|
||||
|
||||
def add_boundary(self):
|
||||
self.translate_all(self.well_ll)
|
||||
ur = self.find_highest_coords()
|
||||
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.num_straps * self.poly_tap.width
|
||||
self.height = ur.y
|
||||
|
||||
def create_modules(self):
|
||||
|
||||
self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", route_layer=self.route_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, tx_type="pmos")
|
||||
|
||||
def add_pins(self):
|
||||
for col in range(self.cols):
|
||||
self.add_pin("pre_bl{0}_out".format(col), "OUTPUT")
|
||||
self.add_pin("vdd", "POWER")
|
||||
self.add_pin("gate", "INPUT")
|
||||
|
||||
def create_instances(self):
|
||||
self.array_insts = []
|
||||
self.pmos_insts = []
|
||||
self.tap_insts = []
|
||||
for col in range(self.cols):
|
||||
|
||||
|
||||
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 place_instances(self):
|
||||
self.add_label("ZERO", self.route_layer)
|
||||
|
||||
self.array_pos = []
|
||||
strap_num = 0
|
||||
cell_y = 0
|
||||
# columns are bit lines4
|
||||
cell_x = 0
|
||||
print("starting array place")
|
||||
|
||||
for col in range(self.cols):
|
||||
|
||||
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))
|
||||
cell_x += self.pmos.width
|
||||
|
||||
|
||||
def create_layout_pins(self):
|
||||
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 extend_implant(self):
|
||||
layer = "nwell"
|
||||
# center of source contact minus radius of the well generated by the contact gives the lowermost well position
|
||||
contact_well_by = self.pmos.pmos.source_contacts[0].cx() - self.pmos.pmos.source_contacts[0].mod.well_width * 0.5
|
||||
|
||||
ptx_well_by = 0.5 * self.pmos.pmos.active_width - 0.5 * self.pmos.pmos.well_width
|
||||
|
||||
well_extend = ptx_well_by - contact_well_by
|
||||
|
||||
|
||||
self.well_ll = vector(0, min(contact_well_by, ptx_well_by))
|
||||
|
||||
height = self.pmos.pmos.active_width + 2 * self.well_enclose_active
|
||||
self.add_rect(layer, self.well_ll, self.width + well_extend, height + 2 * well_extend)
|
||||
|
||||
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, -1.5*spacing)
|
||||
end = vector(end_pin, -1.5*spacing)
|
||||
|
||||
self.vdd = self.add_layout_pin_segment_center("vdd", "m1", start, end)
|
||||
|
||||
for i in range(self.cols):
|
||||
start = self.pmos_insts[i].get_pin("S").center()
|
||||
end = vector(start.x, self.vdd.cy())
|
||||
|
||||
self.add_segment_center(self.route_layer, start, end)
|
||||
self.add_via_stack_center(end, self.route_layer, "m1")
|
||||
|
||||
|
||||
# connect nwell tap to vdd
|
||||
|
||||
start = end
|
||||
end = vector(self.nwell_contact.cx(), start.y)
|
||||
self.add_segment_center(self.route_layer, start, end)
|
||||
|
||||
start = end - vector(0, 0.5 * self.mcon_width)
|
||||
end = self.nwell_contact.center()
|
||||
self.add_segment_center(self.route_layer, start, end)
|
||||
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
# 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.
|
||||
#
|
||||
|
||||
from base import design
|
||||
from base import vector
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
|
||||
from tech import drc
|
||||
|
||||
|
||||
class rom_precharge_cell(design):
|
||||
|
||||
def __init__(self, name="", cell_name=None, route_layer="m1"):
|
||||
|
||||
super().__init__(name, cell_name)
|
||||
self.route_layer = route_layer
|
||||
self.create_netlist()
|
||||
self.create_layout()
|
||||
|
||||
#self.route_layer= route_layer
|
||||
#self.create_netlist()
|
||||
#self.create_layout()
|
||||
|
||||
|
||||
def create_netlist(self):
|
||||
self.add_pins()
|
||||
self.add_pmos()
|
||||
self.create_pmos()
|
||||
|
||||
|
||||
def create_layout(self):
|
||||
self.setup_layout_constants()
|
||||
self.place_pmos()
|
||||
self.add_boundary()
|
||||
|
||||
|
||||
def add_pmos(self):
|
||||
|
||||
self.pmos = factory.create(module_type="ptx",
|
||||
module_name="pre_pmos_mod",
|
||||
tx_type="pmos"
|
||||
)
|
||||
|
||||
def create_pmos(self):
|
||||
self.cell_inst = self.add_inst( name="precharge_pmos",
|
||||
mod=self.pmos,
|
||||
)
|
||||
self.connect_inst(["bitline", "gate", "vdd", "vdd"])
|
||||
|
||||
|
||||
def add_pins(self):
|
||||
pin_list = ["vdd", "gate", "bitline", "vdd"]
|
||||
dir_list = ["OUTPUT", "INPUT", "OUTPUT", "POWER"]
|
||||
|
||||
self.add_pin_list(pin_list, dir_list)
|
||||
|
||||
def setup_layout_constants(self):
|
||||
|
||||
#pmos contact to gate distance
|
||||
self.contact_to_gate = 0.5 * (self.pmos.width - 2 * self.pmos.contact_width - self.pmos.poly_width - 2 * self.active_enclose_contact)
|
||||
|
||||
#height offset to account for active-to-active spacing between adjacent bitlines
|
||||
self.poly_extend_active_spacing = abs( 2 * self.pmos.poly_extend_active - drc("active_to_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
|
||||
|
||||
# width offset to account for poly-active spacing between base and dummy cells on the same bitline
|
||||
self.poly_active_offset = 0.5 * (self.base_width - (self.poly_width + 2 * self.active_enclose_contact + self.pmos.contact_width)) - self.poly_to_active
|
||||
|
||||
#so that the poly taps are far enough apart
|
||||
self.poly_tap_offset = (self.base_width - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly")
|
||||
|
||||
|
||||
def place_pmos(self):
|
||||
|
||||
poly_offset = vector(self.poly_extend_active_spacing * 0.5 + self.pmos.height + 2 * self.poly_extend_active, 0.5 * self.pmos.width)
|
||||
|
||||
# pmos_offset = vector(self.pmos.poly_extend_active, - 0.5 * self.pmos.contact_width - self.active_enclose_contact)
|
||||
|
||||
# pmos_offset = vector(-self.pmos.poly_extend_active - self.poly_extend_active_spacing, 0)
|
||||
pmos_offset = vector(self.pmos.poly_extend_active + self.pmos.height, 0)
|
||||
# add rect of poly to account for offset from drc spacing
|
||||
self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.pmos.poly_width )
|
||||
|
||||
self.cell_inst.place(pmos_offset, rotate=90)
|
||||
# self.add_label("CELL ZERO", self.route_layer)
|
||||
self.add_label("inst_zero", self.route_layer)
|
||||
self.add_layout_pin_rect_center("S", self.route_layer, self.cell_inst.get_pin("S").center())
|
||||
self.add_layout_pin_rect_center("D", self.route_layer, self.cell_inst.get_pin("D").center())
|
||||
|
||||
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()
|
||||
|
||||
|
|
@ -29,7 +29,6 @@ class rom_array_test(openram_test):
|
|||
|
||||
a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4)
|
||||
self.local_check(a)
|
||||
|
||||
globals.end_openram()
|
||||
|
||||
# run the test from the command line
|
||||
|
|
|
|||
|
|
@ -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 globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
|
||||
class rom_bank_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
|
||||
debug.info(2, "Testing 4x4 array for rom cell")
|
||||
|
||||
a = factory.create(module_type="rom_base_bank", strap_spacing = 2)
|
||||
|
||||
self.local_check(a)
|
||||
globals.end_openram()
|
||||
|
||||
# run the test from the command line
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
del sys.argv[1:]
|
||||
header(__file__, OPTS.tech_name)
|
||||
unittest.main(testRunner=debugTestRunner())
|
||||
|
|
@ -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 globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
|
||||
class rom_decoder_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
|
||||
debug.info(2, "Testing 2x4 decoder for rom cell")
|
||||
|
||||
|
||||
a = factory.create(module_type="rom_decoder", num_outputs=8, strap_spacing=2)
|
||||
self.local_check(a)
|
||||
globals.end_openram()
|
||||
|
||||
# run the test from the command line
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
del sys.argv[1:]
|
||||
header(__file__, OPTS.tech_name)
|
||||
unittest.main(testRunner=debugTestRunner())
|
||||
|
|
@ -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 globals
|
||||
from globals import OPTS
|
||||
from sram_factory import factory
|
||||
import debug
|
||||
|
||||
|
||||
class rom_precharge_test(openram_test):
|
||||
|
||||
def runTest(self):
|
||||
config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME"))
|
||||
globals.init_openram(config_file)
|
||||
|
||||
debug.info(2, "Testing precharge array for rom cell")
|
||||
|
||||
|
||||
a = factory.create(module_type="rom_precharge_array", cols=4, strap_spacing=2)
|
||||
self.local_check(a)
|
||||
globals.end_openram()
|
||||
|
||||
# run the test from the command line
|
||||
if __name__ == "__main__":
|
||||
(OPTS, args) = globals.parse_args()
|
||||
del sys.argv[1:]
|
||||
header(__file__, OPTS.tech_name)
|
||||
unittest.main(testRunner=debugTestRunner())
|
||||
Loading…
Reference in New Issue