mirror of https://github.com/VLSIDA/OpenRAM.git
Changes for test generation and simulation
This commit is contained in:
parent
89c7d50bd1
commit
bbf2cd2913
|
|
@ -787,13 +787,15 @@ class layout():
|
||||||
end=bot_pos)
|
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.
|
Connects top/bot columns that are aligned.
|
||||||
"""
|
"""
|
||||||
bins = {}
|
bins = {}
|
||||||
for pin in pins:
|
for pin in pins:
|
||||||
x = pin.cx()
|
x = pin.cx()
|
||||||
|
if round:
|
||||||
|
x = round_to_grid(x)
|
||||||
try:
|
try:
|
||||||
bins[x].append(pin)
|
bins[x].append(pin)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|
@ -819,7 +821,8 @@ class layout():
|
||||||
self.add_via_stack_center(from_layer=pin.layer,
|
self.add_via_stack_center(from_layer=pin.layer,
|
||||||
to_layer=layer,
|
to_layer=layer,
|
||||||
offset=pin.center(),
|
offset=pin.center(),
|
||||||
min_area=True)
|
min_area=True,
|
||||||
|
directions=directions)
|
||||||
|
|
||||||
if name:
|
if name:
|
||||||
self.add_layout_pin_segment_center(text=name,
|
self.add_layout_pin_segment_center(text=name,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class pinv_dec(pinv):
|
||||||
Other stuff is the same (netlist, sizes, etc.)
|
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,
|
debug.info(2,
|
||||||
"creating pinv_dec structure {0} with size of {1}".format(name,
|
"creating pinv_dec structure {0} with size of {1}".format(name,
|
||||||
|
|
@ -37,7 +37,7 @@ class pinv_dec(pinv):
|
||||||
self.supply_layer = "m1"
|
self.supply_layer = "m1"
|
||||||
else:
|
else:
|
||||||
self.supply_layer = "m2"
|
self.supply_layer = "m2"
|
||||||
|
self.flip_io=flip_io
|
||||||
super().__init__(name, size, beta, self.cell_height, add_wells)
|
super().__init__(name, size, beta, self.cell_height, add_wells)
|
||||||
|
|
||||||
def determine_tx_mults(self):
|
def determine_tx_mults(self):
|
||||||
|
|
@ -76,8 +76,13 @@ class pinv_dec(pinv):
|
||||||
pmos_gate_pos = pmos_gate_pin.lc()
|
pmos_gate_pos = pmos_gate_pin.lc()
|
||||||
self.add_path("poly", [nmos_gate_pos, pmos_gate_pos])
|
self.add_path("poly", [nmos_gate_pos, pmos_gate_pos])
|
||||||
|
|
||||||
|
|
||||||
# Center is completely symmetric.
|
# Center is completely symmetric.
|
||||||
contact_width = self.poly_contact.width
|
contact_width = self.poly_contact.width
|
||||||
|
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() \
|
contact_offset = nmos_gate_pin.lc() \
|
||||||
- vector(self.poly_extend_active + 0.5 * contact_width, 0)
|
- vector(self.poly_extend_active + 0.5 * contact_width, 0)
|
||||||
via = self.add_via_stack_center(from_layer="poly",
|
via = self.add_via_stack_center(from_layer="poly",
|
||||||
|
|
@ -107,8 +112,11 @@ class pinv_dec(pinv):
|
||||||
height=self.height - ll.y + 0.5 * self.pwell_contact.height + self.well_enclose_active)
|
height=self.height - ll.y + 0.5 * self.pwell_contact.height + self.well_enclose_active)
|
||||||
|
|
||||||
if "nwell" in layer:
|
if "nwell" in layer:
|
||||||
ll = (self.pmos_inst.ll() - vector(2 * [self.well_enclose_active])).scale(1, 0)
|
poly_offset = 0
|
||||||
ur = self.pmos_inst.ur() + vector(2 * [self.well_enclose_active])
|
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",
|
self.add_rect(layer="nwell",
|
||||||
offset=ll,
|
offset=ll,
|
||||||
width=ur.x - ll.x,
|
width=ur.x - ll.x,
|
||||||
|
|
|
||||||
|
|
@ -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)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -58,16 +58,17 @@ class rom_base_array(bitcell_base_array):
|
||||||
self.place_precharge()
|
self.place_precharge()
|
||||||
self.place_wordline_contacts()
|
self.place_wordline_contacts()
|
||||||
self.place_bitline_contacts()
|
self.place_bitline_contacts()
|
||||||
self.add_boundary()
|
|
||||||
self.route_precharge()
|
self.route_precharge()
|
||||||
|
self.add_boundary()
|
||||||
|
|
||||||
self.place_rails()
|
self.place_rails()
|
||||||
self.connect_taps()
|
self.connect_taps()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def add_boundary(self):
|
def add_boundary(self):
|
||||||
ll = self.find_lowest_coords()
|
ll = self.find_lowest_coords()
|
||||||
bottom_offset = - self.zero_cell.nmos.end_to_contact + self.precharge_inst.offset.y
|
|
||||||
m1_offset = self.m1_width
|
m1_offset = self.m1_width
|
||||||
self.translate_all(vector(0, ll.y + 0.5 * m1_offset))
|
self.translate_all(vector(0, ll.y + 0.5 * m1_offset))
|
||||||
ur = self.find_highest_coords()
|
ur = self.find_highest_coords()
|
||||||
|
|
@ -209,7 +210,7 @@ class rom_base_array(bitcell_base_array):
|
||||||
|
|
||||||
prechrg_pins.append("precharge")
|
prechrg_pins.append("precharge")
|
||||||
prechrg_pins.append("vdd")
|
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)
|
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_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):
|
def connect_taps(self):
|
||||||
array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))]
|
array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))]
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ class rom_base_bank(design):
|
||||||
def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2):
|
def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2):
|
||||||
super().__init__(name=name)
|
super().__init__(name=name)
|
||||||
self.word_size = word_size * 8
|
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_outputs = self.rows
|
||||||
self.num_inputs = ceil(log(self.rows, 2))
|
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,
|
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
|
# Read data as hexidecimal text file
|
||||||
hex_file = open(data_file, 'r')
|
hex_file = open(data_file, 'r')
|
||||||
hex_data = hex_file.read()
|
hex_data = hex_file.read()
|
||||||
|
|
@ -72,24 +72,55 @@ class rom_base_bank(design):
|
||||||
|
|
||||||
bits_per_row = self.words_per_row * word_size * 8
|
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 = []
|
chunked_data = []
|
||||||
|
|
||||||
for i in range(0, len(bin_data), bits_per_row):
|
for i in range(0, len(bin_data), bits_per_row):
|
||||||
word = bin_data[i:i + bits_per_row]
|
row_data = bin_data[i:i + bits_per_row]
|
||||||
if len(word) < bits_per_row:
|
if len(row_data) < bits_per_row:
|
||||||
word = [0] * (bits_per_row - len(word)) + word
|
row_data = [0] * (bits_per_row - len(row_data)) + row_data
|
||||||
chunked_data.append(word)
|
chunked_data.append(row_data)
|
||||||
|
|
||||||
|
|
||||||
|
# if endian == "big":
|
||||||
|
|
||||||
if endian == "big":
|
|
||||||
chunked_data.reverse()
|
|
||||||
|
|
||||||
self.data = chunked_data
|
self.data = chunked_data
|
||||||
self.cols = bits_per_row
|
if scramble_bits:
|
||||||
self.rows = int(num_words / (self.words_per_row))
|
scrambled_chunked = []
|
||||||
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))
|
|
||||||
|
|
||||||
|
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))
|
# 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):
|
def create_netlist(self):
|
||||||
self.add_modules()
|
self.add_modules()
|
||||||
|
|
@ -147,6 +178,20 @@ class rom_base_bank(design):
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
|
|
||||||
print("Creating bank modules")
|
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",
|
self.array = factory.create(module_type="rom_base_array",
|
||||||
cols=self.cols,
|
cols=self.cols,
|
||||||
rows=self.rows,
|
rows=self.rows,
|
||||||
|
|
@ -163,7 +208,7 @@ class rom_base_bank(design):
|
||||||
num_outputs=self.rows,
|
num_outputs=self.rows,
|
||||||
strap_spacing=self.strap_spacing,
|
strap_spacing=self.strap_spacing,
|
||||||
route_layer=self.route_layer,
|
route_layer=self.route_layer,
|
||||||
cols=self.cols)
|
fanout=(self.cols)*wordline_effort )
|
||||||
|
|
||||||
|
|
||||||
self.column_mux = factory.create(module_type="rom_column_mux_array",
|
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,
|
num_outputs=self.words_per_row,
|
||||||
strap_spacing=self.strap_spacing,
|
strap_spacing=self.strap_spacing,
|
||||||
route_layer=self.route_layer,
|
route_layer=self.route_layer,
|
||||||
cols=1,
|
fanout=2,
|
||||||
invert_outputs=True )
|
invert_outputs=True )
|
||||||
|
|
||||||
self.control_logic = factory.create(module_type="rom_control_logic",
|
self.control_logic = factory.create(module_type="rom_control_logic",
|
||||||
num_outputs=(self.rows + self.cols + self.words_per_row) * 0.5,
|
num_outputs=(self.cols + self.words_per_row * precharge_cell_effort) \
|
||||||
clk_fanout=(self.col_bits + self.row_bits) * 2,
|
+ (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 )
|
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",
|
module_name="rom_output_buffer",
|
||||||
rows=self.word_size,
|
rows=self.word_size,
|
||||||
cols=4)
|
fanout=4,
|
||||||
|
invert_outputs=True)
|
||||||
|
|
||||||
|
|
||||||
def create_instances(self):
|
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)]
|
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)]
|
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)]
|
outputs = ["rom_out_{}".format(bl) for bl in range(self.word_size)]
|
||||||
|
|
||||||
|
|
||||||
array_pins = bitlines + wordlines + prechrg + vdd + gnd
|
array_pins = bitlines + wordlines + prechrg + vdd + gnd
|
||||||
|
|
||||||
row_decode_pins = addr_msb + wordlines + prechrg + clk + vdd + gnd
|
row_decode_pins = addr_msb + wordlines + clk + clk + vdd + gnd
|
||||||
col_decode_pins = addr_lsb + select_lines + prechrg + 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.array_inst = self.add_inst(name="rom_bit_array", mod=self.array)
|
||||||
self.connect_inst(array_pins)
|
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.col_decode_inst = self.add_inst(name="rom_column_decoder", mod=self.column_decode)
|
||||||
self.connect_inst(col_decode_pins)
|
self.connect_inst(col_decode_pins)
|
||||||
|
|
||||||
self.output_buf_inst = self.add_inst(name="rom_output_buffer", mod=self.output_buffer)
|
self.bitline_inv_inst = self.add_inst(name="rom_bitline_inverter", mod=self.bitline_inv)
|
||||||
self.connect_inst(output_buffer_pins)
|
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):
|
def place_instances(self):
|
||||||
self.place_row_decoder()
|
self.place_row_decoder()
|
||||||
self.place_data_array()
|
self.place_data_array()
|
||||||
|
self.place_bitline_inverter()
|
||||||
self.place_col_mux()
|
self.place_col_mux()
|
||||||
self.place_col_decoder()
|
self.place_col_decoder()
|
||||||
self.place_control_logic()
|
self.place_control_logic()
|
||||||
|
|
@ -249,7 +311,7 @@ class rom_base_bank(design):
|
||||||
|
|
||||||
|
|
||||||
def place_row_decoder(self):
|
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)
|
self.decode_inst.place(offset=self.decode_offset)
|
||||||
|
|
||||||
def place_data_array(self):
|
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()
|
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)))
|
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):
|
def place_control_logic(self):
|
||||||
|
|
||||||
|
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_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)
|
||||||
self.control_inst.place(offset=self.control_offset, mirror="XY")
|
|
||||||
|
|
||||||
def place_col_decoder(self):
|
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()
|
col_decode_y = self.mux_inst.get_pin("sel_0").cy() - self.col_decode_inst.get_pin("wl_0").cy()
|
||||||
|
|
@ -275,27 +344,17 @@ class rom_base_bank(design):
|
||||||
self.col_decode_inst.place(offset=self.col_decode_offset)
|
self.col_decode_inst.place(offset=self.col_decode_offset)
|
||||||
|
|
||||||
def place_col_mux(self):
|
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_offset = vector(mux_x_offset, mux_y_offset)
|
||||||
self.mux_inst.place(offset=self.mux_offset)
|
self.mux_inst.place(offset=self.mux_offset)
|
||||||
|
|
||||||
def place_output_buffer(self):
|
def place_output_buffer(self):
|
||||||
output_x = self.col_decode_inst.rx() + self.output_buf_inst.height
|
output_x = self.col_decode_inst.rx() + self.output_inv_inst.height
|
||||||
output_y = self.col_decode_inst.by() + self.output_buf_inst.width
|
output_y = self.mux_inst.by() - self.word_size * self.m1_pitch
|
||||||
self.output_buf_offset = vector(output_x, output_y)
|
self.output_inv_offset = vector(output_x, output_y)
|
||||||
self.output_buf_inst.place(offset=self.output_buf_offset, rotate=270)
|
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):
|
def route_decode_outputs(self):
|
||||||
# for the row decoder
|
# for the row decoder
|
||||||
|
|
@ -325,88 +384,105 @@ class rom_base_bank(design):
|
||||||
start = vector(wl_bus_wire.cx(), end.y)
|
start = vector(wl_bus_wire.cx(), end.y)
|
||||||
|
|
||||||
self.add_segment_center(self.interconnect_layer, start, end)
|
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):
|
def route_precharge(self):
|
||||||
|
|
||||||
prechrg_control = self.control_inst.get_pin("prechrg")
|
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")
|
array_prechrg = self.array_inst.get_pin("precharge")
|
||||||
|
|
||||||
|
|
||||||
# Route precharge signal to the row decoder
|
# 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)
|
# start = end + vector(0.5 * self.interconnect_layer_width, 0)
|
||||||
self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center())
|
# self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center())
|
||||||
|
|
||||||
self.add_via_stack_center(from_layer=self.route_stack[0],
|
self.add_via_stack_center(from_layer=self.route_stack[0],
|
||||||
to_layer=prechrg_control.layer,
|
to_layer=prechrg_control.layer,
|
||||||
offset=prechrg_control.center())
|
offset=prechrg_control.center())
|
||||||
|
|
||||||
# Route precharge to col decoder
|
# Route precharge to col decoder
|
||||||
start = row_decode_prechrg.center() - vector(0, self.route_layer_pitch + 2 * self.route_layer_width)
|
start = prechrg_control.center()
|
||||||
mid = vector(col_decode_prechrg.cx(), start.y)
|
mid1 = vector(self.control_inst.rx(), prechrg_control.cy())
|
||||||
end = vector(col_decode_prechrg.cx(), 0.5 * (self.col_decode_inst.uy() + mid.y) )
|
mid2 = vector(self.control_inst.rx(), col_decode_prechrg.cy())
|
||||||
self.add_path(self.route_stack[0], [start, mid, end])
|
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],
|
self.add_via_stack_center(from_layer=self.route_stack[0],
|
||||||
to_layer=col_decode_prechrg.layer,
|
to_layer=col_decode_prechrg.layer,
|
||||||
offset=end)
|
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
|
# Route precharge to main array
|
||||||
end = vector(col_decode_prechrg.cx(), array_prechrg.cy())
|
# end = vector(col_decode_prechrg.cx(), array_prechrg.cy())
|
||||||
self.add_segment_center(self.route_stack[0], array_prechrg.center(), end)
|
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):
|
def route_clock(self):
|
||||||
clk_out = self.control_inst.get_pin("clk_out")
|
clk_out = self.control_inst.get_pin("clk_out")
|
||||||
row_decode_clk = self.decode_inst.get_pin("clk")
|
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],
|
self.add_via_stack_center(from_layer=self.route_stack[2],
|
||||||
to_layer=clk_out.layer,
|
to_layer=clk_out.layer,
|
||||||
offset=clk_out.center())
|
offset=clk_out.center())
|
||||||
|
|
||||||
# Route clock to row decoder
|
# Route clock to row decoder
|
||||||
end = row_decode_clk.rc() + vector( 2 * self.route_layer_pitch + self.route_layer_width, 0)
|
mid = vector(self.control_inst.rx() + self.m1_pitch, clk_out.cy())
|
||||||
self.add_path(self.route_stack[2], [clk_out.center(), end])
|
|
||||||
|
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],
|
self.add_via_stack_center(from_layer=self.route_stack[2],
|
||||||
to_layer=row_decode_clk.layer,
|
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
|
# Route clock to column decoder
|
||||||
end = col_decode_clk.lc() - vector( 2 * self.route_layer_pitch + self.route_layer_width, 0)
|
# 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_path(self.route_stack[2], [clk_out.center(), end])
|
||||||
|
|
||||||
self.add_via_stack_center(from_layer=self.route_stack[2],
|
# self.add_via_stack_center(from_layer=self.route_stack[2],
|
||||||
to_layer=row_decode_clk.layer,
|
# to_layer=row_decode_clk.layer,
|
||||||
offset=end)
|
# 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):
|
def route_array_outputs(self):
|
||||||
for i in range(self.cols):
|
array_out_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.cols)]
|
||||||
bl_out = self.array_inst.get_pin("bl_0_{}".format(i)).center()
|
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):
|
def route_output_buffers(self):
|
||||||
mux = self.mux_inst
|
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)]
|
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)
|
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")
|
self.copy_layout_pin(self.control_inst, "clk_in", "clk")
|
||||||
|
|
||||||
for i in range(self.word_size):
|
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):
|
for lsb in range(self.col_bits):
|
||||||
name = "addr_{}".format(lsb)
|
name = "addr_{}".format(lsb)
|
||||||
self.copy_layout_pin(self.col_decode_inst, "A{}".format(lsb), name)
|
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"):
|
if not inst.mod.name.__contains__("contact"):
|
||||||
self.copy_layout_pin(inst, "vdd")
|
self.copy_layout_pin(inst, "vdd")
|
||||||
self.copy_layout_pin(inst, "gnd")
|
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())
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ class rom_control_logic(design):
|
||||||
if self.height is not None:
|
if self.height is not None:
|
||||||
|
|
||||||
self.driver_height = 0.5 * self.height
|
self.driver_height = 0.5 * self.height
|
||||||
self.gate_height = 0.25 * self.height
|
self.gate_height = 0.5 * self.height
|
||||||
else:
|
else:
|
||||||
self.gate_height = 20 * self.m1_pitch
|
self.gate_height = 20 * self.m1_pitch
|
||||||
self.driver_height = self.gate_height
|
self.driver_height = self.gate_height
|
||||||
|
|
@ -51,16 +51,18 @@ class rom_control_logic(design):
|
||||||
self.route_insts()
|
self.route_insts()
|
||||||
|
|
||||||
def add_modules(self):
|
def add_modules(self):
|
||||||
|
self.buf_mod = factory.create(module_type="pdriver",
|
||||||
self.buf_mod = factory.create(module_type="pinvbuf",
|
module_name="rom_clock_driver",
|
||||||
module_name="rom_control_logic_pinv",
|
|
||||||
height=self.gate_height,
|
height=self.gate_height,
|
||||||
route_in_cell=True )
|
fanout=self.clk_fanout + 2,
|
||||||
|
add_wells=True,
|
||||||
|
)
|
||||||
self.nand_mod = factory.create(module_type="pnand2",
|
self.nand_mod = factory.create(module_type="pnand2",
|
||||||
module_name="rom_control_nand",
|
module_name="rom_control_nand",
|
||||||
height=self.gate_height,
|
height=self.gate_height,
|
||||||
add_wells=False)
|
add_wells=False)
|
||||||
self.driver_mod = factory.create(module_type="pdriver",
|
self.driver_mod = factory.create(module_type="pdriver",
|
||||||
|
module_name="rom_precharge_driver",
|
||||||
inverting=True,
|
inverting=True,
|
||||||
fanout=self.output_size,
|
fanout=self.output_size,
|
||||||
height=self.driver_height,
|
height=self.driver_height,
|
||||||
|
|
@ -77,34 +79,36 @@ class rom_control_logic(design):
|
||||||
|
|
||||||
def create_instances(self):
|
def create_instances(self):
|
||||||
|
|
||||||
self.buf_inst = self.add_inst(name="clk_invbuf", mod=self.buf_mod)
|
self.buf_inst = self.add_inst(name="clk_driver", mod=self.buf_mod)
|
||||||
self.connect_inst(["clk_in", "clk_bar", "clk_out", "vdd", "gnd"])
|
self.connect_inst(["clk_in", "clk_out", "vdd", "gnd"])
|
||||||
|
|
||||||
self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod)
|
self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod)
|
||||||
self.connect_inst(["CS", "clk_out", "pre_drive", "vdd", "gnd"])
|
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"])
|
self.connect_inst(["pre_drive", "prechrg", "vdd", "gnd"])
|
||||||
|
|
||||||
|
|
||||||
def place_instances(self):
|
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()
|
# 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.nand_inst.place(offset=[self.buf_inst.width, 0])
|
||||||
self.driver_inst.place(offset=[0, self.buf_inst.height + buf_correction])
|
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):
|
def route_insts(self):
|
||||||
|
|
||||||
route_width = drc["minwidth_{}".format(self.route_stack[2])]
|
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, "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.buf_inst, "Z", "clk_out")
|
||||||
self.copy_layout_pin(self.driver_inst, "Z", "prechrg")
|
self.copy_layout_pin(self.driver_inst, "Z", "prechrg")
|
||||||
self.copy_layout_pin(self.nand_inst, "A", "CS")
|
self.copy_layout_pin(self.nand_inst, "A", "CS")
|
||||||
self.copy_layout_pin(self.buf_inst, "gnd")
|
self.copy_layout_pin(self.buf_inst, "gnd")
|
||||||
self.copy_layout_pin(self.driver_inst, "vdd")
|
self.copy_layout_pin(self.driver_inst, "vdd")
|
||||||
self.copy_layout_pin(self.buf_inst, "vdd")
|
self.copy_layout_pin(self.buf_inst, "vdd")
|
||||||
# self.copy_layout_pin(self.buf_inst, "vdd")
|
|
||||||
|
|
||||||
clk = self.buf_inst.get_pin("Z")
|
clk = self.buf_inst.get_pin("Z")
|
||||||
|
|
||||||
|
|
@ -114,7 +118,7 @@ class rom_control_logic(design):
|
||||||
# Connect buffered clock bar to nand input
|
# Connect buffered clock bar to nand input
|
||||||
|
|
||||||
mid = vector(clk.lx() - route_width - 2 * self.m1_space)
|
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,
|
self.add_via_stack_center(from_layer=clk.layer,
|
||||||
to_layer=self.route_stack[2],
|
to_layer=self.route_stack[2],
|
||||||
|
|
@ -126,15 +130,17 @@ class rom_control_logic(design):
|
||||||
|
|
||||||
# Connect nand output to precharge driver
|
# Connect nand output to precharge driver
|
||||||
nand_Z = self.nand_inst.get_pin("Z")
|
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")
|
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,
|
self.add_via_stack_center(from_layer=nand_Z.layer,
|
||||||
to_layer=self.route_stack[2],
|
to_layer=self.route_stack[2],
|
||||||
offset=nand_output)
|
offset=nand_Z.center())
|
||||||
|
|
||||||
self.add_via_stack_center(from_layer=driver_A.layer,
|
self.add_via_stack_center(from_layer=driver_A.layer,
|
||||||
to_layer=self.route_stack[2],
|
to_layer=self.route_stack[2],
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ from openram.tech import drc
|
||||||
|
|
||||||
|
|
||||||
class rom_decoder(design):
|
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
|
# 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
|
# 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.route_layer = route_layer
|
||||||
self.output_layer = output_layer
|
self.output_layer = output_layer
|
||||||
self.inv_route_layer = "m2"
|
self.inv_route_layer = "m2"
|
||||||
self.cols=cols
|
self.fanout=fanout
|
||||||
self.invert_outputs=invert_outputs
|
self.invert_outputs=invert_outputs
|
||||||
self.create_netlist()
|
self.create_netlist()
|
||||||
|
|
||||||
|
|
@ -58,6 +58,17 @@ class rom_decoder(design):
|
||||||
self.route_supplies()
|
self.route_supplies()
|
||||||
self.add_boundary()
|
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):
|
def setup_layout_constants(self):
|
||||||
self.inv_route_width = drc["minwidth_{}".format(self.inv_route_layer)]
|
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),
|
self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name),
|
||||||
rows=self.num_outputs,
|
rows=self.num_outputs,
|
||||||
cols=ceil(self.cols * 0.5),
|
fanout=ceil(self.fanout),
|
||||||
invert_outputs=self.invert_outputs,
|
invert_outputs=self.invert_outputs,
|
||||||
tap_spacing=self.strap_spacing)
|
tap_spacing=self.strap_spacing)
|
||||||
|
|
||||||
|
|
@ -224,7 +235,7 @@ class rom_decoder(design):
|
||||||
def connect_inputs(self):
|
def connect_inputs(self):
|
||||||
|
|
||||||
self.copy_layout_pin(self.array_inst, "precharge")
|
self.copy_layout_pin(self.array_inst, "precharge")
|
||||||
|
self.copy_layout_pin(self.array_inst, "precharge_r")
|
||||||
for i in range(self.num_inputs):
|
for i in range(self.num_inputs):
|
||||||
wl = (self.num_inputs - i) * 2 - 1
|
wl = (self.num_inputs - i) * 2 - 1
|
||||||
wl_bar = wl - 1
|
wl_bar = wl - 1
|
||||||
|
|
|
||||||
|
|
@ -19,16 +19,16 @@ class rom_wordline_driver_array(design):
|
||||||
Creates a Wordline Buffer/Inverter array
|
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)
|
design.__init__(self, name)
|
||||||
debug.info(1, "Creating {0}".format(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.rows = rows
|
||||||
self.cols = cols
|
self.fanout = fanout
|
||||||
self.invert_outputs=invert_outputs
|
self.invert_outputs=invert_outputs
|
||||||
self.tap_spacing = tap_spacing
|
self.tap_spacing = tap_spacing
|
||||||
|
self.flip_io = flip_io
|
||||||
if OPTS.tech_name == "sky130":
|
if OPTS.tech_name == "sky130":
|
||||||
self.supply_layer = "m1"
|
self.supply_layer = "m1"
|
||||||
else:
|
else:
|
||||||
|
|
@ -51,6 +51,7 @@ class rom_wordline_driver_array(design):
|
||||||
self.place_drivers()
|
self.place_drivers()
|
||||||
self.route_layout()
|
self.route_layout()
|
||||||
self.route_supplies()
|
self.route_supplies()
|
||||||
|
if self.tap_spacing != 0:
|
||||||
self.place_taps()
|
self.place_taps()
|
||||||
self.add_boundary()
|
self.add_boundary()
|
||||||
|
|
||||||
|
|
@ -70,13 +71,14 @@ class rom_wordline_driver_array(design):
|
||||||
|
|
||||||
if self.invert_outputs:
|
if self.invert_outputs:
|
||||||
self.wl_driver = factory.create(module_type="pinv_dec",
|
self.wl_driver = factory.create(module_type="pinv_dec",
|
||||||
size=self.cols,
|
size=self.fanout,
|
||||||
height=b.height,
|
height=b.height,
|
||||||
add_wells=False)
|
add_wells=False,
|
||||||
|
flip_io=self.flip_io)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
self.wl_driver = factory.create(module_type="pbuf_dec",
|
self.wl_driver = factory.create(module_type="pbuf_dec",
|
||||||
size=self.cols,
|
size=self.fanout,
|
||||||
height=b.height,
|
height=b.height,
|
||||||
add_wells=False)
|
add_wells=False)
|
||||||
|
|
||||||
|
|
@ -108,7 +110,7 @@ class rom_wordline_driver_array(design):
|
||||||
def place_drivers(self):
|
def place_drivers(self):
|
||||||
y_offset = 0
|
y_offset = 0
|
||||||
for row in range(self.rows):
|
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
|
y_offset += self.tap.pitch_offset
|
||||||
offset = [0, y_offset]
|
offset = [0, y_offset]
|
||||||
|
|
||||||
|
|
@ -123,20 +125,34 @@ class rom_wordline_driver_array(design):
|
||||||
""" Route all of the signals """
|
""" Route all of the signals """
|
||||||
route_width = drc["minwidth_{}".format(self.route_layer)]
|
route_width = drc["minwidth_{}".format(self.route_layer)]
|
||||||
for row in range(self.rows):
|
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, "vdd")
|
||||||
self.copy_layout_pin(inst, "gnd")
|
self.copy_layout_pin(inst, "gnd")
|
||||||
|
|
||||||
self.copy_layout_pin(inst, "A", "in_{0}".format(row))
|
self.copy_layout_pin(inst, "A", "in_{0}".format(row))
|
||||||
|
|
||||||
|
out_pin = inst.get_pin("Z")
|
||||||
# output each WL on the right
|
# 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, \
|
end = vector(wl_offset.x, \
|
||||||
self.get_pin("in_{}".format(row)).cy() + 0.5 * route_width)
|
self.get_pin("in_{}".format(row)).cy() + 0.5 * route_width)
|
||||||
self.add_segment_center(layer=self.route_layer,
|
self.add_segment_center(layer=self.route_layer,
|
||||||
start=wl_offset,
|
start=wl_offset,
|
||||||
end=end)
|
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))
|
self.add_layout_pin_rect_center(text="out_{}".format(row), layer=self.route_layer, offset=end - vector(0, 0.5 * route_width))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,11 @@ class rom_bank_test(openram_test):
|
||||||
debug.info(1, "Testing 1kB 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)
|
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)
|
self.local_check(a)
|
||||||
|
|
||||||
|
|
||||||
openram.end_openram()
|
openram.end_openram()
|
||||||
|
|
||||||
# run the test from the command line
|
# run the test from the command line
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
@ -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())
|
||||||
|
|
@ -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())
|
||||||
Loading…
Reference in New Issue