From ce8197d206a0741ac1c620e2c21c99b0cd4fd148 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Fri, 30 Dec 2022 00:35:15 -0800 Subject: [PATCH] pitch match decoder and array --- compiler/modules/rom_base_array.py | 92 +++++++---- compiler/modules/rom_base_bank.py | 165 ++++++++++++++++---- compiler/modules/rom_base_cell.py | 13 +- compiler/modules/rom_control_logic.py | 81 ++++++++++ compiler/modules/rom_decoder.py | 17 +- compiler/modules/rom_dummy_cell.py | 24 ++- compiler/modules/rom_inv_array.py | 3 +- compiler/modules/rom_poly_tap.py | 33 ++-- compiler/modules/rom_precharge_array.py | 1 + compiler/modules/rom_precharge_cell.py | 6 +- compiler/tests/05_rom_array_test.py | 2 +- compiler/tests/05_rom_base_bank_test.py | 2 +- compiler/tests/05_rom_control_logic_test.py | 37 +++++ 13 files changed, 361 insertions(+), 115 deletions(-) create mode 100644 compiler/modules/rom_control_logic.py create mode 100644 compiler/tests/05_rom_control_logic_test.py diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 6cec6480..a46cce33 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -16,11 +16,12 @@ from openram.tech import drc class rom_base_array(bitcell_base_array): - def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0, route_layer="li", output_layer="m2"): + def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0, route_layer="li", output_layer="m2", pitch_match=False): super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset) self.data = bitmap + self.pitch_match = pitch_match self.route_layer = route_layer self.output_layer = output_layer self.strap_spacing = strap_spacing @@ -44,14 +45,18 @@ class rom_base_array(bitcell_base_array): def create_layout(self): + self.create_layout_constants() self.place_array() + if self.pitch_match: + self.route_pitch_offsets() + self.place_precharge() self.place_wordline_contacts() self.place_bitline_contacts() - self.place_precharge() + + self.place_rails() self.route_precharge() - self.add_boundary() self.add_label("ARRAY ZERO", self.route_layer) self.add_label("array height", self.route_layer, [0, self.height]) @@ -95,6 +100,12 @@ class rom_base_array(bitcell_base_array): self.precharge_array = factory.create(module_type="rom_precharge_array", cols=self.column_size, strap_spacing=self.strap_spacing, route_layer=self.route_layer) + def create_layout_constants(self): + self.route_width = drc("minwidth_" + self.route_layer) + + self.route_pitch = drc("{0}_to_{0}".format(self.route_layer)) + + def add_pins(self): for bl_name in self.get_bitline_names(): self.add_pin(bl_name, "INOUT") @@ -116,9 +127,13 @@ class rom_base_array(bitcell_base_array): row_list = [] # for each new strap placed, offset the column index refrenced to get correct bit in the data array - strap_offset = 0 - first_in_col = True # cols are bit lines + strap_row = False + pre_strap_row = False + if row % self.strap_spacing == 0 and self.pitch_match: + strap_row = True + if (row + 1) % self.strap_spacing == 0 and self.pitch_match: + pre_strap_row = True for col in range(self.column_size): if col % self.strap_spacing == 0: @@ -127,7 +142,6 @@ class rom_base_array(bitcell_base_array): #print("tap instance added at c{0}, r{1}".format(col, row)) self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) self.connect_inst([]) - strap_offset += 1 name = "bit_r{0}_c{1}".format(row, col) @@ -137,19 +151,23 @@ class rom_base_array(bitcell_base_array): # if the last row and 0 below add both contacts if (row < self.row_size - 1 and row > 0 and self.data[row + 1][col] == 0 and self.data[row - 1][col] == 0) or \ (row == self.row_size - 1 and self.data[row - 1][col] == 0) or \ - (row == 0 and self.data[row + 1][col] == 0): + (row == 0 and self.data[row + 1][col] == 0) or \ + (row < self.row_size - 1 and self.data[row + 1][col] == 0 and strap_row) or \ + (row > 0 and self.data[row - 1][col] == 0 and pre_strap_row): new_inst = self.add_inst(name=name, mod=self.cell_ac) # if dummy/0 is below and not above, add a source contact # if in the first row, add a source contact elif (row > 0 and self.data[row - 1][col] == 0) or \ - (row == 0): + (row == 0) or \ + (strap_row): new_inst=self.add_inst(name=name, mod=self.cell_sc) elif (row < self.row_size - 1 and self.data[row + 1][col] == 0) or \ - (row == self.row_size - 1): + (row == self.row_size - 1) or \ + (pre_strap_row): new_inst=self.add_inst(name=name, mod=self.cell_dc) else: @@ -187,7 +205,6 @@ class rom_base_array(bitcell_base_array): row_list.append(new_inst) - name = "tap_r{0}_c{1}".format(row, self.array_col_size) #print(*row_list) self.tap_inst[row, self.column_size]=self.add_inst(name=name, mod=self.zero_tap) @@ -222,9 +239,7 @@ class rom_base_array(bitcell_base_array): def place_rails(self): - width = drc("minwidth_" + self.route_layer) - drc_rule = "{0}_to_{0}".format(self.route_layer) - spacing = drc(drc_rule) + spacing = self.route_pitch rail_y = self.cell_list[self.row_size - 1][0].offset.y + self.dummy.base_width + spacing # self.dummy.height * (self.row_size) @@ -237,7 +252,7 @@ class rom_base_array(bitcell_base_array): rail_start = vector(start_x , rail_y) rail_end = vector(end_x, rail_y) - self.gnd = self.add_layout_pin_rect_ends( name="gnd", + self.gnd = self.add_layout_pin_rect_ends(name="gnd", layer="m1", start=rail_start, end=rail_end) @@ -249,22 +264,22 @@ class rom_base_array(bitcell_base_array): self.add_via_stack_center(via_pos, self.route_layer, "m1", ["H", "V"]) - - prechrg_vdd = self.precharge_inst.get_pin("vdd") def place_array(self): self.cell_pos = {} self.strap_pos = {} # rows are wordlines + + pitch_offset = 0 for row in range(self.row_size): - # strap_cols = -1 + if row % self.strap_spacing == 0 and row != 0 and self.pitch_match: + pitch_offset += self.poly_tap.width - cell_y = row * (self.dummy.height) + cell_y = row * (self.dummy.height) + pitch_offset cell_x = 0 - for col in range(self.column_size): if col % self.strap_spacing == 0: @@ -286,6 +301,19 @@ class rom_base_array(bitcell_base_array): # self.add_layout_pin_rect_center("wl{}".format(row), "m2", tap_pin) + def route_pitch_offsets(self): + + for row in range(0 , self.row_size, self.strap_spacing): + if row != 0: + for col in range(self.column_size): + source = self.cell_inst[row, col].get_pin("S") + drain = self.cell_inst[row - 1, col].get_pin("D") + + start = vector(drain.cx(), source.cy()) + end = drain.center() + self.add_segment_center(self.route_layer, start, end) + + def place_precharge(self): self.precharge_offset = vector(0, - self.precharge_inst.height - self.dummy.nmos.end_to_contact - 2 * drc["nwell_enclose_active"]) @@ -293,14 +321,15 @@ class rom_base_array(bitcell_base_array): self.precharge_inst.place(offset=self.precharge_offset) self.copy_layout_pin(self.precharge_inst, "vdd") + self.copy_layout_pin(self.precharge_inst, "gate", "precharge") def place_wordline_contacts(self): - width = drc["minwidth_{}".format(self.route_layer)] + width = self.route_width - height = drc["minwidth_{}".format(self.route_layer)] + height = self.route_width offset = vector(self.poly_contact.width * 0.5, self.dummy.poly.offset.y) @@ -308,36 +337,31 @@ class rom_base_array(bitcell_base_array): poly_via = self.tap_inst[wl, 0].get_pin("via") self.copy_layout_pin(self.tap_inst[wl, 0], "via", self.wordline_names[0][wl]) - self.add_via_stack_center(poly_via.center(), "m1", self.output_layer) + # self.add_via_stack_center(poly_via.center(), "m1", self.output_layer) - corrected_offset = offset - vector(0.5 * width, 0.5 * height) # self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.dummy.height, length=None) def place_bitline_contacts(self): - src_pin = self.cell_nc.source_pos + rail_y = self.precharge_inst.get_pin("vdd").cy() for bl in range(self.column_size): - - # self.copy_layout_pin(self.cell_list[0][bl], "S", self.bitline_names[0][bl]) - src_pin = self.cell_list[0][bl].get_pin("S") prechg_pin_name = "pre_bl{0}_out".format(bl) pre_pin = self.precharge_inst.get_pin(prechg_pin_name) - - # offset = src_pin_offset + vector(src_pin.x, 0) - - - middle_offset = (pre_pin.cy() - src_pin.cy()) * 0.5 + middle_offset = (src_pin.cy() - pre_pin.cy() ) * 0.5 corrected = vector(src_pin.cx(), src_pin.cy() - middle_offset) self.add_via_stack_center(corrected, self.route_layer, self.output_layer) - self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, corrected ) + output_pos = vector(corrected.x, rail_y) + + self.add_segment_center(self.output_layer, corrected, output_pos) - # self.gnd[0].y() + self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, output_pos ) + def route_precharge(self): diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index 2ce14ab7..d288fdc2 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -1,40 +1,82 @@ -import math +from math import ceil, log, sqrt from openram.base import vector from openram.base import design from openram import OPTS from openram.sram_factory import factory -import tech from openram.tech import drc class rom_base_bank(design): - def __init__(self, strap_spacing=0, data_file=None, name="") -> None: - self.rows = 4 - self.cols = 4 - self.num_inputs = 2 - self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] + def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2) -> None: + + # self.cols = word_size * 8 + self.read_binary(word_size=word_size, data_file=data_file) + + self.num_outputs = self.rows + self.num_inputs = ceil(log(self.rows, 2)) + + # self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] self.strap_spacing = strap_spacing self.route_layer = "li" - self.bus_layer = "m1" - self.interconnect_layer = "m2" + self.bus_layer = "m2" + self.interconnect_layer = "m1" - - super().__init__(name=name) self.setup_layout_constants() self.create_netlist() self.create_layout() + """ + Reads a hexadecimal file from a given directory to be used as the data written to the ROM + endian is either "big" or "little" + word_size is the number of bytes per word + sets the row and column size based on the size of binary input, tries to keep array as square as possible, + """ + def read_binary(self, data_file, word_size=2, endian="big"): + + hex_file = open(data_file, 'r') + hex_data = hex_file.read() + bin_data = list("{0:08b}".format(int(hex_data, 16))) + bin_data = [int(x) for x in bin_data] + + # data size in bytes + data_size = len(bin_data) / 8 + num_words = int(data_size / word_size) + + bytes_per_col = sqrt(num_words) + + self.words_per_row = int(ceil(bytes_per_col /(2*word_size))) + + bits_per_row = self.words_per_row * word_size * 8 + + chunked_data = [] + + for i in range(0, len(bin_data), bits_per_row): + word = bin_data[i:i + bits_per_row] + if len(word) < bits_per_row: + word = [0] * (bits_per_row - len(word)) + word + chunked_data.append(word) + + if endian == "big": + chunked_data.reverse() + + self.data = chunked_data + self.cols = bits_per_row + self.rows = int(num_words / (self.words_per_row)) + # print("hex: {0}, binary: {1}, chunked: {2}".format(hex_data, bin_data, chunked_data)) + + def create_netlist(self): self.add_modules() + # self.add_pins() self.create_instances() def create_layout(self): self.place_instances() - self.create_wl_bus() + # self.channel_route() self.route_decode_outputs() - self.route_array_inputs() + self.route_control() self.route_supplies() self.height = self.array_inst.height @@ -47,12 +89,31 @@ class rom_base_bank(design): self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_layer)] self.bus_layer_width = drc["minwidth_{}".format(self.bus_layer)] self.bus_layer_pitch = drc["{0}_to_{0}".format(self.bus_layer)] + self.interconnect_layer_width = drc["minwidth_{}".format(self.interconnect_layer)] + self.interconnect_layer_pitch = drc["{0}_to_{0}".format(self.interconnect_layer)] + + def add_pins(self): + self.add_pin("READ", "INPUT") + self.add_pin("CS", "INPUT") + + for i in range(self.num_inputs): + self.add_pin("addr_{}".format(i), "INPUT") + + + out_pins = [] + for j in range(self.num_outputs): + out_pins.append("rom_out_{}".format(j)) + self.add_pin_list(out_pins, "OUTPUT") + + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + def add_modules(self): - self.array = factory.create(module_type="rom_base_array", cols=self.cols, rows=self.rows, strap_spacing=self.strap_spacing, bitmap=self.data, route_layer=self.route_layer) + self.array = factory.create(module_type="rom_base_array", cols=self.cols, rows=self.rows, strap_spacing=self.strap_spacing, bitmap=self.data, route_layer=self.route_layer, pitch_match=True) self.decode_array = factory.create(module_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer) - + self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.rows + self.cols) / 2, height=self.decode_array.inv_inst.height) def create_instances(self): @@ -66,7 +127,7 @@ class rom_base_bank(design): name = "wl_{}".format(wl) array_pins.append(wl) - array_pins.append("array_precharge") + array_pins.append("precharge") array_pins.append("vdd") array_pins.append("gnd") @@ -78,7 +139,7 @@ class rom_base_bank(design): name = "wl_{}".format(wl) decode_pins.append(name) - decode_pins.append("decode_precharge") + decode_pins.append("precharge") decode_pins.append("vdd") decode_pins.append("gnd") @@ -89,20 +150,26 @@ class rom_base_bank(design): self.decode_inst = self.add_inst(name="rom_decoder", mod=self.decode_array) self.connect_inst(decode_pins) + self.control_inst = self.add_inst(name="rom_control", mod=self.control_logic) + self.connect_inst(["READ", "CS", "precharge", "vdd", "gnd"]) + def place_instances(self): - - array_x = self.decode_inst.width + (self.rows + 2) * ( self.route_layer_width + self.route_layer_pitch ) - array_y = self.array.height - + + array_x = self.decode_inst.width + (2) * ( self.route_layer_width + self.route_layer_pitch ) + array_y = self.decode_array.inv_inst.height - self.array.precharge_inst.cy() - self.array.dummy.height * 0.5 self.array_offset = vector(array_x ,array_y) self.decode_offset = vector(0, 0) - self.array_inst.place(offset=self.array_offset, mirror="MX") + self.control_offset = vector(0,0) + + self.array_inst.place(offset=self.array_offset) self.decode_inst.place(offset=self.decode_offset) + self.control_inst.place(offset=self.control_offset, mirror="MX") + def create_wl_bus(self): bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width @@ -119,13 +186,17 @@ class rom_base_bank(design): decode_output = self.decode_array.output_names[wl] decode_out_pin = self.decode_inst.get_pin(decode_output) - wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] + array_wl = self.array.wordline_names[0][wl] + array_wl_pin = self.array_inst.get_pin(array_wl) + + + # wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] start = decode_out_pin.center() - end = vector(wl_bus_wire.cx(), start.y) + end = vector(array_wl_pin.cx(), start.y) - self.add_segment_center(self.interconnect_layer, start, end) - self.add_via_stack_center(end, self.route_layer, self.interconnect_layer ) + self.add_segment_center(self.bus_layer, start, end) + self.add_via_stack_center(array_wl_pin.center(), self.bus_layer, self.interconnect_layer ) def route_array_inputs(self): @@ -142,18 +213,52 @@ class rom_base_bank(design): self.add_segment_center(self.interconnect_layer, start, end) self.add_via_stack_center(start, self.route_layer, self.interconnect_layer ) + def channel_route(self): + route_nets = [] + for wl in range(self.rows): + array_wl = self.array.wordline_names[0][wl] + + array_wl_pin = self.array_inst.get_pin(array_wl) + + decode_output = self.decode_array.output_names[wl] + decode_out_pin = self.decode_inst.get_pin(decode_output) + + route_nets.append([array_wl_pin, decode_out_pin]) + + array_prechrg = self.array_inst.get_pin("precharge") + decode_prechrg = self.decode_inst.get_pin("precharge") + route_nets.append([array_prechrg, decode_prechrg]) + + channel_start = vector(decode_out_pin.cx(), self.decode_array.array_inst.by()) + + channel = self.create_vertical_channel_route(netlist=route_nets, offset=channel_start, layer_stack=self.m1_stack, directions="nonpref") + + + def route_control(self): + + prechrg_control = self.control_inst.get_pin("prechrg") + decode_prechrg = self.decode_inst.get_pin("precharge") + array_prechrg = self.array_inst.get_pin("precharge") + + end = vector(decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy()) + + self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end) + + start = end + vector(0.5 * self.interconnect_layer_width, 0) + self.add_segment_center(self.interconnect_layer, start, decode_prechrg.center()) + + + def route_supplies(self): gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0) - print() - print(self.decode_inst.get_pin("gnd").center()) + decode_gnd = self.decode_inst.get_pin("gnd") decode_vdd = self.decode_inst.get_pin("vdd") array_vdd = self.array_inst.get_pin("vdd") - self.add_segment_center("m1", gnd_start, decode_gnd.center()) + # self.add_segment_center("m1", gnd_start, decode_gnd.center()) - self.add_power_pin("gnd", decode_vdd.center()) self.add_power_pin("vdd", decode_gnd.center()) diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index b6b5a8dd..668bc82d 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -17,9 +17,7 @@ class rom_base_cell(rom_dummy_cell): def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"): super().__init__(name, cell_name, add_source_contact, add_drain_contact, route_layer) - #self.route_layer= route_layer - #self.create_netlist() - #self.create_layout() + def create_netlist(self): @@ -27,7 +25,6 @@ class rom_base_cell(rom_dummy_cell): self.add_nmos() self.create_nmos() - def create_layout(self): self.setup_drc_offsets() self.place_nmos() @@ -64,15 +61,7 @@ class rom_base_cell(rom_dummy_cell): self.copy_layout_pin(self.cell_inst, "S", "S") self.copy_layout_pin(self.cell_inst, "D", "D") self.source_pos = self.cell_inst.get_pin("S").center() - # if self.add_source_contact != False: - # # drain_x = 0 - # # drain_y = 0.5 * (self.width - self.poly_extend_active_spacing) - - # print("drained") - # print(drain_pos) - # self.add_layout_pin_rect_center("S", self.route_layer, drain_pos) - # self.add_label("S", self.route_layer, self.cell_inst.get_pin("S").center()) diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py new file mode 100644 index 00000000..4d3da899 --- /dev/null +++ b/compiler/modules/rom_control_logic.py @@ -0,0 +1,81 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2022 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# + +from openram.sram_factory import factory +from openram.base import vector, design + + +class rom_control_logic(design): + def __init__(self, num_outputs, name="", height=None): + self.output_size = num_outputs + self.mod_height = height + + # dff = factory.create(module_type="dff") + + # if height == None: + # self.mod_height = dff.height * 0.5 + # else: + # self.mod_height = height + + super().__init__(name) + self.create_netlist() + self.create_layout() + self.add_boundary() + + + def create_netlist(self): + self.add_modules() + self.add_pins() + + def create_layout(self): + self.create_instances() + self.height=self.nand_inst.height + self.width=self.nand_inst.width + self.inv_inst.width + self.driver_inst.width + self.place_instances() + self.route_insts() + + def add_modules(self): + + self.inv_mod = factory.create(module_type="pinv", module_name="rom_control_logic_pinv", height=self.mod_height) + self.nand_mod = factory.create(module_type="pnand2", module_name="rom_control_nand", height=self.mod_height) + self.driver_mod = factory.create(module_type="pdriver", inverting=True, fanout=self.output_size, height=self.mod_height, add_wells=False) + + + def add_pins(self): + self.add_pin("READ", "INPUT") + self.add_pin("CS", "INPUT") + self.add_pin("prechrg", "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def create_instances(self): + + self.inv_inst = self.add_inst(name="read_signal_inv", mod=self.inv_mod) + self.connect_inst(["READ", "READ_BAR", "vdd", "gnd"]) + + self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod) + self.connect_inst(["CS", "READ_BAR", "pre_drive", "vdd", "gnd"]) + + self.driver_inst = self.add_inst(name="driver_inst", mod=self.driver_mod) + self.connect_inst(["pre_drive", "prechrg", "vdd", "gnd"]) + + + def place_instances(self): + self.nand_inst.place(offset=[self.inv_inst.width, 0]) + self.driver_inst.place(offset=[self.nand_inst.width + self.inv_inst.width, 0]) + + def route_insts(self): + + self.copy_layout_pin(self.inv_inst, "A", "READ") + self.copy_layout_pin(self.driver_inst, "Z", "prechrg") + self.copy_layout_pin(self.nand_inst, "B", "CS") + + self.add_path("li", [self.inv_inst.get_pin("Z").center(), self.nand_inst.get_pin("A").center()]) + + self.add_path("li", [self.nand_inst.get_pin("Z").center(), self.driver_inst.get_pin("A").center()]) + \ No newline at end of file diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index 0cd1ba16..34fb5453 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -5,15 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # - from math import ceil, log -from openram.base import design from openram.sram_factory import factory -from openram.base import vector +from openram.base import vector, design from openram import OPTS from openram.tech import drc + class rom_decoder(design): def __init__(self, num_outputs, strap_spacing, name="", route_layer="li", output_layer="m2"): @@ -25,7 +24,7 @@ class rom_decoder(design): self.num_inputs = ceil(log(num_outputs, 2)) self.create_decode_map() - for i in range(2 * self.num_inputs): print(self.decode_map[i]) + # for i in range(2 * self.num_inputs): print(self.decode_map[i]) super().__init__(name) @@ -152,7 +151,6 @@ class rom_decoder(design): def place_input_inverters(self): - print(self.array_inst.ll().x) self.inv_inst.place(vector(self.array_inst.ll().x, 0)) @@ -163,7 +161,6 @@ class rom_decoder(design): def create_outputs(self): self.output_names = [] - self.outputs = [] for j in range(self.num_outputs): name = "out_{0}".format(j) self.output_names.append(name) @@ -179,6 +176,8 @@ class rom_decoder(design): def connect_inputs(self): + self.copy_layout_pin(self.array_inst, "precharge") + for i in range(self.num_inputs): wl = self.num_inputs * 2 - i * 2 - 1 wl_bar = wl - 1 @@ -235,14 +234,8 @@ class rom_decoder(design): offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy())) - - - # self.add_rect_center(self.route_layer, offset, width, height) - - start = end - vector(0, 0.5 * minwidth) end = vector(start.x, array_gnd[1].uy()) - # self.add_segment_center("m1", start, end) diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py index 4ddbc1c7..bf5932b6 100644 --- a/compiler/modules/rom_dummy_cell.py +++ b/compiler/modules/rom_dummy_cell.py @@ -18,8 +18,8 @@ class rom_dummy_cell(design): def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"): super().__init__(name, cell_name) self.route_layer = route_layer - self.add_source_contact=add_source_contact - self.add_drain_contact=add_drain_contact + self.add_source_contact="li" + self.add_drain_contact="li" self.create_netlist() self.create_layout() @@ -70,12 +70,22 @@ class rom_dummy_cell(design): def add_boundary(self): - #cell width with offsets applied, height becomes width when the cells are rotated - # self.width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active - self.width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active - # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied - self.height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) + width = self.nmos.width + self.active_space + #cell width with offsets applied, height becomes width when the cells are rotated + # width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active + # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied + height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) + + # make the cells square so the pitch of wordlines will match bitlines + print("height: {0} width: {1}".format(height, width)) + if width > height: + self.width = width + self.height = width + else: + self.width = height + self.height = height + super().add_boundary() diff --git a/compiler/modules/rom_inv_array.py b/compiler/modules/rom_inv_array.py index cc87dc24..5774e2fc 100644 --- a/compiler/modules/rom_inv_array.py +++ b/compiler/modules/rom_inv_array.py @@ -56,7 +56,7 @@ class rom_inv_array(design): def create_modules(self): self.inv_mod = factory.create(module_type="pinv", module_name="inv_array_mod", height=self.inv_size, add_wells=False) - self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size) + self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size, add_wells=True) # For layout constants self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=0) @@ -73,7 +73,6 @@ class rom_inv_array(design): for col in range(self.cols): name = "Xinv_c{0}".format(col) if col == self.cols - 1: - print("TAP ME DOWN") self.inv_insts.append(self.add_inst(name=name, mod=self.end_inv)) else: self.inv_insts.append(self.add_inst(name=name, mod=self.inv_mod)) diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index c01ac380..ec6a1a4e 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -13,7 +13,7 @@ from openram.sram_factory import factory class rom_poly_tap(design): - def __init__(self, name, strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m1"): + def __init__(self, name="", strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m1"): super().__init__(name, cell_name, prop) self.strap_layer=strap_layer self.length = strap_length @@ -37,13 +37,20 @@ class rom_poly_tap(design): def add_boundary(self): + contact_width = self.poly_contact.width + 2 * self.contact_x_offset + + offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact) + print("THINGY {}".format(offset)) self.height = self.dummy.height - self.width = self.poly_contact.width + 2 * self.contact_x_offset + self.width = contact_width + self.pitch_offset + + print("poly height: {0}, width: {1}".format(self.height, self.width)) super().add_boundary() def place_via(self): contact_width = self.poly_contact.width + # DRC rule here is hard coded since licon.9 isnt included in skywater130 tech file # poly contact spacing to P-diffusion < 0.235um (licon.9 + psdm.5a) @@ -59,23 +66,16 @@ class rom_poly_tap(design): # self.contact_x_offset = 0 else: contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x - print(self.tx_type) - print(contact_y) # contact_x = - contact_width * 0.5 - self.contact_x_offset contact_x = contact_width * 0.5 + self.contact_x_offset self.contact_offset = vector(contact_x, contact_y) - print("polycule") - print(self.contact_offset) + self.via = self.add_via_stack_center(from_layer="poly", to_layer=self.strap_layer, offset=self.contact_offset) self.add_layout_pin_rect_center("via", self.strap_layer, self.contact_offset) - # if self.length == 0: - # self.add_layout_pin_rect_center(text="poly_tap", - # layer=self.strap_layer, - # offset=print()contact_offset, - # ) + @@ -88,14 +88,21 @@ class rom_poly_tap(design): self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) def extend_poly(self): + + base_contact_width = self.poly_contact.width + 2 * self.contact_x_offset + + self.pitch_offset = (base_contact_width - self.active_enclose_contact - self.active_extend_contact) - self.active_space + + poly_x = self.poly_contact.width + self.contact_x_offset poly_y = self.contact_offset.y - self.poly_width * 0.5 extend_offset = vector(poly_x, poly_y) - self.add_rect("poly", extend_offset, self.contact_x_offset, self.poly_width) + + self.add_rect("poly", extend_offset, self.contact_x_offset + self.pitch_offset, self.poly_width) poly_x = 0 extend_offset = vector(poly_x, poly_y) - self.add_rect("poly", extend_offset, self.contact_x_offset, self.poly_width) + self.add_rect("poly", extend_offset, self.contact_x_offset , self.poly_width) diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index dc7fbb77..8acfb8c8 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -139,6 +139,7 @@ class rom_precharge_array(design): def create_layout_pins(self): + self.copy_layout_pin(self.tap_insts[0], "via", "gate") for col in range(self.cols): source_pin = self.pmos_insts[col].get_pin("D") bl = "pre_bl{0}_out".format(col) diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 2eb5c447..d41f07c2 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -50,12 +50,12 @@ class rom_precharge_cell(design): self.cell_inst = self.add_inst( name="precharge_pmos", mod=self.pmos, ) - self.connect_inst(["bitline", "gate", "vdd", "vdd"]) + self.connect_inst(["bitline", "gate", "vdd", "body"]) def add_pins(self): - pin_list = ["vdd", "gate", "bitline", "vdd"] - dir_list = ["OUTPUT", "INPUT", "OUTPUT", "POWER"] + pin_list = ["vdd", "gate", "bitline", "body"] + dir_list = ["POWER", "INPUT", "OUTPUT", "INPUT"] self.add_pin_list(pin_list, dir_list) diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/05_rom_array_test.py index 13708a6c..790d8839 100644 --- a/compiler/tests/05_rom_array_test.py +++ b/compiler/tests/05_rom_array_test.py @@ -27,7 +27,7 @@ class rom_array_test(openram_test): data = [[1, 0, 0, 0, 0, 1, 0, 0, 1], [0, 1, 1, 1, 0, 1, 0, 0, 1], [1, 0, 1, 1, 0, 1, 0, 0, 1], [1, 1, 0, 1, 1, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 0, 0, 1], [0, 1, 1, 1, 1, 0, 0, 0, 1], [1, 0, 1, 1, 1, 0, 0, 0, 1], [1, 1, 0, 0, 1, 1, 0, 0, 1]] - a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4) + a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4, pitch_match=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/05_rom_base_bank_test.py b/compiler/tests/05_rom_base_bank_test.py index 2685b57b..277205b1 100644 --- a/compiler/tests/05_rom_base_bank_test.py +++ b/compiler/tests/05_rom_base_bank_test.py @@ -24,7 +24,7 @@ class rom_bank_test(openram_test): debug.info(2, "Testing 4x4 array for rom cell") - a = factory.create(module_type="rom_base_bank", strap_spacing = 2) + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data", word_size=1) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/05_rom_control_logic_test.py b/compiler/tests/05_rom_control_logic_test.py new file mode 100644 index 00000000..4e13b9bf --- /dev/null +++ b/compiler/tests/05_rom_control_logic_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import unittest +from testutils import * +import sys, os + +import openram +from openram import OPTS +from openram.sram_factory import factory +from openram import debug + + +class rom_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + debug.info(2, "Testing control logic for rom cell") + + + a = factory.create(module_type="rom_control_logic", num_outputs=4) + self.local_check(a) + openram.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner())