add top level pins for sim

This commit is contained in:
Jacob Walker 2023-02-01 14:49:59 -08:00
parent 81bf2d7ae7
commit 736bd51fe1
11 changed files with 161 additions and 124 deletions

View File

@ -266,7 +266,7 @@ class rom_base_array(bitcell_base_array):
self.cell_pos[row, col] = vector(cell_x, cell_y)
self.cell_inst[row, col].place(self.cell_pos[row, col])
cell_x += self.zero_cell.width
self.add_label("debug", "li", self.cell_pos[row, col])
# self.add_label("debug", "li", self.cell_pos[row, col])
self.strap_pos[row, self.column_size] = vector(cell_x, cell_y)
@ -326,7 +326,7 @@ class rom_base_array(bitcell_base_array):
def place_precharge(self):
self.precharge_offset = vector(0, - self.precharge_inst.height - self.zero_cell.nmos.end_to_contact - 2 * drc["nwell_enclose_active"])
self.precharge_offset = vector(0, - self.precharge_inst.height - self.zero_cell.nmos.end_to_contact - 2 * drc["nwell_enclose_active"] - 3 * self.m1_pitch)
self.precharge_inst.place(offset=self.precharge_offset)

View File

@ -2,7 +2,7 @@
from math import ceil, log, sqrt
from openram.base import vector
from openram.base import design
from openram import OPTS
from openram import OPTS, debug
from openram.sram_factory import factory
from openram.tech import drc, layer
@ -14,8 +14,8 @@ class rom_base_bank(design):
word size is in bytes
"""
def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2) -> None:
def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2):
super().__init__(name=name)
self.word_size = word_size * 8
self.read_binary(word_size=word_size, data_file=data_file)
@ -31,7 +31,7 @@ class rom_base_bank(design):
self.bitline_layer = "m1"
self.wordline_layer = "m2"
super().__init__(name=name)
if "li" in layer:
self.route_stack = self.m1_stack
else:
@ -39,6 +39,7 @@ class rom_base_bank(design):
self.route_layer = self.route_stack[0]
self.setup_layout_constants()
self.create_netlist()
if not OPTS.netlist_only:
self.create_layout()
"""
Reads a hexadecimal file from a given directory to be used as the data written to the ROM
@ -48,10 +49,17 @@ class rom_base_bank(design):
"""
def read_binary(self, data_file, word_size=2, endian="big"):
# Read data as hexidecimal text file
hex_file = open(data_file, 'r')
hex_data = hex_file.read()
bin_data = list("{0:08b}".format(int(hex_data, 16)))
# Convert from hex into an int
data_int = int(hex_data, 16)
# Then from int into a right aligned, zero padded string
bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4)
# Then turn the string into a list of ints
bin_data = list(bin_string)
bin_data = [int(x) for x in bin_data]
# data size in bytes
@ -78,17 +86,20 @@ class rom_base_bank(design):
self.data = chunked_data
self.cols = bits_per_row
self.rows = int(num_words / (self.words_per_row))
debug.info(1, "Read rom binary: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, num_words, self.cols, self.rows, 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.add_pins()
print("Creating ROM bank instances")
self.create_instances()
def create_layout(self):
print("Creating ROM bank instances")
self.create_instances()
print("Placing ROM bank instances")
self.place_instances()
@ -101,13 +112,12 @@ class rom_base_bank(design):
print("Routing clock signal")
self.route_clock()
self.route_array_outputs()
# self.route_supplies()
self.place_top_level_pins()
self.route_supplies()
self.height = self.array_inst.height
self.width = self.array_inst.width
self.add_boundary()
print("Rom bank placement complete")
def setup_layout_constants(self):
self.route_layer_width = drc["minwidth_{}".format(self.route_stack[0])]
@ -121,11 +131,11 @@ class rom_base_bank(design):
self.add_pin("clk", "INPUT")
self.add_pin("CS", "INPUT")
for i in range(self.num_inputs):
for i in range(self.row_bits + self.col_bits):
self.add_pin("addr_{}".format(i), "INPUT")
out_pins = []
for j in range(self.rows):
for j in range(self.word_size):
out_pins.append("rom_out_{}".format(j))
self.add_pin_list(out_pins, "OUTPUT")
@ -155,12 +165,12 @@ class rom_base_bank(design):
cols=self.cols)
self.column_mux = factory.create(module_type="rom_column_mux_array",
columns=self.cols,
word_size=self.word_size,
bitline_layer=self.interconnect_layer)
tap_spacing=self.strap_spacing,
bitline_layer=self.interconnect_layer,
input_layer=self.bitline_layer)
self.column_decode = factory.create(module_name="rom_column_decode",
module_type="rom_decoder",
@ -175,53 +185,35 @@ class rom_base_bank(design):
clk_fanout=(self.col_bits + self.row_bits) * 2,
height=self.column_decode.height )
print("Col decode height of {}".format(self.column_decode.height))
def create_instances(self):
gnd = ["gnd"]
vdd = ["vdd"]
prechrg = ["precharge"]
clk = ["clk_int"]
array_pins = []
decode_pins = []
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("precharge")
array_pins.append("vdd")
array_pins.append("gnd")
for addr in range(self.row_bits):
name = "row_addr_{}".format(addr)
decode_pins.append(name)
for wl in range(self.rows):
name = "wl_{}".format(wl)
decode_pins.append(name)
decode_pins.append("precharge")
decode_pins.append("clk_int")
decode_pins.append("vdd")
decode_pins.append("gnd")
bitlines = ["bl_{}".format(bl) for bl in range(self.cols)]
select_lines = ["word_sel_{}".format(word) for word in range(self.words_per_row)]
bitline_out = ["rom_out_{}".format(bl) for bl in range(self.word_size)]
addr_lsb = ["col_addr_{}".format(addr) for addr in range(self.col_bits)]
col_mux_pins = bitlines + select_lines + bitline_out + gnd
wordlines = ["wl_{}".format(wl) for wl in range(self.rows)]
addr_msb = ["addr_{}".format(addr + self.col_bits) for addr in range(self.row_bits)]
addr_lsb = ["addr_{}".format(addr) for addr in range(self.col_bits)]
select_lines = ["word_sel_{}".format(word) for word in range(self.words_per_row)]
outputs = ["rom_out_{}".format(bl) for bl in range(self.word_size)]
array_pins = bitlines + wordlines + prechrg + vdd + gnd
row_decode_pins = addr_msb + wordlines + prechrg + clk + vdd + gnd
col_decode_pins = addr_lsb + select_lines + prechrg + clk + vdd + gnd
col_mux_pins = bitlines + select_lines + outputs + 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_row_decoder", mod=self.decode_array)
self.connect_inst(decode_pins)
self.connect_inst(row_decode_pins)
self.control_inst = self.add_inst(name="rom_control", mod=self.control_logic)
self.connect_inst(["clk", "CS", "precharge", "clk_int", "vdd", "gnd"])
@ -269,7 +261,7 @@ class rom_base_bank(design):
self.col_decode_inst.place(offset=self.col_decode_offset)
def place_col_mux(self):
mux_y_offset = self.array_inst.by() - self.mux_inst.height - self.route_layer_pitch
mux_y_offset = self.array_inst.by() - self.mux_inst.height - 5 * self.route_layer_pitch
mux_x_offset = self.array_inst.get_pin("bl_0_0").cx() - self.mux_inst.get_pin("bl_0").cx()
self.mux_offset = vector(mux_x_offset, mux_y_offset)
@ -298,7 +290,7 @@ class rom_base_bank(design):
col_decode_pins = [self.col_decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.words_per_row)]
sel_pins = [self.mux_inst.get_pin("sel_{}".format(wl)) for wl in range(self.words_per_row)]
sel_pins.extend(col_decode_pins)
self.connect_row_pins(self.array.bitline_layer, sel_pins, round=True)
self.connect_row_pins(self.wordline_layer, sel_pins, round=True)
@ -391,34 +383,49 @@ class rom_base_bank(design):
self.add_path(self.array.bitline_layer, [bl_out, bl_mux])
def place_top_level_pins(self):
self.copy_layout_pin(self.control_inst, "CS", "CS")
for i in range(self.word_size):
self.copy_layout_pin(self.mux_inst, "bl_out_{}".format(i), "rom_out_{}".format(i))
for lsb in range(self.col_bits):
name = "addr_{}".format(lsb)
self.copy_layout_pin(self.col_decode_inst, "A{}".format(lsb), name)
for msb in range(self.col_bits, self.row_bits + self.col_bits):
name = "addr_{}".format(msb)
pin_num = msb - self.col_bits
self.copy_layout_pin(self.decode_inst, "A{}".format(pin_num), name)
def route_supplies(self):
for inst in self.insts:
if not inst.mod.name.__contains__("contact"):
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0)
# gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0)
decode_gnd = self.decode_inst.get_pin("gnd")
decode_vdd = self.decode_inst.get_pin("vdd")
array_vdd = self.array_inst.get_pin("vdd")
# 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())
# 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)
# 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)
# 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)
# vdd_start = vector(decode_vdd.cx(), vdd_start.y)
self.add_segment_center(self.interconnect_layer, vdd_start, decode_vdd.center())
# self.add_segment_center(self.interconnect_layer, vdd_start, decode_vdd.center())

View File

@ -80,7 +80,7 @@ class rom_base_cell(design):
# 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))
# print("height: {0} width: {1}".format(height, width))
if width > height:
self.width = width
self.height = width

View File

@ -57,19 +57,13 @@ class rom_column_mux(pgate):
self.place_ptx()
# cell = factory.create(module_type=OPTS.bitcell)
# if(cell_props.use_strap == True and OPTS.num_ports == 1):
# strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version)
# precharge_width = cell.width + strap.width
# else:
# precharge_width = cell.width
self.width = self.bitcell.width
self.height = self.nmos_lower.uy() + self.pin_height
self.connect_poly()
self.add_bitline_pins()
self.connect_bitlines()
# self.add_pn_wells()
self.add_pn_wells()
def add_ptx(self):
self.bitcell = factory.create(module_type="rom_base_cell")
@ -107,7 +101,7 @@ class rom_column_mux(pgate):
def place_ptx(self):
""" Create the two pass gate NMOS transistors to switch the bitlines"""
""" Create the pass gate NMOS transistor to switch the bitline """
# Space it in the center
nmos_lower_position = self.nmos.active_offset.scale(0, 1) \
@ -148,7 +142,9 @@ class rom_column_mux(pgate):
nmos_lower_s_pin = self.nmos_lower.get_pin("S")
nmos_lower_d_pin = self.nmos_lower.get_pin("D")
self.add_via_stack_center(from_layer=nmos_lower_s_pin.layer,
to_layer=self.input_layer,
offset=nmos_lower_s_pin.center())
self.add_via_stack_center(from_layer=nmos_lower_d_pin.layer,
to_layer=self.output_layer,
@ -160,14 +156,14 @@ class rom_column_mux(pgate):
+ nmos_lower_s_pin.uc().scale(0, 0.5)
mid2 = bl_pin.bc().scale(0, 0.4) \
+ nmos_lower_s_pin.uc().scale(1, 0.5)
self.add_path(self.col_mux_stack[2],
self.add_path(self.input_layer,
[bl_pin.bc(), mid1, mid2, nmos_lower_s_pin.center()])
# halfway up, move over
mid1 = bl_out_pin.uc().scale(1, 0.4) \
+ nmos_lower_d_pin.bc().scale(0, 0.4)
mid2 = bl_out_pin.uc().scale(0, 0.4) \
+ nmos_lower_d_pin.bc().scale(1, 0.4)
self.add_path(self.col_mux_stack[0],
self.add_path(self.output_layer,
[bl_out_pin.uc(), mid1, mid2, nmos_lower_d_pin.center()])
@ -197,7 +193,7 @@ class rom_column_mux(pgate):
# rbc_width = self.bitcell.width
# Add it to the right, aligned in between the two tx
active_pos = vector(self.bitcell.width,
self.nmos_upper.by() - 0.5 * self.poly_space)
self.nmos_lower.uy() + self.active_contact.height + self.active_space)
self.add_via_center(layers=self.active_stack,
offset=active_pos,
@ -205,16 +201,17 @@ class rom_column_mux(pgate):
well_type="p")
# If there is a li layer, include it in the power stack
self.add_via_center(layers=self.col_mux_stack,
self.add_via_stack_center(from_layer=self.active_stack[2],
to_layer=self.supply_stack[0],
offset=active_pos)
self.add_layout_pin_rect_center(text="gnd",
layer="m1",
layer=self.supply_stack[0],
offset=active_pos)
# Add well enclosure over all the tx and contact
if "pwell" in layer:
self.add_rect(layer="pwell",
offset=vector(0, 0),
width=rbc_width,
height=self.height)
# if "pwell" in layer:
# self.add_rect(layer="pwell",
# offset=vector(0, 0),
# width=rbc_width,
# height=self.height)

View File

@ -20,7 +20,7 @@ class rom_column_mux_array(design):
Array of column mux to read the bitlines from ROM, based on the RAM column mux
"""
def __init__(self, name, columns, word_size, input_layer="m2", bitline_layer="m1", sel_layer="m2"):
def __init__(self, name, columns, word_size, tap_spacing=4, input_layer="m2", bitline_layer="m1", sel_layer="m2"):
super().__init__(name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("cols: {0} word_size: {1} ".format(columns, word_size))
@ -29,6 +29,7 @@ class rom_column_mux_array(design):
self.word_size = word_size
self.words_per_row = int(self.columns / self.word_size)
self.input_layer = input_layer
self.tap_spacing = tap_spacing
# self.sel_layer = layer_props.column_mux_array.select_layer
self.sel_layer = sel_layer
@ -44,14 +45,6 @@ class rom_column_mux_array(design):
if not OPTS.netlist_only:
self.create_layout()
def get_bl_name(self):
bl_name = self.mux.get_bl_names()
return bl_name
def get_br_name(self, port=0):
br_name = self.mux.get_br_names()
return br_name
def create_netlist(self):
self.add_modules()
self.add_pins()
@ -61,12 +54,14 @@ class rom_column_mux_array(design):
self.setup_layout_constants()
self.place_array()
self.add_routing()
# Find the highest shapes to determine height before adding well
highest = self.find_highest_coords()
self.height = highest.y
self.add_layout_pins()
if "pwell" in layer:
self.add_enclosure(self.mux_inst, "pwell")
self.add_boundary()
self.DRC_LVS()
@ -80,8 +75,8 @@ class rom_column_mux_array(design):
self.add_pin("gnd")
def add_modules(self):
self.mux = factory.create(module_type="rom_column_mux")
self.mux = factory.create(module_type="rom_column_mux", input_layer=self.input_layer, output_layer=self.bitline_layer)
self.tap = factory.create(module_type="rom_poly_tap", add_tap=True)
self.cell = factory.create(module_type="rom_base_cell")
def setup_layout_constants(self):
@ -145,8 +140,12 @@ class rom_column_mux_array(design):
def add_horizontal_input_rail(self):
""" Create address input rails below the mux transistors """
tap_offset = 0
for j in range(self.words_per_row):
offset = vector(0, self.route_height + (j - self.words_per_row) * self.cell.width)
if j % self.tap_spacing == 0 and j != 0:
tap_offset += self.tap.pitch_offset
offset = vector(0, self.route_height + tap_offset + (j - self.words_per_row) * self.cell.width)
self.add_layout_pin(text="sel_{}".format(j),
layer=self.sel_layer,
offset=offset,
@ -208,6 +207,9 @@ class rom_column_mux_array(design):
directions=self.via_directions)
def add_taps(self):
pass
def graph_exclude_columns(self, column_include_num):
"""

View File

@ -19,11 +19,9 @@ class rom_control_logic(design):
self.height = height
if self.height is not None:
print("got height of {}".format(self.height))
self.driver_height = 0.6 * self.height
self.gate_height = 0.2 * self.height
self.driver_height = 0.5 * self.height
self.gate_height = 0.25 * self.height
else:
print("got none height")
self.gate_height = 20 * self.m1_pitch
self.driver_height = self.gate_height
@ -98,12 +96,11 @@ class rom_control_logic(design):
def route_insts(self):
route_width = drc["minwidth_{}".format(self.route_stack[2])]
self.copy_layout_pin(self.buf_inst, "A", "clk_in")
self.copy_layout_pin(self.buf_inst, "Zb", "clkb_out")
self.copy_layout_pin(self.buf_inst, "Z", "clk_out")
self.copy_layout_pin(self.driver_inst, "Z", "prechrg")
self.copy_layout_pin(self.nand_inst, "B", "CS")
self.copy_layout_pin(self.nand_inst, "A", "CS")
self.copy_layout_pin(self.buf_inst, "gnd")
self.copy_layout_pin(self.driver_inst, "vdd")
self.copy_layout_pin(self.buf_inst, "vdd")

View File

@ -112,17 +112,17 @@ class rom_decoder(design):
cols=self.num_inputs)
self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), \
rows=self.num_outputs, \
cols=self.cols,
self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name),
rows=self.num_outputs,
cols=ceil(self.cols * 0.5),
invert_outputs=self.invert_outputs,
tap_spacing=self.strap_spacing)
self.array_mod = factory.create(module_type="rom_base_array", \
module_name="{}_array".format(self.name), \
cols=self.num_outputs, \
rows=2 * self.num_inputs, \
self.array_mod = factory.create(module_type="rom_base_array",
module_name="{}_array".format(self.name),
cols=self.num_outputs,
rows=2 * self.num_inputs,
bitmap=self.decode_map,
strap_spacing = self.strap_spacing,
bitline_layer=self.output_layer,

View File

@ -109,7 +109,7 @@ class rom_precharge_array(design):
def create_precharge_tx(self, col):
name = "Xpmos_c{0}".format(col)
name = "pmos_c{0}".format(col)
pmos = self.add_inst(name=name, mod=self.pmos)
self.array_insts.append(pmos)
self.pmos_insts.append(pmos)

View File

@ -88,7 +88,6 @@ class rom_wordline_driver_array(design):
"""
if layer_props.wordline_driver.vertical_supply:
print("copied")
# self.route_vertical_pins("vdd", self.wld_inst)
# self.route_vertical_pins("gnd", self.wld_inst)
self.route_vertical_pins("vdd", [self], layer=self.supply_layer)

View File

@ -13,7 +13,7 @@ import sys, os
import openram
from openram import OPTS
from openram.sram_factory import factory
import debug
from openram import debug
class rom_bank_test(openram_test):
@ -21,8 +21,7 @@ class rom_bank_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 4x4 array for rom cell")
debug.info(1, "Testing 1kB rom cell")
a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_1kB", word_size=1)

View File

@ -0,0 +1,36 @@
#!/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_bank_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(1, "Testing 32 byte rom cell")
a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_64B", word_size=1)
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())