diff --git a/compiler/modules/hierarchical_predecode.py b/compiler/modules/hierarchical_predecode.py index fa44b080..d998d882 100644 --- a/compiler/modules/hierarchical_predecode.py +++ b/compiler/modules/hierarchical_predecode.py @@ -40,7 +40,6 @@ class hierarchical_predecode(design.design): def add_modules(self): """ Add the INV and AND gate modules """ - # FIXME: Default parms are required for hard cells for now. if self.number_of_inputs == 2: self.and_mod = factory.create(module_type="and2_dec", height=self.cell_height) @@ -60,7 +59,6 @@ class hierarchical_predecode(design.design): size=1) self.add_mod(self.inv) - def create_layout(self): """ The general organization is from left to right: 1) a set of M2 rails for input signals diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 54e35d9e..34ad4ca9 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -180,6 +180,7 @@ class port_data(design.design): # Precharge will be shifted left if needed self.precharge_array = factory.create(module_type="precharge_array", columns=self.num_cols + 1, + port=self.port, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port]) self.add_mod(self.precharge_array) @@ -195,6 +196,7 @@ class port_data(design.design): if self.col_addr_size > 0: self.column_mux_array = factory.create(module_type="column_mux_array", columns=self.num_cols, + port=self.port, word_size=self.word_size, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port]) @@ -250,6 +252,7 @@ class port_data(design.design): # module, which happens before we create the real precharge_array self.precharge_array = factory.create(module_type="precharge_array", columns=self.num_cols + 1, + port=self.port, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port]) @@ -536,11 +539,18 @@ class port_data(design.design): # This could be a channel route, but in some techs the bitlines # are too close together. - self.channel_route_bitlines(inst1=inst1, - inst1_bls_template=inst1_bls_templ, - inst2=inst2, - num_bits=self.word_size, - inst1_start_bit=start_bit) + if OPTS.tech_name == "s8": + self.connect_bitlines(inst1=inst1, + inst1_bls_template=inst1_bls_templ, + inst2=inst2, + num_bits=self.word_size, + inst1_start_bit=start_bit) + else: + self.channel_route_bitlines(inst1=inst1, + inst1_bls_template=inst1_bls_templ, + inst2=inst2, + num_bits=self.word_size, + inst1_start_bit=start_bit) def route_write_driver_to_column_mux_or_precharge_array(self, port): """ Routing of BL and BR between sense_amp and column mux or precharge array """ @@ -562,11 +572,17 @@ class port_data(design.design): # This could be a channel route, but in some techs the bitlines # are too close together. - self.channel_route_bitlines(inst1=inst1, inst2=inst2, - num_bits=self.word_size, - inst1_bls_template=inst1_bls_templ, - inst1_start_bit=start_bit) - + if OPTS.tech_name == "s8": + self.connect_bitlines(inst1=inst1, inst2=inst2, + num_bits=self.word_size, + inst1_bls_template=inst1_bls_templ, + inst1_start_bit=start_bit) + else: + self.channel_route_bitlines(inst1=inst1, inst2=inst2, + num_bits=self.word_size, + inst1_bls_template=inst1_bls_templ, + inst1_start_bit=start_bit) + def route_write_driver_to_sense_amp(self, port): """ Routing of BL and BR between write driver and sense amp """ diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index af612af4..2acb1063 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -7,7 +7,6 @@ # import design import debug -from tech import drc from vector import vector from sram_factory import factory from globals import OPTS @@ -19,13 +18,14 @@ class precharge_array(design.design): of bit line columns, height is the height of the bit-cell array. """ - def __init__(self, name, columns, size=1, bitcell_bl="bl", bitcell_br="br"): + def __init__(self, name, columns, port, size=1, bitcell_bl="bl", bitcell_br="br"): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} size: {1} bl: {2} br: {3}".format(columns, size, bitcell_bl, bitcell_br)) self.columns = columns self.size = size + self.port = port self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br @@ -106,7 +106,7 @@ class precharge_array(design.design): xoffset = 0 for i in range(self.columns): tempx = xoffset - if cell_properties.bitcell.mirror.y and (i + 1) % 2: + if cell_properties.bitcell.mirror.y and (i + 1 + self.port) % 2: mirror = "MY" tempx = tempx + self.pc_cell.width else: diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 5dc9cbf8..3d80525a 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -7,7 +7,7 @@ # import design import debug -from tech import layer +from tech import layer, preferred_directions from vector import vector from sram_factory import factory from globals import OPTS @@ -20,12 +20,13 @@ class single_level_column_mux_array(design.design): Array of column mux to read the bitlines through the 6T. """ - def __init__(self, name, columns, word_size, bitcell_bl="bl", bitcell_br="br"): + def __init__(self, name, columns, port, word_size, bitcell_bl="bl", bitcell_br="br"): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br)) self.columns = columns + self.port = port self.word_size = word_size self.words_per_row = int(self.columns / self.word_size) self.bitcell_bl = bitcell_bl @@ -33,10 +34,15 @@ class single_level_column_mux_array(design.design): if "li" in layer: self.col_mux_stack = self.li_stack - self.col_mux_stack_pitch = self.li_pitch + self.col_mux_stack_pitch = self.m1_pitch else: self.col_mux_stack = self.m1_stack self.col_mux_stack_pitch = self.m1_pitch + + if preferred_directions[self.col_mux_stack[0]] == "V": + self.via_directions = ("H", "H") + else: + self.via_directions = "pref" self.create_netlist() if not OPTS.netlist_only: @@ -112,7 +118,7 @@ class single_level_column_mux_array(design.design): # For every column, add a pass gate for col_num in range(self.columns): xoffset = col_num * self.mux.width - if cell_properties.bitcell.mirror.y and col_num % 2: + if cell_properties.bitcell.mirror.y and (col_num + self.port) % 2: mirror = "MY" xoffset = xoffset + self.mux.width else: @@ -173,73 +179,53 @@ class single_level_column_mux_array(design.design): self.get_pin("sel_{}".format(sel_index)).cy()) # Add the poly contact with a shift to account for the rotation self.add_via_center(layers=self.poly_stack, - offset=offset) + offset=offset, + directions=self.via_directions) self.add_path("poly", [offset, gate_offset]) def route_bitlines(self): """ Connect the output bit-lines to form the appropriate width mux """ - from tech import cell_properties for j in range(self.columns): - bl_offset = self.mux_inst[j].get_pin("bl_out").bc() - br_offset = self.mux_inst[j].get_pin("br_out").bc() - bl_out_offset = bl_offset - vector(0, (self.words_per_row + 1) * self.col_mux_stack_pitch) - br_out_offset = br_offset - vector(0, (self.words_per_row + 2) * self.col_mux_stack_pitch) + bl_offset_begin = self.mux_inst[j].get_pin("bl_out").bc() + br_offset_begin = self.mux_inst[j].get_pin("br_out").bc() - bl_out_offset_end = bl_out_offset + vector(0, self.route_height) - br_out_offset_end = br_out_offset + vector(0, self.route_height) + bl_out_offset_begin = bl_offset_begin - vector(0, (self.words_per_row + 1) * self.col_mux_stack_pitch) + br_out_offset_begin = br_offset_begin - vector(0, (self.words_per_row + 2) * self.col_mux_stack_pitch) - if cell_properties.bitcell.mirror.y and j % 2: - tmp_bl_out_end = br_out_offset_end - tmp_br_out_end = bl_out_offset_end - else: - tmp_bl_out_end = bl_out_offset_end - tmp_br_out_end = br_out_offset_end - - if (j % self.words_per_row) == 0: - # Create the metal1 to connect the n-way mux output from the pass gate - # These will be located below the select lines. Yes, these are M2 width - # to ensure vias are enclosed and M1 min width rules. - width = self.m2_width + self.mux.width * (self.words_per_row - 1) - - if cell_properties.bitcell.mirror.y and (j % 2) == 0: - bl = self.mux.get_pin("bl") - br = self.mux.get_pin("br") - dist = abs(bl.ll().x - br.ll().x) - else: - dist = 0 - - self.add_path(self.col_mux_stack[0], [bl_out_offset, bl_out_offset + vector(width + dist, 0)]) - self.add_path(self.col_mux_stack[0], [br_out_offset, br_out_offset + vector(width - dist, 0)]) + # 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() + br_offset_end = self.mux_inst[j + self.words_per_row - 1].get_pin("br_out").bc() + bl_out_offset_end = bl_offset_end - vector(0, (self.words_per_row + 1) * self.col_mux_stack_pitch) + br_out_offset_end = br_offset_end - vector(0, (self.words_per_row + 2) * self.col_mux_stack_pitch) + + self.add_path(self.col_mux_stack[0], [bl_out_offset_begin, bl_out_offset_end]) + self.add_path(self.col_mux_stack[0], [br_out_offset_begin, br_out_offset_end]) # Extend the bitline output rails and gnd downward on the first bit of each n-way mux self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j / self.words_per_row)), layer=self.col_mux_stack[2], - start=bl_out_offset, - end=tmp_bl_out_end) + start=bl_offset_begin, + end=bl_out_offset_begin) self.add_layout_pin_segment_center(text="br_out_{}".format(int(j / self.words_per_row)), layer=self.col_mux_stack[2], - start=br_out_offset, - end=tmp_br_out_end) - - # This via is on the right of the wire - self.add_via_center(layers=self.col_mux_stack, - offset=bl_out_offset) - - # This via is on the left of the wire - self.add_via_center(layers=self.col_mux_stack, - offset=br_out_offset) + start=br_offset_begin, + end=br_out_offset_begin) else: - self.add_path(self.col_mux_stack[2], [bl_out_offset, bl_offset]) - self.add_path(self.col_mux_stack[2], [br_out_offset, br_offset]) + self.add_path(self.col_mux_stack[2], [bl_out_offset_begin, bl_offset_begin]) + self.add_path(self.col_mux_stack[2], [br_out_offset_begin, br_offset_begin]) - # This via is on the right of the wire - self.add_via_center(layers=self.col_mux_stack, - offset=bl_out_offset) - # This via is on the left of the wire - self.add_via_center(layers=self.col_mux_stack, - offset=br_out_offset) + # This via is on the right of the wire + self.add_via_center(layers=self.col_mux_stack, + offset=bl_out_offset_begin, + directions=self.via_directions) + + # This via is on the left of the wire + self.add_via_center(layers=self.col_mux_stack, + offset=br_out_offset_begin, + directions=self.via_directions) def get_drain_cin(self): """Get the relative capacitance of the drain of the NMOS pass TX""" diff --git a/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py b/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py index 84e62a96..7feb067e 100755 --- a/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py +++ b/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py @@ -29,19 +29,19 @@ class single_level_column_mux_pbitcell_test(openram_test): factory.reset() debug.info(1, "Testing sample for 2-way column_mux_array in multi-port") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") + a = factory.create(module_type="single_level_column_mux_array", columns=16, port=0, word_size=8, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array in multi-port") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + a = factory.create(module_type="single_level_column_mux_array", columns=16, port=0, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)") - a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + a = factory.create(module_type="single_level_column_mux_array", columns=32, port=0, word_size=4, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)") - a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2") + a = factory.create(module_type="single_level_column_mux_array", columns=32, port=3, word_size=4, bitcell_bl="bl2", bitcell_br="br2") self.local_check(a) globals.end_openram() diff --git a/compiler/tests/07_single_level_column_mux_array_test.py b/compiler/tests/07_single_level_column_mux_array_test.py index c5d48689..fb608f68 100755 --- a/compiler/tests/07_single_level_column_mux_array_test.py +++ b/compiler/tests/07_single_level_column_mux_array_test.py @@ -23,15 +23,15 @@ class single_level_column_mux_test(openram_test): # check single level column mux array in single port debug.info(1, "Testing sample for 2-way column_mux_array") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8) + a = factory.create(module_type="single_level_column_mux_array", columns=16, port=0, word_size=8) self.local_check(a) debug.info(1, "Testing sample for 4-way column_mux_array") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4) + a = factory.create(module_type="single_level_column_mux_array", columns=16, port=0, word_size=4) self.local_check(a) debug.info(1, "Testing sample for 8-way column_mux_array") - a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4) + a = factory.create(module_type="single_level_column_mux_array", columns=32, port=0, word_size=4) self.local_check(a) globals.end_openram() diff --git a/compiler/tests/08_precharge_array_1rw1r_test.py b/compiler/tests/08_precharge_array_1rw1r_test.py index 8f51c2d4..1381b93a 100755 --- a/compiler/tests/08_precharge_array_1rw1r_test.py +++ b/compiler/tests/08_precharge_array_1rw1r_test.py @@ -29,7 +29,7 @@ class precharge_test(openram_test): factory.reset() debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell") - pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0") + pc = factory.create(module_type="precharge_array", columns=3, port=0, bitcell_bl="bl0", bitcell_br="br0") self.local_check(pc) # debug.info(2, "Checking 3 column precharge array for pbitcell (innermost connections)") diff --git a/compiler/tests/08_precharge_array_test.py b/compiler/tests/08_precharge_array_test.py index b301a909..c3b823b3 100755 --- a/compiler/tests/08_precharge_array_test.py +++ b/compiler/tests/08_precharge_array_test.py @@ -23,7 +23,7 @@ class precharge_test(openram_test): # check precharge array in single port debug.info(2, "Checking 3 column precharge") - pc = factory.create(module_type="precharge_array", columns=3) + pc = factory.create(module_type="precharge_array", columns=3, port=0) self.local_check(pc) globals.end_openram() diff --git a/compiler/tests/18_port_data_1rw_1r_test.py b/compiler/tests/18_port_data_1rw_1r_test.py index e9e282a5..8081416e 100755 --- a/compiler/tests/18_port_data_1rw_1r_test.py +++ b/compiler/tests/18_port_data_1rw_1r_test.py @@ -36,7 +36,7 @@ class port_data_1rw_1r_test(openram_test): self.local_check(a) a = factory.create("port_data", sram_config=c, port=1) self.local_check(a) - + c.num_words=32 c.words_per_row=2 factory.reset()