From 648e57d19587b9d2afb653009f6231b320a25787 Mon Sep 17 00:00:00 2001 From: Michael Timothy Grimes Date: Wed, 26 Sep 2018 14:53:55 -0700 Subject: [PATCH] Altering bank select for port specific use. Altering bank select test to test different port types. Altering bank for control signal changes. --- compiler/modules/bank.py | 326 +++++++++++++++----------- compiler/modules/bank_select.py | 15 +- compiler/tests/19_bank_select_test.py | 12 +- 3 files changed, 211 insertions(+), 142 deletions(-) mode change 100755 => 100644 compiler/tests/19_bank_select_test.py diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index ffb222d5..98373f3d 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -53,6 +53,7 @@ class bank(design.design): self.add_modules() self.create_modules() + def create_layout(self): self.place_modules() self.setup_routing_constraints() @@ -65,17 +66,22 @@ class bank(design.design): self.bank_center=self.offset_all_coordinates().scale(-1,-1) self.DRC_LVS() - + + def add_pins(self): self.read_index = [] + self.port_id = [] port_number = 0 for port in range(OPTS.num_rw_ports): self.read_index.append("{}".format(port_number)) + self.port_id.append("rw") port_number += 1 for port in range(OPTS.num_w_ports): + self.port_id.append("w") port_number += 1 for port in range(OPTS.num_r_ports): self.read_index.append("{}".format(port_number)) + self.port_id.append("r") port_number += 1 """ Adding pins for Bank module""" @@ -94,14 +100,17 @@ class bank(design.design): if self.num_banks > 1: for port in range(self.total_ports): self.add_pin("bank_sel{}".format(port),"INPUT") - self.add_pin("s_en", "INPUT") + for port in range(self.total_read): + self.add_pin("s_en{0}".format(port), "INPUT") for port in range(self.total_write): self.add_pin("w_en{0}".format(port), "INPUT") - for pin in ["clk_buf_bar","clk_buf"]: - self.add_pin(pin,"INPUT") + for port in range(self.total_ports): + self.add_pin("clk_buf_bar{0}".format(port),"INPUT") + self.add_pin("clk_buf{0}".format(port),"INPUT") self.add_pin("vdd","POWER") self.add_pin("gnd","GROUND") + def route_layout(self): """ Create routing amoung the modules """ self.route_central_bus() @@ -118,6 +127,7 @@ class bank(design.design): self.route_bank_select() self.route_vdd_gnd() + def create_modules(self): """ Add modules. The order should not matter! """ @@ -155,10 +165,10 @@ class bank(design.design): self.place_row_decoder() self.place_wordline_driver() self.place_column_decoder() - self.place_bank_select() - + + def compute_sizes(self): """ Computes the required sizes to create the bank """ @@ -180,13 +190,25 @@ class bank(design.design): # Number of control lines in the bus self.num_control_lines = 4 # The order of the control signals on the control bus: - self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en"] + self.input_control_signals = [] + port_num = 0 + for port in range(OPTS.num_rw_ports): + self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "w_en{}".format(port_num), "s_en{}".format(port_num)]) + port_num += 1 + for port in range(OPTS.num_w_ports): + self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "w_en{}".format(port_num)]) + port_num += 1 + for port in range(OPTS.num_r_ports): + self.input_control_signals.append(["clk_buf{}".format(port_num), "clk_buf_bar{}".format(port_num), "s_en{}".format(port_num)]) + port_num += 1 # These will be outputs of the gaters if this is multibank, if not, normal signals. - if self.num_banks > 1: - self.control_signals = ["gated_"+str for str in self.input_control_signals] - else: - self.control_signals = self.input_control_signals + self.control_signals = [] + for port in range(self.total_ports): + if self.num_banks > 1: + self.control_signals.append(["gated_"+str for str in self.input_control_signals[port]]) + else: + self.control_signals.append(self.input_control_signals[port]) # The central bus is the column address (one hot) and row address (binary) if self.col_addr_size>0: self.num_col_addr_lines = 2**self.col_addr_size @@ -291,6 +313,7 @@ class bank(design.design): temp.append("gnd") self.connect_inst(temp) + def place_bitcell_array(self): """ Placing Bitcell Array """ self.bitcell_array_inst.place(vector(0,0)) @@ -307,9 +330,10 @@ class bank(design.design): for i in range(self.num_cols): temp.append(self.read_bl_list[port]+"[{0}]".format(i)) temp.append(self.read_br_list[port]+"[{0}]".format(i)) - temp.extend([self.prefix+"clk_buf_bar", "vdd"]) + temp.extend([self.prefix+"clk_buf_bar{0}".format(self.read_index[port]), "vdd"]) self.connect_inst(temp) + def place_precharge_array(self): """ Placing Precharge """ @@ -319,6 +343,7 @@ class bank(design.design): # The enclosure is for the well and the spacing is to the bitcell wells y_offset = self.bitcell_array.height + self.m2_gap self.precharge_array_inst[port].place(vector(0,y_offset)) + def create_column_mux_array(self): """ Creating Column Mux when words_per_row > 1 . """ @@ -342,6 +367,7 @@ class bank(design.design): temp.append("gnd") self.connect_inst(temp) + def place_column_mux_array(self): """ Placing Column Mux when words_per_row > 1 . """ if self.col_addr_size > 0: @@ -353,6 +379,7 @@ class bank(design.design): for port in range(self.total_ports): y_offset = self.column_mux_height self.col_mux_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) + def create_sense_amp_array(self): """ Creating Sense amp """ @@ -372,9 +399,10 @@ class bank(design.design): temp.append(self.read_bl_list[port]+"_out[{0}]".format(bit)) temp.append(self.read_br_list[port]+"_out[{0}]".format(bit)) - temp.extend([self.prefix+"s_en", "vdd", "gnd"]) + temp.extend([self.prefix+"s_en{}".format(port), "vdd", "gnd"]) self.connect_inst(temp) + def place_sense_amp_array(self): """ Placing Sense amp """ @@ -382,6 +410,7 @@ class bank(design.design): for port in range(self.total_read): y_offset = self.column_mux_height + self.sense_amp_array.height + self.m2_gap self.sense_amp_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) + def create_write_driver_array(self): """ Creating Write Driver """ @@ -404,6 +433,7 @@ class bank(design.design): temp.extend([self.prefix+"w_en{0}".format(port), "vdd", "gnd"]) self.connect_inst(temp) + def place_write_driver_array(self): """ Placing Write Driver """ @@ -412,7 +442,6 @@ class bank(design.design): y_offset = self.sense_amp_array.height + self.column_mux_height \ + self.m2_gap + self.write_driver_array.height self.write_driver_array_inst[port].place(vector(0,y_offset).scale(-1,-1)) - def create_row_decoder(self): @@ -431,6 +460,7 @@ class bank(design.design): temp.extend(["vdd", "gnd"]) self.connect_inst(temp) + def place_row_decoder(self): """ Place the hierarchical row decoder """ @@ -459,11 +489,12 @@ class bank(design.design): temp.append("dec_out{0}[{1}]".format(port,row)) for row in range(self.num_rows): temp.append(self.total_wl_list[port]+"[{0}]".format(row)) - temp.append(self.prefix+"clk_buf") + temp.append(self.prefix+"clk_buf{0}".format(port)) temp.append("vdd") temp.append("gnd") self.connect_inst(temp) + def place_wordline_driver(self): """ Place the Wordline Driver """ @@ -505,6 +536,7 @@ class bank(design.design): temp.extend(["vdd", "gnd"]) self.connect_inst(temp) + def place_column_decoder(self): """ Place a 2:4 or 3:8 column address decoder. @@ -532,12 +564,13 @@ class bank(design.design): mod=self.bank_select)) temp = [] - temp.extend(self.input_control_signals) + temp.extend(self.input_control_signals[port]) temp.append("bank_sel{}".format(port)) - temp.extend(self.control_signals) + temp.extend(self.control_signals[port]) temp.extend(["vdd", "gnd"]) self.connect_inst(temp) + def place_bank_select(self): """ Place the bank select logic. """ @@ -548,9 +581,9 @@ class bank(design.design): for port in range(self.total_ports): x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) if self.col_addr_size > 0: - y_off = min(self.col_decoder_inst[0].by(), self.col_mux_array_inst[0].by()) + y_off = min(self.col_decoder_inst[port].by(), self.col_mux_array_inst[port].by()) else: - y_off = self.row_decoder_inst[0].by() + y_off = self.row_decoder_inst[port].by() y_off -= (self.bank_select.height + drc["well_to_well"]) self.bank_select_pos = vector(x_off,y_off) self.bank_select_inst[port].place(self.bank_select_pos) @@ -590,18 +623,31 @@ class bank(design.design): # Precharge has no gnd #if inst != self.precharge_array_inst[port]: self.copy_layout_pin(inst, "gnd") - + + def route_bank_select(self): """ Route the bank select logic. """ for port in range(self.total_ports): - for input_name in self.input_control_signals+["bank_sel"]: - self.copy_layout_pin(self.bank_select_inst[port], input_name) - - for gated_name in self.control_signals: + if self.port_id[port] == "rw": + bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "s_en", "bank_sel"] + gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en", "gated_s_en"] + elif self.port_id[port] == "w": + bank_sel_signals = ["clk_buf", "clk_buf_bar", "w_en", "bank_sel"] + gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_w_en"] + else: + bank_sel_signals = ["clk_buf", "clk_buf_bar", "s_en", "bank_sel"] + gated_bank_sel_signals = ["gated_clk_buf", "gated_clk_buf_bar", "gated_s_en"] + + copy_control_signals = self.input_control_signals[port]+["bank_sel{}".format(port)] + for signal in range(len(copy_control_signals)): + self.copy_layout_pin(self.bank_select_inst[port], bank_sel_signals[signal], copy_control_signals[signal]) + + for signal in range(len(gated_bank_sel_signals)): # Connect the inverter output to the central bus - out_pos = self.bank_select_inst[port].get_pin(gated_name).rc() - bus_pos = vector(self.bus_xoffset[gated_name].x, out_pos.y) + out_pos = self.bank_select_inst[port].get_pin(gated_bank_sel_signals[signal]).rc() + name = self.control_signals[port][signal] + bus_pos = vector(self.bus_xoffset[name].x, out_pos.y) self.add_path("metal3",[out_pos, bus_pos]) self.add_via_center(layers=("metal2", "via2", "metal3"), offset=bus_pos, @@ -619,7 +665,8 @@ class bank(design.design): After the modules are instantiated, find the dimensions for the control bus, power ring, etc. """ - + # FIXME: calculate for multiport + #The minimum point is either the bottom of the address flops, #the column decoder (if there is one). write_driver_min_y_offset = self.write_driver_array_inst[0].by() - 3*self.m2_pitch @@ -653,7 +700,6 @@ class bank(design.design): self.height = ur.y - ll.y self.width = ur.x - ll.x - def route_central_bus(self): """ Create the address, supply, and control signal central bus lines. """ @@ -662,16 +708,16 @@ 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, 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)) - + for port in range(self.total_ports): + 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[port], + length=control_bus_length, + vertical=True, + make_pins=(self.num_banks==1)) def route_precharge_to_bitcell_array(self): @@ -712,7 +758,8 @@ class bank(design.design): vector(bitcell_bl.x,yoffset), bitcell_bl]) self.add_path("metal2",[col_mux_br, vector(col_mux_br.x,yoffset), vector(bitcell_br.x,yoffset), bitcell_br]) - + + def route_sense_amp_to_col_mux_or_bitcell_array(self): """ Routing of BL and BR between sense_amp and column mux or bitcell array """ @@ -736,61 +783,61 @@ class bank(design.design): vector(connect_bl.x,yoffset), connect_bl]) self.add_path("metal2",[sense_amp_br, vector(sense_amp_br.x,yoffset), vector(connect_br.x,yoffset), connect_br]) - - + + def route_sense_amp_out(self): """ Add pins for the sense amp output """ # FIXME: Update for multiport - for bit in range(self.word_size): - data_pin = self.sense_amp_array_inst[0].get_pin("data[{}]".format(bit)) - self.add_layout_pin_rect_center(text="dout0[{}]".format(bit), - layer=data_pin.layer, - offset=data_pin.center(), - height=data_pin.height(), - width=data_pin.width()) - + for port in range(self.total_read): + for bit in range(self.word_size): + data_pin = self.sense_amp_array_inst[port].get_pin("data[{}]".format(bit)) + self.add_layout_pin_rect_center(text="dout{0}[{1}]".format(self.read_index[port],bit), + layer=data_pin.layer, + offset=data_pin.center(), + height=data_pin.height(), + width=data_pin.width()) + def route_row_decoder(self): """ Routes the row decoder inputs and supplies """ # FIXME: Update for multiport # Create inputs for the row address lines - for row in range(self.row_addr_size): - addr_idx = row + self.col_addr_size - decoder_name = "addr[{}]".format(row) - addr_name = "addr0[{}]".format(addr_idx) - self.copy_layout_pin(self.row_decoder_inst[0], decoder_name, addr_name) + for port in range(self.total_ports): + for row in range(self.row_addr_size): + addr_idx = row + self.col_addr_size + decoder_name = "addr[{}]".format(row) + addr_name = "addr{0}[{1}]".format(port,addr_idx) + self.copy_layout_pin(self.row_decoder_inst[port], decoder_name, addr_name) def route_write_driver(self): """ Connecting write driver """ - - for row in range(self.word_size): - data_name = "data[{}]".format(row) - din_name = "din0[{}]".format(row) - self.copy_layout_pin(self.write_driver_array_inst[0], data_name, din_name) - + for port in range(self.total_ports): + for row in range(self.word_size): + data_name = "data[{}]".format(row) + din_name = "din{0}[{1}]".format(port,row) + self.copy_layout_pin(self.write_driver_array_inst[port], data_name, din_name) def route_wordline_driver(self): """ Connecting Wordline driver output to Bitcell WL connection """ + for port in range(self.total_ports): + for row in range(self.num_rows): + # The pre/post is to access the pin from "outside" the cell to avoid DRCs + decoder_out_pos = self.row_decoder_inst[port].get_pin("decode[{}]".format(row)).rc() + driver_in_pos = self.wordline_driver_inst[port].get_pin("in[{}]".format(row)).lc() + mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0) + mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1) + self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos]) - for row in range(self.num_rows): - # The pre/post is to access the pin from "outside" the cell to avoid DRCs - decoder_out_pos = self.row_decoder_inst[0].get_pin("decode[{}]".format(row)).rc() - driver_in_pos = self.wordline_driver_inst[0].get_pin("in[{}]".format(row)).lc() - mid1 = decoder_out_pos.scale(0.5,1)+driver_in_pos.scale(0.5,0) - mid2 = decoder_out_pos.scale(0.5,0)+driver_in_pos.scale(0.5,1) - self.add_path("metal1", [decoder_out_pos, mid1, mid2, driver_in_pos]) - - # The mid guarantees we exit the input cell to the right. - driver_wl_pos = self.wordline_driver_inst[0].get_pin("wl[{}]".format(row)).rc() - bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[0]+"[{}]".format(row)).lc() - mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) - mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) - self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) - + # The mid guarantees we exit the input cell to the right. + driver_wl_pos = self.wordline_driver_inst[port].get_pin("wl[{}]".format(row)).rc() + bitcell_wl_pos = self.bitcell_array_inst.get_pin(self.total_wl_list[port]+"[{}]".format(row)).lc() + mid1 = driver_wl_pos.scale(0.5,1)+bitcell_wl_pos.scale(0.5,0) + mid2 = driver_wl_pos.scale(0.5,0)+bitcell_wl_pos.scale(0.5,1) + self.add_path("metal1", [driver_wl_pos, mid1, mid2, bitcell_wl_pos]) def route_column_address_lines(self): @@ -798,49 +845,45 @@ class bank(design.design): if not self.col_addr_size>0: return - - - if self.col_addr_size == 1: - - # Connect to sel[0] and sel[1] - decode_names = ["Zb", "Z"] - - # The Address LSB - self.copy_layout_pin(self.col_decoder_inst[0], "A", "addr0[0]") - - elif self.col_addr_size > 1: - decode_names = [] - for i in range(self.num_col_addr_lines): - decode_names.append("out[{}]".format(i)) - - for i in range(self.col_addr_size): - decoder_name = "in[{}]".format(i) - addr_name = "addr0[{}]".format(i) - self.copy_layout_pin(self.col_decoder_inst[0], decoder_name, addr_name) + for port in range(self.total_ports): + if self.col_addr_size == 1: + # Connect to sel[0] and sel[1] + decode_names = ["Zb", "Z"] + + # The Address LSB + self.copy_layout_pin(self.col_decoder_inst[port], "A", "addr{}[0]".format(port)) + + elif self.col_addr_size > 1: + decode_names = [] + for i in range(self.num_col_addr_lines): + decode_names.append("out[{}]".format(i)) - # This will do a quick "river route" on two layers. - # When above the top select line it will offset "inward" again to prevent conflicts. - # This could be done on a single layer, but we follow preferred direction rules for later routing. - top_y_offset = self.col_mux_array_inst[0].get_pin("sel[{}]".format(self.num_col_addr_lines-1)).cy() - for (decode_name,i) in zip(decode_names,range(self.num_col_addr_lines)): - mux_name = "sel[{}]".format(i) - mux_addr_pos = self.col_mux_array_inst[0].get_pin(mux_name).lc() - - decode_out_pos = self.col_decoder_inst[0].get_pin(decode_name).center() + for i in range(self.col_addr_size): + decoder_name = "in[{}]".format(i) + addr_name = "addr{0}[{1}]".format(port,i) + self.copy_layout_pin(self.col_decoder_inst[port], decoder_name, addr_name) + - # To get to the edge of the decoder and one track out - delta_offset = self.col_decoder_inst[0].rx() - decode_out_pos.x + self.m2_pitch - if decode_out_pos.y > top_y_offset: - mid1_pos = vector(decode_out_pos.x + delta_offset + i*self.m2_pitch,decode_out_pos.y) - else: - mid1_pos = vector(decode_out_pos.x + delta_offset + (self.num_col_addr_lines-i)*self.m2_pitch,decode_out_pos.y) - mid2_pos = vector(mid1_pos.x,mux_addr_pos.y) - #self.add_wire(("metal1","via1","metal2"),[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos]) - self.add_path("metal1",[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos]) - + # This will do a quick "river route" on two layers. + # When above the top select line it will offset "inward" again to prevent conflicts. + # This could be done on a single layer, but we follow preferred direction rules for later routing. + top_y_offset = self.col_mux_array_inst[port].get_pin("sel[{}]".format(self.num_col_addr_lines-1)).cy() + for (decode_name,i) in zip(decode_names,range(self.num_col_addr_lines)): + mux_name = "sel[{}]".format(i) + mux_addr_pos = self.col_mux_array_inst[port].get_pin(mux_name).lc() + + decode_out_pos = self.col_decoder_inst[port].get_pin(decode_name).center() - + # To get to the edge of the decoder and one track out + delta_offset = self.col_decoder_inst[port].rx() - decode_out_pos.x + self.m2_pitch + if decode_out_pos.y > top_y_offset: + mid1_pos = vector(decode_out_pos.x + delta_offset + i*self.m2_pitch,decode_out_pos.y) + else: + mid1_pos = vector(decode_out_pos.x + delta_offset + (self.num_col_addr_lines-i)*self.m2_pitch,decode_out_pos.y) + mid2_pos = vector(mid1_pos.x,mux_addr_pos.y) + #self.add_wire(("metal1","via1","metal2"),[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos]) + self.add_path("metal1",[decode_out_pos, mid1_pos, mid2_pos, mux_addr_pos]) def add_lvs_correspondence_points(self): @@ -894,30 +937,39 @@ class bank(design.design): # From control signal to the module pin # Connection from the central bus to the main control block crosses # pre-decoder and this connection is in metal3 - connection = [] - connection.append((self.prefix+"clk_buf_bar", self.precharge_array_inst[0].get_pin("en").lc())) - connection.append((self.prefix+"w_en0", self.write_driver_array_inst[0].get_pin("en").lc())) - connection.append((self.prefix+"s_en", self.sense_amp_array_inst[0].get_pin("en").lc())) - - for (control_signal, pin_pos) in connection: - control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y) - self.add_path("metal1", [control_pos, pin_pos]) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=control_pos, - rotate=90) - - # clk to wordline_driver - control_signal = self.prefix+"clk_buf" - pin_pos = self.wordline_driver_inst[0].get_pin("en").uc() - mid_pos = pin_pos + vector(0,self.m1_pitch) - control_x_offset = self.bus_xoffset[control_signal].x - control_pos = vector(control_x_offset + self.m1_width, mid_pos.y) - self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos]) - control_via_pos = vector(control_x_offset, mid_pos.y) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=control_via_pos, - rotate=90) + write_inst = 0 + read_inst = 0 + # Control lines for RW ports + for port in range(self.total_ports): + connection = [] + if (self.port_id[port] == "rw") or (self.port_id[port] == "r"): + connection.append((self.prefix+"clk_buf_bar{}".format(port), self.precharge_array_inst[read_inst].get_pin("en").lc())) + if (self.port_id[port] == "rw") or (self.port_id[port] == "w"): + connection.append((self.prefix+"w_en{}".format(port), self.write_driver_array_inst[write_inst].get_pin("en").lc())) + write_inst += 1 + if (self.port_id[port] == "rw") or (self.port_id[port] == "r"): + connection.append((self.prefix+"s_en{}".format(port), self.sense_amp_array_inst[read_inst].get_pin("en").lc())) + read_inst += 1 + + for (control_signal, pin_pos) in connection: + control_pos = vector(self.bus_xoffset[control_signal].x ,pin_pos.y) + self.add_path("metal1", [control_pos, pin_pos]) + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=control_pos, + rotate=90) + + # clk to wordline_driver + control_signal = self.prefix+"clk_buf{}".format(port) + pin_pos = self.wordline_driver_inst[port].get_pin("en").uc() + mid_pos = pin_pos + vector(0,self.m1_pitch) + control_x_offset = self.bus_xoffset[control_signal].x + control_pos = vector(control_x_offset + self.m1_width, mid_pos.y) + self.add_wire(("metal1","via1","metal2"),[pin_pos, mid_pos, control_pos]) + control_via_pos = vector(control_x_offset, mid_pos.y) + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=control_via_pos, + rotate=90) def analytical_delay(self, slew, load): diff --git a/compiler/modules/bank_select.py b/compiler/modules/bank_select.py index 037d1ca9..ef4b0a09 100644 --- a/compiler/modules/bank_select.py +++ b/compiler/modules/bank_select.py @@ -15,9 +15,11 @@ class bank_select(design.design): banks are created in upper level SRAM module """ - def __init__(self, name="bank_select"): + def __init__(self, name="bank_select", port="rw"): design.design.__init__(self, name) + self.port = port + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -38,10 +40,17 @@ class bank_select(design.design): def add_pins(self): # Number of control lines in the bus - self.num_control_lines = 4 + if self.port == "rw": + self.num_control_lines = 4 + else: + self.num_control_lines = 3 # The order of the control signals on the control bus: # FIXME: Update for multiport (these names are not right) - self.input_control_signals = ["clk_buf", "clk_buf_bar", "w_en0", "s_en"] + self.input_control_signals = ["clk_buf", "clk_buf_bar"] + if (self.port == "rw") or (self.port == "w"): + self.input_control_signals.append("w_en") + if (self.port == "rw") or (self.port == "r"): + self.input_control_signals.append("s_en") # These will be outputs of the gaters if this is multibank self.control_signals = ["gated_"+str for str in self.input_control_signals] diff --git a/compiler/tests/19_bank_select_test.py b/compiler/tests/19_bank_select_test.py old mode 100755 new mode 100644 index 0f4cb05f..ed6e431c --- a/compiler/tests/19_bank_select_test.py +++ b/compiler/tests/19_bank_select_test.py @@ -17,8 +17,16 @@ class bank_select_test(openram_test): globals.init_openram("config_20_{0}".format(OPTS.tech_name)) import bank_select - debug.info(1, "No column mux") - a = bank_select.bank_select() + debug.info(1, "No column mux, rw control logic") + a = bank_select.bank_select(port="rw") + self.local_check(a) + + debug.info(1, "No column mux, w control logic") + a = bank_select.bank_select(port="w") + self.local_check(a) + + debug.info(1, "No column mux, r control logic") + a = bank_select.bank_select(port="r") self.local_check(a) globals.end_openram()