diff --git a/compiler/modules/write_mask_and_array.py b/compiler/modules/write_mask_and_array.py index f337ab7a..c87d3a90 100644 --- a/compiler/modules/write_mask_and_array.py +++ b/compiler/modules/write_mask_and_array.py @@ -108,8 +108,21 @@ class write_mask_and_array(design.design): end=vector(self.width, en_pin.cy())) for i in range(self.num_wmasks): + # Route the A pin over to the left so that it doesn't conflict with the sense + # amp output which is usually in the center + a_pin = self.and2_insts[i].get_pin("A") + a_pos = a_pin.center() + in_pos = vector(self.and2_insts[i].lx(), + a_pos.y) + self.add_via_stack_center(from_layer=a_pin.layer, + to_layer="m2", + offset=in_pos) + self.add_layout_pin_rect_center(text="wmask_in_{0}".format(i), + layer="m2", + offset=in_pos) + self.add_path(a_pin.layer, [in_pos, a_pos]) + # Copy remaining layout pins - self.copy_layout_pin(self.and2_insts[i], "A", "wmask_in_{0}".format(i)) self.copy_layout_pin(self.and2_insts[i], "Z", "wmask_out_{0}".format(i)) # Add via connections to metal3 for AND array's B pin @@ -122,7 +135,7 @@ class write_mask_and_array(design.design): for supply in ["gnd", "vdd"]: supply_pin=self.and2_insts[i].get_pin(supply) if "li" in layer: - self.add_power_pin(supply, supply_pin.center(), start_layer="li", directions = ("H", "H")) + self.add_power_pin(supply, supply_pin.center(), start_layer="li", directions=("H", "H")) else: self.add_power_pin(supply, supply_pin.center()) diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 7d2ccfa8..4e2be40e 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -70,93 +70,12 @@ class sram_1bank(sram_base): # If a horizontal channel, they rely on the vertical channel non-preferred (contacted) pitch. # If a vertical channel, they rely on the horizontal channel non-preferred (contacted) pitch. # So, m3 non-pref pitch means that this is routed on the m2 layer. - if self.write_size: - self.data_bus_gap = self.m4_nonpref_pitch * 2 - self.data_bus_size = self.m4_nonpref_pitch * (self.word_size + self.num_spare_cols) + self.data_bus_gap - self.wmask_bus_gap = self.m2_nonpref_pitch * 2 - self.wmask_bus_size = self.m2_nonpref_pitch * (max(self.num_wmasks + 1, self.col_addr_size + 1)) + self.wmask_bus_gap - if self.num_spare_cols: - self.spare_wen_bus_gap = self.m2_nonpref_pitch * 2 - self.spare_wen_bus_size = self.m2_nonpref_pitch * (max(self.num_spare_cols + 1, self.col_addr_size + 1)) + self.spare_wen_bus_gap - else: - self.spare_wen_bus_size = 0 - - elif self.num_spare_cols and not self.write_size: - self.data_bus_gap = self.m4_nonpref_pitch * 2 - self.data_bus_size = self.m4_nonpref_pitch * (self.word_size + self.num_spare_cols) + self.data_bus_gap - self.spare_wen_bus_gap = self.m2_nonpref_pitch * 2 - self.spare_wen_bus_size = self.m2_nonpref_pitch * (max(self.num_spare_cols + 1, self.col_addr_size + 1)) + self.spare_wen_bus_gap - - else: - self.data_bus_gap = self.m3_nonpref_pitch * 2 - self.data_bus_size = self.m3_nonpref_pitch * (max(self.word_size + 1, self.col_addr_size + 1)) + self.data_bus_gap - - self.col_addr_bus_gap = self.m2_nonpref_pitch * 2 - self.col_addr_bus_size = self.m2_nonpref_pitch * (self.col_addr_size) + self.col_addr_bus_gap + self.data_bus_gap = self.m4_nonpref_pitch * 2 + self.data_bus_size = self.m4_nonpref_pitch * (self.word_size + self.num_spare_cols + self.num_wmasks + self.col_addr_size + self.num_spare_cols) + self.data_bus_gap # Port 0 port = 0 - if port in self.write_ports: - if self.write_size: - bus_size = max(self.wmask_bus_size, self.spare_wen_bus_size) - # Add the write mask flops below the write mask AND array. - wmask_pos[port] = vector(self.bank.bank_array_ll.x, - - bus_size - self.dff.height) - self.wmask_dff_insts[port].place(wmask_pos[port]) - - # Add the data flops below the write mask flops. - data_pos[port] = vector(self.bank.bank_array_ll.x, - - self.data_bus_size - bus_size - 2 * self.dff.height) - self.data_dff_insts[port].place(data_pos[port]) - - #Add spare write enable flops to the right of write mask flops - if self.num_spare_cols: - spare_wen_pos[port] = vector(self.bank.bank_array_ll.x + self.wmask_dff_insts[port].width + self.bank.m2_gap, - - bus_size - self.dff.height) - self.spare_wen_dff_insts[port].place(spare_wen_pos[port]) - - elif self.num_spare_cols and not self.write_size: - # Add spare write enable flops below bank (lower right) - spare_wen_pos[port] = vector(self.bank.bank_array_ll.x, - - self.spare_wen_bus_size - self.dff.height) - self.spare_wen_dff_insts[port].place(spare_wen_pos[port]) - - # Add the data flops below the spare write enable flops. - data_pos[port] = vector(self.bank.bank_array_ll.x, - - self.data_bus_size - self.spare_wen_bus_size - 2 * self.dff.height) - self.data_dff_insts[port].place(data_pos[port]) - - else: - # Add the data flops below the bank to the right of the lower-left of bank array - # This relies on the lower-left of the array of the bank - # decoder in upper left, bank in upper right, sensing in lower right. - # These flops go below the sensing and leave a gap to channel route to the - # sense amps. - data_pos[port] = vector(self.bank.bank_array_ll.x, - -self.data_bus_size - self.dff.height) - self.data_dff_insts[port].place(data_pos[port]) - - else: - wmask_pos[port] = vector(self.bank.bank_array_ll.x, 0) - data_pos[port] = vector(self.bank.bank_array_ll.x, 0) - spare_wen_pos[port] = vector(self.bank.bank_array_ll.x, 0) - - # Add the col address flops below the bank to the left of the lower-left of bank array - if self.col_addr_dff: - if self.write_size: - col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap, - -bus_size - self.col_addr_dff_insts[port].height) - elif self.num_spare_cols and not self.write_size: - col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap, - -self.spare_wen_bus_size - self.col_addr_dff_insts[port].height) - else: - col_addr_pos[port] = vector(self.bank.bank_array_ll.x - self.col_addr_dff_insts[port].width - self.bank.m2_gap, - -self.data_bus_size - self.col_addr_dff_insts[port].height) - self.col_addr_dff_insts[port].place(col_addr_pos[port]) - else: - col_addr_pos[port] = vector(self.bank.bank_array_ll.x, 0) - # This includes 2 M2 pitches for the row addr clock line. control_pos[port] = vector(-self.control_logic_insts[port].width - 2 * self.m2_pitch, self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - 2 * self.bank.m2_gap) @@ -169,64 +88,45 @@ class sram_1bank(sram_base): row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_dff_insts[port].place(row_addr_pos[port]) + # Add the col address flops below the bank to the right of the control logic + x_offset = self.control_logic_insts[port].rx() + self.dff.width + y_offset = - self.data_bus_size - self.dff.height + if self.col_addr_dff: + col_addr_pos[port] = vector(x_offset, + y_offset) + self.col_addr_dff_insts[port].place(col_addr_pos[port]) + x_offset = self.col_addr_dff_insts[port].rx() + else: + col_addr_pos[port] = vector(x_offset, 0) + + if port in self.write_ports: + if self.write_size: + # Add the write mask flops below the write mask AND array. + wmask_pos[port] = vector(x_offset, + y_offset) + self.wmask_dff_insts[port].place(wmask_pos[port]) + x_offset = self.wmask_dff_insts[port].rx() + + # Add spare write enable flops to the right of write mask flops + if self.num_spare_cols: + spare_wen_pos[port] = vector(x_offset, + y_offset) + self.spare_wen_dff_insts[port].place(spare_wen_pos[port]) + x_offset = self.spare_wen_dff_insts[port].rx() + + # Add the data flops below the write mask flops. + data_pos[port] = vector(x_offset, + y_offset) + self.data_dff_insts[port].place(data_pos[port]) + + else: + wmask_pos[port] = vector(x_offset, y_offset) + data_pos[port] = vector(x_offset, y_offset) + spare_wen_pos[port] = vector(x_offset, y_offset) + if len(self.all_ports)>1: # Port 1 port = 1 - - if port in self.write_ports: - if self.write_size: - bus_size = max(self.wmask_bus_size, self.spare_wen_bus_size) - # Add the write mask flops above the write mask AND array. - wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.wmask_dff_insts[port].width, - self.bank.height + bus_size + self.dff.height) - self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX") - - # Add the data flops above the write mask flops - data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, - self.bank.height + bus_size + self.data_bus_size + 2 * self.dff.height) - self.data_dff_insts[port].place(data_pos[port], mirror="MX") - - if self.num_spare_cols: - spare_wen_pos[port] = vector(self.bank.bank_array_ur.x - self.wmask_dff_insts[port].width - - self.spare_wen_dff_insts[port].width - self.bank.m2_gap, - self.bank.height + bus_size + self.dff.height) - self.spare_wen_dff_insts[port].place(spare_wen_pos[port], mirror="MX") - - # Place dffs when spare cols is enabled - elif self.num_spare_cols and not self.write_size: - # Spare wen flops on the upper right, below data flops - spare_wen_pos[port] = vector(self.bank.bank_array_ur.x - self.spare_wen_dff_insts[port].width, - self.bank.height + self.spare_wen_bus_size + self.dff.height) - self.spare_wen_dff_insts[port].place(spare_wen_pos[port], mirror="MX") - # Add the data flops above the spare write enable flops - data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, - self.bank.height + self.spare_wen_bus_size + self.data_bus_size + 2 * self.dff.height) - self.data_dff_insts[port].place(data_pos[port], mirror="MX") - - else: - # Add the data flops above the bank to the left of the upper-right of bank array - # This relies on the upper-right of the array of the bank - # decoder in upper left, bank in upper right, sensing in lower right. - # These flops go below the sensing and leave a gap to channel route to the - # sense amps. - data_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, - self.bank.height + self.data_bus_size + self.dff.height) - self.data_dff_insts[port].place(data_pos[port], mirror="MX") - - # Add the col address flops above the bank to the right of the upper-right of bank array - if self.col_addr_dff: - if self.write_size: - col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap, - self.bank.height + bus_size + self.dff.height) - elif self.num_spare_cols and not self.write_size: - col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap, - self.bank.height + self.spare_wen_bus_size + self.dff.height) - else: - col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap, - self.bank.height + self.data_bus_size + self.dff.height) - self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX") - else: - col_addr_pos[port] = self.bank_inst.ur() # This includes 2 M2 pitches for the row addr clock line control_pos[port] = vector(self.bank_inst.rx() + self.control_logic_insts[port].width + 2 * self.m2_pitch, @@ -242,6 +142,42 @@ class sram_1bank(sram_base): row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY") + # Add the col address flops below the bank to the right of the control logic + x_offset = self.control_logic_insts[port].lx() - 2 * self.dff.width + y_offset = self.bank.height + self.data_bus_size + self.dff.height + if self.col_addr_dff: + col_addr_pos[port] = vector(x_offset - self.col_addr_dff_insts[port].width, + y_offset) + self.col_addr_dff_insts[port].place(col_addr_pos[port], mirror="MX") + x_offset = self.col_addr_dff_insts[port].lx() + else: + col_addr_pos[port] = vector(x_offset, y_offset) + + if port in self.write_ports: + if self.write_size: + # Add the write mask flops below the write mask AND array. + wmask_pos[port] = vector(x_offset - self.wmask_dff_insts[port].width, + y_offset) + self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX") + x_offset = self.wmask_dff_insts[port].lx() + + # Add spare write enable flops to the right of write mask flops + if self.num_spare_cols: + spare_wen_pos[port] = vector(x_offset - self.spare_wen_dff_insts[port].width, + y_offset) + self.spare_wen_dff_insts[port].place(spare_wen_pos[port], mirror="MX") + x_offset = self.spare_wen_dff_insts[port].lx() + + # Add the data flops below the write mask flops. + data_pos[port] = vector(x_offset - self.data_dff_insts[port].width, + y_offset) + self.data_dff_insts[port].place(data_pos[port], mirror="MX") + + else: + wmask_pos[port] = vector(x_offset, y_offset) + data_pos[port] = vector(x_offset, y_offset) + spare_wen_pos[port] = vector(x_offset, y_offset) + def add_layout_pins(self): """ Add the top-level pins for a single bank SRAM with control. @@ -250,7 +186,6 @@ class sram_1bank(sram_base): lowest_coord = self.find_lowest_coords() bbox = [lowest_coord, highest_coord] - for port in self.all_ports: # Depending on the port, use the bottom/top or left/right sides # Port 0 is left/bottom @@ -370,17 +305,83 @@ class sram_1bank(sram_base): self.route_row_addr_dff() - if self.col_addr_dff: - self.route_col_addr_dff() + # if self.col_addr_dff: + # self.route_col_addr_dff() - self.route_data_dff() + # self.route_data_dff() - if self.write_size: - self.route_wmask_dff() + # if self.write_size: + # self.route_wmask_dff() - if self.num_spare_cols: - self.route_spare_wen_dff() + # if self.num_spare_cols: + # self.route_spare_wen_dff() + for port in self.all_ports: + self.route_dff(port) + def route_dff(self, port): + + route_map = [] + + # column mux dff + if self.col_addr_size > 0: + dff_names = ["dout_{}".format(x) for x in range(self.col_addr_size)] + dff_pins = [self.col_addr_dff_insts[port].get_pin(x) for x in dff_names] + bank_names = ["addr{0}_{1}".format(port, x) for x in range(self.col_addr_size)] + bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] + route_map.extend(list(zip(bank_pins, dff_pins))) + + # spare wen dff + if self.num_spare_cols > 0 and port in self.write_ports: + dff_names = ["dout_{}".format(x) for x in range(self.num_spare_cols)] + dff_pins = [self.spare_wen_dff_insts[port].get_pin(x) for x in dff_names] + bank_names = ["bank_spare_wen{0}_{1}".format(port, x) for x in range(self.num_spare_cols)] + bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] + route_map.extend(list(zip(bank_pins, dff_pins))) + + # wmask dff + if self.num_wmasks > 0 and port in self.write_ports: + dff_names = ["dout_{}".format(x) for x in range(self.num_wmasks)] + dff_pins = [self.wmask_dff_insts[port].get_pin(x) for x in dff_names] + bank_names = ["bank_wmask{0}_{1}".format(port, x) for x in range(self.num_wmasks)] + bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] + route_map.extend(list(zip(bank_pins, dff_pins))) + + if port in self.write_ports: + # data dff + dff_names = ["dout_{}".format(x) for x in range(self.word_size + self.num_spare_cols)] + dff_pins = [self.data_dff_insts[port].get_pin(x) for x in dff_names] + bank_names = ["din{0}_{1}".format(port, x) for x in range(self.word_size + self.num_spare_cols)] + bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] + route_map.extend(list(zip(bank_pins, dff_pins))) + + if self.num_wmasks > 0 and port in self.write_ports: + vertical_layer = "m4" + layer_stack = self.m3_stack + else: + vertical_layer = "m2" + layer_stack = self.m1_stack + for (pin1, pin2) in route_map: + if pin1.layer != vertical_layer: + self.add_via_stack_center(from_layer=pin1.layer, + to_layer=vertical_layer, + offset=pin1.center()) + if pin2.layer != vertical_layer: + self.add_via_stack_center(from_layer=pin2.layer, + to_layer=vertical_layer, + offset=pin2.center()) + + if port == 0: + offset = vector(self.control_logic_insts[port].rx() + self.dff.width, + - self.data_bus_size + 2 * self.m1_pitch) + else: + offset = vector(0, + self.bank.height + 2 * self.m1_space) + + if len(route_map) > 0: + self.create_horizontal_channel_route(netlist=route_map, + offset=offset, + layer_stack=layer_stack) + def route_clk(self): """ Route the clock network """ @@ -423,8 +424,7 @@ class sram_1bank(sram_base): mid_pos = vector(clk_steiner_pos.x, dff_clk_pos.y) self.add_wire(self.m2_stack[::-1], [dff_clk_pos, mid_pos, clk_steiner_pos]) - - if port in self.write_ports: + elif port in self.write_ports: data_dff_clk_pin = self.data_dff_insts[port].get_pin("clk") data_dff_clk_pos = data_dff_clk_pin.center() mid_pos = vector(clk_steiner_pos.x, data_dff_clk_pos.y) @@ -436,24 +436,6 @@ class sram_1bank(sram_base): self.add_wire(self.m2_stack[::-1], [data_dff_clk_pos, mid_pos, clk_steiner_pos]) - if self.write_size: - wmask_dff_clk_pin = self.wmask_dff_insts[port].get_pin("clk") - wmask_dff_clk_pos = wmask_dff_clk_pin.center() - mid_pos = vector(clk_steiner_pos.x, wmask_dff_clk_pos.y) - # In some designs, the steiner via will be too close to the mid_pos via - # so make the wire as wide as the contacts - self.add_path("m2", [mid_pos, clk_steiner_pos], width=max(m2_via.width, m2_via.height)) - self.add_wire(self.m2_stack[::-1], [wmask_dff_clk_pos, mid_pos, clk_steiner_pos]) - - if self.num_spare_cols: - spare_wen_dff_clk_pin = self.spare_wen_dff_insts[port].get_pin("clk") - spare_wen_dff_clk_pos = spare_wen_dff_clk_pin.center() - mid_pos = vector(clk_steiner_pos.x, spare_wen_dff_clk_pos.y) - # In some designs, the steiner via will be too close to the mid_pos via - # so make the wire as wide as the contacts - self.add_path("m2", [mid_pos, clk_steiner_pos], width=max(m2_via.width, m2_via.height)) - self.add_wire(self.m2_stack[::-1], [spare_wen_dff_clk_pos, mid_pos, clk_steiner_pos]) - def route_control_logic(self): """ Route the control logic pins that are not inputs """