diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 5c08df30..af093d03 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -54,8 +54,8 @@ class bank(design.design): def create_netlist(self): self.compute_sizes() - self.add_pins() self.add_modules() + self.add_pins() # Must create the replica bitcell array first self.create_instances() @@ -78,9 +78,10 @@ class bank(design.design): for port in self.read_ports: for bit in range(self.word_size): self.add_pin("dout{0}_{1}".format(port,bit),"OUT") - self.add_pin("rbl_bl{0}_{0}".format(port),"OUT") - for port in self.read_ports: - self.add_pin("rbl_wl{0}_{0}".format(port),"IN") + for port in self.read_ports: + self.add_pin(self.bitcell_array.get_rbl_bl_name(port),"OUT") + for port in self.read_ports: + self.add_pin(self.bitcell_array.get_rbl_wl_name(port),"IN") for port in self.write_ports: for bit in range(self.word_size): self.add_pin("din{0}_{1}".format(port,bit),"IN") @@ -247,7 +248,7 @@ class bank(design.design): # LOWER RIGHT QUADRANT # To the left of the bitcell array - x_offset = self.bitcell_array_right + self.port_address.width + self.m2_gap + x_offset = self.bitcell_array_right + self.port_address.width self.port_address_offsets[port] = vector(x_offset,self.main_bitcell_array_bottom) # UPPER RIGHT QUADRANT @@ -684,11 +685,12 @@ class bank(design.design): control_bus_length = self.max_y_offset - self.main_bitcell_array_top - 2*self.m1_pitch control_bus_offset = vector(self.bitcell_array_right, self.max_y_offset - control_bus_length) - + + # The bus for the right port is reversed so that the rbl_wl is closest to the array self.bus_xoffset[1] = self.create_bus(layer="metal2", pitch=self.m2_pitch, offset=control_bus_offset, - names=self.control_signals[1], + names=list(reversed(self.control_signals[1])), length=control_bus_length, vertical=True, make_pins=(self.num_banks==1)) @@ -950,13 +952,15 @@ class bank(design.design): if port in self.read_ports: connection.append((self.prefix+"s_en{}".format(port), self.port_data_inst[port].get_pin("s_en").lc())) - + for (control_signal, pin_pos) in connection: + control_mid_pos = self.bus_xoffset[port][control_signal] control_pos = vector(self.bus_xoffset[port][control_signal].x ,pin_pos.y) - self.add_path("metal1", [control_pos, pin_pos]) + self.add_wire(("metal1","via1","metal2"), [control_mid_pos, control_pos, pin_pos]) self.add_via_center(layers=("metal1", "via1", "metal2"), offset=control_pos) + # clk to wordline_driver control_signal = self.prefix+"wl_en{}".format(port) if port%2: diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index e39dbb9f..52207a77 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -95,6 +95,18 @@ class control_logic(design.design): size=4, height=dff_height) self.add_mod(self.and2) + + if self.port_type=="rw": + self.rbl_driver = factory.create(module_type="pand2", + size=self.num_cols, + height=dff_height) + self.add_mod(self.rbl_driver) + elif self.port_type=="r": + self.rbl_driver = factory.create(module_type="pbuf", + size=self.num_cols, + height=dff_height) + self.add_mod(self.rbl_driver) + # clk_buf drives a flop for every address and control bit # plus about 5 fanouts for the control logic @@ -131,12 +143,14 @@ class control_logic(design.design): height=dff_height) self.add_mod(self.inv) - # p_en_bar drives every column in the bicell array + # p_en_bar drives every column in the bitcell array self.p_en_bar_driver = factory.create(module_type="pdriver", neg_polarity=True, fanout=self.num_cols, height=dff_height) self.add_mod(self.p_en_bar_driver) + + # if (self.port_type == "rw") or (self.port_type == "r"): # from importlib import reload @@ -366,11 +380,13 @@ class control_logic(design.design): self.create_wlen_row() if (self.port_type == "rw") or (self.port_type == "w"): self.create_wen_row() - if (self.port_type == "rw") or (self.port_type == "r"): + if (self.port_type == "rw") or (self.port_type == "r"): self.create_rbl_row() - self.create_pen_row() self.create_sen_row() self.create_delay() + if (self.port_type == "rw") or (self.port_type == "r") or self.words_per_row>1: + self.create_pen_row() + def place_instances(self): @@ -400,9 +416,10 @@ class control_logic(design.design): height = self.w_en_inst.uy() control_center_y = self.w_en_inst.uy() row += 1 - if (self.port_type == "rw") or (self.port_type == "r"): + if (self.port_type == "rw") or (self.port_type == "r"): self.place_rbl_row(row) row += 1 + if (self.port_type == "rw") or (self.port_type == "r") or self.words_per_row>1: self.place_pen_row(row) row += 1 self.place_sen_row(row) @@ -431,8 +448,9 @@ class control_logic(design.design): self.route_wen() if (self.port_type == "rw") or (self.port_type == "r"): self.route_rbl() - self.route_pen() self.route_sen() + if (self.port_type == "rw") or (self.port_type == "r") or self.words_per_row>1: + self.route_pen() self.route_clk_buf() self.route_gated_clk_bar() self.route_gated_clk_buf() @@ -451,8 +469,8 @@ class control_logic(design.design): # Add the RBL above the rows # Add to the right of the control rows and routing channel - offset = vector(0, y_off) - self.delay_inst.place(offset) + offset = vector(self.delay_chain.width, y_off) + self.delay_inst.place(offset, mirror="MY") def create_clk_buf_row(self): @@ -589,11 +607,15 @@ class control_logic(design.design): self.connect_output(self.wl_en_inst, "Z", "wl_en") def create_rbl_row(self): - - # input: gated_clk_bar, we_bar, output: rbl_in - self.rbl_inst=self.add_inst(name="and2_rbl", - mod=self.and2) - self.connect_inst(["gated_clk_bar", "we_bar", "rbl_wl", "vdd", "gnd"]) + + self.rbl_inst=self.add_inst(name="rbl_driver", + mod=self.rbl_driver) + if self.port_type == "rw": + # input: gated_clk_bar, we_bar, output: rbl_wl + self.connect_inst(["gated_clk_bar", "we_bar", "rbl_wl", "vdd", "gnd"]) + elif self.port_type == "r": + # input: gated_clk_bar, output: rbl_wl + self.connect_inst(["gated_clk_bar", "rbl_wl", "vdd", "gnd"]) def place_rbl_row(self,row): x_off = self.control_x_offset @@ -608,20 +630,14 @@ class control_logic(design.design): """ Connect the logic for the rbl_in generation """ if self.port_type == "rw": - input_name = "we_bar" # Connect the NAND gate inputs to the bus rbl_in_map = zip(["A", "B"], ["gated_clk_bar", "we_bar"]) - self.connect_vertical_bus(rbl_in_map, self.rbl_inst, self.rail_offsets) - - - # Connect the output of the precharge enable to the RBL input - #if self.port_type == "rw": - # out_pos = self.rbl_in_inst.get_pin("Z").center() - #else: - # out_pos = vector(self.rail_offsets["gated_clk_bar"].x, self.rbl_inst.by()-3*self.m2_pitch) - - self.copy_layout_pin(self.rbl_inst, "Z", "rbl_wl") + else: + rbl_in_map = zip(["A"], ["gated_clk_bar"]) + self.connect_vertical_bus(rbl_in_map, self.rbl_inst, self.rail_offsets) + self.connect_output(self.rbl_inst, "Z", "rbl_wl") + # Input from RBL goes to the delay line for futher delay self.copy_layout_pin(self.delay_inst, "in", "rbl_bl") def create_pen_row(self): @@ -727,7 +743,6 @@ class control_logic(design.design): self.row_end_inst.append(self.w_en_inst) def route_wen(self): - if self.port_type == "rw": input_name = "we" else: diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 8d158bfe..ce0d742e 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -99,13 +99,13 @@ class sram_1bank(sram_base): # 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 - self.bank.m2_gap) + self.bank.bank_array_ll.y - self.control_logic_insts[port].mod.control_logic_center.y - 2*self.bank.m2_gap ) self.control_logic_insts[port].place(control_pos[port]) # The row address bits are placed above the control logic aligned on the right. x_offset = self.control_logic_insts[port].rx() - self.row_addr_dff_insts[port].width - # It is aove the control logic but below the top of the bitcell array - y_offset = max(self.control_logic_insts[port].uy(), self.bank.bank_array_ur.y - self.row_addr_dff_insts[port].height) + # It is above the control logic but below the top of the bitcell array + y_offset = max(self.control_logic_insts[port].uy(), self.bank_inst.uy() - self.row_addr_dff_insts[port].height) row_addr_pos[port] = vector(x_offset, y_offset) self.row_addr_dff_insts[port].place(row_addr_pos[port]) @@ -137,6 +137,30 @@ class sram_1bank(sram_base): # Port 1 port = 1 + + # Add the col address flops above the bank to the right of the upper-right of bank array + if self.col_addr_dff: + col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap, + self.bank.height + max_gap_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, + self.bank.bank_array_ur.y + self.control_logic_insts[port].height - + (self.control_logic_insts[port].height - self.control_logic_insts[port].mod.control_logic_center.y) + + 2*self.bank.m2_gap) + #import pdb; pdb.set_trace() + self.control_logic_insts[port].place(control_pos[port], mirror="XY") + + # The row address bits are placed above the control logic aligned on the left. + x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width + # It is below the control logic but below the bottom of the bitcell array + y_offset = min(self.control_logic_insts[port].by(), self.bank_inst.by() + self.row_addr_dff_insts[port].height) + row_addr_pos[port] = vector(x_offset, y_offset) + self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY") + # 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. @@ -153,29 +177,6 @@ class sram_1bank(sram_base): wmask_pos[port] = vector(self.bank.bank_array_ur.x - self.data_dff_insts[port].width, self.bank.height + max_gap_size + self.data_dff_insts[port].height) self.wmask_dff_insts[port].place(wmask_pos[port], mirror="MX") - else: - data_pos[port] = self.bank_inst.ur() - - # Add the col address flops above the bank to the right of the upper-right of bank array - if self.col_addr_dff: - col_addr_pos[port] = vector(self.bank.bank_array_ur.x + self.bank.m2_gap, - self.bank.height + max_gap_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, - self.bank.bank_array_ur.y + self.control_logic_insts[port].mod.control_logic_center.y + self.bank.m2_gap) - self.control_logic_insts[port].place(control_pos[port], mirror="XY") - - # The row address bits are placed above the control logic aligned on the left. - x_offset = control_pos[port].x - self.control_logic_insts[port].width + self.row_addr_dff_insts[port].width - # It is above the control logic but below the top of the bitcell array - y_offset = min(self.control_logic_insts[port].by(), self.bank.bank_array_ll.y - self.row_addr_dff_insts[port].height) - row_addr_pos[port] = vector(x_offset, y_offset) - self.row_addr_dff_insts[port].place(row_addr_pos[port], mirror="XY") - def add_layout_pins(self): @@ -271,20 +272,23 @@ class sram_1bank(sram_base): def route_control_logic(self): - """ Route the outputs from the control logic module """ + """ Route the control logic pins that are not inputs """ + for port in self.all_ports: for signal in self.control_logic_outputs[port]: # The clock gets routed separately and is not a part of the bank if "clk" in signal: continue - if signal.startswith("rbl"): - continue src_pin = self.control_logic_insts[port].get_pin(signal) dest_pin = self.bank_inst.get_pin(signal+"{}".format(port)) - self.connect_rail_from_left_m2m3(src_pin, dest_pin) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=src_pin.rc()) - + self.connect_vbus_m2m3(src_pin, dest_pin) + + for port in self.read_ports: + # Only input (besides pins) is the replica bitline + src_pin = self.control_logic_insts[port].get_pin("rbl_bl") + dest_pin = self.bank_inst.get_pin("rbl_bl{}".format(port)) + self.connect_vbus_m2m3(src_pin, dest_pin) + def route_row_addr_dff(self): """ Connect the output of the row flops to the bank pins """ diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index 096f4987..ec2bc608 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -114,7 +114,7 @@ class sram_base(design, verilog, lef): self.add_lvs_correspondence_points() - self.offset_all_coordinates() + #self.offset_all_coordinates() highest_coord = self.find_highest_coords() self.width = highest_coord[0] @@ -514,21 +514,28 @@ class sram_base(design, verilog, lef): return insts - def connect_rail_from_left_m2m3(self, src_pin, dest_pin): - """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """ - in_pos = src_pin.rc() + def connect_vbus_m2m3(self, src_pin, dest_pin): + """ Helper routine to connect an instance to a vertical bus. + Routes horizontal then vertical L shape. + Dest pin is assumed to be on M2. + Src pin can be on M1/M2/M3.""" + + if src_pin.cx()