Changes for test generation and simulation

This commit is contained in:
Jacob Walker 2023-02-27 14:48:10 -08:00
parent 89c7d50bd1
commit bbf2cd2913
12 changed files with 363 additions and 178 deletions

View File

@ -787,13 +787,15 @@ class layout():
end=bot_pos)
def connect_col_pins(self, layer, pins, name=None, full=False):
def connect_col_pins(self, layer, pins, name=None, full=False, round=False, directions="pref"):
"""
Connects top/bot columns that are aligned.
"""
bins = {}
for pin in pins:
x = pin.cx()
if round:
x = round_to_grid(x)
try:
bins[x].append(pin)
except KeyError:
@ -819,7 +821,8 @@ class layout():
self.add_via_stack_center(from_layer=pin.layer,
to_layer=layer,
offset=pin.center(),
min_area=True)
min_area=True,
directions=directions)
if name:
self.add_layout_pin_segment_center(text=name,

View File

@ -20,7 +20,7 @@ class pinv_dec(pinv):
Other stuff is the same (netlist, sizes, etc.)
"""
def __init__(self, name, size=1, beta=parameter["beta"], height=None, add_wells=True):
def __init__(self, name, size=1, beta=parameter["beta"], height=None, add_wells=True, flip_io=False):
debug.info(2,
"creating pinv_dec structure {0} with size of {1}".format(name,
@ -37,7 +37,7 @@ class pinv_dec(pinv):
self.supply_layer = "m1"
else:
self.supply_layer = "m2"
self.flip_io=flip_io
super().__init__(name, size, beta, self.cell_height, add_wells)
def determine_tx_mults(self):
@ -76,9 +76,14 @@ class pinv_dec(pinv):
pmos_gate_pos = pmos_gate_pin.lc()
self.add_path("poly", [nmos_gate_pos, pmos_gate_pos])
# Center is completely symmetric.
contact_width = self.poly_contact.width
contact_offset = nmos_gate_pin.lc() \
if self.flip_io:
contact_offset = pmos_gate_pin.rc() \
+ vector(self.poly_extend_active + 0.6 * contact_width, 0)
else:
contact_offset = nmos_gate_pin.lc() \
- vector(self.poly_extend_active + 0.5 * contact_width, 0)
via = self.add_via_stack_center(from_layer="poly",
to_layer=self.route_layer,
@ -107,8 +112,11 @@ class pinv_dec(pinv):
height=self.height - ll.y + 0.5 * self.pwell_contact.height + self.well_enclose_active)
if "nwell" in layer:
ll = (self.pmos_inst.ll() - vector(2 * [self.well_enclose_active])).scale(1, 0)
ur = self.pmos_inst.ur() + vector(2 * [self.well_enclose_active])
poly_offset = 0
if self.flip_io:
poly_offset = 1.2 * self.poly_contact.width
ll = (self.pmos_inst.ll() - vector(2 * [self.well_enclose_active])).scale(1, 0) - vector(0, poly_offset)
ur = self.pmos_inst.ur() + vector(2 * [self.well_enclose_active + poly_offset])
self.add_rect(layer="nwell",
offset=ll,
width=ur.x - ll.x,

View File

@ -1,39 +0,0 @@
from openram.base import design
from openram.base import vector
from openram.sram_factory import factory
class rom_array_gnd_tap(design):
def __init__(self, name, length, cell_name=None, prop=None):
super().__init__(name, cell_name, prop)
self.length = length
self.create_layout()
def create_layout(self):
self.add_cell()
self.add_boundary()
self.place_gnd_rail()
def add_boundary(self):
self.height = self.dummy.height
self.width = self.dummy.width
super().add_boundary()
def add_cell(self):
self.dummy = factory.create(module_type="rom_dummy_cell")
def place_gnd_rail(self):
rail_start = vector(-self.dummy.width / 2 ,0)
rail_end = vector(self.dummy.width * self.length, 0)
self.add_layout_pin_rect_ends( name="gnd",
layer="m1",
start=rail_start,
end=rail_end)

View File

@ -58,16 +58,17 @@ class rom_base_array(bitcell_base_array):
self.place_precharge()
self.place_wordline_contacts()
self.place_bitline_contacts()
self.add_boundary()
self.route_precharge()
self.add_boundary()
self.place_rails()
self.connect_taps()
def add_boundary(self):
ll = self.find_lowest_coords()
bottom_offset = - self.zero_cell.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()
@ -209,7 +210,7 @@ class rom_base_array(bitcell_base_array):
prechrg_pins.append("precharge")
prechrg_pins.append("vdd")
self.precharge_inst = self.add_inst(name="decode_array_precharge", mod=self.precharge_array)
self.precharge_inst = self.add_inst(name="bitcell_array_precharge", mod=self.precharge_array)
self.connect_inst(prechrg_pins)
@ -390,6 +391,9 @@ class rom_base_array(bitcell_base_array):
self.add_path(layer="m1", coordinates=[start, mid1, mid2, end])
self.add_layout_pin_rect_center(text="precharge_r", layer="m1", offset=mid1)
def connect_taps(self):
array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))]

View File

@ -17,7 +17,7 @@ class rom_base_bank(design):
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)
self.read_binary(word_size=word_size, data_file=data_file, scramble_bits=True, endian="little")
self.num_outputs = self.rows
self.num_inputs = ceil(log(self.rows, 2))
@ -48,7 +48,7 @@ class rom_base_bank(design):
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"):
def read_binary(self, data_file, word_size=2, endian="big", scramble_bits=False):
# Read data as hexidecimal text file
hex_file = open(data_file, 'r')
hex_data = hex_file.read()
@ -72,25 +72,56 @@ class rom_base_bank(design):
bits_per_row = self.words_per_row * word_size * 8
self.cols = bits_per_row
self.rows = int(num_words / (self.words_per_row))
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()
row_data = bin_data[i:i + bits_per_row]
if len(row_data) < bits_per_row:
row_data = [0] * (bits_per_row - len(row_data)) + row_data
chunked_data.append(row_data)
# if endian == "big":
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))
if scramble_bits:
scrambled_chunked = []
for row_data in chunked_data:
scambled_data = []
for bit in range(self.word_size):
for word in range(self.words_per_row):
scambled_data.append(row_data[bit + word * self.word_size])
scrambled_chunked.append(scambled_data)
self.data = scrambled_chunked
# self.data.reverse()
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))
# self.print_data(chunked_data)
# print("Scrambled")
# self.print_data(scrambled_chunked)
# self.print_word(self.data, 0, 0)
# self.print_word(self.data, 0, 1)
# self.print_word(self.data, 0, 2)
# self.print_word(self.data, 0, 3)
# print("hex: {0}, binary: {1}, chunked: {2}".format(hex_data, bin_data, chunked_data))
def print_data(self, data_array):
for row in range(len(data_array)):
print(data_array[row])
def print_word(self, data_array, bl, word):
for bit in range(self.word_size):
print(data_array[bl][word + self.words_per_row * bit], end =" ")
print("")
def create_netlist(self):
self.add_modules()
self.add_pins()
@ -147,6 +178,20 @@ class rom_base_bank(design):
def add_modules(self):
print("Creating bank modules")
# TODO: provide technology-specific calculation of these parameters
# in sky130 the address control buffer is composed of 2 size 2 NAND gates,
# with a beta of 3, each of these gates has gate capacitance of 2 min sized inverters, therefor a load of 4
addr_control_buffer_effort = 4
# a single min sized nmos makes up 1/4 of the input capacitance of a min sized inverter
bitcell_effort = 0.25
# Takes into account inverter sizing
wordline_effort = bitcell_effort * 0.5
# a single min sized pmos plus a single min sized nmos have approximately half the gate capacitance of a min inverter
# an additional 0.2 accounts for the long wire capacitance and add delay to gaurentee the read timing
precharge_cell_effort = 0.5 + 0.2
self.array = factory.create(module_type="rom_base_array",
cols=self.cols,
rows=self.rows,
@ -163,7 +208,7 @@ class rom_base_bank(design):
num_outputs=self.rows,
strap_spacing=self.strap_spacing,
route_layer=self.route_layer,
cols=self.cols)
fanout=(self.cols)*wordline_effort )
self.column_mux = factory.create(module_type="rom_column_mux_array",
@ -178,18 +223,27 @@ class rom_base_bank(design):
num_outputs=self.words_per_row,
strap_spacing=self.strap_spacing,
route_layer=self.route_layer,
cols=1,
fanout=2,
invert_outputs=True )
self.control_logic = factory.create(module_type="rom_control_logic",
num_outputs=(self.rows + self.cols + self.words_per_row) * 0.5,
clk_fanout=(self.col_bits + self.row_bits) * 2,
num_outputs=(self.cols + self.words_per_row * precharge_cell_effort) \
+ (addr_control_buffer_effort * self.col_bits),
clk_fanout=(self.row_bits * addr_control_buffer_effort) + (precharge_cell_effort * self.rows),
height=self.column_decode.height )
self.output_buffer = factory.create(module_type="rom_wordline_driver_array",
self.bitline_inv = factory.create(module_type="rom_wordline_driver_array",
module_name="rom_bitline_inverter",
rows=self.cols,
fanout=4,
invert_outputs=True,
tap_spacing=0,
flip_io=True)
self.output_inv = factory.create(module_type="rom_wordline_driver_array",
module_name="rom_output_buffer",
rows=self.word_size,
cols=4)
fanout=4,
invert_outputs=True)
def create_instances(self):
@ -206,18 +260,21 @@ class rom_base_bank(design):
select_lines = ["word_sel_{}".format(word) for word in range(self.words_per_row)]
bitline_bar = ["bl_b_{}".format(bl) for bl in range(self.cols)]
pre_buf_outputs = ["rom_out_prebuf_{}".format(bit) for bit in range(self.word_size)]
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
row_decode_pins = addr_msb + wordlines + clk + clk + vdd + gnd
col_decode_pins = addr_lsb + select_lines + prechrg + prechrg + vdd + gnd
col_mux_pins = bitlines + select_lines + pre_buf_outputs + gnd
col_mux_pins = bitline_bar + select_lines + pre_buf_outputs + gnd
output_buffer_pins = pre_buf_outputs + outputs + vdd + gnd
bitline_inv_pins = bitlines + bitline_bar + vdd + gnd
output_buf_pins = pre_buf_outputs + outputs + vdd + gnd
self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array)
self.connect_inst(array_pins)
@ -234,14 +291,19 @@ class rom_base_bank(design):
self.col_decode_inst = self.add_inst(name="rom_column_decoder", mod=self.column_decode)
self.connect_inst(col_decode_pins)
self.output_buf_inst = self.add_inst(name="rom_output_buffer", mod=self.output_buffer)
self.connect_inst(output_buffer_pins)
self.bitline_inv_inst = self.add_inst(name="rom_bitline_inverter", mod=self.bitline_inv)
self.connect_inst(bitline_inv_pins)
self.output_inv_inst = self.add_inst(name="rom_output_inverter", mod=self.output_inv)
self.connect_inst(output_buf_pins)
def place_instances(self):
self.place_row_decoder()
self.place_data_array()
self.place_bitline_inverter()
self.place_col_mux()
self.place_col_decoder()
self.place_control_logic()
@ -249,7 +311,7 @@ class rom_base_bank(design):
def place_row_decoder(self):
self.decode_offset = vector(0, self.control_inst.height - self.decode_array.control_array.height)
self.decode_offset = vector(0, self.control_inst.height )
self.decode_inst.place(offset=self.decode_offset)
def place_data_array(self):
@ -263,11 +325,18 @@ class rom_base_bank(design):
array_align = self.decode_inst.get_pin("wl_0").cy() - self.array_inst.get_pin("wl_0_0").cy()
self.array_inst.place(offset=(self.array_offset + vector(0, array_align)))
def place_bitline_inverter(self):
self.bitline_inv_inst.place(offset=[0,0], rotate=90)
inv_y_offset = self.array_inst.by() - self.bitline_inv_inst.width - 2 * self.m1_pitch
inv_x_offset = self.array_inst.get_pin("bl_0_0").cx() - self.bitline_inv_inst.get_pin("out_0").cx()
self.inv_offset = vector(inv_x_offset, inv_y_offset)
self.bitline_inv_inst.place(offset=self.inv_offset, rotate=90)
def place_control_logic(self):
self.control_offset = vector(self.control_inst.width + self.decode_array.control_array.width + 2 * (self.route_layer_pitch + self.route_layer_width), self.col_decode_inst.by() + self.control_logic.height)
self.control_inst.place(offset=self.control_offset, mirror="XY")
self.control_offset = vector(self.col_decode_inst.lx() - self.control_inst.width - 3 * self.m1_pitch, self.decode_inst.by() - self.control_logic.height - self.m1_pitch)
self.control_inst.place(offset=self.control_offset)
def place_col_decoder(self):
col_decode_y = self.mux_inst.get_pin("sel_0").cy() - self.col_decode_inst.get_pin("wl_0").cy()
@ -275,28 +344,18 @@ 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 - 5 * self.route_layer_pitch
mux_y_offset = self.bitline_inv_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()
mux_x_offset = self.bitline_inv_inst.get_pin("out_0").cx() - self.mux_inst.get_pin("bl_0").cx()
self.mux_offset = vector(mux_x_offset, mux_y_offset)
self.mux_inst.place(offset=self.mux_offset)
def place_output_buffer(self):
output_x = self.col_decode_inst.rx() + self.output_buf_inst.height
output_y = self.col_decode_inst.by() + self.output_buf_inst.width
self.output_buf_offset = vector(output_x, output_y)
self.output_buf_inst.place(offset=self.output_buf_offset, rotate=270)
output_x = self.col_decode_inst.rx() + self.output_inv_inst.height
output_y = self.mux_inst.by() - self.word_size * self.m1_pitch
self.output_inv_offset = vector(output_x, output_y)
self.output_inv_inst.place(offset=self.output_inv_offset, rotate=270)
# 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 the row decoder
route_pins = [self.array_inst.get_pin("wl_0_{}".format(wl)) for wl in range(self.rows)]
@ -325,88 +384,105 @@ class rom_base_bank(design):
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_precharge(self):
prechrg_control = self.control_inst.get_pin("prechrg")
row_decode_prechrg = self.decode_inst.get_pin("precharge")
col_decode_prechrg = self.col_decode_inst.get_pin("precharge")
col_decode_prechrg = self.col_decode_inst.get_pin("precharge_r")
col_decode_clk = self.col_decode_inst.get_pin("clk")
array_prechrg = self.array_inst.get_pin("precharge")
# Route precharge signal to the row decoder
end = vector(row_decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy())
# end = vector(row_decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy())
self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end)
# self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end)
start = end + vector(0.5 * self.interconnect_layer_width, 0)
self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center())
# start = end + vector(0.5 * self.interconnect_layer_width, 0)
# self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center())
self.add_via_stack_center(from_layer=self.route_stack[0],
to_layer=prechrg_control.layer,
offset=prechrg_control.center())
# Route precharge to col decoder
start = row_decode_prechrg.center() - vector(0, self.route_layer_pitch + 2 * self.route_layer_width)
mid = vector(col_decode_prechrg.cx(), start.y)
end = vector(col_decode_prechrg.cx(), 0.5 * (self.col_decode_inst.uy() + mid.y) )
self.add_path(self.route_stack[0], [start, mid, end])
start = prechrg_control.center()
mid1 = vector(self.control_inst.rx(), prechrg_control.cy())
mid2 = vector(self.control_inst.rx(), col_decode_prechrg.cy())
end = col_decode_prechrg.center()
self.add_path(self.route_stack[0], [start, mid1, mid2, end])
self.add_via_stack_center(from_layer=self.route_stack[0],
to_layer=col_decode_prechrg.layer,
offset=end)
self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center())
start = mid1
mid1 = vector(self.control_inst.rx(), start.y)
mid2 = vector(mid1.x, col_decode_clk.cy())
end = col_decode_clk.center()
self.add_path(self.route_stack[0], [start, mid1, mid2, end])
# self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center())
# Route precharge to main array
end = vector(col_decode_prechrg.cx(), array_prechrg.cy())
self.add_segment_center(self.route_stack[0], array_prechrg.center(), end)
# end = vector(col_decode_prechrg.cx(), array_prechrg.cy())
mid = vector(col_decode_prechrg.cx(), array_prechrg.cy() )
self.add_path(self.route_stack[0], [array_prechrg.center(), mid, col_decode_prechrg.center()])
def route_clock(self):
clk_out = self.control_inst.get_pin("clk_out")
row_decode_clk = self.decode_inst.get_pin("clk")
col_decode_clk = self.col_decode_inst.get_pin("clk")
self.add_via_stack_center(from_layer=self.route_stack[2],
to_layer=clk_out.layer,
offset=clk_out.center())
# Route clock to row decoder
end = row_decode_clk.rc() + vector( 2 * self.route_layer_pitch + self.route_layer_width, 0)
self.add_path(self.route_stack[2], [clk_out.center(), end])
mid = vector(self.control_inst.rx() + self.m1_pitch, clk_out.cy())
addr_control_clk = row_decode_clk.rc() + vector( 2 * self.route_layer_pitch + self.route_layer_width, 0)
row_decode_prechrg = self.decode_inst.get_pin("precharge")
self.add_path(self.route_stack[2], [clk_out.center(), mid, addr_control_clk, row_decode_prechrg.center()])
self.add_via_stack_center(from_layer=self.route_stack[2],
to_layer=row_decode_clk.layer,
offset=end)
offset=addr_control_clk)
self.add_segment_center(row_decode_clk.layer, end, row_decode_clk.rc())
self.add_segment_center(row_decode_clk.layer, addr_control_clk, row_decode_clk.rc())
# Route clock to column decoder
end = col_decode_clk.lc() - vector( 2 * self.route_layer_pitch + self.route_layer_width, 0)
self.add_path(self.route_stack[2], [clk_out.center(), end])
# end = col_decode_clk.lc() - vector( 2 * self.route_layer_pitch + self.route_layer_width, 0)
# self.add_path(self.route_stack[2], [clk_out.center(), end])
self.add_via_stack_center(from_layer=self.route_stack[2],
to_layer=row_decode_clk.layer,
offset=end)
# self.add_via_stack_center(from_layer=self.route_stack[2],
# to_layer=row_decode_clk.layer,
# offset=end)
self.add_segment_center(col_decode_clk.layer, end, col_decode_clk.lc())
# self.add_segment_center(col_decode_clk.layer, end, col_decode_clk.lc())
def route_array_outputs(self):
for i in range(self.cols):
bl_out = self.array_inst.get_pin("bl_0_{}".format(i)).center()
array_out_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.cols)]
inv_in_pins = [self.bitline_inv_inst.get_pin("in_{}".format(bl)) for bl in range(self.cols)]
inv_out_pins = [self.bitline_inv_inst.get_pin("out_{}".format(bl)) for bl in range(self.cols)]
mux_pins = [self.mux_inst.get_pin("bl_{}".format(bl)) for bl in range(self.cols)]
self.connect_col_pins(self.interconnect_layer, array_out_pins + inv_in_pins, round=True, directions="nonpref")
self.connect_col_pins(self.interconnect_layer, inv_out_pins + mux_pins, round=True, directions="nonpref")
bl_mux = self.mux_inst.get_pin("bl_{}".format(i)).center()
self.add_path(self.array.bitline_layer, [bl_out, bl_mux])
def route_output_buffers(self):
mux = self.mux_inst
buf = self.output_buf_inst
buf = self.output_inv_inst
route_nets = [ [mux.get_pin("bl_out_{}".format(bit)), buf.get_pin("in_{}".format(bit))] for bit in range(self.word_size)]
channel_ll = vector( route_nets[0][0].cx(), route_nets[0][1].cy() + self.m1_pitch * 3)
@ -429,7 +505,7 @@ class rom_base_bank(design):
self.copy_layout_pin(self.control_inst, "clk_in", "clk")
for i in range(self.word_size):
self.copy_layout_pin(self.output_buf_inst, "out_{}".format(i), "rom_out_{}".format(i))
self.copy_layout_pin(self.output_inv_inst, "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)
@ -448,27 +524,7 @@ class rom_base_bank(design):
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)
# 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())

View File

@ -20,7 +20,7 @@ class rom_control_logic(design):
if self.height is not None:
self.driver_height = 0.5 * self.height
self.gate_height = 0.25 * self.height
self.gate_height = 0.5 * self.height
else:
self.gate_height = 20 * self.m1_pitch
self.driver_height = self.gate_height
@ -51,16 +51,18 @@ class rom_control_logic(design):
self.route_insts()
def add_modules(self):
self.buf_mod = factory.create(module_type="pinvbuf",
module_name="rom_control_logic_pinv",
self.buf_mod = factory.create(module_type="pdriver",
module_name="rom_clock_driver",
height=self.gate_height,
route_in_cell=True )
fanout=self.clk_fanout + 2,
add_wells=True,
)
self.nand_mod = factory.create(module_type="pnand2",
module_name="rom_control_nand",
height=self.gate_height,
add_wells=False)
self.driver_mod = factory.create(module_type="pdriver",
module_name="rom_precharge_driver",
inverting=True,
fanout=self.output_size,
height=self.driver_height,
@ -77,34 +79,36 @@ class rom_control_logic(design):
def create_instances(self):
self.buf_inst = self.add_inst(name="clk_invbuf", mod=self.buf_mod)
self.connect_inst(["clk_in", "clk_bar", "clk_out", "vdd", "gnd"])
self.buf_inst = self.add_inst(name="clk_driver", mod=self.buf_mod)
self.connect_inst(["clk_in", "clk_out", "vdd", "gnd"])
self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod)
self.connect_inst(["CS", "clk_out", "pre_drive", "vdd", "gnd"])
self.driver_inst = self.add_inst(name="driver_inst", mod=self.driver_mod)
self.driver_inst = self.add_inst(name="precharge_driver", mod=self.driver_mod)
self.connect_inst(["pre_drive", "prechrg", "vdd", "gnd"])
def place_instances(self):
buf_correction = drc["minwidth_{}".format(self.route_stack[0])] * 0.5
# nand_y = self.buf_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy()
self.nand_inst.place(offset=[0, self.nand_inst.height + self.buf_mod.inv2.height + buf_correction], mirror="MX")
self.driver_inst.place(offset=[0, self.buf_inst.height + buf_correction])
self.nand_inst.place(offset=[self.buf_inst.width, 0])
self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height], mirror="MX")
offset = self.driver_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy()
print("offset: {}".format(offset))
self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height - offset], mirror="MX")
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, "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")
# self.copy_layout_pin(self.buf_inst, "vdd")
clk = self.buf_inst.get_pin("Z")
@ -114,7 +118,7 @@ class rom_control_logic(design):
# Connect buffered clock bar to nand input
mid = vector(clk.lx() - route_width - 2 * self.m1_space)
self.add_path(self.route_stack[2], [clk.center(), mid, nand_B.center()])
self.add_path(self.route_stack[2], [clk.center(), nand_B.center()])
self.add_via_stack_center(from_layer=clk.layer,
to_layer=self.route_stack[2],
@ -126,15 +130,17 @@ class rom_control_logic(design):
# Connect nand output to precharge driver
nand_Z = self.nand_inst.get_pin("Z")
nand_output = vector(nand_Z.cx(), nand_B.cy() + 3 * route_width)
driver_A = self.driver_inst.get_pin("A")
self.add_path(self.route_stack[2], [nand_output, driver_A.center()])
mid = vector(driver_A.cx(), driver_A.cy() - 4 * route_width)
self.add_path(self.route_stack[2], [nand_Z.center(), mid, driver_A.center()])
self.add_via_stack_center(from_layer=nand_Z.layer,
to_layer=self.route_stack[2],
offset=nand_output)
offset=nand_Z.center())
self.add_via_stack_center(from_layer=driver_A.layer,
to_layer=self.route_stack[2],

View File

@ -14,7 +14,7 @@ from openram.tech import drc
class rom_decoder(design):
def __init__(self, num_outputs, cols, strap_spacing, name="", route_layer="m1", output_layer="m1", invert_outputs=False):
def __init__(self, num_outputs, fanout, strap_spacing, name="", route_layer="m1", output_layer="m1", invert_outputs=False):
# word lines/ rows / inputs in the base array become the address lines / cols / inputs in the decoder
# bit lines / cols / outputs in the base array become the word lines / rows / outputs in the decoder
@ -33,7 +33,7 @@ class rom_decoder(design):
self.route_layer = route_layer
self.output_layer = output_layer
self.inv_route_layer = "m2"
self.cols=cols
self.fanout=fanout
self.invert_outputs=invert_outputs
self.create_netlist()
@ -57,6 +57,17 @@ class rom_decoder(design):
self.connect_inputs()
self.route_supplies()
self.add_boundary()
def add_boundary(self):
ll = self.find_lowest_coords()
m1_offset = self.m1_width
self.translate_all(vector(0, ll.y))
ur = self.find_highest_coords()
ur = vector(ur.x, ur.y)
super().add_boundary(ll, ur)
self.width = ur.x
self.height = ur.y
def setup_layout_constants(self):
self.inv_route_width = drc["minwidth_{}".format(self.inv_route_layer)]
@ -114,7 +125,7 @@ class rom_decoder(design):
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),
fanout=ceil(self.fanout),
invert_outputs=self.invert_outputs,
tap_spacing=self.strap_spacing)
@ -224,7 +235,7 @@ class rom_decoder(design):
def connect_inputs(self):
self.copy_layout_pin(self.array_inst, "precharge")
self.copy_layout_pin(self.array_inst, "precharge_r")
for i in range(self.num_inputs):
wl = (self.num_inputs - i) * 2 - 1
wl_bar = wl - 1

View File

@ -19,16 +19,16 @@ class rom_wordline_driver_array(design):
Creates a Wordline Buffer/Inverter array
"""
def __init__(self, name, rows, cols, invert_outputs=False, tap_spacing=4):
def __init__(self, name, rows, fanout, invert_outputs=False, tap_spacing=4, flip_io=False):
design.__init__(self, name)
debug.info(1, "Creating {0}".format(self.name))
self.add_comment("rows: {0} cols: {1}".format(rows, cols))
self.add_comment("rows: {0} Buffer size of: {1}".format(rows, fanout))
self.rows = rows
self.cols = cols
self.fanout = fanout
self.invert_outputs=invert_outputs
self.tap_spacing = tap_spacing
self.flip_io = flip_io
if OPTS.tech_name == "sky130":
self.supply_layer = "m1"
else:
@ -51,7 +51,8 @@ class rom_wordline_driver_array(design):
self.place_drivers()
self.route_layout()
self.route_supplies()
self.place_taps()
if self.tap_spacing != 0:
self.place_taps()
self.add_boundary()
def add_pins(self):
@ -70,13 +71,14 @@ class rom_wordline_driver_array(design):
if self.invert_outputs:
self.wl_driver = factory.create(module_type="pinv_dec",
size=self.cols,
size=self.fanout,
height=b.height,
add_wells=False)
add_wells=False,
flip_io=self.flip_io)
else:
self.wl_driver = factory.create(module_type="pbuf_dec",
size=self.cols,
size=self.fanout,
height=b.height,
add_wells=False)
@ -108,7 +110,7 @@ class rom_wordline_driver_array(design):
def place_drivers(self):
y_offset = 0
for row in range(self.rows):
if row % self.tap_spacing == 0:
if self.tap_spacing != 0 and row % self.tap_spacing == 0:
y_offset += self.tap.pitch_offset
offset = [0, y_offset]
@ -123,20 +125,34 @@ class rom_wordline_driver_array(design):
""" Route all of the signals """
route_width = drc["minwidth_{}".format(self.route_layer)]
for row in range(self.rows):
inst = self.wld_inst[row]
if self.flip_io:
row_num = self.rows - row - 1
else:
row_num = row
inst = self.wld_inst[row_num]
self.copy_layout_pin(inst, "vdd")
self.copy_layout_pin(inst, "gnd")
self.copy_layout_pin(inst, "A", "in_{0}".format(row))
out_pin = inst.get_pin("Z")
# output each WL on the right
wl_offset = inst.get_pin("Z").rc() - vector( 0.5 * route_width, 0)
if self.flip_io:
wl_offset = out_pin.lc() - vector(1.6 * route_width, 0)
else:
wl_offset = out_pin.rc() - vector( 0.5 * route_width, 0)
end = vector(wl_offset.x, \
self.get_pin("in_{}".format(row)).cy() + 0.5 * route_width)
self.add_segment_center(layer=self.route_layer,
start=wl_offset,
end=end)
if self.flip_io:
self.add_segment_center(layer=self.route_layer,
start=out_pin.lc(),
end=vector(wl_offset.x - 0.5 * route_width, out_pin.cy()))
self.add_layout_pin_rect_center(text="out_{}".format(row), layer=self.route_layer, offset=end - vector(0, 0.5 * route_width))

View File

@ -24,8 +24,11 @@ class rom_bank_test(openram_test):
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)
print('wriitng file')
a.sp_write(OPTS.openram_temp + 'simulation_file.sp')
self.local_check(a)
openram.end_openram()
# run the test from the command line

View File

@ -0,0 +1,39 @@
#!/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 2kB rom cell")
a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_2kB", word_size=1)
print('wriitng file')
a.sp_write(OPTS.openram_temp + 'simulation_file.sp')
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())

View File

@ -0,0 +1,39 @@
#!/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 4kB rom cell")
a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_4kB", word_size=2)
print('wriitng file')
a.sp_write(OPTS.openram_temp + 'simulation_file.sp')
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())

View File

@ -0,0 +1,39 @@
#!/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 8kB rom cell")
a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_8kB", word_size=2)
print('wriitng file')
a.sp_write(OPTS.openram_temp + 'simulation_file_8kB.sp')
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())