diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index d4ab62e5..ea7881ed 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -101,7 +101,6 @@ class bank(design.design): self.route_row_decoder() self.route_column_address_lines() self.route_control_lines() - self.add_control_pins() if self.num_banks > 1: self.route_bank_select() @@ -505,13 +504,15 @@ class bank(design.design): # and control lines. # The bank is at (0,0), so this is to the left of the y-axis. # 2 pitches on the right for vias/jogs to access the inputs - control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, 0) - control_bus_length = self.bitcell_array_inst.uy() - self.bus_xoffset = self.create_vertical_bus(layer="metal2", - pitch=self.m2_pitch, - offset=control_bus_offset, - names=self.control_signals, - length=control_bus_length) + control_bus_offset = vector(-self.m2_pitch * self.num_control_lines - self.m2_width, self.min_y_offset) + control_bus_length = self.max_y_offset - self.min_y_offset + self.bus_xoffset = self.create_bus(layer="metal2", + pitch=self.m2_pitch, + offset=control_bus_offset, + names=self.control_signals, + length=control_bus_length, + vertical=True, + make_pins=(self.num_banks==1)) @@ -750,52 +751,7 @@ class bank(design.design): offset=control_via_pos, rotate=90) - def add_control_pins(self): - """ Add the control signal input pins """ - for ctrl in self.control_signals: - # xoffsets are the center of the rail - x_offset = self.bus_xoffset[ctrl].x - 0.5*self.m2_width - if self.num_banks > 1: - # it's not an input pin if we have multiple banks - self.add_label_pin(text=ctrl, - layer="metal2", - offset=vector(x_offset, self.min_y_offset), - width=self.m2_width, - height=self.max_y_offset-self.min_y_offset) - else: - self.add_layout_pin(text=ctrl, - layer="metal2", - offset=vector(x_offset, self.min_y_offset), - width=self.m2_width, - height=self.max_y_offset-self.min_y_offset) - - - def connect_rail_from_right(self,inst, pin, rail): - """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """ - in_pin = inst.get_pin(pin).lc() - rail_pos = vector(self.rail_1_x_offsets[rail], in_pin.y) - self.add_wire(("metal3","via2","metal2"),[in_pin, rail_pos, rail_pos - vector(0,self.m2_pitch)]) - # Bring it up to M2 for M2/M3 routing - self.add_via(layers=("metal1","via1","metal2"), - offset=in_pin + contact.m1m2.offset, - rotate=90) - self.add_via(layers=("metal2","via2","metal3"), - offset=in_pin + self.m2m3_via_offset, - rotate=90) - - - def connect_rail_from_left(self,inst, pin, rail): - """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """ - in_pin = inst.get_pin(pin).rc() - rail_pos = vector(self.rail_1_x_offsets[rail], in_pin.y) - self.add_wire(("metal3","via2","metal2"),[in_pin, rail_pos, rail_pos - vector(0,self.m2_pitch)]) - self.add_via(layers=("metal1","via1","metal2"), - offset=in_pin + contact.m1m2.offset, - rotate=90) - self.add_via(layers=("metal2","via2","metal3"), - offset=in_pin + self.m2m3_via_offset, - rotate=90) def analytical_delay(self, slew, load): """ return analytical delay of the bank""" diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index cf62851f..5e744bfa 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -99,7 +99,7 @@ class control_logic(design.design): self.internal_bus_list = ["clk_buf", "clk_buf_bar", "we", "cs"] # leave space for the bus plus one extra space self.internal_bus_width = (len(self.internal_bus_list)+1)*self.m2_pitch - # Ooutputs to the bank + # Outputs to the bank self.output_list = ["s_en", "w_en", "clk_buf_bar", "clk_buf"] self.supply_list = ["vdd", "gnd"] @@ -137,10 +137,11 @@ class control_logic(design.design): # This offset is used for placement of the control logic in # the SRAM level. self.control_logic_center = vector(self.ctrl_dff_inst.rx(), self.rbl_inst.by()) - - self.height = self.rbl_inst.uy() + + # Extra pitch on top and right + self.height = self.rbl_inst.uy() + self.m3_pitch # Max of modules or logic rows - self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.width = max(self.rbl_inst.rx(), max([inst.rx() for inst in self.row_end_inst])) + self.m2_pitch def add_routing(self): diff --git a/compiler/modules/dff_array.py b/compiler/modules/dff_array.py index 5a09ae33..ef59f8a6 100644 --- a/compiler/modules/dff_array.py +++ b/compiler/modules/dff_array.py @@ -125,28 +125,21 @@ class dff_array(design.design): # Create vertical spines to a single horizontal rail clk_pin = self.dff_insts[0,0].get_pin("clk") debug.check(clk_pin.layer=="metal2","DFF clk pin not on metal2") - if self.columns==1: - self.add_layout_pin(text="clk", - layer="metal2", - offset=clk_pin.ll().scale(1,0), - width=self.m2_width, - height=self.height) - else: - self.add_layout_pin_segment_center(text="clk", - layer="metal3", - start=vector(0,self.m3_pitch+self.m3_width), - end=vector(self.width,self.m3_pitch+self.m3_width)) - for col in range(self.columns): - clk_pin = self.dff_insts[0,col].get_pin("clk") - # Make a vertical strip for each column - self.add_rect(layer="metal2", - offset=clk_pin.ll().scale(1,0), - width=self.m2_width, - height=self.height) - # Drop a via to the M3 pin - self.add_via_center(layers=("metal2","via2","metal3"), - offset=vector(clk_pin.cx(),self.m3_pitch+self.m3_width)) - + self.add_layout_pin_segment_center(text="clk", + layer="metal3", + start=vector(0,self.m3_pitch+self.m3_width), + end=vector(self.width,self.m3_pitch+self.m3_width)) + for col in range(self.columns): + clk_pin = self.dff_insts[0,col].get_pin("clk") + # Make a vertical strip for each column + self.add_rect(layer="metal2", + offset=clk_pin.ll().scale(1,0), + width=self.m2_width, + height=self.height) + # Drop a via to the M3 pin + self.add_via_center(layers=("metal2","via2","metal3"), + offset=vector(clk_pin.cx(),self.m3_pitch+self.m3_width)) + def analytical_delay(self, slew, load=0.0): diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py index bf6b8f92..941304e8 100644 --- a/compiler/modules/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -42,9 +42,9 @@ class replica_bitline(design.design): #self.add_lvs_correspondence_points() - # Plus a pitch for the WL contacts on the RBL - self.width = self.rbl_inst.rx() - self.dc_inst.lx() + self.m1_pitch - self.height = max(self.rbl_inst.uy(), self.dc_inst.uy()) + # Extra pitch on top and right + self.width = self.rbl_inst.rx() - self.dc_inst.lx() + self.m2_pitch + self.height = max(self.rbl_inst.uy(), self.dc_inst.uy()) + self.m3_pitch self.DRC_LVS() diff --git a/compiler/sram_1bank.py b/compiler/sram_1bank.py index 7d99299d..d58bcc85 100644 --- a/compiler/sram_1bank.py +++ b/compiler/sram_1bank.py @@ -29,26 +29,29 @@ class sram_1bank(sram_base): # No orientation or offset self.bank_inst = self.add_bank(0, [0, 0], 1, 1) + # The control logic is placed such that the center (between the delay/RBL and + # the actual control logic is aligned with the center of the bank (between + # the sense amps/column mux and cell array) control_pos = vector(-self.control_logic.width - self.m3_pitch, self.bank.bank_center.y - self.control_logic.control_logic_center.y) self.add_control_logic(position=control_pos) - # Leave room for the control routes to the left of the flops + # The row address bits are placed above the control logic aligned on the right. row_addr_pos = vector(self.control_logic_inst.rx() - self.row_addr_dff.width, - control_pos.y + self.control_logic.height + self.m1_pitch) + self.control_logic_inst.uy()) self.add_row_addr_dff(row_addr_pos) # This is M2 pitch even though it is on M1 to help stem via spacings on the trunk data_gap = -self.m2_pitch*(self.word_size+1) # Add the column address below the bank under the control - # Keep it aligned with the data flops + # The column address flops are aligned with the data flops if self.col_addr_dff: col_addr_pos = vector(self.bank.bank_center.x - self.col_addr_dff.width - self.bank.central_bus_width, data_gap - self.col_addr_dff.height) self.add_col_addr_dff(col_addr_pos) - # Add the data flops below the bank + # Add the data flops below the bank to the right of the center of bank: # This relies on the center point 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 @@ -104,13 +107,34 @@ class sram_1bank(sram_base): def route_clk(self): """ Route the clock network """ - debug.warning("Clock is top-level must connect.") - # For now, just have four clock pins for the address (x2), data, and control - if self.col_addr_dff: - self.copy_layout_pin(self.col_addr_dff_inst, "clk") - self.copy_layout_pin(self.row_addr_dff_inst, "clk") - self.copy_layout_pin(self.data_dff_inst, "clk") + + # This is the actual input to the SRAM self.copy_layout_pin(self.control_logic_inst, "clk") + + debug.warning("Clock is top-level must connect.") + + # Connect all of these clock pins to the clock in the central bus + # This is something like a "spine" clock distribution. The two spines + # are clk_buf and clk_buf_bar + bank_clk_buf_pin = self.bank_inst.get_pin("clk_buf") + bank_clk_buf_pos = bank_clk_buf_pin.center() + bank_clk_buf_bar_pin = self.bank_inst.get_pin("clk_buf_bar") + bank_clk_buf_bar_pos = bank_clk_buf_bar_pin.center() + + if self.col_addr_dff: + dff_clk_pin = self.col_addr_dff_inst.get_pin("clk") + dff_clk_pos = dff_clk_pin.center() + mid_pos = vector(bank_clk_buf_pos.x, dff_clk_pos.y) + self.add_wire(("metal3","via2","metal2"),[dff_clk_pos, mid_pos, bank_clk_buf_pos]) + + self.copy_layout_pin(self.row_addr_dff_inst, "clk") + #self.copy_layout_pin(self.data_dff_inst, "clk") + + data_dff_clk_pin = self.data_dff_inst.get_pin("clk") + data_dff_clk_pos = data_dff_clk_pin.center() + mid_pos = vector(bank_clk_buf_pos.x, data_dff_clk_pos.y) + self.add_wire(("metal3","via2","metal2"),[data_dff_clk_pos, mid_pos, bank_clk_buf_pos]) + def route_vdd_gnd(self): """ Propagate all vdd/gnd pins up to this level for all modules """ diff --git a/compiler/sram_base.py b/compiler/sram_base.py index 812c0950..c10019ff 100644 --- a/compiler/sram_base.py +++ b/compiler/sram_base.py @@ -362,8 +362,7 @@ class sram_base(design): inputs.append("ADDR[{}]".format(i)) outputs.append("A[{}]".format(i)) - # FIXME clk->clk_buf - self.connect_inst(inputs + outputs + ["clk", "vdd", "gnd"]) + self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) def add_data_dff(self, position): """ Add and place all data flops """ @@ -377,8 +376,7 @@ class sram_base(design): inputs.append("DIN[{}]".format(i)) outputs.append("BANK_DIN[{}]".format(i)) - # FIXME clk->clk_buf_bar - self.connect_inst(inputs + outputs + ["clk", "vdd", "gnd"]) + self.connect_inst(inputs + outputs + ["clk_buf", "vdd", "gnd"]) def add_control_logic(self, position): """ Add and place control logic """ diff --git a/compiler/tests/20_sram_1bank_test.py b/compiler/tests/20_sram_1bank_test.py index 4b929e87..8b83f54a 100755 --- a/compiler/tests/20_sram_1bank_test.py +++ b/compiler/tests/20_sram_1bank_test.py @@ -35,7 +35,7 @@ class sram_1bank_test(openram_test): debug.info(1, "Single bank, eight way column mux with control logic") a = sram(word_size=2, num_words=128, num_banks=1, name="sram4") self.local_check(a, final_verification=True) - + globals.end_openram() # instantiate a copy of the class to actually run the test