From bab92fcf38cbbcd01f84861ca17fc583c7cd1a30 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 19 Mar 2018 15:11:42 -0700 Subject: [PATCH] Rework hierarchical decoder to not be folded. Remove address from central bank bus and access via side pins now. Eight way column mux now works. --- compiler/base/design.py | 2 + compiler/base/hierarchy_spice.py | 2 + compiler/modules/bank.py | 170 +++++------------- compiler/modules/hierarchical_decoder.py | 5 +- .../modules/single_level_column_mux_array.py | 2 +- compiler/modules/wordline_driver.py | 1 + compiler/pgates/pinvbuf.py | 2 +- compiler/sram.py | 120 ++++++------- compiler/tests/19_multi_bank_test.py | 7 +- 9 files changed, 114 insertions(+), 197 deletions(-) diff --git a/compiler/base/design.py b/compiler/base/design.py index 1d38f5a9..572c8860 100644 --- a/compiler/base/design.py +++ b/compiler/base/design.py @@ -30,6 +30,8 @@ class design(hierarchy_spice.spice, hierarchy_layout.layout): # These modules ensure unique names or have no changes if they # aren't unique ok_list = ['ms_flop.ms_flop', + 'dff.dff', + 'dff_buf.dff_buf', 'bitcell.bitcell', 'contact.contact', 'ptx.ptx', diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index d41ae0d9..e4d03536 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -91,6 +91,8 @@ class spice(verilog.verilog): group of modules are generated.""" if (check and (len(self.insts[-1].mod.pins) != len(args))): + debug.error("Connections: {}".format(self.insts[-1].mod.pins)) + debug.error("Connections: {}".format(args)) debug.error("Number of net connections ({0}) does not match last instance ({1})".format(len(self.insts[-1].mod.pins), len(args)), 1) self.conns.append(args) diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 9528f510..efbcfafc 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -161,17 +161,15 @@ class bank(design.design): # 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 - self.num_addr_lines = self.num_col_addr_lines + self.row_addr_size else: self.num_col_addr_lines = 0 - self.num_addr_lines = self.row_addr_size # M1/M2 routing pitch is based on contacted pitch self.m1_pitch = contact.m1m2.height + max(self.m1_space,self.m2_space) self.m2_pitch = contact.m2m3.height + max(self.m2_space,self.m3_space) # The width of this bus is needed to place other modules (e.g. decoder) - self.central_bus_width = self.m2_pitch * (self.num_control_lines + self.num_addr_lines + 1) + self.central_bus_width = self.m2_pitch * self.num_control_lines @@ -362,12 +360,10 @@ class bank(design.design): # The predecoder is below the x-axis and the main decoder is above the x-axis # The address flop and decoder are aligned in the x coord. - decoder_x_offset = self.row_decoder.width + self.central_bus_width - offset = vector(decoder_x_offset, - self.row_decoder.predecoder_height) + x_offset = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) self.row_decoder_inst=self.add_inst(name="row_decoder", mod=self.row_decoder, - offset=offset.scale(-1,-1)) + offset=vector(x_offset,0)) temp = [] for i in range(self.row_addr_size): @@ -381,12 +377,10 @@ class bank(design.design): """ Wordline Driver """ # The wordline driver is placed to the right of the main decoder width. - # This means that it slightly overlaps with the hierarchical decoder, - # but it shares power rails. This may differ for other decoders later... - x_offset = self.row_decoder.width + self.central_bus_width - self.row_decoder.row_decoder_width + x_offset = -(self.central_bus_width + self.wordline_driver.width) + self.m2_pitch self.wordline_driver_inst=self.add_inst(name="wordline_driver", mod=self.wordline_driver, - offset=vector(x_offset,0).scale(-1,-1)) + offset=vector(x_offset,0)) temp = [] for i in range(self.num_rows): @@ -404,8 +398,8 @@ class bank(design.design): Create a 2:4 or 3:8 column address decoder. """ # Place the col decoder aligned left to row decoder - x_off = -(self.central_bus_width + self.row_decoder.width) - y_off = -(self.row_decoder.predecoder_height + self.col_decoder.height + 2*drc["well_to_well"]) + x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) + y_off = -(self.col_decoder.height + 2*drc["well_to_well"]) self.col_decoder_inst=self.add_inst(name="col_address_decoder", mod=self.col_decoder, offset=vector(x_off,y_off)) @@ -445,10 +439,10 @@ class bank(design.design): if not self.num_banks > 1: return - xoffset = -(self.central_bus_width + self.bank_select.width) + x_off = -(self.row_decoder.width + self.central_bus_width + self.wordline_driver.width) # extra space to allow vias - yoffset = self.min_point + 2*self.supply_rail_pitch + self.m1_space - self.bank_select_pos = vector(xoffset,yoffset) + y_off = self.min_point + 2*self.supply_rail_pitch + self.m1_space + self.bank_select_pos = vector(x_off,y_off) self.bank_select_inst = self.add_inst(name="bank_select", mod=self.bank_select, offset=self.bank_select_pos) @@ -536,12 +530,11 @@ class bank(design.design): """ Create the address, supply, and control signal central bus lines. """ # Overall central bus width. It includes all the column mux lines, - # control lines, and address flop to decoder lines. + # 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_x_offset = -self.m2_pitch * (self.num_control_lines) - address_bus_x_offset = control_bus_x_offset - self.m2_pitch*(self.num_addr_lines) - + control_bus_x_offset = -self.m2_pitch * self.num_control_lines + # Track the bus offsets for other modules to access self.bus_xoffset = {} @@ -556,35 +549,6 @@ class bank(design.design): width=self.m2_width, height=self.height) - # Row address lines (to left of col address lines) - # goes from bottom of bitcell array down to the bottom of the column decoder/addresses - for i in range(self.row_addr_size): - addr_idx = i + self.col_addr_size - x_offset = address_bus_x_offset + i*self.m2_pitch - name = "A[{}]".format(addr_idx) - # Make the xoffset map the center of the rail - self.bus_xoffset[name]=x_offset + 0.5*self.m2_width - # Add a label pin for LVS correspondence and visual help inspecting the rail. - self.add_layout_pin(text=name, - layer="metal2", - offset=vector(x_offset, self.min_point), - width=self.m2_width, - height=-self.min_point) - - # Column mux lines if there is column mux - # goes from bottom of bitcell array down to the bottom of the column decoder/addresses - if self.col_addr_size>0: - for i in range(self.num_col_addr_lines): - x_offset = address_bus_x_offset + (i+self.row_addr_size)*self.m2_pitch - name = "sel[{}]".format(i) # One hot select signals - # Make the xoffset map the center of the rail - self.bus_xoffset[name]=x_offset + 0.5*self.m2_width - # Add a label pin for LVS correspondence - self.add_label_pin(text=name, - layer="metal2", - offset=vector(x_offset, self.col_decoder_inst.by()), - width=self.m2_width, - height=-self.col_decoder_inst.by()) def route_precharge_to_bitcell_array(self): @@ -654,33 +618,14 @@ class bank(design.design): def route_row_decoder(self): """ Routes the row decoder inputs and supplies """ - for i in range(self.row_addr_size): - addr_idx = i + self.col_addr_size - # before this index, we are using 2x4 decoders - switchover_index = 2*self.row_decoder.no_of_pre2x4 - # so decide what modulus to perform the height spacing - if i < switchover_index: - position_heights = i % 2 - else: - position_heights = (i-switchover_index) % 3 - - # 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)).lr() \ - + vector(0,position_heights*self.bitcell.height+self.m2_pitch) - rail_position = vector(self.bus_xoffset["A[{}]".format(addr_idx)], - decoder_in_position.y) - self.add_path("metal1",[decoder_in_position,rail_position]) - - decoder_in_via = decoder_in_position - vector(0,0.5*self.m2_width) - self.add_via(layers=("metal1", "via1", "metal2"), - offset=decoder_in_via, - rotate=90) + # # Create inputs for the row address lines + # for i in range(self.row_addr_size): + # addr_idx = i + self.col_addr_size + # decoder_name = "A[{}]".format(i) + # addr_name = "A[{}]".format(addr_idx) + # self.copy_layout_pin(self.row_decoder_inst, decoder_name, addr_name) + - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=rail_position, - rotate=90) - # Route the power and ground, but only BELOW the y=0 since the # others are connected with the wordline driver. # These must be on M3 to not interfere with column mux address pins. @@ -730,70 +675,51 @@ class bank(design.design): - - def route_column_address_lines(self): """ Connecting the select lines of column mux to the address bus """ if not self.col_addr_size>0: return - # Connect the select lines to the column mux - # These must be in metal3 so that they don't overlap any gnd lines from decoders - for i in range(self.num_col_addr_lines): - name = "sel[{}]".format(i) - mux_addr_pos = self.col_mux_array_inst.get_pin(name).lc() - wire_pos = vector(self.bus_xoffset[name], mux_addr_pos.y) - self.add_path("metal1", [wire_pos,mux_addr_pos]) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=wire_pos, - rotate=90) + if self.col_addr_size == 1: - decode_out_pos = self.col_decoder_inst.get_pin("Zb").rc() - selx_pos = vector(self.bus_xoffset["sel[0]"],decode_out_pos.y) - self.add_path("metal1",[decode_out_pos, selx_pos]) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=selx_pos, - rotate=90) - decode_out_pos = self.col_decoder_inst.get_pin("Z").rc() - selx_pos = vector(self.bus_xoffset["sel[1]"],decode_out_pos.y) - self.add_path("metal1",[decode_out_pos, selx_pos]) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=selx_pos, - rotate=90) - + # Connect to sel[0] and sel[1] + decode_names = ["Zb", "Z"] + # The Address LSB - decode_in_pin = self.col_decoder_inst.get_pin("A") - pin_pos = vector(decode_in_pin.cx(), self.min_point) - self.add_layout_pin_center_segment(text="A[0]", - layer="metal2", - start=pin_pos, - end=decode_in_pin.bc()) + self.copy_layout_pin(self.col_decoder_inst, "A", "A[0]") elif self.col_addr_size > 1: - # Route the col decoder outputs to the col select bus + decode_names = [] for i in range(self.num_col_addr_lines): - name = "sel[{}]".format(i) - decode_out_pos = self.col_decoder_inst.get_pin("out[{}]".format(i)).rc() - selx_pos = vector(self.bus_xoffset[name],decode_out_pos.y) - self.add_path("metal1",[decode_out_pos, selx_pos]) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=selx_pos, - rotate=90) + decode_names.append("out[{}]".format(i)) - # Route from the col decoder up to the address bus for i in range(self.col_addr_size): decoder_name = "in[{}]".format(i) addr_name = "A[{}]".format(i) - decode_in_pin = self.col_decoder_inst.get_pin(decoder_name) - pin_pos = vector(decode_in_pin.cx(), self.min_point) - self.add_layout_pin_center_segment(text=addr_name, - layer="metal2", - start=pin_pos, - end=decode_in_pin.bc()) - + self.copy_layout_pin(self.col_decoder_inst, decoder_name, addr_name) + + # 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.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.get_pin(mux_name).lc() + + decode_out_pos = self.col_decoder_inst.get_pin(decode_name).center() + + # To get to the edge of the decoder and one track out + delta_offset = self.col_decoder_inst.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]) + # route the gnd rails, add contact to rail as well for gnd_pin in self.col_decoder_inst.get_pins("gnd"): left_rail_pos = vector(self.left_gnd_x_center, gnd_pin.cy()) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index ac36359a..fc338082 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -154,12 +154,11 @@ class hierarchical_decoder(design.design): else: nand_width = self.nand3.width self.routing_width = self.metal2_pitch*self.total_number_of_predecoder_outputs - self.row_decoder_width = nand_width + self.routing_width + self.inv.width self.row_decoder_height = self.inv.height * self.rows # Calculates height and width of hierarchical decoder self.height = self.row_decoder_height - self.width = self.predecoder_width + self.row_decoder_width + self.width = self.predecoder_width + self.routing_width + nand_width + self.inv.width def create_pre_decoder(self): """ Creates pre-decoder and places labels input address [A] """ @@ -479,7 +478,7 @@ class hierarchical_decoder(design.design): def connect_rail_m3(self, rail_index, pin): """ Connect the routing rail to the given metal1 pin """ - mid_point = vector(pin.cx(), pin.cy()-self.inv.height/2) + mid_point = vector(pin.cx(), pin.cy()+self.inv.height/2) rail_pos = vector(self.rail_x_offsets[rail_index],mid_point.y) self.add_via_center(layers=("metal1", "via1", "metal2"), offset=pin.center(), diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 61e2d533..8677cd3a 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -119,7 +119,7 @@ class single_level_column_mux_array(design.design): def add_horizontal_input_rail(self): """ Create address input rails on M1 below the mux transistors """ for j in range(self.words_per_row): - offset = vector(0, self.route_height - (j+1)*self.m1_pitch) + offset = vector(0, self.route_height + (j-self.words_per_row)*self.m1_pitch) self.add_layout_pin(text="sel[{}]".format(j), layer="metal1", offset=offset, diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index 67d414af..aa7eba01 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -22,6 +22,7 @@ class wordline_driver(design.design): self.rows = rows self.add_pins() self.design_layout() + self.offset_all_coordinates() self.DRC_LVS() def add_pins(self): diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index 2e0cc20b..fcb137dc 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -28,7 +28,7 @@ class pinvbuf(design.design): self.inv2 = pinv(size=inv2_size) self.add_mod(self.inv2) - self.width = self.inv1.width + self.inv2.width + self.width = 2*self.inv1.width + self.inv2.width self.height = 2*self.inv1.height self.create_layout() diff --git a/compiler/sram.py b/compiler/sram.py index 41156aee..5dd27885 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -20,9 +20,15 @@ class sram(design.design): c = reload(__import__(OPTS.control_logic)) self.mod_control_logic = getattr(c, OPTS.control_logic) - - c = reload(__import__(OPTS.dff_array)) - self.mod_dff_array = getattr(c, OPTS.dff_array) + + if num_banks>1: + # Use a buffered array for big arrays + # Also ensures we have Qbar when FF doesn't + c = reload(__import__(OPTS.dff_buf_array)) + self.mod_dff_array = getattr(c, OPTS.dff_buf_array) + else: + c = reload(__import__(OPTS.dff_array)) + self.mod_dff_array = getattr(c, OPTS.dff_array) c = reload(__import__(OPTS.bitcell)) self.mod_bitcell = getattr(c, OPTS.bitcell) @@ -200,6 +206,32 @@ class sram(design.design): self.width = self.bank_inst[1].ur().x self.height = self.control_logic_inst.uy() + + 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, 0], 1, 1) + + # 3/5/18 MRG: Cannot reference positions inside submodules because boundaries + # are not recomputed using instance placement. So, place the control logic such that it aligns + # with the top of the SRAM. + control_gap = 2*self.m3_width + control_pos = vector(-self.control_logic.width-control_gap, + self.bank.height-self.control_logic.height-3*self.supply_rail_width) + self.add_control_logic(position=control_pos) + + # Leave room for the control routes to the left of the flops + addr_pos = vector(self.control_logic_inst.lx() + 4*self.m2_pitch, + 3*self.supply_rail_pitch) + self.add_control_addr_dff(addr_pos) + + self.width = self.bank.width + self.control_logic.height + control_gap + self.height = self.bank.height + def route_shared_banks(self): """ Route the shared signals for two and four bank configurations. """ @@ -777,9 +809,10 @@ class sram(design.design): def create_multi_bank_modules(self): """ Create the multibank address flops and bank decoder """ - self.msb_address = self.mod_ms_flop_array(name="msb_address", - columns=self.num_banks/2, - word_size=self.num_banks/2) + + self.msb_address = self.mod_dff_array(name="msb_address", + rows=1, + columns=self.num_banks/2) self.add_mod(self.msb_address) if self.num_banks>2: @@ -794,9 +827,9 @@ class sram(design.design): self.add_mod(self.control_logic) # Create the address and control flops (but not the clk) - dff_size = self.addr_size + len(self.control_logic.get_inputs())-1 - self.addr_ctrl_dff = self.mod_dff_array(name="dff_array", rows=dff_size, columns=1) - self.add_mod(self.addr_ctrl_dff) + dff_size = self.addr_size + self.addr_dff = self.mod_dff_array(name="dff_array", rows=dff_size, columns=1) + self.add_mod(self.addr_dff) # Create the bank module (up to four are instantiated) self.bank = bank(word_size=self.word_size, @@ -902,9 +935,9 @@ class sram(design.design): def add_control_addr_dff(self, position): """ Add and place address and control flops """ - self.addr_ctrl_dff_inst = self.add_inst(name="address", - mod=self.addr_ctrl_dff, - offset=position) + self.addr_dff_inst = self.add_inst(name="address", + mod=self.addr_dff, + offset=position) # inputs, outputs/output/bar inputs = [] outputs = [] @@ -912,12 +945,6 @@ class sram(design.design): inputs.append("ADDR[{}]".format(i)) outputs.append("A[{}]".format(i)) - for i in self.control_logic_inputs: - if i == "clk": - continue - inputs.append(i) - outputs.append(i+"_s") - self.connect_inst(inputs + outputs + ["clk", "vdd", "gnd"]) def add_control_logic(self, position): @@ -951,31 +978,6 @@ class sram(design.design): layer="metal2", offset=self.vert_control_bus_positions[n]) - 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, 0], 1, 1) - - # 3/5/18 MRG: Cannot reference positions inside submodules because boundaries - # are not recomputed using instance placement. So, place the control logic such that it aligns - # with the top of the SRAM. - control_gap = 2*self.m3_width - control_pos = vector(-self.control_logic.width-control_gap, - self.bank.height-self.control_logic.height-3*self.supply_rail_width) - self.add_control_logic(position=control_pos) - - # Leave room for the control routes to the left of the flops - addr_pos = vector(self.control_logic_inst.lx() + 4*self.m2_pitch, - 3*self.supply_rail_pitch) - self.add_control_addr_dff(addr_pos) - - self.width = self.bank.width + self.control_logic.height + control_gap - self.height = self.bank.height - def add_single_bank_pins(self): """ Add the top-level pins for a single bank SRAM with control. @@ -985,13 +987,9 @@ class sram(design.design): self.copy_layout_pin(self.bank_inst, "DATA[{}]".format(i)) for i in range(self.addr_size): - self.copy_layout_pin(self.addr_ctrl_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i)) + self.copy_layout_pin(self.addr_dff_inst, "din[{}]".format(i),"ADDR[{}]".format(i)) - ctrl_flops = ["din[{}]".format(i) for i in range(self.addr_size,self.addr_size+3)] - for (old,new) in zip(ctrl_flops,["CSb","WEb","OEb"]): - self.copy_layout_pin(self.addr_ctrl_dff_inst, old, new) - - self.copy_layout_pin(self.addr_ctrl_dff_inst, "clk") + self.copy_layout_pin(self.addr_dff_inst, "clk") # Power ring contains the power pins @@ -1068,7 +1066,7 @@ class sram(design.design): for i in range(self.addr_size): flop_name = "dout[{}]".format(i) bank_name = "A[{}]".format(i) - flop_pin = self.addr_ctrl_dff_inst.get_pin(flop_name) + flop_pin = self.addr_dff_inst.get_pin(flop_name) bank_pin = self.bank_inst.get_pin(bank_name) flop_pos = flop_pin.center() bank_pos = vector(bank_pin.cx(),flop_pos.y) @@ -1080,24 +1078,14 @@ class sram(design.design): offset=bank_pos, rotate=90) - # Connect the output of the flops to the control pins - for i in range(3): - flop_name = "dout[{}]".format(self.addr_size+i) - ctrl_name = ["csb","web","oeb"][i] - flop_pin = self.addr_ctrl_dff_inst.get_pin(flop_name) - ctrl_pin = self.control_logic_inst.get_pin(ctrl_name) - flop_pos = flop_pin.center() - ctrl_pos = ctrl_pin.bc() - mid_pos = vector(ctrl_pos.x, flop_pos.y) - self.add_wire(("metal3","via2","metal2"),[flop_pos, mid_pos, ctrl_pos]) - self.add_via_center(layers=("metal2","via2","metal3"), - offset=flop_pos, - rotate=90) + # Connect the control pins as inputs + for n in self.control_logic_inputs + ["clk"]: + self.copy_layout_pin(self.control_logic_inst, n.lower(), n) # Connect the clock between the flops and control module # FIXME: Buffered clock should drive the flops, but then # it would change the setup time... - flop_pin = self.addr_ctrl_dff_inst.get_pin("clk") + flop_pin = self.addr_dff_inst.get_pin("clk") ctrl_pin = self.control_logic_inst.get_pin("clk") flop_pos = flop_pin.uc() ctrl_pos = ctrl_pin.bc() @@ -1111,7 +1099,7 @@ class sram(design.design): """ Route vdd for the control and dff array """ # Route the vdd rails to the LEFT - modules = [ self.control_logic_inst, self.addr_ctrl_dff_inst] + modules = [ self.control_logic_inst, self.addr_dff_inst] for inst in modules: for vdd_pin in inst.get_pins("vdd"): if vdd_pin.layer != "metal1": @@ -1140,7 +1128,7 @@ class sram(design.design): """ Route gnd for the control and dff array """ # Route the gnd rails to the LEFT - modules = [ self.control_logic_inst, self.addr_ctrl_dff_inst] + modules = [ self.control_logic_inst, self.addr_dff_inst] for inst in modules: for gnd_pin in inst.get_pins("gnd"): if gnd_pin.layer != "metal1": diff --git a/compiler/tests/19_multi_bank_test.py b/compiler/tests/19_multi_bank_test.py index ef4c38cd..94221ba4 100644 --- a/compiler/tests/19_multi_bank_test.py +++ b/compiler/tests/19_multi_bank_test.py @@ -33,10 +33,9 @@ class multi_bank_test(openram_test): a = bank.bank(word_size=4, num_words=64, words_per_row=4, num_banks=2, name="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="bank4") - # self.local_check(a) + debug.info(1, "Eight way column mux") + a = bank.bank(word_size=2, num_words=128, words_per_row=8, num_banks=2, name="bank4") + self.local_check(a) OPTS.check_lvsdrc = True globals.end_openram()