diff --git a/compiler/bank.py b/compiler/bank.py index 176eac74..230074d6 100644 --- a/compiler/bank.py +++ b/compiler/bank.py @@ -38,13 +38,24 @@ class bank(design.design): self.words_per_row = words_per_row self.num_banks = num_banks + # The local control signals are gated when we have bank select logic, + # so this prefix will be added to all of the signals. + if self.num_banks>1: + self.prefix="gated_" + else: + self.prefix="" + self.compute_sizes() - self.add_pins() + self.add_pins() self.create_modules() self.add_modules() self.setup_layout_constraints() self.route_layout() + # Add and route the bank select logic + if(self.num_banks > 1): + self.add_bank_select() + # Can remove the following, but it helps for debug! self.add_lvs_correspondence_points() @@ -61,14 +72,9 @@ class bank(design.design): # the signals gated_*. if(self.num_banks > 1): self.add_pin("bank_select") - self.add_pin("s_en") - self.add_pin("w_en") - self.add_pin("tri_en_bar") - self.add_pin("tri_en") - self.add_pin("clk_bar") - self.add_pin("clk") - self.add_pin("vdd") - self.add_pin("gnd") + for pin in ["s_en","w_en","tri_en_bar","tri_en", + "clk_bar","clk","vdd","gnd"]: + self.add_pin(pin) def route_layout(self): """ Create routing amoung the modules """ @@ -82,12 +88,11 @@ class bank(design.design): self.route_msf_address() self.route_control_lines() self.add_control_pins() - if self.num_banks > 1: - self.route_bank_select() self.route_vdd_supply() self.route_gnd_supply() - #self.offset_all_coordinates() + self.offset_all_coordinates() + def add_modules(self): """ Add modules. The order should not matter! """ @@ -109,8 +114,6 @@ class bank(design.design): self.add_row_decoder() self.add_wordline_driver() self.add_msf_address() - if(self.num_banks > 1): - self.add_bank_select() def compute_sizes(self): """ Computes the required sizes to create the bank """ @@ -132,9 +135,12 @@ class bank(design.design): # Number of control lines in the bus self.num_control_lines = 6 # The order of the control signals on the control bus: - self.control_signals = ["clk", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"] + self.input_control_signals = ["clk", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"] + # These will be outputs of the gaters if this is multibank if self.num_banks>1: - self.control_signals = ["gated_"+str for str in self.control_signals] + self.control_signals = ["gated_"+str for str in self.input_control_signals] + else: + self.control_signals = self.input_control_signals # The central bus is the column address (both polarities), row address if self.col_addr_size>0: self.num_addr_lines = 2**self.col_addr_size + self.row_addr_size @@ -146,6 +152,7 @@ class bank(design.design): self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3")) self.m1_pitch = self.m1m2_via.height + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"]) self.m2_pitch = self.m2m3_via.height + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"]) + self.m1_width = drc["minwidth_metal1"] self.m2_width = drc["minwidth_metal2"] self.m3_width = drc["minwidth_metal3"] @@ -212,13 +219,6 @@ class bank(design.design): self.inv = pinv() self.add_mod(self.inv) - # 4x Inverter - self.inv4x = pinv(nmos_width=4*drc["minwidth_tx"]) - self.add_mod(self.inv4x) - - self.nor2 = nor_2() - self.add_mod(self.nor2) - # Vertical metal rail gap definition self.metal2_extend_contact = (self.m1m2_via.second_layer_height - self.m1m2_via.contact_width) / 2 @@ -226,6 +226,7 @@ class bank(design.design): self.gap_between_rail_offset = self.gap_between_rails + drc["minwidth_metal2"] self.via_shift = (self.m1m2_via.second_layer_width - self.m1m2_via.first_layer_width) / 2 + self.via_shift_offset = vector(0,self.via_shift) def add_bitcell_array(self): """ Adding Bitcell Array """ @@ -257,7 +258,7 @@ class bank(design.design): for i in range(self.num_cols): temp.append("bl[{0}]".format(i)) temp.append("br[{0}]".format(i)) - temp.extend(["clk_bar", "vdd"]) + temp.extend([self.prefix+"clk_bar", "vdd"]) self.connect_inst(temp) def add_column_mux_array(self): @@ -296,7 +297,7 @@ class bank(design.design): temp.append("bl_out[{0}]".format(i)) temp.append("br_out[{0}]".format(i)) - temp.extend(["s_en", "vdd", "gnd"]) + temp.extend([self.prefix+"s_en", "vdd", "gnd"]) self.connect_inst(temp) def add_write_driver_array(self): @@ -317,7 +318,7 @@ class bank(design.design): else: temp.append("bl_out[{0}]".format(i)) temp.append("br_out[{0}]".format(i)) - temp.extend(["w_en", "vdd", "gnd"]) + temp.extend([self.prefix+"w_en", "vdd", "gnd"]) self.connect_inst(temp) def add_msf_data_in(self): @@ -335,7 +336,7 @@ class bank(design.design): for i in range(self.word_size): temp.append("data_in[{0}]".format(i)) temp.append("data_in_bar[{0}]".format(i)) - temp.extend(["clk_bar", "vdd", "gnd"]) + temp.extend([self.prefix+"clk_bar", "vdd", "gnd"]) self.connect_inst(temp) def add_tri_gate_array(self): @@ -351,7 +352,7 @@ class bank(design.design): temp.append("data_out[{0}]".format(i)) for i in range(self.word_size): temp.append("DATA[{0}]".format(i)) - temp.extend(["tri_en", "tri_en_bar", "vdd", "gnd"]) + temp.extend([self.prefix+"tri_en", self.prefix+"tri_en_bar", "vdd", "gnd"]) self.connect_inst(temp) def add_row_decoder(self): @@ -396,11 +397,7 @@ class bank(design.design): temp.append("dec_out[{0}]".format(i)) for i in range(self.num_rows): temp.append("wl[{0}]".format(i)) - - if(self.num_banks > 1): - temp.append("gated_clk") - else: - temp.append("clk") + temp.append(self.prefix+"clk") temp.append("vdd") temp.append("gnd") self.connect_inst(temp) @@ -429,10 +426,7 @@ class bank(design.design): temp.extend(["sel[1]","sel[0]"]) else: temp.extend(["A[{0}]".format(i),"A_bar[{0}]".format(i)]) - if(self.num_banks > 1): - temp.append("gated_clk") - else: - temp.append("clk") + temp.append(self.prefix+"clk") temp.extend(["vdd", "gnd"]) self.connect_inst(temp) @@ -440,12 +434,15 @@ class bank(design.design): def add_column_decoder(self): """ Create a 2:4 decoder to decode column select lines if the col_addr_size = 4 """ - # FIXME: Should just load this rather than reference a level down + if self.col_addr_size == 1: return # This is done from the FF outputs directly if self.col_addr_size == 2: + # FIXME: Should just load this rather than reference a level down self.col_decoder = self.decoder.pre2_4 elif self.col_addr_size == 3: + debug.error("8 way column mux not yet supported...", -1) + # FIXME: Should just load this rather than reference a level down self.col_decoder = self.decoder.pre3_8 else: # No error checking before? @@ -473,103 +470,182 @@ class bank(design.design): NOR+INV gates to gate the control signals in case of multiple banks are created in upper level SRAM module """ - xoffset_nor = self.start_of_left_central_bus + self.nor2.width + self.inv4x.width - xoffset_inv = xoffset_nor + self.nor2.width - self.bank_select_or_position = vector(-xoffset_nor, self.min_point) + + # 4x Inverter + self.inv4x = pinv(nmos_width=4*drc["minwidth_tx"]) + self.add_mod(self.inv4x) + + self.nor2 = nor_2() + self.add_mod(self.nor2) + + self.nand2 = nand_2() + self.add_mod(self.nand2) + + # left of gnd rail is the "bus start" + bus_start = self.gnd_x_offset - 2*drc["minwidth_metal2"] + xoffset_nand = bus_start - self.nand2.width - self.inv4x.width - 2*self.m2_pitch + xoffset_nor = bus_start - self.nor2.width - self.inv4x.width - 2*self.m2_pitch + xoffset_inv = bus_start - self.inv4x.width + xoffset_bank_sel_inv = xoffset_nor - self.inv.width - 3*self.m2_pitch + xoffset_inputs = xoffset_bank_sel_inv - 6*self.m2_pitch # bank select inverter - self.bank_select_inv_position = vector(self.bank_select_or_position.x - - 5 * drc["minwidth_metal2"] - - self.inv4x.width, + self.bank_select_inv_position = vector(xoffset_bank_sel_inv, self.min_point) - self.add_inst(name="bank_select_inv", - mod=self.inv4x, - offset=self.bank_select_inv_position) - self.connect_inst(["bank_select", "bank_select_bar", "vdd", "gnd"]) + # bank select inverter (must be made unique if more than one OR) + bank_sel_inv=self.add_inst(name="bank_sel_inv", + mod=self.inv, + offset=[xoffset_bank_sel_inv,self.min_point]) + self.connect_inst(["bank_sel", "bank_sel_bar", "vdd", "gnd"]) + + # bank_sel is vertical wire + xoffset_bank_sel = xoffset_bank_sel_inv + self.add_label_pin(text="bank_sel", + layer="metal2", + offset=vector(xoffset_bank_sel, self.min_point), + width=self.m2_width, + height=self.decoder_min_point-self.min_point-self.m2_pitch) + in_pin = bank_sel_inv.get_pin("A").ll() + self.add_via(layers=("metal1","via1","metal2"), + offset=in_pin) + self.add_layout_pin(text="bank_sel", + layer="metal3", + offset=vector(self.left_vdd_x_offset, self.min_point), + width=xoffset_bank_sel - self.left_vdd_x_offset, + height=self.m3_width) + self.add_via(layers=("metal2","via2","metal3"), + offset=vector(xoffset_bank_sel_inv, self.min_point)) - for i in range(self.numb_control_lines): - # central control bus index - # 5 = clk,4 = tri_en_bar,3 = tri_en,2 = clk_bar,1 = w_en,0 = s_en - name_nor = "bank_selector_nor_{0}".format(i) - name_inv = "bank_selector_inv_{0}".format(i) - nor2_inv_connection_height = self.inv4x.A_position.y - self.nor2.Z_position.y + 0.5 * drc["minwidth_metal1"] + # bank_sel_bar is vertical wire + xoffset_bank_sel_bar = xoffset_bank_sel_inv+self.inv.width-self.m2_width + self.add_label_pin(text="bank_sel_bar", + layer="metal2", + offset=vector(xoffset_bank_sel_bar, self.min_point), + width=self.m2_width, + height=2*self.inv.height) + out_pin = bank_sel_inv.get_pin("Z").lr() + self.add_via(layers=("metal1","via1","metal2"), + offset=out_pin-vector(self.m2_width,0)) - if (i % 2): - y_offset = self.min_point + self.inv.height*(i + 1) - mod_dir = "MX" - # nor2 output to inv input - y_correct = self.nor2.Z_position.y + nor2_inv_connection_height - 0.5 * drc["minwidth_metal1"] + + + for i in range(self.num_control_lines): + input_name = self.input_control_signals[i] + gated_name = self.control_signals[i] + name_nand = "nand_{}".format(input_name) + name_nor = "nor_{}".format(input_name) + name_inv = "inv_{}".format(input_name) + + y_offset = self.min_point + self.inv.height * i + if i%2: + y_offset += self.inv.height + mirror = "MX" else: - y_offset = self.min_point + self.inv.height*i - mod_dir = "R0" - # nor2 output to inv input - y_correct = 0.5 * drc["minwidth_metal1"] - self.nor2.Z_position.y - connection = vector(xoffset_inv, y_offset - y_correct) - - if i == 3: - self.add_inst(name=name_nor, - mod=self.nor2, - offset=[xoffset_nor, y_offset], - mirror=mod_dir) - self.connect_inst(["gated_tri_en_bar", - "bank_select_bar", - self.control_signals[i].format(i), - "vdd", - "gnd"]) - # connect the metal1 layer to connect to the old inv output - offset = connection - vector(0, 0.5*drc["minwidth_metal1"]) - self.add_rect(layer="metal1", - offset=offset, - width=self.inv4x.width, - height=drc["minwidth_metal1"]) - elif i == 5: - offset = [xoffset_nor, y_offset - self.nor2.A_position.y - - 0.5*drc["minwidth_metal1"]] - self.add_rect(layer="metal1", - offset=offset, - width=self.nor2.width + self.inv4x.width, - height=drc["minwidth_metal1"]) - else: - self.add_inst(name=name_nor, - mod=self.nor2, - offset=[xoffset_nor, y_offset], - mirror=mod_dir) - self.connect_inst([self.gated_control_signals[i], - "bank_select_bar", - "net_block_nor_inv[{0}]".format(i), - "vdd", - "gnd"]) - - self.add_inst(name=name_inv, - mod=self.inv4x, - offset=[xoffset_inv, y_offset], - mirror=mod_dir) - self.connect_inst(["net_block_nor_inv[{0}]".format(i), - self.control_signals[i], - "vdd", - "gnd"]) - - # nor2 output to inv input - for i in range(self.numb_control_lines - 1): - nor2_inv_connection_height = (self.inv4x.A_position.y - - self.nor2.Z_position.y - + 0.5 * drc["minwidth_metal1"]) + mirror = "" + + # These require OR (nor2+inv) gates since they are active low. + # (writes occur on clk low) + if input_name in ("clk", "tri_en_bar"): - if (i % 2): - y_offset = self.min_point + self.inv.height * (i + 1) - mod_dir = "MX" - y_correct = (-self.nor2.Z_position.y + 0.5 * drc["minwidth_metal1"] - - nor2_inv_connection_height) + logic_inst=self.add_inst(name=name_nor, + mod=self.nor2, + offset=[xoffset_nor, y_offset], + mirror=mirror) + self.connect_inst([input_name, + "bank_sel_bar", + gated_name+"_temp_bar", + "vdd", + "gnd"]) + xoffset_bank_signal = xoffset_bank_sel_bar + + + # the rest are AND (nand2+inv) gates else: - y_offset = self.min_point + self.inv.height*i - mod_dir = "R0" - y_correct = self.nor2.Z_position.y - 0.5 * drc["minwidth_metal1"] - # nor2 output to inv input - connection = vector(xoffset_inv, y_offset + y_correct) - self.add_rect(layer="metal1", - offset=connection, - width=drc["minwidth_metal1"], - height=nor2_inv_connection_height) + logic_inst=self.add_inst(name=name_nand, + mod=self.nand2, + offset=[xoffset_nand, y_offset], + mirror=mirror) + bank_sel_signal = "bank_sel" + self.connect_inst([input_name, + "bank_sel", + gated_name+"_temp_bar", + "vdd", + "gnd"]) + xoffset_bank_signal = xoffset_bank_sel + + # They all get inverters on the output + inv_inst=self.add_inst(name=name_inv, + mod=self.inv4x, + offset=[xoffset_inv, y_offset], + mirror=mirror) + self.connect_inst([gated_name+"_temp_bar", + gated_name, + "vdd", + "gnd"]) + + + # Connect the logic output to inverter input + pre = logic_inst.get_pin("Z").lc() + out_position = logic_inst.get_pin("Z").rc() + vector(0.5*self.m1_width,0) + in_position = inv_inst.get_pin("A").lc() + vector(0.5*self.m1_width,0) + post = inv_inst.get_pin("A").rc() + self.add_path("metal1", [pre, out_position, in_position, post]) + + # Connect the inverter output to the central bus + out_pin = inv_inst.get_pin("Z") + bus_pos = vector(self.central_line_xoffset[gated_name], out_pin.rc().y) + self.add_path("metal3",[out_pin.rc(), bus_pos]) + self.add_via(layers=("metal2", "via2", "metal3"), + offset=bus_pos - vector(0,0.5*self.m2m3_via.height)) + self.add_via(layers=("metal1", "via1", "metal2"), + offset=out_pin.lr() - self.via_shift_offset, + rotate=90) + self.add_via(layers=("metal2", "via2", "metal3"), + offset=out_pin.lr() - self.via_shift_offset, + rotate=90) + + # Connect the logic B input to bank_sel/bank_sel_bar + logic_pin = logic_inst.get_pin("B") + input_pos = vector(xoffset_bank_signal,logic_pin.cy()) + self.add_path("metal2",[logic_pin.lc(), input_pos]) + self.add_via(layers=("metal1", "via1", "metal2"), + offset=logic_pin.ll()-self.via_shift_offset, + rotate=90) + + + # Connect the logic A input to the input pin + logic_pos = logic_inst.get_pin("A").ll() + input_pos = vector(self.left_vdd_x_offset,logic_pos.y) + self.add_via(layers=("metal1", "via1", "metal2"), + offset=logic_pos-self.via_shift_offset, + rotate=90) + + self.add_via(layers=("metal2", "via2", "metal3"), + offset=logic_pos-self.via_shift_offset, + rotate=90) + + self.add_layout_pin(text=input_name, + layer="metal3", + offset=vector(self.left_vdd_x_offset,logic_pos.y - self.via_shift_offset.y), + height=self.m3_width, + width=logic_pos.x-self.left_vdd_x_offset) + + + + # Add vdd/gnd supply rails + gnd_pin = inv_inst.get_pin("gnd") + left_gnd_pos = vector(xoffset_bank_sel_inv,gnd_pin.rc().y) + right_gnd_pos = vector(self.gnd_x_offset,gnd_pin.rc().y) + self.add_path("metal1",[left_gnd_pos, right_gnd_pos]) + right_via_pos = vector(self.gnd_x_offset,gnd_pin.lr().y) + self.add_via(layers=("metal1", "via1", "metal2"), + offset=right_via_pos + vector(self.m1m2_via.height,0) - self.via_shift_offset, + rotate=90) + + vdd_pin = inv_inst.get_pin("vdd") + left_vdd_pos = vector(self.left_vdd_x_offset,vdd_pin.lc().y) + self.add_path("metal1",[left_vdd_pos,vdd_pin.rc()]) + def setup_layout_constraints(self): """ Calculating layout constraints, width, height etc """ @@ -580,13 +656,17 @@ class bank(design.design): # Leave room for the output below the tri gate. tri_gate_min_point = self.tri_gate_array_inst.ll().y - 3*self.m2_pitch addr_min_point = self.msf_address_inst.ll().y - 2*self.m2_pitch + if self.col_addr_size >1: - decoder_min_point = self.col_decoder_inst.ll().y + self.decoder_min_point = self.col_decoder_inst.ll().y else: - decoder_min_point = 0 - self.min_point = min(tri_gate_min_point, addr_min_point, decoder_min_point) + self.decoder_min_point = addr_min_point + if self.num_banks>1: - self.min_point -= self.num_control_lines * self.bitcell.height + self.min_point = min(self.decoder_min_point - self.num_control_lines * self.bitcell.height, tri_gate_min_point) + else: + self.min_point = min(addr_min_point, tri_gate_min_point) + # The max point is always the top of the precharge bitlines self.max_point = self.precharge_array_inst.uy() @@ -594,7 +674,7 @@ class bank(design.design): self.height = self.max_point - self.min_point # Add an extra gap between the bitcell and the rail - self.right_vdd_x_offset = self.bitcell_array_inst.ur().x + 3 * drc["minwidth_metal1"] + self.right_vdd_x_offset = self.bitcell_array_inst.ur().x + 3 * self.m1_width offset = vector(self.right_vdd_x_offset, self.min_point) self.add_layout_pin(text="vdd", layer="metal1", @@ -603,7 +683,7 @@ class bank(design.design): height=self.height) # from the edge of the decoder is another 2 times minwidth metal1 - self.left_vdd_x_offset = min(self.msf_address_inst.ll().x, self.row_decoder_inst.ll().x) - self.vdd_rail_width - 2*drc["minwidth_metal1"] + self.left_vdd_x_offset = min(self.msf_address_inst.ll().x, self.row_decoder_inst.ll().x) - self.vdd_rail_width - 2*self.m1_width offset = vector(self.left_vdd_x_offset, self.min_point) self.add_layout_pin(text="vdd", layer="metal1", @@ -640,7 +720,7 @@ class bank(design.design): height=self.height) # row address lines (to the left of the column mux or GND rail) - # goes from 0 down to the min point + # goes from 0 down to the bottom of the address flops for i in range(self.row_addr_size): x_offset = self.start_of_left_central_bus + i * self.m2_pitch name = "A[{}]".format(i) @@ -648,9 +728,9 @@ class bank(design.design): # Add a label pin for LVS correspondence and visual help inspecting the rail. self.add_label_pin(text=name, layer="metal2", - offset=vector(x_offset, self.min_point), + offset=vector(x_offset, self.decoder_min_point), width=self.m2_width, - height=-self.min_point) + height=-self.decoder_min_point) # column mux lines if there is column mux [2 or 4 lines] (to the left of the GND rail) # goes from 0 down to the min point @@ -662,9 +742,9 @@ class bank(design.design): # Add a label pin for LVS correspondence self.add_label_pin(text=name, layer="metal2", - offset=vector(x_offset, self.min_point), + offset=vector(x_offset, self.decoder_min_point), width=self.m2_width, - height=-self.min_point) + height=-self.decoder_min_point) @@ -691,7 +771,7 @@ class bank(design.design): tri_gate_in = self.tri_gate_array_inst.get_pin("in[{}]".format(i)).bc() sa_data_out = self.sense_amp_array_inst.get_pin("data[{}]".format(i)).rc() # rc to get enough overlap - startY = self.tri_gate_array_inst.ll().y - 2*drc["minwidth_metal3"] + 0.5*drc["minwidth_metal1"] + startY = self.tri_gate_array_inst.ll().y - 2*drc["minwidth_metal3"] + 0.5*self.m1_width start = vector(tri_gate_in.x - 3 * drc["minwidth_metal3"], startY) m3_min = vector([drc["minwidth_metal3"]] * 2) @@ -734,7 +814,7 @@ class bank(design.design): # Connect the address rails to the decoder # Note that the decoder inputs are long vertical rails so spread out the connections vertically. - decoder_in_position = self.row_decoder_inst.get_pin("A[{}]".format(i)).br() + vector(0,position_heights*self.bitcell.height+self.m2_pitch) + decoder_in_position = self.row_decoder_inst.get_pin("A[{}]".format(i)).lr() + vector(0,position_heights*self.bitcell.height+self.m2_pitch) rail_position = vector(self.central_line_xoffset["A[{}]".format(i)]+drc["minwidth_metal2"],decoder_in_position.y) self.add_path("metal1",[decoder_in_position,rail_position]) @@ -778,8 +858,8 @@ class bank(design.design): for i in range(self.num_rows): # The pre/post is to access the pin from "outside" the cell to avoid DRCs pre = self.row_decoder_inst.get_pin("decode[{}]".format(i)).lc() - decoder_out_position = self.row_decoder_inst.get_pin("decode[{}]".format(i)).rc() + vector(0.5*drc["minwidth_metal1"],0) - driver_in_position = self.wordline_driver_inst.get_pin("in[{}]".format(i)).lc() + vector(0.5*drc["minwidth_metal1"],0) + decoder_out_position = self.row_decoder_inst.get_pin("decode[{}]".format(i)).rc() + vector(0.5*self.m1_width,0) + driver_in_position = self.wordline_driver_inst.get_pin("in[{}]".format(i)).lc() + vector(0.5*self.m1_width,0) post = self.wordline_driver_inst.get_pin("in[{}]".format(i)).rc() self.add_path("metal1", [pre, decoder_out_position, driver_in_position, post]) @@ -839,7 +919,7 @@ class bank(design.design): self.add_path("metal1",[decode_out_position, selx_position]) # via on end - decode_out_via = self.col_decoder_inst.get_pin("out[{}]".format(i)).br() + decode_out_via = self.col_decoder_inst.get_pin("out[{}]".format(i)).lr() selx_via = vector(self.central_line_xoffset[name],decode_out_via.y - drc["minwidth_metal2"]) self.add_via(layers=("metal1", "via1", "metal2"), offset=selx_via) @@ -870,7 +950,7 @@ class bank(design.design): mid_position = vector(in_position.x,dout_position.y) self.add_path("metal3",[dout_position, mid_position, in_position]) - dout_via = self.msf_address_inst.get_pin("dout[{}]".format(ff_index)).br() + dout_via = self.msf_address_inst.get_pin("dout[{}]".format(ff_index)).lr() in_via = self.col_decoder_inst.get_pin("in[{}]".format(i)).ul() self.add_via(layers=("metal2", "via2", "metal3"), offset=dout_via, @@ -934,7 +1014,7 @@ class bank(design.design): dout_position = self.msf_address_inst.get_pin("dout[{}]".format(i)).rc() rail_position = vector(self.central_line_xoffset["A[{}]".format(i)]+drc["minwidth_metal2"],dout_position.y) self.add_path("metal1",[dout_position, rail_position]) - dout_via = self.msf_address_inst.get_pin("dout[{}]".format(i)).br() + vector(self.m1m2_via.height,0) + dout_via = self.msf_address_inst.get_pin("dout[{}]".format(i)).lr() + vector(self.m1m2_via.height,0) self.add_via(layers=("metal1", "via1", "metal2"), offset=dout_via, rotate=90) @@ -947,7 +1027,7 @@ class bank(design.design): for gnd_pin in self.msf_address_inst.get_pins("gnd"): if gnd_pin.layer != "metal2": continue - gnd_via = gnd_pin.br() + vector(self.m1m2_via.height,0) + gnd_via = gnd_pin.lr() + vector(self.m1m2_via.height,0) self.add_via(layers=("metal1", "via1", "metal2"), offset=gnd_via, rotate=90) @@ -1019,16 +1099,12 @@ class bank(design.design): # Connection from the central bus to the main control block crosses # pre-decoder and this connection is in metal3 connection = [] - if self.num_banks>1: - prefix="gated_" - else: - prefix="" - connection.append((prefix+"clk_bar", self.msf_data_in_inst.get_pin("clk").lc())) - connection.append((prefix+"tri_en_bar", self.tri_gate_array_inst.get_pin("en_bar").lc())) - connection.append((prefix+"tri_en", self.tri_gate_array_inst.get_pin("en").lc())) - connection.append((prefix+"clk_bar", self.precharge_array_inst.get_pin("en").lc())) - connection.append((prefix+"w_en", self.write_driver_array_inst.get_pin("en").lc())) - connection.append((prefix+"s_en", self.sense_amp_array_inst.get_pin("en").lc())) + connection.append((self.prefix+"clk_bar", self.msf_data_in_inst.get_pin("clk").lc())) + connection.append((self.prefix+"tri_en_bar", self.tri_gate_array_inst.get_pin("en_bar").lc())) + connection.append((self.prefix+"tri_en", self.tri_gate_array_inst.get_pin("en").lc())) + connection.append((self.prefix+"clk_bar", self.precharge_array_inst.get_pin("en").lc())) + connection.append((self.prefix+"w_en", self.write_driver_array_inst.get_pin("en").lc())) + connection.append((self.prefix+"s_en", self.sense_amp_array_inst.get_pin("en").lc())) for (control_signal, pin_position) in connection: control_x_offset = self.central_line_xoffset[control_signal] + self.m2_width @@ -1040,143 +1116,28 @@ class bank(design.design): rotate=90) # clk to msf address - control_signal = prefix+"clk" + control_signal = self.prefix+"clk" pin_position = self.msf_address_inst.get_pin("clk").uc() mid_position = pin_position + vector(0,self.m1_pitch) control_x_offset = self.central_line_xoffset[control_signal] - control_position = vector(control_x_offset + drc["minwidth_metal1"], mid_position.y) + control_position = vector(control_x_offset + self.m1_width, mid_position.y) self.add_path("metal1",[pin_position, mid_position, control_position]) control_via_position = vector(control_x_offset, mid_position.y-0.5*drc["minwidth_metal2"]) self.add_via(layers=("metal1", "via1", "metal2"), offset=control_via_position) # clk to wordline_driver - control_signal = prefix+"clk" + control_signal = self.prefix+"clk" pin_position = self.wordline_driver_inst.get_pin("en").uc() mid_position = pin_position + vector(0,self.m1_pitch) control_x_offset = self.central_line_xoffset[control_signal] - control_position = vector(control_x_offset + drc["minwidth_metal1"], mid_position.y) + control_position = vector(control_x_offset + self.m1_width, mid_position.y) self.add_wire(("metal1","via1","metal2"),[pin_position, mid_position, control_position]) control_via_position = vector(control_x_offset, mid_position.y-0.5*drc["minwidth_metal2"]) self.add_via(layers=("metal1", "via1", "metal2"), offset=control_via_position) - - def route_bank_select(self): - """ Route array of or gates to gate the control signals in case - of multiple banks are created in upper level SRAM module """ - return - bank_select_line_xoffset = (self.bank_select_or_position.x - - 3*drc["minwidth_metal2"]) - self.add_rect(layer="metal2", - offset=[bank_select_line_xoffset, - self.bank_select_or_position.y], - width=drc["minwidth_metal2"], - height=self.num_control_lines*self.inv.height) - - # bank select inverter routing - # output side - start = self.bank_select_inv_position + self.inv4x.Z_position - end = self.bank_select_or_position + self.nor2.B_position - mid = vector(start.x, end.y) - self.add_path("metal1", [start, mid, end]) - - # input side - start = self.bank_select_inv_position + self.inv4x.A_position - end = vector(self.left_vdd_x_offset, start.y + 3 * drc["minwidth_metal3"]) - mid = vector(start.x, end.y) - self.add_wire(("metal2", "via1", "metal1"), [start, mid, end]) - - # save position - self.bank_select_position = end - vector(0, 0.5 * drc["minwidth_metal2"]) - self.add_via(layers=("metal2", "via2", "metal3"), - offset=self.bank_select_position) - - x_offset = (self.bank_select_or_position.x + self.nor2.width - + self.inv4x.width - drc["minwidth_metal1"]) - for i in range(self.num_control_lines): - base = self.bank_select_or_position.y + self.inv.height * i - if(i % 2): - Z_y_offset = (base + self.inv.height - self.inv4x.Z_position.y - - drc["minwidth_metal1"]) - B_y_offset = (base + self.inv.height - self.nor2.B_position.y - - 0.5 * drc["minwidth_metal1"]) - A_y_offset = (base + self.inv.height - self.nor2.A_position.y - - 0.5 * drc["minwidth_metal1"]) - else: - Z_y_offset = (base + self.inv4x.Z_position.y) - B_y_offset = (base + self.nor2.B_position.y - - 0.5 * drc["minwidth_metal1"]) - A_y_offset = (base + self.nor2.A_position.y - + 0.5 * drc["minwidth_metal1"] - - self.m1m2_via.width) - - # output - self.add_rect(layer="metal3", - offset=[x_offset, Z_y_offset], - width=self.central_line_xoffset[i] - x_offset, - height=drc["minwidth_metal3"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[x_offset, Z_y_offset]) - self.add_via(layers=("metal2", "via2", "metal3"), - offset=[x_offset, Z_y_offset]) - self.add_via(layers=("metal2", "via2", "metal3"), - offset=[self.central_line_xoffset[i], Z_y_offset]) - - # B_input - if i != 5: - self.add_rect(layer="metal1", - offset=[bank_select_line_xoffset, B_y_offset], - width=(self.bank_select_or_position.x - - bank_select_line_xoffset), - height=drc["minwidth_metal1"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[bank_select_line_xoffset, B_y_offset]) - - # A_input - if i != 3: - self.add_rect(layer="metal3", - offset=[self.left_vdd_x_offset, A_y_offset], - width=(self.bank_select_or_position.x - - self.left_vdd_x_offset), - height=drc["minwidth_metal3"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[self.bank_select_or_position.x - + drc["minwidth_metal1"], - A_y_offset], - rotate=90) - self.add_via(layers=("metal2", "via2", "metal3"), - offset=[self.bank_select_or_position.x - + drc["minwidth_metal1"], - A_y_offset], - rotate=90) - else: - # connect A to last A, both are tri_en_bar - via_offset = vector(self.bank_select_or_position.x - + drc["minwidth_metal1"], - A_y_offset) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=via_offset, - rotate=90) - self.add_via(layers=("metal2", "via2", "metal3"), - offset=via_offset, - rotate=90) - - start = via_offset + vector(0, 0.5 * self.m1m2_via.width) - mid = [self.left_vdd_x_offset - self.left_vdd_x_offset - - drc["minwidth_metal2"] - drc["metal2_to_metal2"] - + bank_select_line_xoffset, - start.y] - correct_y = (2 * self.nor2.A_position.y + drc["minwidth_metal1"] - - self.m1m2_via.width) - end = start + vector(0, correct_y) - self.add_wire(("metal3", "via2", "metal2"), [start, mid, end]) - - # Save position - setattr(self,"{0}_position".format(self.control_signals[i]), - [self.left_vdd_x_offset, A_y_offset]) - def route_vdd_supply(self): """ Route vdd for the precharge, sense amp, write_driver, data FF, tristate """ @@ -1187,22 +1148,8 @@ class bank(design.design): self.add_rect(layer="metal1", offset=vdd_pin.ll(), width=self.right_vdd_x_offset - vdd_pin.lx(), - height=drc["minwidth_metal1"]) + height=self.m1_width) - return - - # Connect bank_select_and2_array vdd - if(self.num_banks > 1): - for i in range(self.num_control_lines): - if(i % 2): - self.add_rect(layer="metal1", - offset=[self.left_vdd_x_offset, - self.bank_select_or_position.y - + i * self.inv.height - - 0.5 * drc["minwidth_metal1"]], - width=(self.bank_select_or_position.x - - self.left_vdd_x_offset), - height=drc["minwidth_metal1"]) def route_gnd_supply(self): """ Route gnd for the precharge, sense amp, write_driver, data FF, tristate """ @@ -1220,49 +1167,24 @@ class bank(design.design): offset=contact_offset, rotate=90) - - # Connect bank_select_or2_array gnd - if(self.num_banks > 1): - return - self.bank_select_inv_position - self.add_rect(layer="metal1", - offset=(self.bank_select_inv_position - + self.inv4x.gnd_position), - width=(self.bank_select_or_position.x - - self.bank_select_inv_position.x), - height=drc["minwidth_metal1"]) - - x_offset = (self.bank_select_or_position.x - + self.nor2.width + self.inv4x.width) - for i in range(self.num_control_lines): - if(i % 2 == 0): - y_offset = self.bank_select_or_position.y + i*self.inv.height \ - - 0.5*drc["minwidth_metal1"] - #both M1 & M2 are horizontal, cannot be replaced with wire - self.add_rect(layer="metal1", - offset=[x_offset, y_offset], - width=drc["minwidth_metal1"], - height=drc["minwidth_metal1"]) - self.add_rect(layer="metal2", - offset=[x_offset, y_offset], - width=self.left_gnd_x_offset \ - - x_offset + self.power_rail_width, - height=drc["minwidth_metal2"]) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[x_offset + drc["minwidth_metal1"], - y_offset], - rotate=90) - def add_control_pins(self): """ Add the control signal input pins """ for ctrl in self.control_signals: x_offset = self.central_line_xoffset[ctrl] - self.add_layout_pin(text=ctrl, - layer="metal2", - offset=vector(x_offset, self.min_point), - width=self.m2_width, - height=self.height) + 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_point), + width=self.m2_width, + height=self.height) + else: + self.add_layout_pin(text=ctrl, + layer="metal2", + offset=vector(x_offset, self.min_point), + width=self.m2_width, + height=self.height) def connect_rail_from_right(self,inst, pin, rail): diff --git a/compiler/control_logic.py b/compiler/control_logic.py index 126bd8ef..77630829 100644 --- a/compiler/control_logic.py +++ b/compiler/control_logic.py @@ -34,11 +34,10 @@ class control_logic(design.design): def create_modules(self): """ add all the required modules """ - input_lst =["csb","web","oeb"] - output_lst = ["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar"] - clk =["clk"] + input_lst =["csb","web","oeb","clk"] + output_lst = ["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"] rails = ["vdd", "gnd"] - for pin in input_lst + output_lst + clk + rails: + for pin in input_lst + output_lst + rails: self.add_pin(pin) self.nand2 = nand_2() @@ -153,9 +152,10 @@ class control_logic(design.design): rotate=270) # don't change this order. This pins are meant for internal connection of msf array inside the control logic. # These pins are connecting the msf_array inside of control_logic. - temp = ["oeb", "oe_bar", "oe", - "csb", "cs_bar", "cs", - "web", "we_bar", "we", + temp = ["oeb", "csb", "web", + "oe_bar", "oe", + "cs_bar", "cs", + "we_bar", "we", "clk_buf", "vdd", "gnd"] self.connect_inst(temp) @@ -347,7 +347,7 @@ class control_logic(design.design): for i in range(self.num_rails_1): offset = vector(self.rail_1_start_x + (i+1) * self.m2_pitch,0) - if self.rail_1_names[i] in ["clk_bar", "vdd", "gnd"]: + if self.rail_1_names[i] in ["clk_buf", "clk_bar", "vdd", "gnd"]: self.add_layout_pin(text=self.rail_1_names[i], layer="metal2", offset=offset, @@ -367,8 +367,10 @@ class control_logic(design.design): self.connect_rail_from_left_m2m3(self.msf,"dout_bar[2]","we") # Connect the gnd and vdd of the control - gnd_pins = self.msf.get_pin("gnd") + gnd_pins = self.msf.get_pins("gnd") for p in gnd_pins: + if p.layer != "metal2": + continue gnd_pin = p.rc() gnd_rail_position = vector(self.rail_1_x_offsets["gnd"], gnd_pin.y) self.add_wire(("metal1","via1","metal2"),[gnd_pin, gnd_rail_position, gnd_rail_position - vector(0,self.m2_pitch)]) @@ -376,9 +378,12 @@ class control_logic(design.design): offset=gnd_pin + self.m1m2_via_offset, rotate=90) - vdd_pin = self.msf.get_pin("vdd").bc() - clk_vdd_position = vector(vdd_pin.x,self.clk_buf.get_pin("vdd").uy()) - self.add_path("metal1",[vdd_pin,clk_vdd_position]) + vdd_pins = self.msf.get_pins("vdd") + for p in vdd_pins: + if p.layer != "metal1": + continue + clk_vdd_position = vector(p.bc().x,self.clk_buf.get_pin("vdd").uy()) + self.add_path("metal1",[p.bc(),clk_vdd_position]) self.rail_2_start_x = max (self.row_1_width, self.row_2_width, self.row_3_width) for i in range(self.num_rails_2): @@ -589,8 +594,8 @@ class control_logic(design.design): # Now connect the vdd and gnd rails between the replica bitline and the control logic - (rbl_row3_gnd,rbl_row1_gnd) = self.rbl.get_pin("gnd") - (rbl_row3_vdd,rbl_row1_vdd) = self.rbl.get_pin("vdd") + (rbl_row3_gnd,rbl_row1_gnd) = self.rbl.get_pins("gnd") + (rbl_row3_vdd,rbl_row1_vdd) = self.rbl.get_pins("vdd") self.add_path("metal1",[row1_gnd_end_offset,rbl_row1_gnd.lc()]) self.add_path("metal1",[row1_vdd_end_offset,rbl_row1_vdd.lc()]) diff --git a/compiler/delay_chain.py b/compiler/delay_chain.py index da8df1f4..117dcc25 100644 --- a/compiler/delay_chain.py +++ b/compiler/delay_chain.py @@ -193,7 +193,7 @@ class delay_chain(design.design): # Use the right most parts of the gnd rails and add a U connector # We still have the two gnd pins, but it is an either-or connect - gnd_pins = self.get_pin("gnd") + gnd_pins = self.get_pins("gnd") gnd_start = gnd_pins[0].rc() gnd_mid1 = gnd_start + vector(2*drc["metal1_to_metal1"],0) gnd_end = gnd_pins[1].rc() diff --git a/compiler/geometry.py b/compiler/geometry.py index 80b38543..9fc6458c 100644 --- a/compiler/geometry.py +++ b/compiler/geometry.py @@ -41,8 +41,7 @@ class instance(geometry): self.offset = vector(offset).snap_to_grid() self.mirror = mirror - self.boundary = [vector(0,0),vector(mod.width,mod.height)] - self.transform(offset,mirror,rotate) + self.compute_boundary(offset,mirror,rotate) debug.info(3, "creating instance: " + self.name) @@ -65,10 +64,10 @@ class instance(geometry): ur = vector(max(first[0],second[0]),max(first[1],second[1])) self.boundary=[ll,ur] - def transform(self,offset,mirror,rotate): + def compute_boundary(self,offset=vector(0,0),mirror="",rotate=0): """ Transform with offset, mirror and rotation to get the absolute pin location. We must then re-find the ll and ur. The master is the cell instance. """ - (ll,ur) = self.boundary + (ll,ur) = [vector(0,0),vector(self.mod.width,self.mod.height)] if mirror=="MX": ll=ll.scale(1,-1) ur=ur.scale(1,-1) diff --git a/compiler/hierarchy_layout.py b/compiler/hierarchy_layout.py index e41f3cf2..b2919b77 100644 --- a/compiler/hierarchy_layout.py +++ b/compiler/hierarchy_layout.py @@ -24,7 +24,7 @@ class layout: self.height = None self.insts = [] # Holds module/cell layout instances self.objs = [] # Holds all other objects (labels, geometries, etc) - self.pin_map = {} # Holds name->(vector,layer) map for all pins + self.pin_map = {} # Holds name->pin_layout map for all pins self.visited = False # Flag for traversing the hierarchy self.gds_read() @@ -35,9 +35,9 @@ class layout: def offset_all_coordinates(self): """ This function is called after everything is placed to shift the origin in the lowest left corner """ - coordinate = self.find_lowest_coords() - self.offset_attributes(coordinate) - self.translate(coordinate) + offset = self.find_lowest_coords() + #self.offset_attributes(offset) + self.translate_all(offset) def get_gate_offset(self, x_offset, height, inv_num): """Gets the base offset and y orientation of stacked rows of gates @@ -59,8 +59,7 @@ class layout: def find_lowest_coords(self): """Finds the lowest set of 2d cartesian coordinates within this layout""" - #***1,000,000 number is used to avoid empty sequences errors*** - # FIXME Is this hard coded value ok?? + # FIXME: don't depend on 1e9 try: lowestx1 = min(rect.offset.x for rect in self.objs) lowesty1 = min(rect.offset.y for rect in self.objs) @@ -73,47 +72,24 @@ class layout: [lowestx2, lowesty2] = [1000000.0, 1000000.0] return vector(min(lowestx1, lowestx2), min(lowesty1, lowesty2)) - def offset_attributes(self, coordinate): - """Translates all stored 2d cartesian coordinates within the - attr dictionary""" - # FIXME: This is dangerous. I think we should not do this, but explicitly - # offset the necessary coordinates. - #for attr_key, attr_val in self.attr.items(): - for attr_key in dir(self): - attr_val = getattr(self,attr_key) - - # skip the list of things as these will be offset separately - if (attr_key in ['objs','insts','mods','pins','conns','name_map']): continue - - # if is a list - if isinstance(attr_val, list): - - for i in range(len(attr_val)): - # each unit in the list is a list coordinates - if isinstance(attr_val[i], (list,vector)): - attr_val[i] = vector(attr_val[i] - coordinate) - # the list itself is a coordinate - else: - if len(attr_val)!=2: continue - for val in attr_val: - if not isinstance(val, (int, long, float)): continue - setattr(self,attr_key, vector(attr_val - coordinate)) - break - - # if is a vector coordinate - if isinstance(attr_val, vector): - setattr(self, attr_key, vector(attr_val - coordinate)) - - - - def translate(self, coordinate): - """Translates all 2d cartesian coordinates in a layout given - the (x,y) offset""" + def translate_all(self, offset): + """ + Translates all objects, instances, and pins by the given (x,y) offset + """ for obj in self.objs: - obj.offset = vector(obj.offset - coordinate) + obj.offset = vector(obj.offset - offset) for inst in self.insts: - inst.offset = vector(inst.offset - coordinate) + inst.offset = vector(inst.offset - offset) + # The instances have a precomputed boundary that we need to update. + if inst.__class__.__name__ == "instance": + inst.compute_boundary(offset.scale(-1,-1)) + for pin_name in self.pin_map.keys(): + # All the pins are absolute coordinates that need to be updated. + pin_list = self.pin_map[pin_name] + for pin in pin_list: + pin.rect = [pin.ll() - offset, pin.ur() - offset] + def add_inst(self, name, mod, offset=[0,0], mirror="R0",rotate=0): """Adds an instance of a mod to this module""" @@ -149,6 +125,18 @@ class layout: """ Return a pin list (instead of a single pin) """ return self.pin_map[text] + def copy_layout_pin(self, instance, pin_name, new_name=""): + """ + Create a copied version of the layout pin at the current level. + You can optionally rename the pin to a new name. + """ + pins=instance.get_pins(pin_name) + for pin in pins: + if new_name=="": + new_name = pin.name + self.add_layout_pin(new_name, pin.layer, pin.ll(), pin.width(), pin.height()) + + def add_layout_pin(self, text, layer, offset, width=None, height=None): """Create a labeled pin """ if width==None: diff --git a/compiler/nor_2.py b/compiler/nor_2.py index 13d47ffa..408af41d 100644 --- a/compiler/nor_2.py +++ b/compiler/nor_2.py @@ -340,21 +340,21 @@ class nor_2(design.design): - self.nmos1.height) self.A_loc = vector(xoffset, yoffset) # gate input - offset = self.A_loc - vector(0, 0.5 * self.poly_contact.width) + offset = self.A_loc - vector(0, self.poly_contact.width) self.add_contact(layers=("poly", "contact", "metal1"), offset=offset, rotate=90) # connect gate input to tx gate offset = self.A_loc - vector(self.poly_contact.first_layer_position.y, - 0.5 * self.poly_contact.width) + self.poly_contact.width) self.add_rect(layer="poly", offset=offset, width=self.poly_contact.first_layer_position.y + drc["minwidth_poly"], height=self.poly_contact.first_layer_width) # extend the metal to the boundary of the cell input_length = self.A_loc.x - offset = [0, self.A_loc.y - 0.5 * drc["minwidth_metal1"]] + offset = [0, self.A_loc.y - drc["minwidth_metal1"]] self.add_layout_pin(text="A", layer="metal1", offset=offset, diff --git a/compiler/pin_layout.py b/compiler/pin_layout.py index c23280fa..07933dd6 100644 --- a/compiler/pin_layout.py +++ b/compiler/pin_layout.py @@ -97,8 +97,8 @@ class pin_layout: """ Upper left point """ return vector(self.rect[0].x,self.rect[1].y) - def br(self): - """ Bottom right point """ + def lr(self): + """ Lower right point """ return vector(self.rect[1].x,self.rect[0].y) def ur(self): diff --git a/compiler/ptx.py b/compiler/ptx.py index 9a72f449..68d3bbaf 100644 --- a/compiler/ptx.py +++ b/compiler/ptx.py @@ -50,10 +50,41 @@ class ptx(design.design): # self.connect_fingered_poly() self.offset_all_coordinates() + def offset_attributes(self, coordinate): + """Translates all stored 2d cartesian coordinates within the + attr dictionary""" + # FIXME: This is dangerous. I think we should not do this, but explicitly + # offset the necessary coordinates. It is only used in ptx for now! + + for attr_key in dir(self): + attr_val = getattr(self,attr_key) + + # skip the list of things as these will be offset separately + if (attr_key in ['objs','insts','mods','pins','conns','name_map']): continue + + # if is a list + if isinstance(attr_val, list): + + for i in range(len(attr_val)): + # each unit in the list is a list coordinates + if isinstance(attr_val[i], (list,vector)): + attr_val[i] = vector(attr_val[i] - coordinate) + # the list itself is a coordinate + else: + if len(attr_val)!=2: continue + for val in attr_val: + if not isinstance(val, (int, long, float)): continue + setattr(self,attr_key, vector(attr_val - coordinate)) + break + + # if is a vector coordinate + if isinstance(attr_val, vector): + setattr(self, attr_key, vector(attr_val - coordinate)) + def offset_all_coordinates(self): - coordinate = self.find_lowest_coords() - self.offset_attributes(coordinate) - self.translate(coordinate) + offset = self.find_lowest_coords() + self.offset_attributes(offset) + self.translate_all(offset) # We can do this in ptx because we have offset all modules it uses. # Is this really true considering the paths that connect the src/drain? diff --git a/compiler/replica_bitline.py b/compiler/replica_bitline.py index 75432255..04a2221e 100644 --- a/compiler/replica_bitline.py +++ b/compiler/replica_bitline.py @@ -219,7 +219,7 @@ class replica_bitline(design.design): height=self.rbl.height+self.bitcell.height+2*self.inv.width+0.5*drc["minwidth_metal1"]) # Connect the vdd pins of the bitcell load directly to vdd - vdd_pins = self.rbl_inst.get_pin("vdd") + vdd_pins = self.rbl_inst.get_pins("vdd") for pin in vdd_pins: offset = vector(vdd_start.x,pin.by()) self.add_rect(layer="metal1", @@ -286,9 +286,9 @@ class replica_bitline(design.design): offset=offset) # Connect the bitcell gnd pin to the rail - gnd_pins = self.get_pin("gnd") - gnd_start = self.get_pin("gnd").uc() - rbl_gnd_pins = self.rbl_inst.get_pin("gnd") + gnd_pins = self.get_pins("gnd") + gnd_start = gnd_pins[0].uc() + rbl_gnd_pins = self.rbl_inst.get_pins("gnd") # Find the left most rail on M2 gnd_pin = None for pin in rbl_gnd_pins: @@ -302,7 +302,7 @@ class replica_bitline(design.design): # Add a second gnd pin to the second delay chain rail. No need for full length. - dc_gnd_offset = self.dc_inst.get_pin("gnd")[1].ll() + dc_gnd_offset = self.dc_inst.get_pins("gnd")[1].ll() self.add_layout_pin(text="gnd", layer="metal1", offset=dc_gnd_offset.scale(1,0), diff --git a/compiler/sram.py b/compiler/sram.py index 43ff0978..2bf7d5a8 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -43,7 +43,17 @@ class sram(design.design): self.num_words)) design.design.__init__(self, name) - + + # These aren't for instantiating, but we use them to get the dimensions + self.poly_contact = contact(layer_stack=("poly", "contact", "metal1")) + self.poly_contact_offset = vector(0.5*self.poly_contact.width,0.5*self.poly_contact.height) + self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2")) + self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3")) + + # M1/M2 routing pitch is based on contacted pitch + self.m1_pitch = max(self.m1m2_via.width,self.m1m2_via.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"]) + self.m2_pitch = max(self.m2m3_via.width,self.m2m3_via.height) + max(drc["metal2_to_metal2"],drc["metal3_to_metal3"]) + self.control_size = 6 self.bank_to_bus_distance = 5*drc["minwidth_metal3"] @@ -54,6 +64,7 @@ class sram(design.design): def compute_sizes(self): """ Computes the organization of the memory using bitcell size by trying to make it square.""" + debug.check(self.num_banks in [1,2,4], "Valid number of banks are 1 , 2 and 4.") self.num_words_per_bank = self.num_words/self.num_banks @@ -109,33 +120,34 @@ class sram(design.design): return words_per_row def add_pins(self): - """ app pins """ + """ Add pins for entire SRAM. """ + for i in range(self.word_size): self.add_pin("DATA[{0}]".format(i)) for i in range(self.addr_size): self.add_pin("ADDR[{0}]".format(i)) - for pin in ["CSb","WEb","OEb", - "clk","vdd","gnd"]: + for pin in ["CSb","WEb","OEb","clk","vdd","gnd"]: self.add_pin(pin) def create_layout(self): """ Layout creation """ self.create_modules() - self.add_modules() - self.add_routing() - def add_routing(self): - """ Route all of the modules """ - - if (self.num_banks == 2 or self.num_banks == 4): - self.route_2or4_banks() - if (self.num_banks == 4): - self.route_4_banks() - self.route_bank_and_control() - self.route_supplies() + if self.num_banks == 1: + self.add_single_bank_modules() + self.add_single_bank_pins() + self.route_single_bank() + else: + self.add_multi_bank_modules() + self.route_top_banks() + if self.num_banks > 2: + self.route_bottom_banks() - def create_multibank_modules(self): + + + + def create_multi_bank_modules(self): """ Add the multibank address flops and bank decoder """ self.msf_msb_address = self.mod_ms_flop_array(name="msf_msb_address", @@ -165,63 +177,15 @@ class sram(design.design): if(self.num_banks > 1): self.create_multibank_modules() - # These aren't for instantiating, but we use them to get the dimensions - self.m1m2_via = contact(layer_stack=("metal1", "via1", "metal2")) - self.m2m3_via = contact(layer_stack=("metal2", "via2", "metal3")) - self.bank_count = 0 - self.sram_property = ["bank_clk_positions", - "bank_clk_bar_positions", - "bank_tri_en_positions", - "bank_tri_en_bar_positions", - "bank_w_en_positions", - "bank_s_en_positions"] - self.bank_property = ["clk_position", - "clk_bar_position", - "tri_en_position", - "tri_en_bar_position", - "w_en_position", - "s_en_position", ] - - self.bank_positions = [] - - self.bank_clk_positions = [] - self.bank_clk_bar_positions = [] - self.bank_tri_en_positions = [] - self.bank_tri_en_bar_positions = [] - self.bank_w_en_positions = [] - self.bank_s_en_positions = [] - - # SRAM bank address 3D array - # 2 keys will return a x,y position pair - # example key1 = bank_index , key2 = addr_line_index will return [x,y] - self.sram_bank_adress_positions = [] - - # SRAM data lines 3D array - # 2 keys will return a x,y position pair - # example key1 = bank_index , key2 = data_line_index will return [x,y] - self.sram_bank_data_positions = [] - - # 2D array for bank_select position of banks - self.sram_bank_select_positions = [] - - # Bank power rail positions - self.sram_bank_right_vdd_positions = [] - self.sram_bank_left_vdd_positions = [] - self.sram_bank_left_gnd_positions = [] - - self.power_rail_width = self.bank.power_rail_width - self.sram_power_rail_gap = 4*self.power_rail_width - - self.vdd_position = vector(0, 2*self.power_rail_width) - self.gnd_position = vector(0, 0) + self.power_rail_width = self.bank.vdd_rail_width + self.sram_power_rail_gap = 4*self.bank.vdd_rail_width def add_bank(self, position, x_flip, y_flip): - """ add and place bank. All the pin position is also - translated and saved for later use""" + """ Place a bank at the given position with orientations """ # x_flip == 1 --> no flip in x_axis # x_flip == -1 --> flip in x_axis @@ -230,26 +194,25 @@ class sram(design.design): # x_flip and y_flip are used for position translation - bank_rotation = 180 if (x_flip == -1 and y_flip == -1) else 0 - bank_mirror = "R0" + if x_flip == -1 and y_flip == -1: + bank_rotation = 180 + else: + bank_rotation = 0 - if(x_flip == y_flip): + if x_flip == y_flip: bank_mirror = "R0" - elif(x_flip == -1): + elif x_flip == -1: bank_mirror = "MX" - elif(y_flip == -1): + elif y_flip == -1: bank_mirror = "MY" - - yMetalShift = drc["minwidth_metal3"] if (x_flip == -1) else 0 - xMetalShift = drc["minwidth_metal3"] if (y_flip == -1) else 0 - - position=vector(position) - self.add_inst(name="bank{0}".format(self.bank_count), - mod=self.bank, - offset=position, - mirror=bank_mirror, - rotate=bank_rotation) - self.bank_positions.append(position) + else: + bank_mirror = "R0" + + bank_inst=self.add_inst(name="bank{0}".format(self.bank_count), + mod=self.bank, + offset=position, + mirror=bank_mirror, + rotate=bank_rotation) temp = [] for i in range(self.word_size): @@ -257,64 +220,14 @@ class sram(design.design): for i in range(self.bank_addr_size): temp.append("ADDR[{0}]".format(i)) if(self.num_banks > 1): - temp.append("bank_select[{0}]".format(self.bank_count)) + temp.append("bank_sel[{0}]".format(self.bank_count)) temp.extend(["s_en", "w_en", "tri_en_bar", "tri_en", - "clk_bar","clk" , "vdd", "gnd"]) + "clk_bar","clk_buf" , "vdd", "gnd"]) self.connect_inst(temp) - # Saving control line properties - for i in range(len(self.sram_property)): - sub_mod_offset = getattr(self.bank,self.bank_property[i]) - new=(position + vector(y_flip,x_flip).scale(sub_mod_offset) - - vector(xMetalShift,yMetalShift)) - - pos_list=getattr(self,self.sram_property[i]) - if pos_list is None: - pos_list=[] - pos_list.append(new) - setattr(self,self.sram_property[i],pos_list) - - # Address input lines - bank_address_positions = [] - for addr_position in self.bank.address_positions: - new=(position + vector(y_flip,x_flip).scale(addr_position) - - vector(xMetalShift,yMetalShift)) - bank_address_positions.append(new) - self.sram_bank_adress_positions.append(bank_address_positions) - - # Bank select - if (self.num_banks > 1): - new=(position + vector(y_flip,x_flip).scale(self.bank.bank_select_position) - - vector(xMetalShift,yMetalShift)) - self.sram_bank_select_positions.append(new) - - # Data input lines - bank_data_positions = [] - for data_position in self.bank.data_positions: - new=(position + vector(y_flip,x_flip).scale(data_position) - - vector(xMetalShift,yMetalShift)) - bank_data_positions.append(new) - self.sram_bank_data_positions.append(bank_data_positions) - - # VDD rails - - yPowerShift = self.power_rail_width if(x_flip == -1) else 0 - xPowerShift = self.power_rail_width if(y_flip == -1) else 0 - - # Right vdd - new=(position + vector(y_flip,x_flip).scale(self.bank.right_vdd_position) - - vector(xPowerShift,yPowerShift)) - self.sram_bank_right_vdd_positions.append(new) - # left vdd - new=(position + vector(y_flip,x_flip).scale(self.bank.left_vdd_position) - - vector(xPowerShift,yPowerShift)) - self.sram_bank_left_vdd_positions.append(new) - # left gnd - new=(position + vector(y_flip,x_flip).scale(self.bank.left_gnd_position) - - vector(xPowerShift,yPowerShift)) - self.sram_bank_left_gnd_positions.append(new) - self.bank_count = self.bank_count + 1 + + return bank_inst # FIXME: This should be in geometry.py or it's own class since it is # reusable @@ -360,42 +273,54 @@ class sram(design.design): def add_control_logic(self, position, rotate): """ Add and place control logic """ - self.control_position = position - self.add_inst(name="control", - mod=self.control, - offset=self.control_position, - rotate=rotate) - temp = ["CSb", "WEb", "OEb", "s_en", "w_en", "tri_en", - "tri_en_bar", "clk_bar", "clk", "vdd", "gnd"] + self.control_logic_inst=self.add_inst(name="control", + mod=self.control, + offset=position, + rotate=rotate) + temp = ["CSb", "WEb", "OEb", "clk", "s_en", "w_en", "tri_en", + "tri_en_bar", "clk_bar", "clk_buf", "vdd", "gnd"] self.connect_inst(temp) - def add_singlebank_modules(self): - """ This adds the moduels for a single bank SRAM with control - logic. """ - self.add_bank([0, 0], 1, 1) - # FIXME: document - loc = vector(- 2 * drc["minwidth_metal3"], - self.bank_positions[0].y + self.bank.decoder_position.y - + 2 * drc["minwidth_metal3"]) - self.add_control_logic(loc, 90) + def add_single_bank_modules(self): + """ + This adds the moduels for a single bank SRAM with control + logic. + """ + + # No orientation or offset + self.bank_inst = self.add_bank([0, 0], 1, 1) + + # Control logic is placed to the left of the blank even with the + # decoder bottom. A small gap is in the x-dimension. + control_gap = 2*drc["minwidth_metal3"] + pos = vector(-control_gap, + self.bank.row_decoder_inst.by() + 2*drc["minwidth_metal3"]) + self.add_control_logic(position=pos, + rotate=90) - self.width = self.bank.width + self.control.height + 2*drc["minwidth_metal3"] + self.width = self.bank.width + self.control.height + control_gap self.height = self.bank.height - self.control.CSb_position.rotate_scale(-1,1) - self.CSb_position = (self.control.CSb_position.rotate_scale(-1,1) - +self.control_position) - self.OEb_position = (self.control.OEb_position.rotate_scale(-1,1) - +self.control_position) - self.WEb_position = (self.control.WEb_position.rotate_scale(-1,1) - +self.control_position) - self.clk_position = (self.control.clk_position.rotate_scale(-1,1) - +self.control_position) - for i in range(0, self.word_size): - self.add_label(text="DATA[{0}]".format(i), - layer="metal3", - offset=self.bank.data_positions[i]) - def add_multibank_modules(self): + def add_single_bank_pins(self): + """ + Add the top-level pins for a single bank SRAM with control. + """ + + for i in range(self.word_size): + self.copy_layout_pin(self.bank_inst, "DATA[{}]".format(i)) + + for i in range(self.addr_size): + self.copy_layout_pin(self.bank_inst, "ADDR[{}]".format(i)) + + for (old,new) in zip(["csb","web","oeb","clk"],["CSb","WEb","OEb","clk"]): + self.copy_layout_pin(self.control_logic_inst, old, new) + + self.copy_layout_pin(self.bank_inst, "vdd") + self.copy_layout_pin(self.bank_inst, "gnd") + + + + def add_multi_bank_modules(self): """ This creates either a 2 or 4 bank SRAM with control logic and bank selection logic.""" @@ -491,14 +416,13 @@ class sram(design.design): temp.append("msb{0}".format(i)) temp.append("msb{0}_bar".format(i)) else: - temp.extend(["bank_select[1]", "bank_select[0]"]) - temp.extend(["clk", "vdd", "gnd"]) + temp.extend(["bank_sel[1]", "bank_sel[0]"]) + temp.extend(["clk_buf", "vdd", "gnd"]) self.connect_inst(temp) - self.add_banks_0and1() - - if (self.num_banks == 4): - self.add_banks_2and3() + self.add_top_banks() + if self.num_banks == 4: + self.add_bottom_banks() # Extension of Vertical Rail self.create_bus(layer="metal2", @@ -522,16 +446,7 @@ class sram(design.design): offset=[self.vertical_line_positions[self.control_size + i].x, self.max_point]) - def add_modules(self): - """ add all the modules """ - if (self.num_banks == 1): - self.add_singlebank_modules() - elif (self.num_banks == 2 or self.num_banks == 4): - self.add_multibank_modules() - - self.add_labels() - - def add_banks_0and1(self): + def add_top_banks(self): # Placement of bank 0 self.bank_position_0 = vector(self.bank_w, self.bank_h + self.sram_power_rail_gap) @@ -542,7 +457,7 @@ class sram(design.design): self.bank_position_1 = vector(x_off, self.bank_position_0.y) self.add_bank(self.bank_position_1, -1, 1) - def add_banks_2and3(self): + def add_bottom_banks(self): # Placement of bank 2 y_off = (self.bank_h + self.horizontal_bus_width +2 * self.bank_to_bus_distance @@ -564,10 +479,10 @@ class sram(design.design): mod=self.msb_decoder, offset=self.msb_decoder_position, mirror="MY") - temp = ["msb0", "msb1", "bank_select[{0}]".format(0), - "bank_select[{0}]".format(1), "bank_select[{0}]".format(2), - "bank_select[{0}]".format(3), - "vdd", "gnd"] + temp = ["msb0", "msb1"] + for i in range(4): + temp.append("bank_sel[{}]".format(i)) + temp.extend(["vdd", "gnd"]) self.connect_inst(temp) self.control_position = vector(0, self.msb_decoder_position.y @@ -582,23 +497,9 @@ class sram(design.design): # Max point self.max_point = self.msb_decoder_position.y + self.msb_decoder.height - def add_labels(self): - """ Add the top-level labels for control and address """ - for label in ["CSb", "OEb", "WEb", "clk"]: - offset = getattr(self, label+"_position") - self.add_label(text=label, - layer="metal3", - offset=offset) - # add address label - for addr_pos_lst in self.sram_bank_adress_positions: - for address, address_positions in enumerate(addr_pos_lst): - self.add_label(text="ADDR[{0}]".format(address), - layer="metal3", - offset=address_positions) - - def route_2or4_banks(self): - """ Routing between bank 2 or 4 bank modules """ + def route_top_banks(self): + """ Routing of top two banks """ addr_start_index = len(self.sram_property) + (self.num_banks / 2) bank_select_index = addr_start_index + self.bank.addr_size @@ -652,7 +553,7 @@ class sram(design.design): offset=contact_offset) # Data connection on the horizontal bus - if (self.num_banks == 4): + if self.num_banks == 4: data_connection_top = self.sram_bank_data_positions[2][0].y + self.m2m3_via.height else: data_connection_top=self.horizontal_bus_offset.y @@ -673,7 +574,7 @@ class sram(design.design): offset=[self.sram_bank_data_positions[lower_bank_index][data_index].x, self.horizontal_line_positions[data_index].y]) - def route_4_banks(self): + def route_bottom_banks(self): for i in range(2): lower_bank_index = i upper_bank_index = i + 2 @@ -695,48 +596,55 @@ class sram(design.design): height=self.sram_bank_left_gnd_positions[upper_bank_index].y \ - self.sram_bank_left_gnd_positions[lower_bank_index].y) + 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() + out_pos = vector(dest_pin.cx(), in_pos.y) + self.add_wire(("metal3","via2","metal2"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)]) + self.add_via(layers=("metal2","via2","metal3"), + offset=src_pin.lr(), + rotate=90) + + def connect_rail_from_left_m2m1(self, src_pin, dest_pin): + """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """ + in_pos = src_pin.rc() + out_pos = vector(dest_pin.cx(), in_pos.y) + self.add_wire(("metal2","via1","metal1"),[in_pos, out_pos, out_pos - vector(0,self.m2_pitch)]) + + def route_single_bank(self): + """ Route a single bank SRAM """ + # left pin is on the control logic, right pin is on the bank + connections = [("clk_buf", "clk"), + ("tri_en_bar", "tri_en_bar"), + ("tri_en", "tri_en"), + ("clk_bar", "clk_bar"), + ("w_en", "w_en"), + ("s_en", "s_en")] + for (src,dest) in connections: + src_pin = self.control_logic_inst.get_pin(src) + dest_pin = self.bank_inst.get_pin(dest) + self.connect_rail_from_left_m2m3(src_pin, dest_pin) + + src_pins = self.control_logic_inst.get_pins("vdd") + for src_pin in src_pins: + if src_pin.layer != "metal2": + continue + dest_pin = self.bank_inst.get_pins("vdd")[1] + self.connect_rail_from_left_m2m1(src_pin,dest_pin) + + src_pins = self.control_logic_inst.get_pins("gnd") + for src_pin in src_pins: + if src_pin.layer != "metal2": + continue + dest_pin = self.bank_inst.get_pin("gnd") + self.connect_rail_from_left_m2m3(src_pin,dest_pin) + def route_bank_and_control(self): """ Routing between banks and control """ - if (self.num_banks == 1): - - # FIXME what is this? add comments - # 5 = clk - # 4 = tri_en_bar - # 3 = tri_en - # 2 = clk_bar - # 1 = w_en - # 0 = s_en - - control_side = [] - control_side.append(self.control.clk_position.rotate_scale(-1, 1) - + self.control_position) - control_side.append(self.control.clk_bar_position.rotate_scale(-1, 1) - + self.control_position) - control_side.append(self.control.tri_en_position.rotate_scale(-1, 1) - + self.control_position) - control_side.append(self.control.tri_en_bar_position.rotate_scale(-1, 1) - + self.control_position) - control_side.append(self.control.w_en_position.rotate_scale(-1, 1) - + self.control_position) - control_side.append(self.control.s_en_position.rotate_scale(-1, 1) - + self.control_position) - - bank_side = [] - - for attr_name in (self.sram_property): - bank_side.append(getattr(self,attr_name)[0]) - - for i in range(len(control_side)): - self.add_rect(layer="metal3", - offset=control_side[i], - width=bank_side[i].x - control_side[i].x, - height=drc["minwidth_metal3"]) - self.add_via(layers=("metal2", "via2", "metal3"), - offset=[bank_side[i].x + drc["minwidth_metal2"], - control_side[i].y], - rotate=90) - elif (self.num_banks == 2 or self.num_banks == 4): + if self.num_banks == 1: + pass + elif self.num_banks == 2 or self.num_banks == 4: for i in range(self.control_size): self.add_via(layers=("metal1", "via1", "metal2"), offset=[self.vertical_line_positions[i].x + drc["minwidth_metal2"], @@ -857,44 +765,8 @@ class sram(design.design): self.add_via(layers=("metal1", "via1", "metal2"), offset=contact_pos) - def route_vdd_singlebank(self): - """ Route the vdd for 1 bank SRAMs """ - - # left vdd rail of bank - self.vdd_offset = self.bank.left_vdd_position - self.add_label(text="vdd", - layer="metal1", - offset=self.vdd_offset) - # Add label for right vdd rail bank - self.add_label(text="vdd", - layer="metal1", - offset=self.sram_bank_right_vdd_positions[0]) - - # control logic - self.control_vdd1_position = (self.control_position - + self.control.vdd1_position.rotate_scale(-1, 1)) - self.control_vdd2_position = (self.control_position - + self.control.vdd2_position.rotate_scale(-1, 1)) - - self.add_rect(layer="metal1", - offset=self.control_vdd1_position, - width=self.vdd_offset.x - - self.control_vdd1_position.x, - height=drc["minwidth_metal1"]) - - self.add_rect(layer="metal2", - offset=self.control_vdd2_position, - width=self.vdd_offset.x - - self.control_vdd2_position.x, - height=drc["minwidth_metal2"]) - - self.add_via(layers=("metal1", "via1", "metal2"), - offset=[self.vdd_offset.x, - self.control_vdd2_position.y], - size=(2, 1)) - - def route_vdd_multibank(self): + def route_vdd_multi_bank(self): """ Route the vdd for 2 and 4 bank SRAMs """ # VDD routing between banks self.add_rect(layer="metal1", @@ -1018,35 +890,8 @@ class sram(design.design): self.vdd_position.y]) - def route_gnd_singlebank(self): - """ Route the gnd for 1 bank SRAMs """ - # left gnd rail of bank - self.gnd_offset = self.bank.left_gnd_position - self.add_label(text="gnd", - layer="metal2", - offset=self.gnd_offset) - - self.control_gnd_position = (self.control_position - + self.control.gnd_position.rotate_scale(-1,1) - + vector(drc["minwidth_metal2"],0)) - - self.add_rect(layer="metal3", - offset=self.control_gnd_position, - width=self.gnd_offset.x - self.control_gnd_position.x, - height=drc["minwidth_metal3"]) - - self.add_via(layers=("metal2", "via2", "metal3"), - offset=[self.gnd_offset.x, - self.control_gnd_position.y], - size=(2,1)) - - self.add_via(layers=("metal2", "via2", "metal3"), - offset=self.control_gnd_position, - rotate=90) - - - def route_gnd_multibank(self): + def route_gnd_multi_bank(self): """ Route the gnd for 2 and 4 bank SRAMs """ self.add_rect(layer="metal2", offset=self.gnd_position, @@ -1141,13 +986,12 @@ class sram(design.design): def route_supplies(self): """ vdd/gnd routing of all modules """ - + return if (self.num_banks == 1): - self.route_vdd_singlebank() - self.route_gnd_singlebank() + pass elif (self.num_banks == 2 or self.num_banks == 4): - self.route_vdd_multibank() - self.route_gnd_multibank() + self.route_vdd_multi_bank() + self.route_gnd_multi_bank() else: debug.error("Incorrect number of banks.") diff --git a/compiler/tests/19_four_bank_test.py b/compiler/tests/19_multi_bank_test.py similarity index 91% rename from compiler/tests/19_four_bank_test.py rename to compiler/tests/19_multi_bank_test.py index a5842afb..15d5232d 100644 --- a/compiler/tests/19_four_bank_test.py +++ b/compiler/tests/19_multi_bank_test.py @@ -15,7 +15,7 @@ OPTS = globals.get_opts() -class bank_test(unittest.TestCase): +class multi_bank_test(unittest.TestCase): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) @@ -25,20 +25,20 @@ class bank_test(unittest.TestCase): import bank debug.info(1, "No column mux") - a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=4, name="test_sram1") + a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=2, name="test_bank1") self.local_check(a) debug.info(1, "Two way column mux") - a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=4, name="test_sram2") + a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=2, name="test_bank2") self.local_check(a) debug.info(1, "Four way column mux") - a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=4, name="test_sram3") + a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="test_bank3") self.local_check(a) # Eight way has a short circuit of one column mux select to gnd rail # debug.info(1, "Eight way column mux") - # a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="test_sram4") + # a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="test_bank4") # self.local_check(a) OPTS.check_lvsdrc = True diff --git a/compiler/tests/19_single_bank_test.py b/compiler/tests/19_single_bank_test.py index 4f0b5e04..09a89230 100644 --- a/compiler/tests/19_single_bank_test.py +++ b/compiler/tests/19_single_bank_test.py @@ -16,7 +16,7 @@ OPTS = globals.get_opts() #@unittest.skip("SKIPPING 20_sram_test") -class bank_test(unittest.TestCase): +class single_bank_test(unittest.TestCase): def runTest(self): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) @@ -26,20 +26,20 @@ class bank_test(unittest.TestCase): import bank debug.info(1, "No column mux") - a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="test_sram1") + a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=1, name="test_bank1") self.local_check(a) debug.info(1, "Two way column mux") - a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="test_sram2") + a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=1, name="test_bank2") self.local_check(a) debug.info(1, "Four way column mux") - a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="test_sram3") + a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=1, name="test_bank3") self.local_check(a) # Eight way has a short circuit of one column mux select to gnd rail # debug.info(1, "Eight way column mux") - # a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="test_sram4") + # a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=1, name="test_bank4") # self.local_check(a) OPTS.check_lvsdrc = True diff --git a/compiler/tests/19_two_bank_test.py b/compiler/tests/19_two_bank_test.py deleted file mode 100644 index 8926cc35..00000000 --- a/compiler/tests/19_two_bank_test.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python2.7 -""" -Run a regresion test on various srams -""" - -import unittest -from testutils import header -import sys,os -sys.path.append(os.path.join(sys.path[0],"..")) -import globals -import debug -import calibre - -OPTS = globals.get_opts() - - - -class bank_test(unittest.TestCase): - - def runTest(self): - globals.init_openram("config_20_{0}".format(OPTS.tech_name)) - # we will manually run lvs/drc - OPTS.check_lvsdrc = False - - import bank - - debug.info(1, "No column mux") - a = bank.bank(word_size=4, num_words=16, words_per_row=1, num_banks=2, name="test_sram1") - self.local_check(a) - - debug.info(1, "Two way column mux") - a = bank.bank(word_size=4, num_words=32, words_per_row=2, num_banks=2, name="test_sram2") - self.local_check(a) - - debug.info(1, "Four way column mux") - a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="test_sram3") - self.local_check(a) - - # Eight way has a short circuit of one column mux select to gnd rail - # debug.info(1, "Eight way column mux") - # a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="test_sram4") - # self.local_check(a) - - OPTS.check_lvsdrc = True - globals.end_openram() - - def local_check(self, a): - tempspice = OPTS.openram_temp + "temp.sp" - tempgds = OPTS.openram_temp + "temp.gds" - - a.sp_write(tempspice) - a.gds_write(tempgds) - - self.assertFalse(calibre.run_drc(a.name, tempgds)) - self.assertFalse(calibre.run_lvs(a.name, tempgds, tempspice)) - - os.remove(tempspice) - os.remove(tempgds) - - # reset the static duplicate name checker for unit tests - import design - design.design.name_map=[] - -# instantiate a copy of the class to actually run the test -if __name__ == "__main__": - (OPTS, args) = globals.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main() diff --git a/compiler/tests/20_sram_1bank_test.py b/compiler/tests/20_sram_1bank_test.py index 473d39e7..d9128013 100644 --- a/compiler/tests/20_sram_1bank_test.py +++ b/compiler/tests/20_sram_1bank_test.py @@ -25,10 +25,22 @@ class sram_1bank_test(unittest.TestCase): import sram - debug.info(1, "Testing sample 8bit, 64word SRAM, 1 bank") - a = sram.sram(word_size=8, num_words=128, num_banks=1, name="test_sram1") + debug.info(1, "Single bank, no column mux with control logic") + a = sram.sram(word_size=4, num_words=16, num_banks=1, name="test_sram1") self.local_check(a) + debug.info(1, "Single bank two way column mux with control logic") + a = sram.sram(word_size=4, num_words=32, num_banks=1, name="test_sram2") + self.local_check(a) + + debug.info(1, "Single bank, four way column mux with control logic") + a = sram.sram(word_size=4, num_words=64, num_banks=1, name="test_sram3") + self.local_check(a) + + # debug.info(1, "Single bank, eight way column mux with control logic") + # a = sram.sram(word_size=2, num_words=128, num_banks=1, name="test_sram4") + # self.local_check(a) + OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index cb0d1636..7deaa615 100644 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -25,10 +25,22 @@ class sram_2bank_test(unittest.TestCase): import sram - debug.info(1, "Testing sample 8bit, 128word SRAM, 2 banks") - a = sram.sram(word_size=8, num_words=128, num_banks=2, name="test_sram1") + debug.info(1, "Two bank, no column mux with control logic") + a = sram.sram(word_size=4, num_words=32, num_banks=2, name="test_sram1") self.local_check(a) + debug.info(1, "Two bank two way column mux with control logic") + a = sram.sram(word_size=4, num_words=64, num_banks=2, name="test_sram2") + self.local_check(a) + + debug.info(1, "Two bank, four way column mux with control logic") + a = sram.sram(word_size=4, num_words=128, num_banks=2, name="test_sram3") + self.local_check(a) + + # debug.info(1, "Two bank, eight way column mux with control logic") + # a = sram.sram(word_size=2, num_words=256 num_banks=2, name="test_sram4") + # self.local_check(a) + OPTS.check_lvsdrc = True globals.end_openram() diff --git a/compiler/tests/20_sram_4bank_test.py b/compiler/tests/20_sram_4bank_test.py index 82ecba75..ce0ef968 100644 --- a/compiler/tests/20_sram_4bank_test.py +++ b/compiler/tests/20_sram_4bank_test.py @@ -25,10 +25,22 @@ class sram_4bank_test(unittest.TestCase): import sram - debug.info(1, "Testing sample 8bit, 128word SRAM, 4 banks") - a = sram.sram(word_size=8, num_words=128, num_banks=4, name="test_sram1") + debug.info(1, "Four bank, no column mux with control logic") + a = sram.sram(word_size=4, num_words=32, num_banks=4, name="test_sram1") self.local_check(a) + debug.info(1, "Four bank two way column mux with control logic") + a = sram.sram(word_size=4, num_words=64, num_banks=4, name="test_sram2") + self.local_check(a) + + debug.info(1, "Four bank, four way column mux with control logic") + a = sram.sram(word_size=4, num_words=128, num_banks=4, name="test_sram3") + self.local_check(a) + + # debug.info(1, "Four bank, eight way column mux with control logic") + # a = sram.sram(word_size=2, num_words=256, num_banks=4, name="test_sram4") + # self.local_check(a) + OPTS.check_lvsdrc = True globals.end_openram()