From 559300e5cceeac8d6327d9a84e22d8e9acf61548 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Sun, 22 Jan 2023 18:34:11 -0800 Subject: [PATCH] taps in main array and decoder --- compiler/modules/pinvbuf.py | 37 ++- compiler/modules/rom_base_array.py | 189 +++++++++----- compiler/modules/rom_base_bank.py | 238 ++++++++++++------ compiler/modules/rom_base_cell.py | 18 +- compiler/modules/rom_column_mux.py | 55 ++-- compiler/modules/rom_column_mux_array.py | 28 ++- compiler/modules/rom_control_logic.py | 110 ++++++-- compiler/modules/rom_decoder.py | 95 ++++--- compiler/modules/rom_poly_tap.py | 104 ++++---- compiler/modules/rom_precharge_array.py | 124 +++++---- compiler/modules/rom_precharge_cell.py | 75 +++--- compiler/modules/rom_wordline_driver_array.py | 40 ++- compiler/tests/05_rom_base_bank_test.py | 2 +- compiler/tests/05_rom_control_logic_test.py | 2 +- 14 files changed, 692 insertions(+), 425 deletions(-) diff --git a/compiler/modules/pinvbuf.py b/compiler/modules/pinvbuf.py index 2ac793c6..c277dd2a 100644 --- a/compiler/modules/pinvbuf.py +++ b/compiler/modules/pinvbuf.py @@ -17,13 +17,14 @@ class pinvbuf(pgate): This is a simple inverter/buffer used for driving loads. It is used in the column decoder for 1:2 decoding and as the clock buffer. """ - def __init__(self, name, size=4, height=None): + def __init__(self, name, size=4, height=None, route_in_cell=False): debug.info(1, "creating pinvbuf {}".format(name)) self.add_comment("size: {}".format(size)) self.stage_effort = 4 self.row_height = height + self.route_in_cell = route_in_cell # FIXME: Change the number of stages to support high drives. # stage effort of 4 or less @@ -132,15 +133,35 @@ class pinvbuf(pgate): to_layer=a3_pin.layer, offset=a3_pin.center()) - # inv1 Z to inv4 A (up and over) z1_pin = self.inv1_inst.get_pin("Z") a4_pin = self.inv4_inst.get_pin("A") - mid_point = vector(z1_pin.cx(), a4_pin.cy()) - self.add_wire(route_stack, - [z1_pin.center(), mid_point, a4_pin.center()]) - self.add_via_stack_center(from_layer=z1_pin.layer, - to_layer=route_stack[2], - offset=z1_pin.center()) + if self.route_in_cell: + # inv1 Z to inv4 A (under and up) + mid_point = vector(a4_pin.cx(), z1_pin.cy()) + end_point = a4_pin.center() + # end_point = vector(a4_pin.cx(), a4_pin.by() - self.m1_space - self.contact_space) + self.add_path(route_stack[2], + [z1_pin.center(), mid_point, end_point]) + + self.add_via_stack_center(from_layer=z1_pin.layer, + to_layer=route_stack[2], + offset=z1_pin.center()) + + self.add_via_stack_center(from_layer=a4_pin.layer, + to_layer=route_stack[2], + offset=end_point) + + + self.add_segment_center(a4_pin.layer, end_point, a4_pin.center()) + else: + # inv1 Z to inv4 A (up and over) + + mid_point = vector(z1_pin.cx(), a4_pin.cy()) + self.add_wire(route_stack, + [z1_pin.center(), mid_point, a4_pin.center()]) + self.add_via_stack_center(from_layer=z1_pin.layer, + to_layer=route_stack[2], + offset=z1_pin.center()) def add_layout_pins(self): diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 030cedd7..2d2be82a 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -12,20 +12,25 @@ from .bitcell_base_array import bitcell_base_array from openram.base import vector from openram import OPTS from openram.sram_factory import factory -from openram.tech import drc +from openram.tech import drc, layer 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", pitch_match=False): + def __init__(self, rows, cols, strap_spacing, bitmap, tap_spacing = 4, name="", bitline_layer="m1", wordline_layer="m2", tap_direction="row", pitch_match=False): - super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset) + super().__init__(name=name, rows=rows, cols=cols, column_offset=0) self.data = bitmap + self.tap_direction = tap_direction self.pitch_match = pitch_match - self.route_layer = route_layer - self.output_layer = output_layer + self.bitline_layer = bitline_layer self.strap_spacing = strap_spacing + self.wordline_layer = wordline_layer self.data_col_size = self.column_size + self.tap_spacing = tap_spacing + + + if strap_spacing != 0: self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing) else: @@ -47,20 +52,23 @@ class rom_base_array(bitcell_base_array): def create_layout(self): self.create_layout_constants() self.place_array() - if self.pitch_match: + if self.tap_direction == "row": self.route_pitch_offsets() + self.place_precharge() self.place_wordline_contacts() self.place_bitline_contacts() - - - - self.route_precharge() - self.add_boundary() + self.route_precharge() self.place_rails() - self.add_label("ARRAY ZERO", self.route_layer) - self.add_label("array height", self.route_layer, [0, self.height]) + self.connect_taps() + + + + + + + @@ -79,22 +87,32 @@ class rom_base_array(bitcell_base_array): def add_modules(self): - self.zero_cell = factory.create(module_name="rom_base_zero_cell", module_type="rom_base_cell", bitline_layer=self.route_layer, bit_value=0) - self.one_cell = factory.create(module_name="rom_base_one_cell", module_type="rom_base_cell", bitline_layer=self.route_layer, bit_value=1) + self.zero_cell = factory.create(module_name="rom_base_zero_cell", + module_type="rom_base_cell", + bitline_layer=self.bitline_layer, + bit_value=0) + self.one_cell = factory.create(module_name="rom_base_one_cell", + module_type="rom_base_cell", + bitline_layer=self.bitline_layer, + bit_value=1) - self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing) - - self.zero_tap = factory.create(module_type="rom_poly_tap", strap_length=0) - - - self.precharge_array = factory.create(module_type="rom_precharge_array", cols=self.column_size, strap_spacing=self.strap_spacing, route_layer=self.route_layer) + if self.tap_direction == "row": + self.poly_tap = factory.create(module_type="rom_poly_tap") + else: + self.poly_tap = factory.create(module_type="rom_poly_tap", add_tap=True) + self.precharge_array = factory.create(module_type="rom_precharge_array", + cols=self.column_size, + strap_spacing=self.strap_spacing, + route_layer=self.bitline_layer, + strap_layer=self.wordline_layer, + tap_direction=self.tap_direction) def create_layout_constants(self): - self.route_width = drc("minwidth_" + self.route_layer) + self.route_width = drc("minwidth_" + self.bitline_layer) - self.route_pitch = drc("{0}_to_{0}".format(self.route_layer)) + self.route_pitch = drc("{0}_to_{0}".format(self.bitline_layer)) def add_pins(self): @@ -108,8 +126,10 @@ class rom_base_array(bitcell_base_array): def create_cell_instances(self): self.tap_inst = {} + self.tap_list = [] self.cell_inst = {} self.cell_list = [] + self.current_row = 0 #list of current bitline interconnect nets, starts as the same as the bitline list and is updated when new insts of cells are added self.int_bl_list = self.bitline_names[0].copy() @@ -120,15 +140,10 @@ class rom_base_array(bitcell_base_array): # for each new strap placed, offset the column index refrenced to get correct bit in the data array # cols are bit lines - 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: - self.create_tap(row, col) + self.create_poly_tap(row, col) new_inst = self.create_cell(row, col) @@ -139,7 +154,9 @@ class rom_base_array(bitcell_base_array): name = "tap_r{0}_c{1}".format(row, self.array_col_size) - self.tap_inst[row, 0]=self.add_inst(name=name, mod=self.zero_tap) + new_tap = self.add_inst(name=name, mod=self.poly_tap) + self.tap_inst[row, self.column_size] = new_tap + self.tap_list.append(new_tap) self.connect_inst([]) self.cell_list.append(row_list) @@ -147,7 +164,9 @@ class rom_base_array(bitcell_base_array): def create_poly_tap(self, row, col): name = "tap_r{0}_c{1}".format(row, col) - self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) + new_tap = self.add_inst(name=name, mod=self.poly_tap) + self.tap_inst[row, col]=new_tap + self.tap_list.append(new_tap) self.connect_inst([]) @@ -205,33 +224,32 @@ class rom_base_array(bitcell_base_array): def place_rails(self): + via_width = drc("m2_enclose_via1") * 0.5 + drc("minwidth_via1") + pitch = drc["{0}_to_{0}".format(self.wordline_layer)] - self.route_horizontal_pins("D", insts=self.cell_list[self.row_size - 1]) - self.copy_layout_pin(self, "D", "gnd") + for i in range(self.column_size): + drain = self.cell_list[self.row_size - 1][i].get_pin("D") + + gnd_pos = drain.center() + vector(0, pitch + via_width + self.route_pitch) + self.add_layout_pin_rect_center(text="gnd", layer=self.bitline_layer, offset=gnd_pos) + self.route_horizontal_pins("gnd", insts=[self], yside="cy") + + + self.copy_layout_pin(self.precharge_inst, "vdd") - def place_well_tap(self): - tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 - contact_pos = vector(self.via.cx(), tap_y) - self.add_via_center(layers=self.active_stack, - offset=contact_pos, - implant_type="p", - well_type="p") - self.add_power_pin(name="gnd", - loc=contact_pos, - start_layer=self.active_stack[2]) def place_array(self): self.cell_pos = {} self.strap_pos = {} # rows are wordlines - + col_offset = 0 pitch_offset = 0 for row in range(self.row_size): - # if row % self.strap_spacing == 0 and row != 0 and self.pitch_match: - # pitch_offset += self.poly_tap.width + if row % self.tap_spacing == 0 and self.pitch_match: + pitch_offset += self.active_contact.width + self.active_space cell_y = row * (self.zero_cell.height) + pitch_offset @@ -241,7 +259,9 @@ class rom_base_array(bitcell_base_array): if col % self.strap_spacing == 0: self.strap_pos[row, col] = vector(cell_x, cell_y) self.tap_inst[row, col].place(self.strap_pos[row, col]) - # cell_x += self.poly_tap.width + + if self.tap_direction == "col": + cell_x += self.poly_tap.pitch_offset self.cell_pos[row, col] = vector(cell_x, cell_y) self.cell_inst[row, col].place(self.cell_pos[row, col]) @@ -249,25 +269,59 @@ class rom_base_array(bitcell_base_array): self.add_label("debug", "li", self.cell_pos[row, col]) - self.strap_pos[row, 0] = vector(0, cell_y) - self.tap_inst[row, 0].place(self.strap_pos[row, 0]) + self.strap_pos[row, self.column_size] = vector(cell_x, cell_y) + self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size]) - # tap_pin = self.tap_inst[row, 0].get_pin("poly_tap").center() - # 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") + for row in range(0 , self.row_size, self.tap_spacing): + for col in range(self.column_size): + cell = self.cell_inst[row, col] + + source = cell.get_pin("S") + + if row != 0: + 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) + self.add_segment_center(self.bitline_layer, start, end) + + self.place_well_tap(row, col) + + + + def place_well_tap(self, row, col): + cell = self.cell_inst[row, col] + source = cell.get_pin("S") + + if col != self.column_size - 1: + tap_x = (self.cell_inst[row , col + 1].get_pin("S").cx() + source.cx()) * 0.5 + else: + tap_x = cell.rx() + self.active_space + + if row != 0: + drain = self.cell_inst[row - 1, col].get_pin("D") + tap_y = (source.cy() + drain.cy()) * 0.5 + else: + tap_y = source.cy() - self.contact_width - 2 * self.active_enclose_contact - self.active_space + + + tap_pos = vector(tap_x, tap_y) + + self.add_via_center(layers=self.active_stack, + offset=tap_pos, + implant_type="p", + well_type="p", + directions="nonpref") + self.add_via_stack_center(offset=tap_pos, + from_layer=self.active_stack[2], + to_layer=self.wordline_layer) + self.add_layout_pin_rect_center("gnd", self.wordline_layer, tap_pos) + def place_precharge(self): @@ -285,14 +339,14 @@ class rom_base_array(bitcell_base_array): for wl in range(self.row_size): - self.copy_layout_pin(self.tap_inst[wl, 0], "via", self.wordline_names[0][wl]) + self.copy_layout_pin(self.tap_inst[wl, 0], "poly_tap", self.wordline_names[0][wl]) # self.add_via_stack_center(poly_via.center(), "m1", self.output_layer) # self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.zero_cell.height, length=None) def place_bitline_contacts(self): - rail_y = self.precharge_inst.get_pin("vdd").cy() + rail_y = self.precharge_inst.get_pins("vdd")[0].cy() for bl in range(self.column_size): @@ -303,13 +357,12 @@ class rom_base_array(bitcell_base_array): 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) output_pos = vector(corrected.x, rail_y) - self.add_segment_center(self.output_layer, corrected, output_pos) + self.add_segment_center(self.bitline_layer, corrected, output_pos) - self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, output_pos ) + self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.bitline_layer, output_pos ) @@ -322,7 +375,17 @@ class rom_base_array(bitcell_base_array): bl_start = bl_pin.center() bl_end = vector(bl_start.x, pre_out_pin.cy()) - self.add_segment_center(self.route_layer, bl_start, bl_end) + self.add_segment_center(self.bitline_layer, bl_start, bl_end) + def connect_taps(self): + array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))] + + self.connect_row_pins(layer=self.wordline_layer, pins=array_pins, name=None, round=False) + # self.connect_row_pins(layer="poly", pins=array_pins, name=None, round=False) + + if self.tap_direction == "col": + self.route_vertical_pins("active_tap", insts=self.tap_list, layer=self.supply_stack[0], full_width=False) + + def get_next_cell_in_bl(self, row_start, col): for row in range(row_start + 1, self.row_size): diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index 67bf2796..297af7f1 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -26,14 +26,17 @@ class rom_base_bank(design): # self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] self.strap_spacing = strap_spacing - if "li" in layer: - self.route_layer = "li" - else: - self.route_layer = "m1" - self.bus_layer = "m2" + self.tap_spacing = 8 self.interconnect_layer = "m1" + self.bitline_layer = "m1" + self.wordline_layer = "m2" super().__init__(name=name) + if "li" in layer: + self.route_stack = self.m1_stack + else: + self.route_stack = self.m2_stack + self.route_layer = self.route_stack[0] self.setup_layout_constants() self.create_netlist() self.create_layout() @@ -81,37 +84,46 @@ class rom_base_bank(design): def create_netlist(self): self.add_modules() # self.add_pins() + + print("Creating ROM bank instances") self.create_instances() def create_layout(self): + print("Placing ROM bank instances") self.place_instances() - # self.channel_route() - self.route_decode_outputs() - self.route_control() + print("Routing decoders to array") + self.route_decode_outputs() + + print("Routing precharge signal") + self.route_precharge() + + print("Routing clock signal") + self.route_clock() + self.route_array_outputs() # self.route_supplies() self.height = self.array_inst.height self.width = self.array_inst.width self.add_boundary() + print("Rom bank placement complete") + def setup_layout_constants(self): - self.route_layer_width = drc["minwidth_{}".format(self.route_layer)] - self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_layer)] - self.bus_layer_width = drc["minwidth_{}".format(self.bus_layer)] - self.bus_layer_pitch = drc["{0}_to_{0}".format(self.bus_layer)] + self.route_layer_width = drc["minwidth_{}".format(self.route_stack[0])] + self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_stack[0])] + 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("clk", "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.rows): out_pins.append("rom_out_{}".format(j)) @@ -122,17 +134,54 @@ class rom_base_bank(design): 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, pitch_match=True) - self.decode_array = factory.create(module_name="rom_row_decode", module_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer, cols=self.cols) - self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.rows + self.cols) / 2, height=self.decode_array.buf_inst.height) - self.column_mux = factory.create(module_type="rom_column_mux_array", columns=self.cols, word_size=self.word_size, bitline_layer=self.route_layer) + + print("Creating bank modules") + self.array = factory.create(module_type="rom_base_array", + cols=self.cols, + rows=self.rows, + strap_spacing=self.strap_spacing, + bitmap=self.data, + bitline_layer=self.bitline_layer, + wordline_layer=self.wordline_layer, + pitch_match=True, + tap_spacing=self.tap_spacing) - self.column_decode = factory.create(module_name="rom_column_decode", module_type="rom_decoder", num_outputs=self.words_per_row, strap_spacing=self.strap_spacing, route_layer=self.route_layer, cols=1) + + self.decode_array = factory.create(module_name="rom_row_decode", + module_type="rom_decoder", + num_outputs=self.rows, + strap_spacing=self.strap_spacing, + route_layer=self.route_layer, + cols=self.cols) + + + + + self.column_mux = factory.create(module_type="rom_column_mux_array", + columns=self.cols, + word_size=self.word_size, + bitline_layer=self.interconnect_layer) + + self.column_decode = factory.create(module_name="rom_column_decode", + module_type="rom_decoder", + num_outputs=self.words_per_row, + strap_spacing=self.strap_spacing, + route_layer=self.route_layer, + cols=1, + 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, + height=self.column_decode.height) + + print("Col decode height of {}".format(self.column_decode.height)) def create_instances(self): gnd = ["gnd"] vdd = ["vdd"] prechrg = ["precharge"] + clk = ["clk_int"] array_pins = [] decode_pins = [] @@ -156,6 +205,7 @@ class rom_base_bank(design): decode_pins.append(name) decode_pins.append("precharge") + decode_pins.append("clk_int") decode_pins.append("vdd") decode_pins.append("gnd") @@ -166,7 +216,7 @@ class rom_base_bank(design): addr_lsb = ["col_addr_{}".format(addr) for addr in range(self.col_bits)] col_mux_pins = bitlines + select_lines + bitline_out + gnd - col_decode_pins = addr_lsb + select_lines + prechrg + vdd + gnd + col_decode_pins = addr_lsb + select_lines + prechrg + clk + vdd + gnd self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array) self.connect_inst(array_pins) @@ -174,7 +224,7 @@ class rom_base_bank(design): 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"]) + self.connect_inst(["clk", "CS", "precharge", "clk_int", "vdd", "gnd"]) self.mux_inst = self.add_inst(name="rom_column_mux", mod=self.column_mux) self.connect_inst(col_mux_pins) @@ -187,13 +237,13 @@ class rom_base_bank(design): def place_instances(self): self.place_row_decoder() self.place_data_array() - self.place_control_logic() - self.place_col_decoder() self.place_col_mux() + self.place_col_decoder() + self.place_control_logic() def place_row_decoder(self): - self.decode_offset = vector(0, self.control_inst.height) + self.decode_offset = vector(0, self.control_inst.height - self.decode_array.control_array.height) self.decode_inst.place(offset=self.decode_offset) def place_data_array(self): @@ -208,53 +258,49 @@ class rom_base_bank(design): self.array_inst.place(offset=(self.array_offset + vector(0, array_align))) def place_control_logic(self): - self.control_offset = vector(0,0) - self.control_inst.place(offset=self.control_offset) + + + 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") def place_col_decoder(self): - self.col_decode_offset = vector(self.control_logic.width * 1.3, 0) + col_decode_y = self.mux_inst.get_pin("sel_0").cy() - self.col_decode_inst.get_pin("wl_0").cy() + self.col_decode_offset = vector(self.decode_inst.width - self.col_decode_inst.width, col_decode_y) self.col_decode_inst.place(offset=self.col_decode_offset) def place_col_mux(self): + mux_y_offset = self.array_inst.by() - self.mux_inst.height - self.route_layer_pitch - self.mux_offset = vector(self.decode_inst.width, 0) + mux_x_offset = self.array_inst.get_pin("bl_0_0").cx() - self.mux_inst.get_pin("bl_0").cx() + self.mux_offset = vector(mux_x_offset, mux_y_offset) self.mux_inst.place(offset=self.mux_offset) + # def create_wl_bus(self): + # bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) + # bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width + # self.wl_interconnects = [] - 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)) + # 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() ) + # 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)] decode_pins = [self.decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.rows)] route_pins.extend(decode_pins) self.connect_row_pins(self.interconnect_layer, route_pins, round=True) - # for wl in range(self.rows): - # decode_output = self.decode_array.output_names[wl] - # decode_out_pin = self.decode_inst.get_pin(decode_output) - # array_wl = self.array.wordline_names[0][wl] - # array_wl_pin = self.array_inst.get_pin(array_wl) + # then for the column decoder + col_decode_pins = [self.col_decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.words_per_row)] + sel_pins = [self.mux_inst.get_pin("sel_{}".format(wl)) for wl in range(self.words_per_row)] + sel_pins.extend(col_decode_pins) + self.connect_row_pins(self.array.bitline_layer, sel_pins, round=True) - # # wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] - - # start = decode_out_pin.center() - # end = vector(array_wl_pin.cx(), start.y) - - # 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): @@ -270,44 +316,88 @@ 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): + def route_precharge(self): prechrg_control = self.control_inst.get_pin("prechrg") - decode_prechrg = self.decode_inst.get_pin("precharge") + row_decode_prechrg = self.decode_inst.get_pin("precharge") + col_decode_prechrg = self.col_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()) + + # Route precharge signal to the row decoder + 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) start = end + vector(0.5 * self.interconnect_layer_width, 0) - self.add_segment_center(self.interconnect_layer, start, 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], + 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]) + + 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()) + + # 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) + + + 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]) + + self.add_via_stack_center(from_layer=self.route_stack[2], + to_layer=row_decode_clk.layer, + offset=end) + + self.add_segment_center(row_decode_clk.layer, end, 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]) + + 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()) + + + + + def route_array_outputs(self): + for i in range(self.cols): + bl_out = self.array_inst.get_pin("bl_0_{}".format(i)).center() + bl_mux = self.mux_inst.get_pin("bl_{}".format(i)).center() + + self.add_path(self.array.bitline_layer, [bl_out, bl_mux]) + def route_supplies(self): + + for inst in self.insts: + 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") diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index 83370d4d..c7297ec5 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -15,10 +15,11 @@ from openram.tech import drc class rom_base_cell(design): - def __init__(self, name="", bitline_layer="li", bit_value=1): + def __init__(self, name="", bitline_layer="li", bit_value=1, add_well=False): super().__init__(name) self.bit_value = bit_value self.bitline_layer = bitline_layer + self.add_well=add_well self.create_netlist() self.create_layout() @@ -39,6 +40,7 @@ class rom_base_cell(design): self.place_poly() if self.bit_value == 0: self.short_gate() + @@ -150,7 +152,19 @@ class rom_base_cell(design): self.add_segment_center(self.bitline_layer, self.get_pin("D").center(), self.get_pin("S").center()) - + # def place_tap(self): + + # tap_x = self.poly_contact.width * 0.5 + # tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 + + # contact_pos = vector(tap_x, tap_y) + # self.add_via_center(layers=self.active_stack, + # offset=contact_pos, + # implant_type="p", + # well_type="p") + # self.add_power_pin(name="gnd", + # loc=contact_pos, + # start_layer=self.active_stack[2]) diff --git a/compiler/modules/rom_column_mux.py b/compiler/modules/rom_column_mux.py index ae7ece30..4364d3e2 100644 --- a/compiler/modules/rom_column_mux.py +++ b/compiler/modules/rom_column_mux.py @@ -22,12 +22,12 @@ class rom_column_mux(pgate): Column-mux transistors driven by the decoder must be sized for optimal speed """ - def __init__(self, name, tx_size=8, bitline_layer="li"): + def __init__(self, name, tx_size=8, input_layer="m2", output_layer="m1"): debug.info(2, "creating single ROM column mux cell: {0}".format(name)) self.tx_size = int(tx_size) - self.bitline_layer = bitline_layer - + self.input_layer = input_layer + self.output_layer= output_layer super().__init__(name) @@ -42,16 +42,19 @@ class rom_column_mux(pgate): def create_layout(self): - # If li exists, use li and m1 for the mux, otherwise use m1 and m2 - if self.bitline_layer == "li" : - self.col_mux_stack = self.li_stack - else: - self.col_mux_stack = self.m1_stack - self.pin_layer = self.bitcell.bitline_layer + + self.pin_layer = self.input_layer self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer)) self.pin_width = getattr(self, "{}_width".format(self.pin_layer)) self.pin_height = 2 * self.pin_width + # If li exists, use li and m1 for the mux, otherwise use m1 and m2 + if self.output_layer == "li" : + self.col_mux_stack = self.li_stack + else: + self.col_mux_stack = self.m1_stack + + self.place_ptx() # cell = factory.create(module_type=OPTS.bitcell) @@ -69,7 +72,7 @@ class rom_column_mux(pgate): # self.add_pn_wells() def add_ptx(self): - self.bitcell = factory.create(module_type="rom_base_cell", bitline_layer=self.bitline_layer) + self.bitcell = factory.create(module_type="rom_base_cell") # Adds nmos_lower,nmos_upper to the module self.ptx_width = self.tx_size * drc("minwidth_tx") @@ -98,7 +101,7 @@ class rom_column_mux(pgate): # bl_out and br_out self.add_layout_pin(text="bl_out", - layer=self.col_mux_stack[2], + layer=self.col_mux_stack[0], offset=bl_pos, height=self.pin_height) @@ -147,18 +150,8 @@ class rom_column_mux(pgate): nmos_lower_d_pin = self.nmos_lower.get_pin("D") - # Add vias to bl, br_out, nmos_upper/S, nmos_lower/D - # self.add_via_stack_center(from_layer=bl_pin.layer, - # to_layer=self.col_mux_stack[0], - # offset=bl_pin.bc()) - # self.add_via_stack_center(from_layer=br_out_pin.layer, - # to_layer=self.col_mux_stack[0], - # offset=br_out_pin.uc()) - # self.add_via_stack_center(from_layer=nmos_upper_s_pin.layer, - # to_layer=self.col_mux_stack[2], - # offset=nmos_upper_s_pin.center()) self.add_via_stack_center(from_layer=nmos_lower_d_pin.layer, - to_layer=self.col_mux_stack[2], + to_layer=self.output_layer, offset=nmos_lower_d_pin.center()) # bl -> nmos_upper/D on metal1 @@ -167,29 +160,17 @@ class rom_column_mux(pgate): + nmos_lower_s_pin.uc().scale(0, 0.5) mid2 = bl_pin.bc().scale(0, 0.4) \ + nmos_lower_s_pin.uc().scale(1, 0.5) - self.add_path(self.col_mux_stack[0], + self.add_path(self.col_mux_stack[2], [bl_pin.bc(), mid1, mid2, nmos_lower_s_pin.center()]) # halfway up, move over mid1 = bl_out_pin.uc().scale(1, 0.4) \ + nmos_lower_d_pin.bc().scale(0, 0.4) mid2 = bl_out_pin.uc().scale(0, 0.4) \ + nmos_lower_d_pin.bc().scale(1, 0.4) - self.add_path(self.col_mux_stack[2], + self.add_path(self.col_mux_stack[0], [bl_out_pin.uc(), mid1, mid2, nmos_lower_d_pin.center()]) - # # br -> nmos_lower/D on metal2 - # # br_out -> nmos_lower/S on metal1 - # self.add_path(self.col_mux_stack[0], - # [br_out_pin.uc(), - # vector(nmos_lower_s_pin.cx(), br_out_pin.uy()), - # nmos_lower_s_pin.center()]) - # # halfway up, move over - # mid1 = br_pin.bc().scale(1, 0.5) \ - # + nmos_lower_d_pin.uc().scale(0, 0.5) - # mid2 = br_pin.bc().scale(0, 0.5) \ - # + nmos_lower_d_pin.uc().scale(1, 0.5) - # self.add_path(self.col_mux_stack[2], - # [br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()]) + def extend_implants(self): """ diff --git a/compiler/modules/rom_column_mux_array.py b/compiler/modules/rom_column_mux_array.py index a1a1fc29..1a119044 100644 --- a/compiler/modules/rom_column_mux_array.py +++ b/compiler/modules/rom_column_mux_array.py @@ -9,7 +9,7 @@ from openram import debug from openram.base import design from openram.base import vector from openram.sram_factory import factory -from openram.tech import layer, preferred_directions +from openram.tech import layer, preferred_directions, drc from openram.tech import layer_properties as layer_props from openram import OPTS @@ -20,18 +20,18 @@ class rom_column_mux_array(design): Array of column mux to read the bitlines from ROM, based on the RAM column mux """ - def __init__(self, name, columns, word_size, offsets=None, column_offset=0, bitline_layer="m1"): + def __init__(self, name, columns, word_size, input_layer="m2", bitline_layer="m1", sel_layer="m2"): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} word_size: {1} ".format(columns, word_size)) self.columns = columns self.word_size = word_size - self.offsets = offsets self.words_per_row = int(self.columns / self.word_size) - self.column_offset = column_offset + self.input_layer = input_layer + # self.sel_layer = layer_props.column_mux_array.select_layer + self.sel_layer = sel_layer - self.sel_layer = layer_props.column_mux_array.select_layer self.sel_pitch = getattr(self, self.sel_layer + "_pitch") self.bitline_layer = bitline_layer @@ -89,7 +89,9 @@ class rom_column_mux_array(design): self.width = self.columns * self.mux.width # one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br # one extra route pitch is to space from the sense amp - self.route_height = (self.words_per_row + 3) * self.sel_pitch + self.route_height = (self.words_per_row + 3) * self.cell.width + self.route_layer_width = drc["minwidth_{}".format(self.bitline_layer)] + self.route_layer_pitch = drc["{0}_to_{0}".format(self.bitline_layer)] def create_array(self): self.mux_inst = [] @@ -106,8 +108,7 @@ class rom_column_mux_array(design): def place_array(self): # Default to single spaced columns - if not self.offsets: - self.offsets = [n * self.mux.width for n in range(self.columns)] + self.offsets = [n * self.mux.width for n in range(self.columns)] # For every column, add a pass gate for col_num, xoffset in enumerate(self.offsets[0:self.columns]): @@ -145,7 +146,7 @@ class rom_column_mux_array(design): def add_horizontal_input_rail(self): """ Create address input rails below the mux transistors """ for j in range(self.words_per_row): - offset = vector(0, self.route_height + (j - self.words_per_row) * self.sel_pitch) + offset = vector(0, self.route_height + (j - self.words_per_row) * self.cell.width) self.add_layout_pin(text="sel_{}".format(j), layer=self.sel_layer, offset=offset, @@ -154,6 +155,7 @@ class rom_column_mux_array(design): def add_vertical_poly_rail(self): """ Connect the poly to the address rails """ + # Offset to the first transistor gate in the pass gate for col in range(self.columns): # which select bit should this column connect to depends on the position in the word @@ -165,7 +167,9 @@ class rom_column_mux_array(design): offset = vector(gate_offset.x, self.get_pin("sel_{}".format(sel_index)).cy()) - bl_offset = offset.scale(0, 1) + vector((self.mux_inst[col].get_pin("bl_out").cx()), 0) + bl_x_offset = self.mux_inst[col].get_pin("bl_out").cx() + 2 * self.route_layer_width + self.route_layer_pitch + 0.5 * self.poly_contact.width + + bl_offset = offset.scale(0, 1) + vector(bl_x_offset, 0) self.add_via_stack_center(from_layer="poly", to_layer=self.sel_layer, offset=bl_offset, @@ -178,12 +182,12 @@ class rom_column_mux_array(design): bl_offset_begin = self.mux_inst[j].get_pin("bl_out").bc() - bl_out_offset_begin = bl_offset_begin - vector(0, (self.words_per_row + 1) * self.sel_pitch) + bl_out_offset_begin = bl_offset_begin - vector(0, (self.words_per_row + 1) * self.cell.width) # Add the horizontal wires for the first bit if j % self.words_per_row == 0: bl_offset_end = self.mux_inst[j + self.words_per_row - 1].get_pin("bl_out").bc() - bl_out_offset_end = bl_offset_end - vector(0, (self.words_per_row + 1) * self.sel_pitch) + bl_out_offset_end = bl_offset_end - vector(0, (self.words_per_row + 1) * self.cell.width) self.add_path(self.sel_layer, [bl_out_offset_begin, bl_out_offset_end]) diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index 7801fad5..60410ab9 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -8,26 +8,34 @@ from openram.sram_factory import factory from openram.base import vector, design +from openram.tech import layer, drc class rom_control_logic(design): - def __init__(self, num_outputs, name="", height=None): + + def __init__(self, num_outputs, clk_fanout, name="", height=None): self.output_size = num_outputs - self.mod_height = height + super().__init__(name, prop=False) + self.height = height + if self.height is not None: + + print("got height of {}".format(self.height)) + self.driver_height = 0.6 * self.height + self.gate_height = 0.2 * self.height + else: + print("got none height") + self.gate_height = 20 * self.m1_pitch + self.driver_height = self.gate_height + + + self.clk_fanout = clk_fanout + if "li" in layer: - self.route_layer = "li" + self.route_stack = self.li_stack else: - self.route_layer = "m1" + self.route_stack = self.m1_stack - # 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() @@ -39,29 +47,40 @@ class rom_control_logic(design): 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.height=self.driver_inst.height + self.buf_inst.height + self.width= max(self.nand_inst.width + self.buf_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=True) + self.buf_mod = factory.create(module_type="pinvbuf", + module_name="rom_control_logic_pinv", + height=self.gate_height, + route_in_cell=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", + inverting=True, + fanout=self.output_size, + height=self.driver_height, + add_wells=True) def add_pins(self): - self.add_pin("clk", "INPUT") + self.add_pin("clk_in", "INPUT") self.add_pin("CS", "INPUT") self.add_pin("prechrg", "OUTPUT") + self.add_pin("clk_out", "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(["clk", "clk_bar", "vdd", "gnd"]) + 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.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod) self.connect_inst(["CS", "clk_bar", "pre_drive", "vdd", "gnd"]) @@ -71,16 +90,55 @@ class rom_control_logic(design): 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]) + 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]) def route_insts(self): + + route_width = drc["minwidth_{}".format(self.route_stack[2])] - self.copy_layout_pin(self.inv_inst, "A", "READ") + self.copy_layout_pin(self.buf_inst, "A", "clk_in") + self.copy_layout_pin(self.buf_inst, "Zb", "clkb_out") + self.copy_layout_pin(self.buf_inst, "Z", "clk_out") self.copy_layout_pin(self.driver_inst, "Z", "prechrg") self.copy_layout_pin(self.nand_inst, "B", "CS") + self.copy_layout_pin(self.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") - self.add_path(self.route_layer, [self.inv_inst.get_pin("Z").center(), self.nand_inst.get_pin("A").center()]) + clk_bar = self.buf_inst.get_pin("Zb") - self.add_path(self.route_layer, [self.nand_inst.get_pin("Z").center(), self.driver_inst.get_pin("A").center()]) - \ No newline at end of file + nand_B = self.nand_inst.get_pin("B") + + + # Connect buffered clock bar to nand input + + mid = vector(clk_bar.lx() - route_width - 2 * self.m1_space) + self.add_path(self.route_stack[2], [clk_bar.center(), mid, nand_B.center()]) + + self.add_via_stack_center(from_layer=clk_bar.layer, + to_layer=self.route_stack[2], + offset=clk_bar.center()) + self.add_via_stack_center(from_layer=nand_B.layer, + to_layer=self.route_stack[2], + offset=nand_B.center()) + + + # 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()]) + + + self.add_via_stack_center(from_layer=nand_Z.layer, + to_layer=self.route_stack[2], + offset=nand_output) + + self.add_via_stack_center(from_layer=driver_A.layer, + to_layer=self.route_stack[2], + offset=driver_A.center()) \ No newline at end of file diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index 46687611..4a40444b 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -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="m2"): + def __init__(self, num_outputs, cols, 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 @@ -34,7 +34,11 @@ class rom_decoder(design): self.output_layer = output_layer self.inv_route_layer = "m2" self.cols=cols + self.invert_outputs=invert_outputs self.create_netlist() + + self.width = self.array_mod.height + self.wordline_buf.width + self.height = self.array_mod.width + self.control_array.height self.create_layout() def create_netlist(self): @@ -49,10 +53,9 @@ class rom_decoder(design): self.place_input_buffer() self.place_driver() self.route_outputs() - self.width = self.array_inst.height + self.wordline_buf_inst.width - self.height = self.array_inst.width + self.buf_inst.height + self.connect_inputs() - # self.route_supplies() + self.route_supplies() self.add_boundary() def setup_layout_constants(self): @@ -97,18 +100,24 @@ class rom_decoder(design): for j in range(self.num_outputs): self.add_pin("wl_{0}".format(j), "OUTPUT") - self.add_pin("precharge_gate", "INPUT") + self.add_pin("precharge", "INPUT") + self.add_pin("clk", "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") def add_modules(self): - self.control_array = factory.create(module_type="rom_address_control_array", cols=self.num_inputs) + self.control_array = factory.create(module_type="rom_address_control_array", + cols=self.num_inputs) + self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), \ - rows=self.num_outputs, \ - cols=self.cols) + rows=self.num_outputs, \ + cols=self.cols, + invert_outputs=self.invert_outputs, + tap_spacing=self.strap_spacing) + self.array_mod = factory.create(module_type="rom_base_array", \ module_name="{}_array".format(self.name), \ @@ -116,8 +125,8 @@ class rom_decoder(design): rows=2 * self.num_inputs, \ bitmap=self.decode_map, strap_spacing = self.strap_spacing, - route_layer=self.route_layer, - output_layer=self.output_layer) + bitline_layer=self.output_layer, + tap_direction="col") def create_instances(self): @@ -135,8 +144,8 @@ class rom_decoder(design): for i in range(self.num_inputs): control_pins.append("A{0}".format(i)) - control_pins.append("A{0}_int".format(i)) - control_pins.append("Abar{0}_int".format(i)) + control_pins.append("in_{0}".format(i)) + control_pins.append("inbar_{0}".format(i)) control_pins.append("clk") control_pins.append("vdd") control_pins.append("gnd") @@ -156,7 +165,7 @@ class rom_decoder(design): for i in reversed(range(self.num_inputs)): array_pins.append("inbar_{0}".format(i)) array_pins.append("in_{0}".format(i)) - array_pins.append("precharge_gate") + array_pins.append("precharge") array_pins.append("vdd") array_pins.append("gnd") self.connect_inst(array_pins) @@ -173,10 +182,11 @@ class rom_decoder(design): def place_input_buffer(self): wl = self.array_mod.row_size - 1 align = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl]).cx() - self.buf_inst.get_pin("A0_out").cx() - print("align: {}".format(align)) self.buf_inst.place(vector(align, 0)) + self.copy_layout_pin(self.buf_inst, "clk") + def place_array(self): @@ -196,6 +206,9 @@ class rom_decoder(design): for j in range(self.num_outputs): self.copy_layout_pin(self.wordline_buf_inst, "out_{}".format(j), "wl_{}".format(j)) + offset = self.wordline_buf_inst.get_pin("out_{}".format(j)).center() + + # self.add_via_stack_center(offset, self.output_layer, self.wordline_buf.route_layer) array_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.num_outputs)] driver_pins = [self.wordline_buf_inst.get_pin("in_{}".format(bl)) for bl in range(self.num_outputs)] @@ -229,44 +242,50 @@ class rom_decoder(design): def route_supplies(self): minwidth = drc["minwidth_{}".format(self.inv_route_layer)] pitch = drc["{0}_to_{0}".format(self.inv_route_layer)] + self.copy_layout_pin(self.array_inst, "vdd") + self.copy_layout_pin(self.wordline_buf_inst, "vdd") + self.copy_layout_pin(self.buf_inst, "vdd") + self.copy_layout_pin(self.array_inst, "gnd") + self.copy_layout_pin(self.wordline_buf_inst, "gnd") + self.copy_layout_pin(self.buf_inst, "gnd") # route decode array vdd and inv array vdd together - array_vdd = self.array_inst.get_pin("vdd") - inv_vdd = self.buf_inst.get_pins("vdd")[-1] + # array_vdd = self.array_inst.get_pin("vdd") + # inv_vdd = self.buf_inst.get_pins("vdd")[-1] - end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth) - self.add_segment_center("m1", array_vdd.center(), end) - end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy()) - self.add_segment_center(self.route_layer, inv_vdd.center(), end) + # end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth) + # self.add_segment_center("m1", array_vdd.center(), end) + # end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy()) + # self.add_segment_center(self.route_layer, inv_vdd.center(), end) - end = vector(array_vdd.cx(), inv_vdd.cy()) - self.add_via_stack_center(end, self.route_layer, "m1") - self.add_layout_pin_rect_center("vdd", "m1", end) + # end = vector(array_vdd.cx(), inv_vdd.cy()) + # self.add_via_stack_center(end, self.route_layer, "m1") + # self.add_layout_pin_rect_center("vdd", "m1", end) - # route pin on inv gnd + # # route pin on inv gnd - inv_gnd = self.buf_inst.get_pins("gnd")[0] - array_gnd = self.array_inst.get_pins("gnd") + # inv_gnd = self.buf_inst.get_pins("gnd")[0] + # array_gnd = self.array_inst.get_pins("gnd") - # add x jog + # # add x jog - start = vector(array_gnd[0].cx(), inv_gnd.cy()) - self.add_via_stack_center(start, self.route_layer, "m1") - self.add_layout_pin_rect_center("gnd", "m1", start) + # start = vector(array_gnd[0].cx(), inv_gnd.cy()) + # self.add_via_stack_center(start, self.route_layer, "m1") + # self.add_layout_pin_rect_center("gnd", "m1", start) - end = array_gnd[0].center() - self.add_segment_center("m1", start, end) - # add y jog + # end = array_gnd[0].center() + # self.add_segment_center("m1", start, end) + # # add y jog - width = minwidth - height = array_gnd[0].uy() - array_gnd[-1].uy() + minwidth + # width = minwidth + # height = array_gnd[0].uy() - array_gnd[-1].uy() + minwidth - offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy())) + # offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy())) - start = end - vector(0, 0.5 * minwidth) - end = vector(start.x, array_gnd[1].uy()) + # start = end - vector(0, 0.5 * minwidth) + # end = vector(start.x, array_gnd[1].uy()) diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index c09ef984..31acee5a 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -14,36 +14,43 @@ from openram.tech import drc class rom_poly_tap(design): - def __init__(self, name="", strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m2"): - super().__init__(name, cell_name, prop) + def __init__(self, name="", cell_name=None, tx_type="nmos", strap_layer="m2", add_tap=False): + super().__init__(name, cell_name) self.strap_layer=strap_layer - self.length = strap_length self.tx_type = tx_type + self.add_tap = add_tap + self.pitch_offset = 0 self.create_netlist() self.create_layout() def create_netlist(self): #for layout constants - self.dummy = factory.create(module_type="rom_base_cell") + if self.tx_type == "nmos": + self.dummy = factory.create(module_type="rom_base_cell") + else: + self.dummy = factory.create(module_type="rom_precharge_cell") + self.pmos = factory.create(module_type="ptx", tx_type="pmos") def create_layout(self): self.place_via() - # if self.tx_type == "pmos": - self.extend_poly() - self.place_ptap() + + if self.add_tap: + self.place_active_tap() + self.extend_poly() self.add_boundary() + # if self.length != 0: # self.place_strap() def add_boundary(self): - contact_width = self.poly_contact.width + 2 * self.contact_x_offset + contact_width = self.poly_contact.width - offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact) + # offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact) self.height = self.dummy.height - self.width = contact_width + self.pitch_offset + self.width = contact_width + self.pitch_offset super().add_boundary() @@ -59,59 +66,66 @@ class rom_poly_tap(design): else: assert(False) + contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact + if self.tx_type == "nmos": - contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact + # contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact # contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) - # self.contact_x_offset = 0 - else: - contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x + self.contact_x_offset = 0 + # else: + # contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x - # contact_x = - contact_width * 0.5 - self.contact_x_offset - 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) 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) + self.add_layout_pin_rect_center("poly_tap", self.strap_layer, self.contact_offset) - def place_strap(self): + # def place_strap(self): - strap_start = vector(self.via.lx() , self.via.cy()) + # strap_start = vector(self.via.lx() , self.via.cy()) - strap_end = vector( self.dummy.width * (self.length + 1), self.via.cy()) + # strap_end = vector( self.dummy.width * (self.length + 1), self.via.cy()) - self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) + # 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 + + self.add_segment_center("poly", self.via.center(), vector(self.via.cx() + self.pitch_offset, self.via.cy())) + self.add_segment_center("poly", self.via.center(), vector(0, self.via.cy())) - 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.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) - def place_ptap(self): - tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 + def place_active_tap(self): + gap = self.poly_extend_active - 0.5 * ( self.active_contact.height - self.poly_contact.width ) + offset = self.active_space - gap + # tap_x = self.via.cx() + self.contact_width + self.active_enclose_contact + self.poly_enclose_contact + tap_x = self.via.cx() + offset + tap_y = self.via.cy() + self.dummy.width * 0.5 + contact_pos = vector(tap_x, tap_y) + + + # edge of the next nmos + active_edge = self.dummy.width - self.dummy.cell_inst.height - self.poly_extend_active + + # edge of the active contact + tap_edge = tap_x + 0.5 * self.active_contact.height + self.pitch_offset += (self.active_space * 2) - (tap_edge - active_edge) + self.contact_x_offset + + if self.tx_type == "nmos": + + self.add_via_center(layers=self.active_stack, + offset=contact_pos, + implant_type="p", + well_type="p", + directions="nonpref") + self.add_power_pin(name="gnd", + loc=contact_pos, + start_layer=self.active_stack[2]) + self.add_layout_pin_rect_center("active_tap", self.supply_stack[0], contact_pos) - contact_pos = vector(self.via.cx(), tap_y) - self.add_via_center(layers=self.active_stack, - offset=contact_pos, - implant_type="p", - well_type="p") - self.add_power_pin(name="gnd", - loc=contact_pos, - start_layer=self.active_stack[2]) diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index 247d2d4e..5fd585d1 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -19,25 +19,25 @@ class rom_precharge_array(design): """ An array of inverters to create the inverted address lines for the rom decoder """ - def __init__(self, cols, pmos_size=None, name="", route_layer="li", strap_spacing=None): + def __init__(self, cols, name="", route_layer="li", strap_spacing=None, strap_layer="m2", tap_direction="row"): self.cols = cols self.route_layer = route_layer + self.strap_layer = strap_layer + self.tap_direction = tap_direction + + if self.route_layer == "m1" : + self.supply_layer = "li" + else: + self.supply_layer = "m1" + if name=="": name = "rom_inv_array_{0}".format(cols) - # if pmos_size == None: - # self.pmos_size = dff.height * 0.5 - # else: - # self.pmos_size = inv_size + if strap_spacing != None: self.strap_spacing = strap_spacing else: self.strap_spacing = 0 - if "li" in layer: - self.inv_layer = "li" - else: - self.inv_layer = "m1" - if strap_spacing != 0: self.num_straps = ceil(self.cols / self.strap_spacing) @@ -62,28 +62,30 @@ class rom_precharge_array(design): self.height = self.pmos.width self.place_instances() self.create_layout_pins() - self.add_well_tap() self.route_supply() + self.connect_taps() self.add_boundary() - + self.extend_well() def add_boundary(self): # self.translate_all(self.well_ll) ur = self.find_highest_coords() + self.add_label(layer="nwell", text="upper right",offset=ur) # ur = vector(ur.x, ur.y - self.well_ll.y) super().add_boundary(vector(0, 0), ur) - self.width = self.cols * self.pmos.width self.height = ur.y + self.width = ur.x def create_modules(self): - self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", route_layer=self.route_layer) + self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", route_layer=self.route_layer, supply_layer=self.supply_layer) # For layout constants self.dummy = factory.create(module_type="rom_base_cell") - self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing) + + self.poly_tap = factory.create(module_type="rom_poly_tap", tx_type="pmos", add_tap=(self.tap_direction == "col")) def add_pins(self): for col in range(self.cols): @@ -96,33 +98,34 @@ class rom_precharge_array(design): self.pmos_insts = [] self.tap_insts = [] - self.tap_insts.append(self.add_inst(name="tap_0", mod=self.poly_tap)) - self.connect_inst([]) + self.create_poly_tap(-1) for col in range(self.cols): + if col % self.strap_spacing == 0: + self.create_poly_tap(col) + self.create_precharge_tx(col) - # if col % self.strap_spacing == 0: - # name = "tap_c{}".format(col) - # tap = self.add_inst(name=name, mod=self.poly_tap) - # self.array_insts.append(tap) - # self.tap_insts.append(tap) - # self.connect_inst([]) - name = "Xpmos_c{0}".format(col) - pmos = self.add_inst(name=name, mod=self.pmos) - self.array_insts.append(pmos) - self.pmos_insts.append(pmos) - bl = "pre_bl{0}_out".format(col) - self.connect_inst(["vdd", "gate", bl, "vdd"]) - print(self.array_insts) + def create_precharge_tx(self, col): + name = "Xpmos_c{0}".format(col) + pmos = self.add_inst(name=name, mod=self.pmos) + self.array_insts.append(pmos) + self.pmos_insts.append(pmos) + bl = "pre_bl{0}_out".format(col) + self.connect_inst(["vdd", "gate", bl]) + def create_poly_tap(self, col): + name = "tap_c{}".format( col) + new_tap = self.add_inst(name=name, mod=self.poly_tap) + self.tap_insts.append(new_tap) + self.connect_inst([]) def place_instances(self): self.add_label("ZERO", self.route_layer) self.array_pos = [] - strap_num = 0 + strap_num = 1 cell_y = 0 # columns are bit lines4 cell_x = 0 @@ -130,12 +133,19 @@ class rom_precharge_array(design): self.tap_insts[0].place(vector(cell_x, cell_y)) for col in range(self.cols): + + if col % self.strap_spacing == 0: + self.tap_insts[strap_num].place(vector(cell_x, cell_y)) + strap_num += 1 + + if self.tap_direction == "col": + cell_x += self.poly_tap.pitch_offset + # if col % self.strap_spacing == 0 : # self.tap_insts[strap_num].place(vector(cell_x, cell_y)) # self.add_label("debug", "li", vector(cell_x, cell_y)) # cell_x += self.poly_tap.width - # strap_num += 1 self.pmos_insts[col].place(vector(cell_x, cell_y)) self.add_label("debug", "li", vector(cell_x, cell_y)) @@ -143,51 +153,31 @@ class rom_precharge_array(design): def create_layout_pins(self): - self.copy_layout_pin(self.tap_insts[0], "via", "gate") + self.copy_layout_pin(self.tap_insts[0], "poly_tap", "gate") for col in range(self.cols): source_pin = self.pmos_insts[col].get_pin("D") bl = "pre_bl{0}_out".format(col) self.add_layout_pin_rect_center(bl, self.route_layer, source_pin.center()) - def add_well_tap(self): - - layer_stack = self.active_stack - contact_x = self.pmos_insts[self.cols - 1].rx() + self.active_space - contact_offset = vector(contact_x, self.pmos.height * 0.5) - - self.nwell_contact = self.add_via_center(layers=layer_stack, - offset=contact_offset, - implant_type="n", - well_type="n", - directions=("V", "V")) - def route_supply(self): - - start_pin = self.pmos_insts[0].get_pin("S").lx() - end_pin = self.pmos_insts[-1].get_pin("S").rx() - spacing = drc["{0}_to_{0}".format(self.route_layer)] - start = vector(start_pin, -2*spacing) - end = vector(end_pin, -2*spacing) - - self.vdd = self.add_layout_pin_segment_center("vdd", "m1", start, end) - - for i in range(self.cols): - start = self.pmos_insts[i].get_pin("S").center() - end = vector(start.x, self.vdd.cy()) - - self.add_segment_center(self.route_layer, start, end) - self.add_via_stack_center(end, self.route_layer, "m1") + # self.vdd = self.add_layout_pin_segment_center("vdd", self.supply_layer, start, end) + # vdd = [self.pmos_insts[i].get_pin("vdd") for i in range(self.cols)]routeroute_horizon_horizon + self.route_horizontal_pins("vdd", insts=self.pmos_insts) - # connect nwell tap to vdd - start = end - end = vector(self.nwell_contact.cx(), start.y) - self.add_segment_center(self.route_layer, start, end) - start = end - vector(0, 0.5 * self.mcon_width) - end = self.nwell_contact.center() - self.add_segment_center(self.route_layer, start, end) + def connect_taps(self): + array_pins = [self.tap_insts[i].get_pin("poly_tap") for i in range(len(self.tap_insts))] + self.connect_row_pins(layer=self.strap_layer, pins=array_pins, name=None, round=False) + + def extend_well(self): + well_y = self.pmos_insts[0].get_pin("vdd").cy() - 0.5 * self.nwell_width + + well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width + well_ll = vector(0, well_y) + + self.add_rect("nwell", well_ll, self.width , self.height - well_y) diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 57477626..4108f7cb 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -15,20 +15,16 @@ from openram.tech import drc class rom_precharge_cell(rom_base_cell): - def __init__(self, name="", route_layer="m1"): - + def __init__(self, name="", route_layer="m1", supply_layer="li"): + self.supply_layer = supply_layer super().__init__(name=name, bitline_layer=route_layer) - - - # def create_netlist(self): - # self.add_pins() - # self.add_modules() - # self.create_tx() def create_layout(self): super().create_layout() + + self.place_tap() self.extend_well() @@ -37,19 +33,21 @@ class rom_precharge_cell(rom_base_cell): self.pmos = factory.create(module_type="ptx", module_name="pre_pmos_mod", - tx_type="pmos" + tx_type="pmos", + add_source_contact=self.supply_layer, + add_drain_contact=self.bitline_layer ) def create_tx(self): self.cell_inst = self.add_inst( name="precharge_pmos", mod=self.pmos, ) - self.connect_inst(["bitline", "gate", "vdd", "body"]) + self.connect_inst(["bitline", "gate", "vdd", "vdd"]) def add_pins(self): - pin_list = ["vdd", "gate", "bitline", "body"] - dir_list = ["POWER", "INPUT", "OUTPUT", "POWER"] + pin_list = ["vdd", "gate", "bitline"] + dir_list = ["POWER", "INPUT", "OUTPUT"] self.add_pin_list(pin_list, dir_list) @@ -57,8 +55,6 @@ class rom_precharge_cell(rom_base_cell): self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active) - - #contact to contact distance, minimum cell width before drc offsets self.base_width = self.pmos.width - 2 * self.active_enclose_contact - self.pmos.contact_width @@ -70,37 +66,34 @@ class rom_precharge_cell(rom_base_cell): def extend_well(self): - self.pmos - well_y = - (0.5 * self.nwell_width) + well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width well_ll = vector(0, well_y) # height = self.active_width + 2 * self.well_enclose_active - height = self.height + 0.5 * self.nwell_width + height = self.get_pin("D").cy() + 0.5 * self.nwell_width - well_y self.add_rect("nwell", well_ll, self.width , height) - # def place_tx(self): - # pmos_offset = vector(self.pmos.poly_extend_active + self.pmos.height, 0) + + def place_tap(self): + source = self.cell_inst.get_pin("S") + + tap_y = source.cy() - self.contact_width - 2 * self.active_enclose_contact - self.active_space + + pos = vector(source.cx(), tap_y ) + + self.add_via_center(layers=self.active_stack, + offset=pos, + implant_type="n", + well_type="n", + directions="nonpref") + self.add_via_stack_center(offset=pos, + from_layer=self.active_stack[2], + to_layer=self.supply_layer) - # self.cell_inst.place(pmos_offset, rotate=90) - # self.add_label("inst_zero", self.bitline_layer) - # self.add_layout_pin_rect_center("S", self.bitline_layer, self.cell_inst.get_pin("S").center()) - # self.add_layout_pin_rect_center("D", self.bitline_layer, self.cell_inst.get_pin("D").center()) - - - # def place_poly(self): - # poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.rx() + self.poly_extend_active) - # poly_offset = vector(self.cell_inst.rx() + self.poly_extend_active, self.cell_inst.width * 0.5 ) - - # start = poly_offset - # end = poly_offset + vector(poly_size, 0) - # self.add_segment_center("poly", start, end) - # def add_boundary(self): - - # #cell width with offsets applied, height becomes width when the cells are rotated - # self.width = self.pmos.height + self.poly_extend_active_spacing + 2 * self.pmos.poly_extend_active - - # # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied - # # self.height = self.base_width - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) - - # super().add_boundary() + bitline_offset = vector( 2 * (drc("minwidth_{}".format(self.bitline_layer)) + drc("{0}_to_{0}".format(self.bitline_layer))) ,0) + self.add_layout_pin_rect_center("vdd", self.supply_layer, pos - bitline_offset) + + self.add_path(self.supply_layer, [self.get_pin("vdd").center(), pos, self.get_pin("S").center()]) + + self.remove_layout_pin("S") diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index 9a19919c..b50b7fc8 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -19,14 +19,15 @@ class rom_wordline_driver_array(design): Creates a Wordline Buffer/Inverter array """ - def __init__(self, name, rows, cols): + def __init__(self, name, rows, cols, invert_outputs=False, tap_spacing=4): design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.rows = rows self.cols = cols - + self.invert_outputs=invert_outputs + self.tap_spacing = tap_spacing self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -60,10 +61,25 @@ class rom_wordline_driver_array(design): def add_modules(self): b = factory.create(module_type="rom_base_cell") - self.wl_driver = factory.create(module_type="pbuf_dec", - size=self.cols, - height=b.height, - add_wells=False) + if self.invert_outputs: + self.wl_driver = factory.create(module_type="pinv_dec", + size=self.cols, + height=b.height, + add_wells=False) + + self.wl_driver_tap = factory.create(module_type="pinv_dec", + size=self.cols, + add_wells=True) + else: + self.wl_driver = factory.create(module_type="pbuf_dec", + size=self.cols, + height=b.height, + add_wells=False) + self.wl_driver_tap = factory.create(module_type="pbuf_dec", + size=self.cols, + add_wells=True) + print(self.wl_driver.height) + print(self.wl_driver_tap.height) def route_supplies(self): """ @@ -80,21 +96,25 @@ class rom_wordline_driver_array(design): def create_drivers(self): self.wld_inst = [] for row in range(self.rows): - self.wld_inst.append(self.add_inst(name="wld{0}".format(row), - mod=self.wl_driver)) + if row % self.tap_spacing == 0: + self.wld_inst.append(self.add_inst(name="wld{0}".format(row), + mod=self.wl_driver_tap)) + else: + self.wld_inst.append(self.add_inst(name="wld{0}".format(row), + mod=self.wl_driver)) self.connect_inst(["in_{0}".format(row), "out_{0}".format(row), "vdd", "gnd"]) def place_drivers(self): - + y_offset = 0 for row in range(self.rows): # These are flipped since we always start with an RBL on the bottom - y_offset = self.wl_driver.height * row offset = [0, y_offset] self.wld_inst[row].place(offset=offset) + y_offset += self.wld_inst[row].height self.width = self.wl_driver.width self.height = self.wl_driver.height * self.rows diff --git a/compiler/tests/05_rom_base_bank_test.py b/compiler/tests/05_rom_base_bank_test.py index 277205b1..f8c578dc 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 = 8, data_file="/openram/technology/rom_data", word_size=1) + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_1kB", 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 index 4e13b9bf..e6c5d173 100644 --- a/compiler/tests/05_rom_control_logic_test.py +++ b/compiler/tests/05_rom_control_logic_test.py @@ -25,7 +25,7 @@ class rom_decoder_test(openram_test): debug.info(2, "Testing control logic for rom cell") - a = factory.create(module_type="rom_control_logic", num_outputs=4) + a = factory.create(module_type="rom_control_logic", num_outputs=4, clk_fanout=4, height=40) self.local_check(a) openram.end_openram()