From b867e163a60389f99fd092d560d224db654fab75 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 14 Mar 2018 17:30:41 -0700 Subject: [PATCH] Move label pins to center like layout pins. Rework of control logic with vertical poly. Passes DRC/LVS. Single bank passing DRC. --- compiler/base/hierarchy_layout.py | 2 +- compiler/base/hierarchy_spice.py | 18 + compiler/modules/bank.py | 26 +- compiler/modules/control_logic.py | 770 +++++++++++++--------------- compiler/modules/replica_bitline.py | 202 +++----- compiler/sram.py | 154 ++++-- 6 files changed, 560 insertions(+), 612 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 88248c1f..e75f1be3 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -282,7 +282,7 @@ class layout(lef.lef): height=height) self.add_label(text=text, layer=layer, - offset=offset) + offset=offset+vector(0.5*width,0.5*height)) def add_label(self, text, layer, offset=[0,0],zoom=-1): diff --git a/compiler/base/hierarchy_spice.py b/compiler/base/hierarchy_spice.py index 71921412..d41ae0d9 100644 --- a/compiler/base/hierarchy_spice.py +++ b/compiler/base/hierarchy_spice.py @@ -60,6 +60,24 @@ class spice(verilog.verilog): else: return self.pin_type[name] + def get_inputs(self): + """ These use pin types to determine pin lists. These + may be over-ridden by submodules that didn't use pin directions yet.""" + input_list = [] + for pin in self.pins: + if self.pin_type[pin]=="INPUT": + input_list.append(pin) + return input_list + + def get_outputs(self): + """ These use pin types to determine pin lists. These + may be over-ridden by submodules that didn't use pin directions yet.""" + output_list = [] + for pin in self.pins: + if self.pin_type[pin]=="OUTPUT": + output_list.append(pin) + return output_list + def add_mod(self, mod): """Adds a subckt/submodule to the subckt hierarchy""" diff --git a/compiler/modules/bank.py b/compiler/modules/bank.py index 8eb28893..ab3601e8 100644 --- a/compiler/modules/bank.py +++ b/compiler/modules/bank.py @@ -74,17 +74,19 @@ class bank(design.design): def add_pins(self): """ Adding pins for Bank module""" for i in range(self.word_size): - self.add_pin("DATA[{0}]".format(i)) + self.add_pin("DATA[{0}]".format(i),"INOUT") for i in range(self.addr_size): - self.add_pin("A[{0}]".format(i)) + self.add_pin("A[{0}]".format(i),"INPUT") # For more than one bank, we have a bank select and name # the signals gated_*. if self.num_banks > 1: - self.add_pin("bank_sel") + self.add_pin("bank_sel","INPUT") for pin in ["s_en","w_en","tri_en_bar","tri_en", - "clk_bar","clk_buf","vdd","gnd"]: - self.add_pin(pin) + "clk_buf_bar","clk_buf"]: + self.add_pin(pin,"INPUT") + self.add_pin("vdd","POWER") + self.add_pin("gnd","GROUND") def route_layout(self): """ Create routing amoung the modules """ @@ -151,7 +153,7 @@ 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.input_control_signals = ["clk_buf", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"] + self.input_control_signals = ["clk_buf", "tri_en_bar", "tri_en", "clk_buf_bar", "w_en", "s_en"] # 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] @@ -259,7 +261,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([self.prefix+"clk_bar", "vdd"]) + temp.extend([self.prefix+"clk_buf_bar", "vdd"]) self.connect_inst(temp) def add_column_mux_array(self): @@ -337,7 +339,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([self.prefix+"clk_bar", "vdd", "gnd"]) + temp.extend([self.prefix+"clk_buf_bar", "vdd", "gnd"]) self.connect_inst(temp) def add_tri_gate_array(self): @@ -534,8 +536,8 @@ class bank(design.design): # Add a vdd and gnd power rail above the array self.max_point += self.supply_rail_pitch + self.supply_rail_width - self.height = self.max_point - self.min_point - self.width = self.right_vdd_x_offset - self.left_gnd_x_offset + self.supply_rail_width + self.height = ur.y - ll.y + 4*self.supply_rail_pitch + self.width = ur.x - ll.x + 4*self.supply_rail_pitch @@ -894,10 +896,10 @@ class bank(design.design): # 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_bar", self.msf_data_in_inst.get_pin("clk").lc())) + connection.append((self.prefix+"clk_buf_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+"clk_buf_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())) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 354c33f5..3e52a6f3 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -6,7 +6,6 @@ import contact from pinv import pinv from pnand2 import pnand2 from pnand3 import pnand3 -from pnor2 import pnor2 from pinvbuf import pinvbuf import math from vector import vector @@ -28,39 +27,37 @@ class control_logic(design.design): def create_layout(self): """ Create layout and route between modules """ - self.create_modules() self.setup_layout_offsets() + self.create_modules() + self.add_rails() self.add_modules() - #self.add_routing() + self.add_routing() + + def create_modules(self): """ add all the required modules """ - 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 + rails: - self.add_pin(pin) + for pin in self.input_list + ["clk"]: + self.add_pin(pin,"INPUT") + for pin in self.output_list: + self.add_pin(pin,"OUTPUT") + self.add_pin("vdd","POWER") + self.add_pin("gnd","GROUND") self.nand2 = pnand2() self.add_mod(self.nand2) self.nand3 = pnand3() self.add_mod(self.nand3) - self.nor2 = pnor2() - self.add_mod(self.nor2) # Special gates: inverters for buffering self.clkbuf = pinvbuf(4,16) self.add_mod(self.clkbuf) self.inv = self.inv1 = pinv(1) self.add_mod(self.inv1) - # self.inv2 = pinv(2) - # self.add_mod(self.inv2) - # self.inv4 = pinv(4) - # self.add_mod(self.inv4) - # self.inv8 = pinv(8) - # self.add_mod(self.inv8) - # self.inv16 = pinv(16) - # self.add_mod(self.inv16) + self.inv2 = pinv(2) + self.add_mod(self.inv2) + self.inv8 = pinv(8) + self.add_mod(self.inv8) c = reload(__import__(OPTS.replica_bitline)) replica_bitline = getattr(c, OPTS.replica_bitline) @@ -75,7 +72,7 @@ class control_logic(design.design): def setup_layout_offsets(self): """ Setup layout offsets, determine the size of the busses etc """ # These aren't for instantiating, but we use them to get the dimensions - self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height) + #self.poly_contact_offset = vector(0.5*contact.poly.width,0.5*contact.poly.height) # M1/M2 routing pitch is based on contacted pitch self.m1_pitch = max(contact.m1m2.width,contact.m1m2.height) + max(drc["metal1_to_metal1"],drc["metal2_to_metal2"]) @@ -83,102 +80,98 @@ class control_logic(design.design): # Have the cell gap leave enough room to route an M2 wire. # Some cells may have pwell/nwell spacing problems too when the wells are different heights. - self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"]) + #self.cell_gap = max(self.m2_pitch,drc["pwell_to_nwell"]) - # First RAIL Parameters: gnd, oe, oebar, cs, we, clk_buf, clk_bar - self.rail_1_start_x = 0 - self.num_rails_1 = 7 - self.rail_1_names = ["clk_buf", "gnd", "cs", "we", "vdd", "oe", "clk_bar"] - self.overall_rail_1_gap = (self.num_rails_1 + 2) * self.m2_pitch - self.rail_1_x_offsets = {} + self.input_list =["web","csb","oeb"] + self.input_width = len(self.input_list)*self.m2_pitch + self.input_bar_list = ["clk_buf_bar", "we", "cs", "oe"] + self.input_bar_width = len(self.input_bar_list)*self.m2_pitch + self.output_list = ["s_en", "w_en", "tri_en", "tri_en_bar", "clk_buf_bar", "clk_buf"] + self.supply_list = ["vdd", "gnd"] + self.rail_width = len(self.input_list)*len(self.output_list)*self.m2_pitch + self.rail_x_offsets = {} # GAP between main control and replica bitline - self.replica_bitline_gap = 2*self.m2_pitch - - - + #self.replica_bitline_gap = 2*self.m2_pitch + + def add_rails(self): + """ Add the input signal tracks and their inverted tracks """ + height = 4*self.inv1.height - self.m2_pitch + for i in range(len(self.input_list)): + name = self.input_list[i] + offset = vector(i*self.m2_pitch,0) + self.add_layout_pin(text=name, + layer="metal2", + offset=offset, + width=drc["minwidth_metal2"], + height=height) + self.rail_x_offsets[name]=offset.x + 0.5*drc["minwidth_metal2"] # center offset + + height = 6*self.inv1.height - self.m2_pitch + for i in range(len(self.input_bar_list)): + name = self.input_bar_list[i] + offset = vector(i*self.m2_pitch + self.input_width + self.inv1.width, 0) + # just for LVS correspondence... + self.add_label_pin(text=name, + layer="metal2", + offset=offset, + width=drc["minwidth_metal2"], + height=height) + self.rail_x_offsets[name]=offset.x + 0.5*drc["minwidth_metal2"] # center offset + + def add_modules(self): """ Place all the modules """ + self.add_input_inv() - self.add_clk_buffer(row=0) # 0 and 1st row - self.add_oe_row(row=2) - self.add_sen_row(row=3) - self.add_we_row(row=4) + self.add_clk_buffer(row=0) + self.add_we_row(row=2) + self.add_trien_row(row=3) + self.add_trien_bar_row(row=4) + self.add_rblk_row(row=5) + self.add_sen_row(row=6) + self.add_rbl(row=7) - #self.add_control_routing() - - self.add_rbl(row=5) - - self.add_layout_pins() self.add_lvs_correspondence_points() - self.height = max(self.replica_bitline.width, 4 * self.inv1.height) - self.width = self.replica_bitline_offset.x + self.replica_bitline.height - + self.height = self.rbl_inst.uy() + # Find max of logic rows + max_row = max(self.row_rblk_end_x, self.row_trien_end_x, self.row_trien_bar_end_x, + self.row_sen_end_x, self.row_we_end_x, self.row_we_end_x) + # Max of modules or logic rows + self.width = max(self.clkbuf.rx(), self.rbl_inst.rx(), max_row) def add_routing(self): """ Routing between modules """ - #self.add_clk_routing() - self.add_trien_routing() - self.add_rblk_routing() - self.add_wen_routing() - self.add_sen_routing() - self.add_output_routing() - self.add_supply_routing() + self.route_input_inv() + self.route_trien() + self.route_trien_bar() + self.route_rblk() + self.route_wen() + self.route_sen() + self.route_clk() + self.route_supply() def add_rbl(self,row): """ Add the replica bitline """ - y_off = row * self.inv1.height + y_off = row * self.inv1.height + 2*self.m1_pitch # Add the RBL above the rows # Add to the right of the control rows and routing channel self.replica_bitline_offset = vector(0, y_off) - self.rbl=self.add_inst(name="replica_bitline", - mod=self.replica_bitline, - offset=self.replica_bitline_offset) + self.rbl_inst=self.add_inst(name="replica_bitline", + mod=self.replica_bitline, + offset=self.replica_bitline_offset) self.connect_inst(["rblk", "pre_s_en", "vdd", "gnd"]) - def add_layout_pins(self): - """ Add the input/output layout pins. """ - - # # Top to bottom: CS WE OE signal groups - # pin_set = ["oeb","csb","web"] - # for (i,pin_name) in zip(range(3),pin_set): - # subpin_name="din[{}]".format(i) - # pins=self.msf_inst.get_pins(subpin_name) - # for pin in pins: - # if pin.layer=="metal3": - # self.add_layout_pin(text=pin_name, - # layer="metal3", - # offset=pin.ll(), - # width=pin.width(), - # height=pin.height()) - - pin=self.clkbuf.get_pin("A") - self.add_layout_pin(text="clk", - layer="metal1", - offset=pin.ll().scale(0,1), - width=pin.rx(), - height=pin.height()) - - # pin=self.clkbuf.get_pin("gnd") - # self.add_layout_pin(text="gnd", - # layer="metal1", - # offset=pin.ll(), - # width=self.width) - - # pin=self.clkbuf.get_pin("vdd") - # self.add_layout_pin(text="vdd", - # layer="metal1", - # offset=pin.ll(), - # width=self.width) def add_clk_buffer(self,row): """ Add the multistage clock buffer below the control flops """ + x_off = self.input_width + self.inv1.width + self.input_bar_width y_off = row*self.inv1.height if row % 2: y_off += self.clkbuf.height @@ -186,47 +179,17 @@ class control_logic(design.design): else: mirror="R0" - clkbuf_offset = vector(0,y_off) - self.clkbuf_inst = self.add_inst(name="clkbuf", - mod=self.clkbuf, - offset=clkbuf_offset) + clkbuf_offset = vector(x_off,y_off) + self.clkbuf = self.add_inst(name="clkbuf", + mod=self.clkbuf, + offset=clkbuf_offset) - self.connect_inst(["clk","clk_bar","clk","vdd","gnd"]) - - # # 4 stage clock buffer - # self.clk_inv1_offset = vector(self.rail_1_start_x, y_off) - # self.clk_inv1=self.add_inst(name="inv_clk1_bar", - # mod=self.inv2, - # offset=self.clk_inv1_offset) - # self.connect_inst(["clk", "clk1_bar", "vdd", "gnd"]) - # self.clk_inv2_offset = self.clk_inv1_offset + vector(self.inv2.width,0) - # self.clk_inv2=self.add_inst(name="inv_clk2", - # mod=self.inv4, - # offset=self.clk_inv2_offset) - # self.connect_inst(["clk1_bar", "clk2", "vdd", "gnd"]) - # self.clk_bar_offset = self.clk_inv2_offset + vector(self.inv4.width,0) - # self.clk_bar=self.add_inst(name="inv_clk_bar", - # mod=self.inv8, - # offset=self.clk_bar_offset) - # self.connect_inst(["clk2", "clk_bar", "vdd", "gnd"]) - # self.clk_buf_offset = self.clk_bar_offset + vector(self.inv8.width,0) - # self.clk_buf=self.add_inst(name="inv_clk_buf", - # mod=self.inv16, - # offset=self.clk_buf_offset) - # self.connect_inst(["clk_bar", "clk_buf", "vdd", "gnd"]) - - # # Connect between the inverters - # self.add_path("metal1", [self.clk_inv1.get_pin("Z").center(), - # self.clk_inv2.get_pin("A").center()]) - # self.add_path("metal1", [self.clk_inv2.get_pin("Z").center(), - # self.clk_bar.get_pin("A").center()]) - # self.add_path("metal1", [self.clk_bar.get_pin("Z").center(), - # self.clk_buf.get_pin("A").center()]) + self.connect_inst(["clk","clk_buf_bar","clk_buf","vdd","gnd"]) def add_rblk_row(self,row): - x_off = 0 + x_off = self.input_width + self.inv1.width + self.input_bar_width y_off = row*self.inv1.height if row % 2: y_off += self.inv1.height @@ -234,13 +197,14 @@ class control_logic(design.design): else: mirror="R0" - # input: OE, clk_bar,CS output: rblk_bar + + # input: OE, clk_buf_bar,CS output: rblk_bar self.rblk_bar_offset = vector(x_off, y_off) self.rblk_bar=self.add_inst(name="nand3_rblk_bar", mod=self.nand3, offset=self.rblk_bar_offset, mirror=mirror) - self.connect_inst(["clk_bar", "oe", "cs", "rblk_bar", "vdd", "gnd"]) + self.connect_inst(["clk_buf_bar", "oe", "cs", "rblk_bar", "vdd", "gnd"]) x_off += self.nand3.width # input: rblk_bar, output: rblk @@ -250,12 +214,14 @@ class control_logic(design.design): offset=self.rblk_offset, mirror=mirror) self.connect_inst(["rblk_bar", "rblk", "vdd", "gnd"]) - #x_off += self.inv1.width + x_off += self.inv1.width self.row_rblk_end_x = x_off def add_sen_row(self,row): - x_off = 0 + """ The sense enable buffer gets placed to the far right of the + row. """ + x_off = self.replica_bitline.width - self.inv8.width y_off = row*self.inv1.height if row % 2: y_off += self.inv1.height @@ -267,25 +233,23 @@ class control_logic(design.design): # input: input: pre_s_en_bar, output: s_en self.s_en_offset = vector(x_off, y_off) self.s_en=self.add_inst(name="inv_s_en", - mod=self.inv1, + mod=self.inv8, offset=self.s_en_offset, mirror=mirror) self.connect_inst(["pre_s_en_bar", "s_en", "vdd", "gnd"]) - x_off += self.inv1.width - + x_off -= self.inv2.width # input: pre_s_en, output: pre_s_en_bar self.pre_s_en_bar_offset = vector(x_off, y_off) self.pre_s_en_bar=self.add_inst(name="inv_pre_s_en_bar", - mod=self.inv1, + mod=self.inv2, offset=self.pre_s_en_bar_offset, mirror=mirror) self.connect_inst(["pre_s_en", "pre_s_en_bar", "vdd", "gnd"]) - #x_off += self.inv1.width - - self.row_sen_end_x = x_off - def add_oe_row(self, row): - x_off = 0 + self.row_sen_end_x = self.replica_bitline.width + + def add_trien_row(self, row): + x_off = self.input_width + self.inv1.width + self.input_bar_width y_off = row*self.inv1.height if row % 2: y_off += self.inv1.height @@ -293,56 +257,147 @@ class control_logic(design.design): else: mirror="R0" - # input: oe output: oe_bar - self.oe_inv_offset = vector(x_off, y_off) - self.oe_inv=self.add_inst(name="oe_inv", - mod=self.inv1, - offset=self.oe_inv_offset, - mirror=mirror) - self.connect_inst(["oe", "oe_bar", "vdd", "gnd"]) - x_off += self.inv1.width + self.cell_gap - - # input: clk_buf, OE_bar output: tri_en + x_off += self.nand2.width + + # BUFFER INVERTERS FOR TRI_EN self.tri_en_offset = vector(x_off, y_off) - self.tri_en=self.add_inst(name="nor2_tri_en", - mod=self.nor2, + self.tri_en=self.add_inst(name="inv_tri_en1", + mod=self.inv2, offset=self.tri_en_offset, mirror=mirror) - self.connect_inst(["clk_buf", "oe_bar", "tri_en", "vdd", "gnd"]) - x_off += self.nor2.width + self.cell_gap - - # input: OE, clk_bar output: tri_en_bar - self.tri_en_bar_offset = vector(x_off,y_off) - self.tri_en_bar=self.add_inst(name="nand2_tri_en", - mod=self.nand2, - offset=self.tri_en_bar_offset, - mirror=mirror) - self.connect_inst(["clk_bar", "oe", "tri_en_bar", "vdd", "gnd"]) - #x_off += self.nand2.width + self.connect_inst(["pre_tri_en_bar", "pre_tri_en1", "vdd", "gnd"]) + x_off += self.inv2.width + + self.tri_en_buf1_offset = vector(x_off, y_off) + self.tri_en_buf1=self.add_inst(name="tri_en_buf1", + mod=self.inv2, + offset=self.tri_en_buf1_offset, + mirror=mirror) + self.connect_inst(["pre_tri_en1", "pre_tri_en_bar1", "vdd", "gnd"]) + x_off += self.inv2.width + + self.tri_en_buf2_offset = vector(x_off, y_off) + self.tri_en_buf2=self.add_inst(name="tri_en_buf2", + mod=self.inv8, + offset=self.tri_en_buf2_offset, + mirror=mirror) + self.connect_inst(["pre_tri_en_bar1", "tri_en", "vdd", "gnd"]) + x_off += self.inv8.width #x_off += self.inv1.width + self.cell_gap - self.row_oe_end_x = x_off - - def add_we_row(self,row): - x_off = 0 + self.row_trien_end_x = x_off + + + def add_trien_bar_row(self, row): + x_off = self.input_width + self.inv1.width + self.input_bar_width y_off = row*self.inv1.height if row % 2: y_off += self.inv1.height mirror="MX" else: mirror="R0" + + + # input: OE, clk_buf_bar output: tri_en_bar + self.tri_en_bar_offset = vector(x_off,y_off) + self.tri_en_bar=self.add_inst(name="nand2_tri_en", + mod=self.nand2, + offset=self.tri_en_bar_offset, + mirror=mirror) + self.connect_inst(["clk_buf_bar", "oe", "pre_tri_en_bar", "vdd", "gnd"]) + x_off += self.nand2.width + + # BUFFER INVERTERS FOR TRI_EN + self.tri_en_bar_buf1_offset = vector(x_off, y_off) + self.tri_en_bar_buf1=self.add_inst(name="tri_en_bar_buf1", + mod=self.inv2, + offset=self.tri_en_bar_buf1_offset, + mirror=mirror) + self.connect_inst(["pre_tri_en_bar", "pre_tri_en2", "vdd", "gnd"]) + x_off += self.inv2.width + + self.tri_en_bar_buf2_offset = vector(x_off, y_off) + self.tri_en_bar_buf2=self.add_inst(name="tri_en_bar_buf2", + mod=self.inv8, + offset=self.tri_en_bar_buf2_offset, + mirror=mirror) + self.connect_inst(["pre_tri_en2", "tri_en_bar", "vdd", "gnd"]) + x_off += self.inv8.width - # input: WE, clk_bar, CS output: w_en_bar + #x_off += self.inv1.width + self.cell_gap + + + + self.row_trien_bar_end_x = x_off + + def route_input_inv(self): + """ Route the input inverters """ + self.connect_rail_from_left(self.cs_inv,"A","csb") + self.connect_rail_from_left(self.we_inv,"A","web") + self.connect_rail_from_left(self.oe_inv,"A","oeb") + + self.connect_rail_from_right(self.cs_inv,"Z","cs") + self.connect_rail_from_right(self.we_inv,"Z","we") + self.connect_rail_from_right(self.oe_inv,"Z","oe") + + + def add_input_inv(self): + """ Add the three input inverters """ + y_off = 0 + mirror = "R0" + + # input: csb output: cs + self.cs_inv_offset = vector(self.input_width, y_off) + self.cs_inv=self.add_inst(name="cs_inv", + mod=self.inv1, + offset=self.cs_inv_offset, + mirror=mirror) + self.connect_inst(["csb", "cs", "vdd", "gnd"]) + y_off += 2*self.inv1.height + mirror = "MX" + + # input: oeb output: oe + self.oe_inv_offset = vector(self.input_width, y_off) + self.oe_inv=self.add_inst(name="oe_inv", + mod=self.inv1, + offset=self.oe_inv_offset, + mirror=mirror) + self.connect_inst(["oeb", "oe", "vdd", "gnd"]) + + # Skip a row to prevent via conflict + y_off += 2*self.inv1.height + mirror = "MX" + + # input: web output: we + self.we_inv_offset = vector(self.input_width, y_off) + self.we_inv=self.add_inst(name="we_inv", + mod=self.inv1, + offset=self.we_inv_offset, + mirror=mirror) + self.connect_inst(["web", "we", "vdd", "gnd"]) + + + def add_we_row(self,row): + x_off = self.input_width + self.inv1.width + self.input_bar_width + y_off = row*self.inv1.height + if row % 2: + y_off += self.inv1.height + mirror="MX" + else: + mirror="R0" + + + # input: WE, clk_buf_bar, CS output: w_en_bar self.w_en_bar_offset = vector(x_off, y_off) self.w_en_bar=self.add_inst(name="nand3_w_en_bar", mod=self.nand3, offset=self.w_en_bar_offset, mirror=mirror) - self.connect_inst(["clk_bar", "cs", "we", "w_en_bar", "vdd", "gnd"]) + self.connect_inst(["clk_buf_bar", "cs", "we", "w_en_bar", "vdd", "gnd"]) x_off += self.nand3.width # input: w_en_bar, output: pre_w_en @@ -356,94 +411,56 @@ class control_logic(design.design): x_off += self.inv1.width # BUFFER INVERTERS FOR W_EN - # FIXME: Can we remove these two invs and size the previous one? self.pre_w_en_bar_offset = vector(x_off, y_off) self.pre_w_en_bar=self.add_inst(name="inv_pre_w_en_bar", - mod=self.inv1, + mod=self.inv2, offset=self.pre_w_en_bar_offset, mirror=mirror) self.connect_inst(["pre_w_en", "pre_w_en_bar", "vdd", "gnd"]) - x_off += self.inv1.width + x_off += self.inv2.width self.w_en_offset = vector(x_off, y_off) self.w_en=self.add_inst(name="inv_w_en2", - mod=self.inv1, + mod=self.inv8, offset=self.w_en_offset, mirror=mirror) self.connect_inst(["pre_w_en_bar", "w_en", "vdd", "gnd"]) - #x_off += self.inv1.width + x_off += self.inv8.width self.row_we_end_x = x_off - # def add_control_routing(self): - # """ Route the vertical rails for internal control signals """ - # control_rail_height = 3*self.inv1.height - - # 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_buf", "clk_bar", "vdd", "gnd"]: - # self.add_layout_pin(text=self.rail_1_names[i], - # layer="metal2", - # offset=offset, - # width=drc["minwidth_metal2"], - # height=control_rail_height) - # else: - # # just for LVS correspondence... - # self.add_label_pin(text=self.rail_1_names[i], - # layer="metal2", - # offset=offset, - # width=drc["minwidth_metal2"], - # height=control_rail_height) - # self.rail_1_x_offsets[self.rail_1_names[i]]=offset.x + 0.5*drc["minwidth_metal2"] # center offset - - # # # Connect the gnd and vdd of the control - # # gnd_pins = self.msf_inst.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(("metal3","via2","metal2"),[gnd_pin, gnd_rail_position]) - # # self.add_via_center(layers=("metal2","via2","metal3"), - # # offset=gnd_pin, - # # rotate=90) - # # self.add_via_center(layers=("metal2","via2","metal3"), - # # offset=gnd_rail_position, - # # rotate=90) - - # # vdd_pins = self.msf_inst.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]) - - - - def add_rblk_routing(self): + def route_rblk(self): """ Connect the logic for the rblk generation """ - self.connect_rail_from_right(self.rblk_bar,"A","clk_bar") - self.connect_rail_from_right(self.rblk_bar,"B","oe") - self.connect_rail_from_right(self.rblk_bar,"C","cs") + self.connect_rail_from_left(self.rblk_bar,"A","clk_buf_bar") + self.connect_rail_from_left(self.rblk_bar,"B","oe") + self.connect_rail_from_left(self.rblk_bar,"C","cs") # Connect the NAND3 output to the inverter # The pins are assumed to extend all the way to the cell edge - rblk_bar_pin = self.rblk_bar.get_pin("Z").center() - inv_in_pin = self.rblk.get_pin("A").center() - mid1 = vector(inv_in_pin.x,rblk_bar_pin.y) - self.add_path("metal1",[rblk_bar_pin,mid1,inv_in_pin]) + rblk_bar_pos = self.rblk_bar.get_pin("Z").center() + inv_in_pos = self.rblk.get_pin("A").center() + mid1 = vector(inv_in_pos.x,rblk_bar_pos.y) + self.add_path("metal1",[rblk_bar_pos,mid1,inv_in_pos]) # Connect the output to the RBL - rblk_pin = self.rblk.get_pin("Z").center() - rbl_in_pin = self.rbl.get_pin("en").center() - mid1 = vector(rblk_pin.x,rbl_in_pin.y) - self.add_path("metal1",[rblk_pin,mid1,rbl_in_pin]) + rblk_pos = self.rblk.get_pin("Z").center() + rbl_in_pos = self.rbl_inst.get_pin("en").center() + mid1 = vector(rbl_in_pos.x,rblk_pos.y) + self.add_wire(("metal3","via2","metal2"),[rblk_pos,mid1,rbl_in_pos]) + self.add_via_center(layers=("metal1","via1","metal2"), + offset=rblk_pos, + rotate=90) + self.add_via_center(layers=("metal2","via2","metal3"), + offset=rblk_pos, + rotate=90) + + def connect_rail_from_right(self,inst, pin, rail): """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """ in_pos = inst.get_pin(pin).center() - rail_pos = vector(self.rail_1_x_offsets[rail], in_pos.y) + rail_pos = vector(self.rail_x_offsets[rail], in_pos.y) self.add_wire(("metal1","via1","metal2"),[in_pos, rail_pos]) self.add_via_center(layers=("metal1","via1","metal2"), offset=rail_pos, @@ -451,8 +468,8 @@ class control_logic(design.design): def connect_rail_from_right_m2m3(self,inst, pin, rail): """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """ - in_pos = inst.get_pin(pin).center() - vector(contact.m1m2.height,0) - rail_pos = vector(self.rail_1_x_offsets[rail], in_pos.y) + in_pos = inst.get_pin(pin).center() + rail_pos = vector(self.rail_x_offsets[rail], in_pos.y) self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos]) # Bring it up to M2 for M2/M3 routing self.add_via_center(layers=("metal1","via1","metal2"), @@ -468,20 +485,17 @@ class control_logic(design.design): def connect_rail_from_left(self,inst, pin, rail): """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """ - in_pos = inst.get_pin(pin).rc() - rail_pos = vector(self.rail_1_x_offsets[rail], in_pos.y) + in_pos = inst.get_pin(pin).lc() + rail_pos = vector(self.rail_x_offsets[rail], in_pos.y) self.add_wire(("metal1","via1","metal2"),[in_pos, rail_pos]) self.add_via_center(layers=("metal1","via1","metal2"), - offset=in_pos, - rotate=90) - self.add_via_center(layers=("metal2","via2","metal3"), offset=rail_pos, rotate=90) def connect_rail_from_left_m2m3(self,inst, pin, rail): """ Helper routine to connect an unrotated/mirrored oriented instance to the rails """ - in_pos = inst.get_pin(pin).rc() - rail_pos = vector(self.rail_1_x_offsets[rail], in_pos.y) + in_pos = inst.get_pin(pin).lc() + rail_pos = vector(self.rail_x_offsets[rail], in_pos.y) self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos]) self.add_via_center(layers=("metal2","via2","metal3"), offset=in_pos, @@ -491,206 +505,148 @@ class control_logic(design.design): rotate=90) - def add_wen_routing(self): - self.connect_rail_from_right(self.w_en_bar,"A","clk_bar") - self.connect_rail_from_right(self.w_en_bar,"B","cs") - self.connect_rail_from_right(self.w_en_bar,"C","we") + def route_wen(self): + self.connect_rail_from_left(self.w_en_bar,"A","clk_buf_bar") + self.connect_rail_from_left(self.w_en_bar,"B","cs") + self.connect_rail_from_left(self.w_en_bar,"C","we") # Connect the NAND3 output to the inverter # The pins are assumed to extend all the way to the cell edge - w_en_bar_pin = self.w_en_bar.get_pin("Z").center() - inv_in_pin = self.pre_w_en.get_pin("A").center() - mid1 = vector(inv_in_pin.x,w_en_bar_pin.y) - self.add_path("metal1",[w_en_bar_pin,mid1,inv_in_pin]) + w_en_bar_pos = self.w_en_bar.get_pin("Z").center() + inv_in_pos = self.pre_w_en.get_pin("A").center() + mid1 = vector(inv_in_pos.x,w_en_bar_pos.y) + self.add_path("metal1",[w_en_bar_pos,mid1,inv_in_pos]) self.add_path("metal1",[self.pre_w_en.get_pin("Z").center(), self.pre_w_en_bar.get_pin("A").center()]) self.add_path("metal1",[self.pre_w_en_bar.get_pin("Z").center(), self.w_en.get_pin("A").center()]) - - def add_trien_routing(self): - self.connect_rail_from_right(self.oe_inv,"A","oe") + self.connect_output(self.w_en, "Z", "w_en") + + def route_trien(self): - self.connect_rail_from_right(self.tri_en,"A","clk_buf") - oe_inv_out_pos = self.oe_inv.get_pin("Z").ul() - in_pos = self.tri_en.get_pin("B").rc() - mid1 = vector(oe_inv_out_pos.x,in_pos.y) - self.add_path("metal1",[oe_inv_out_pos,mid1,in_pos]) - - self.connect_rail_from_right_m2m3(self.tri_en_bar,"A","clk_bar") - self.connect_rail_from_right_m2m3(self.tri_en_bar,"B","oe") + # Connect the NAND2 output to the buffer + tri_en_bar_pos = self.tri_en_bar.get_pin("Z").center() + inv_in_pos = self.tri_en.get_pin("A").center() + mid1 = vector(tri_en_bar_pos.x,inv_in_pos.y) + self.add_wire(("metal1","via1","metal2"),[tri_en_bar_pos,mid1,inv_in_pos]) + + # Connect the INV output to the buffer + tri_en_pos = self.tri_en.get_pin("Z").center() + inv_in_pos = self.tri_en_buf1.get_pin("A").center() + mid_xoffset = 0.5*(tri_en_pos.x + inv_in_pos.x) + mid1 = vector(mid_xoffset,tri_en_pos.y) + mid2 = vector(mid_xoffset,inv_in_pos.y) + self.add_path("metal1",[tri_en_pos,mid1,mid2,inv_in_pos]) + + self.add_path("metal1",[self.tri_en_buf1.get_pin("Z").center(), self.tri_en_buf2.get_pin("A").center()]) + + self.connect_output(self.tri_en_buf2, "Z", "tri_en") + + def route_trien_bar(self): + + self.connect_rail_from_left(self.tri_en_bar,"A","clk_buf_bar") + self.connect_rail_from_left(self.tri_en_bar,"B","oe") + # Connect the NAND2 output to the buffer + tri_en_bar_pos = self.tri_en_bar.get_pin("Z").center() + inv_in_pos = self.tri_en_bar_buf1.get_pin("A").center() + mid_xoffset = 0.5*(tri_en_bar_pos.x + inv_in_pos.x) + mid1 = vector(mid_xoffset,tri_en_bar_pos.y) + mid2 = vector(mid_xoffset,inv_in_pos.y) + self.add_path("metal1",[tri_en_bar_pos,mid1,mid2,inv_in_pos]) + self.add_path("metal1",[self.tri_en_bar_buf1.get_pin("Z").center(), self.tri_en_bar_buf2.get_pin("A").center()]) + + self.connect_output(self.tri_en_bar_buf2, "Z", "tri_en_bar") - def add_sen_routing(self): - rbl_out_pos = self.rbl.get_pin("out").ul() - in_pos = self.pre_s_en_bar.get_pin("A").rc() + def route_sen(self): + rbl_out_pos = self.rbl_inst.get_pin("out").bc() + in_pos = self.pre_s_en_bar.get_pin("A").lc() mid1 = vector(rbl_out_pos.x,in_pos.y) - self.add_path("metal1",[rbl_out_pos,mid1,in_pos]) + self.add_wire(("metal1","via1","metal2"),[rbl_out_pos,mid1,in_pos]) #s_en_pos = self.s_en.get_pin("Z").lc() self.add_path("metal1",[self.pre_s_en_bar.get_pin("Z").center(), self.s_en.get_pin("A").center()]) - - # def add_clk_routing(self): - # """ Route the clk and clk_bar signal internally """ - # # clk_buf - # clk_buf_pos = self.clk_buf.get_pin("Z").rc() - # clk_buf_rail_position = vector(self.rail_1_x_offsets["clk_buf"], clk_buf_pos.y) - # self.add_wire(("metal1","via1","metal2"),[clk_buf_pos, clk_buf_rail_position]) - # self.add_via_center(layers=("metal1","via1","metal2"), - # offset=clk_buf_rail_position, - # rotate=90) - - # # clk_bar, routes over the clock buffer vdd rail - # clk_pin = self.clk_bar.get_pin("Z") - # vdd_pin = self.clk_bar.get_pin("vdd") - # # move the output pin up to metal2 - # self.add_via_center(layers=("metal1","via1","metal2"), - # offset=clk_pin.rc(), - # rotate=90) - # # route to a position over the supply rail - # in_pos = vector(clk_pin.rx(), vdd_pin.cy()) - # self.add_path("metal2",[clk_pin.rc(), in_pos]) - # # connect that position to the control bus - # rail_pos = vector(self.rail_1_x_offsets["clk_bar"], in_pos.y) - # self.add_wire(("metal3","via2","metal2"),[in_pos, rail_pos]) - # self.add_via_center(layers=("metal2","via2","metal3"), - # offset=in_pos, - # rotate=90) - # self.add_via_center(layers=("metal2","via2","metal3"), - # offset=rail_pos, - # rotate=90) + self.connect_output(self.s_en, "Z", "s_en") - # # clk_buf to msf control flops - # msf_clk_pos = self.msf_inst.get_pin("clk").bc() - # mid1 = msf_clk_pos - vector(0,self.m2_pitch) - # clk_buf_rail_position = vector(self.rail_1_x_offsets["clk_buf"], mid1.y) - # # route on M2 to allow vdd connection - # self.add_wire(("metal2","via1","metal1"),[msf_clk_pos, mid1, clk_buf_rail_position]) + def route_clk(self): + """ Route the clk and clk_buf_bar signal internally """ - def connect_right_pin_to_output_pin(self, inst, pin_name, out_name): - """ Create an output pin on the bottom side from the pin of a given instance. """ - out_pin = inst.get_pin(pin_name) - # shift it to the right side of the cell - right_pos=out_pin.center() + vector(inst.rx()-out_pin.cx(),0) - self.add_path("metal1",[out_pin.center(), right_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=right_pos) - self.add_layout_pin_center_segment(text=out_name, + clk_pin = self.clkbuf.get_pin("A") + self.add_layout_pin_center_segment(text="clk", layer="metal2", - start=right_pos.scale(1,0), + start=clk_pin.bc(), + end=clk_pin.bc().scale(1,0)) + + self.connect_rail_from_right_m2m3(self.clkbuf, "Zb", "clk_buf_bar") + self.connect_output(self.clkbuf, "Z", "clk_buf") + self.connect_output(self.clkbuf, "Zb", "clk_buf_bar") + + def connect_output(self, inst, pin_name, out_name): + """ Create an output pin on the right side from the pin of a given instance. """ + out_pin = inst.get_pin(pin_name) + right_pos=out_pin.center() + vector(self.width-out_pin.cx(),0) + self.add_layout_pin_center_segment(text=out_name, + layer="metal1", + start=out_pin.center(), end=right_pos) - def connect_left_pin_to_output_pin(self, inst, pin_name, out_name): - """ Create an output pin on the bottom side from the pin of a given instance. """ - out_pin = inst.get_pin(pin_name) - # shift it to the right side of the cell - left_pos=out_pin.center() - vector(out_pin.cx()-inst.lx(),0) - self.add_path("metal1",[out_pin.center(), left_pos]) - self.add_via_center(layers=("metal1","via1","metal2"), - offset=left_pos) - self.add_layout_pin_center_segment(text=out_name, - layer="metal2", - start=left_pos.scale(1,0), - end=left_pos) - - def add_output_routing(self): - """ Output pin routing """ - self.connect_right_pin_to_output_pin(self.tri_en, "Z", "tri_en") - self.connect_right_pin_to_output_pin(self.tri_en_bar, "Z", "tri_en_bar") - self.connect_right_pin_to_output_pin(self.w_en, "Z", "w_en") - self.connect_left_pin_to_output_pin(self.s_en, "Z", "s_en") - def add_supply_routing(self): + def route_supply(self): + """ Route the vdd and gnd for the rows of logic. """ - rows_start = self.rail_1_start_x + self.overall_rail_1_gap - rows_end = max(self.row_1_end_x,self.row_2_end_x,self.row_3_end_x) - vdd_rail_position = vector(self.rail_1_x_offsets["vdd"], 0) + rows_start = 0 + rows_end = self.width well_width = drc["minwidth_well"] - # M1 gnd rail from inv1 to max - start_offset = self.clkbuf.get_pin("gnd").lc() - row1_gnd_end_offset = vector(rows_end,start_offset.y) - self.add_path("metal1",[start_offset,row1_gnd_end_offset]) - rail_position = vector(self.rail_1_x_offsets["gnd"], start_offset.y) - self.add_wire(("metal1","via1","metal2"),[vector(rows_start,start_offset.y), rail_position, rail_position + vector(0,self.m2_pitch)]) + for i in range(7): + if i%2: + name = "vdd" + well_type = "nwell" + else: + name = "gnd" + well_type = "pwell" - # also add a well + around the rail - self.add_rect(layer="pwell", - offset=vector(rows_start,start_offset.y), - width=rows_end-rows_start, - height=well_width) - self.add_rect(layer="vtg", - offset=vector(rows_start,start_offset.y), - width=rows_end-rows_start, - height=well_width) - - # M1 vdd rail from inv1 to max - start_offset = self.clkbuf.get_pin("vdd").lc() - row1_vdd_end_offset = vector(rows_end,start_offset.y) - self.add_path("metal1",[start_offset,row1_vdd_end_offset]) - rail_position = vector(self.rail_1_x_offsets["vdd"], start_offset.y) - self.add_wire(("metal1","via1","metal2"),[vector(rows_start,start_offset.y), rail_position, rail_position - vector(0,self.m2_pitch)]) - - # also add a well +- around the rail - self.add_rect(layer="nwell", - offset=vector(rows_start,start_offset.y)-vector(0,0.5*well_width), - width=rows_end-rows_start, - height=well_width) - self.add_rect(layer="vtg", - offset=vector(rows_start,start_offset.y)-vector(0,0.5*well_width), - width=rows_end-rows_start, - height=well_width) + yoffset = i*self.inv1.height + self.add_layout_pin_center_segment(text=name, + layer="metal1", + start=vector(rows_start,yoffset), + end=vector(rows_end,yoffset)) - # M1 gnd rail from inv1 to max - start_offset = vector(rows_start, self.tri_en.get_pin("gnd").lc().y) - row3_gnd_end_offset = vector(rows_end,start_offset.y) - self.add_path("metal1",[start_offset,row3_gnd_end_offset]) - rail_position = vector(self.rail_1_x_offsets["gnd"], start_offset.y) - self.add_wire(("metal1","via1","metal2"),[vector(rows_start,start_offset.y), rail_position, rail_position - vector(0,self.m2_pitch)]) + # # also add a well +- around the rail + # well_offset = vector(rows_start,yoffset-0.5*well_width) + # self.add_rect(layer=well_type, + # offset=well_offset, + # width=rows_end-rows_start, + # height=well_width) + # self.add_rect(layer="vtg", + # offset=well_offset, + # width=rows_end-rows_start, + # height=well_width) - # also add a well +- around the rail - self.add_rect(layer="pwell", - offset=vector(rows_start,start_offset.y)-vector(0,0.5*well_width), - width=rows_end-rows_start, - height=well_width) - self.add_rect(layer="vtg", - offset=vector(rows_start,start_offset.y)-vector(0,0.5*well_width), - width=rows_end-rows_start, - height=well_width) + for vdd_pin in self.rbl_inst.get_pins("vdd"): + if vdd_pin.layer != "metal1": + continue + left = vdd_pin.lc().scale(0,1) + right = left + vector(rows_end,0) + self.add_layout_pin_center_segment(text="vdd", + layer="metal1", + start=left, + end=right) - - # M1 vdd rail from inv1 to max - start_offset = vector(rows_start, self.w_en_bar.get_pin("vdd").lc().y) - row3_vdd_end_offset = vector(rows_end,start_offset.y) - self.add_path("metal1",[start_offset,row3_vdd_end_offset]) - rail_position = vector(self.rail_1_x_offsets["vdd"], start_offset.y) - self.add_wire(("metal1","via1","metal2"),[vector(rows_start,start_offset.y), rail_position, rail_position - vector(0,self.m2_pitch)]) - - - # Now connect the vdd and gnd rails between the replica bitline and the control logic - (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()]) - self.add_path("metal1",[row3_gnd_end_offset,rbl_row3_gnd.lc()]) - # row 3 may have a jog due to unequal row heights, so force the full overlap at the end - self.add_path("metal1",[row3_vdd_end_offset - vector(self.m1_pitch,0),row3_vdd_end_offset,rbl_row3_vdd.ul()]) - - - # also add a well - around the rail - self.add_rect(layer="nwell", - offset=vector(rows_start,start_offset.y)-vector(0,well_width), - width=rows_end-rows_start, - height=well_width) - self.add_rect(layer="vtg", - offset=vector(rows_start,start_offset.y)-vector(0,well_width), - width=rows_end-rows_start, - height=well_width) + for gnd_pin in self.rbl_inst.get_pins("gnd"): + if gnd_pin.layer != "metal1": + continue + left = gnd_pin.lc().scale(0,1) + right = left + vector(rows_end,0) + self.add_layout_pin_center_segment(text="gnd", + layer="metal1", + start=left, + end=right) def add_lvs_correspondence_points(self): @@ -712,9 +668,9 @@ class control_logic(design.design): # height=pin.height(), # width=pin.width()) - pin=self.rbl.get_pin("out") + pin=self.rbl_inst.get_pin("out") self.add_label_pin(text="out", - layer="metal1", + layer=pin.layer, offset=pin.ll(), height=pin.height(), width=pin.width()) diff --git a/compiler/modules/replica_bitline.py b/compiler/modules/replica_bitline.py index fbd1f361..e86de04f 100644 --- a/compiler/modules/replica_bitline.py +++ b/compiler/modules/replica_bitline.py @@ -41,8 +41,12 @@ class replica_bitline(design.design): self.offset_all_coordinates() self.add_layout_pins() + #self.add_lvs_correspondence_points() + self.width = self.right_gnd_pin.rx() - self.left_gnd_pin.lx() + self.height = self.left_gnd_pin.uy() - self.left_gnd_pin.by() + self.DRC_LVS() def calculate_module_offsets(self): @@ -124,9 +128,6 @@ class replica_bitline(design.design): self.connect_inst(["bl[0]", "br[0]"] + ["gnd"]*self.bitcell_loads + ["vdd", "gnd"]) - self.height = max(self.rbl_inst.uy(),self.dc_inst.uy()) + self.m2_pitch - self.width = self.rbl_inst.rx() + self.m2_width - @@ -209,46 +210,28 @@ class replica_bitline(design.design): # Route the vdd lines from left to right # Add via for the delay chain - left_vdd_start = self.dc_inst.ll().scale(1,0) - vector(2*self.m2_pitch,2*self.m2_pitch) - left_vdd_end = vector(left_vdd_start.x, self.rbl_inst.uy()+2*self.m2_pitch) - left_vdd_pin=self.add_layout_pin_center_segment(text="vdd", - layer="metal2", - start=left_vdd_start, - end=left_vdd_end) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=left_vdd_start, - rotate=90) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=left_vdd_end, - rotate=90) + left_vdd_start = self.dc_inst.ll().scale(1,0) + left_vdd_end = vector(left_vdd_start.x, self.rbl_inst.uy()) + self.left_vdd_pin=self.add_layout_pin_center_segment(text="vdd", + layer="metal2", + start=left_vdd_start, + end=left_vdd_end) # Vdd line to the left of the replica bitline - center_vdd_start = self.rbc_inst.ll() - vector(3*self.m2_pitch,2*self.m2_pitch) - center_vdd_end = vector(center_vdd_start.x, self.rbl_inst.uy()+2*self.m2_pitch) - center_vdd_pin=self.add_layout_pin_center_segment(text="vdd", - layer="metal2", - start=center_vdd_start, - end=center_vdd_end) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=center_vdd_start, - rotate=90) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=center_vdd_end, - rotate=90) + center_vdd_start = self.rbc_inst.ll() - vector(3*self.m2_pitch,0) + center_vdd_end = vector(center_vdd_start.x, self.rbl_inst.uy()) + self.center_vdd_pin=self.add_layout_pin_center_segment(text="vdd", + layer="metal2", + start=center_vdd_start, + end=center_vdd_end) # Vdd line to the right of the replica bitline - right_vdd_start = self.rbc_inst.lr() + vector(2*self.m2_pitch,-2*self.m2_pitch) - right_vdd_end = vector(right_vdd_start.x, self.rbl_inst.uy()+2*self.m2_pitch) - right_vdd_pin=self.add_layout_pin_center_segment(text="vdd", - layer="metal2", - start=right_vdd_start, - end=right_vdd_end) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=right_vdd_start, - rotate=90) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=right_vdd_end, - rotate=90) + right_vdd_start = self.rbc_inst.lr() + vector(2*self.m2_pitch,0) + right_vdd_end = vector(right_vdd_start.x, self.rbl_inst.uy()) + self.right_vdd_pin=self.add_layout_pin_center_segment(text="vdd", + layer="metal2", + start=right_vdd_start, + end=right_vdd_end) @@ -258,8 +241,8 @@ class replica_bitline(design.design): for pin in rbl_vdd_pins: if pin.layer != "metal1": continue - start = vector(center_vdd_pin.cx(),pin.cy()) - end = vector(right_vdd_pin.cx(),pin.cy()) + start = vector(self.center_vdd_pin.cx(),pin.cy()) + end = vector(self.right_vdd_pin.cx(),pin.cy()) self.add_segment_center(layer="metal1", start=start, end=end) @@ -277,7 +260,7 @@ class replica_bitline(design.design): for pin in dc_vdd_pins: if pin.layer != "metal1": continue - start = vector(left_vdd_pin.cx(),pin.cy()) + start = vector(self.left_vdd_pin.cx(),pin.cy()) # Note, we don't connect to center because of via conflicts # with the RBL pins #end = vector(center_vdd_pin.cx(),pin.cy()) @@ -289,15 +272,11 @@ class replica_bitline(design.design): offset=start, rotate=90) - # self.add_via_center(layers=("metal1", "via1", "metal2"), - # offset=end, - #rotate=90) - # Add via for the inverter pin = self.rbl_inv_inst.get_pin("vdd") - start = vector(left_vdd_pin.cx(),pin.cy()) - end = vector(center_vdd_pin.cx(),pin.cy()) + start = vector(self.left_vdd_pin.cx(),pin.cy()) + end = vector(self.center_vdd_pin.cx(),pin.cy()) self.add_segment_center(layer="metal1", start=start, end=end) @@ -313,7 +292,7 @@ class replica_bitline(design.design): # Add via for the RBC pin = self.rbc_inst.get_pin("vdd") start = pin.lc() - end = vector(right_vdd_pin.cx(),pin.cy()) + end = vector(self.right_vdd_pin.cx(),pin.cy()) self.add_segment_center(layer="metal1", start=start, end=end) @@ -321,34 +300,18 @@ class replica_bitline(design.design): offset=end, rotate=90) - # Connect the RBL rails at the top and bottom + # Create the RBL rails too rbl_pins = self.rbl_inst.get_pins("vdd") for pin in rbl_pins: if pin.layer != "metal2": continue - end = vector(pin.cx(),right_vdd_pin.uy()) - self.add_segment_center(layer="metal2", - start=pin.uc(), - end=end) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=end, - rotate=90) - - start = vector(pin.cx(),right_vdd_pin.by()) - self.add_segment_center(layer="metal2", - start=pin.bc(), - end=start) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=start, - rotate=90) + start = vector(pin.cx(),self.right_vdd_pin.by()) + end = vector(pin.cx(),self.right_vdd_pin.uy()) + self.add_layout_pin_center_segment(text="vdd", + layer="metal2", + start=start, + end=end) - # Connect the rails at the top and bottom - self.add_segment_center(layer="metal1", - start=left_vdd_end, - end=right_vdd_end) - self.add_segment_center(layer="metal1", - start=left_vdd_start, - end=right_vdd_start) @@ -359,46 +322,28 @@ class replica_bitline(design.design): # Route the gnd lines from left to right # Add via for the delay chain - left_gnd_start = self.dc_inst.ll().scale(1,0) - vector(self.m2_pitch,self.m2_pitch) + left_gnd_start = self.dc_inst.ll().scale(1,0) - vector(self.m2_pitch,0) left_gnd_end = vector(left_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch) - left_gnd_pin=self.add_layout_pin_center_segment(text="gnd", - layer="metal2", - start=left_gnd_start, - end=left_gnd_end) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=left_gnd_start, - rotate=90) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=left_gnd_end, - rotate=90) + self.left_gnd_pin=self.add_layout_pin_center_segment(text="gnd", + layer="metal2", + start=left_gnd_start, + end=left_gnd_end) # Gnd line to the left of the replica bitline - center_gnd_start = self.rbc_inst.ll().scale(1,0) - vector(2*self.m2_pitch,self.m2_pitch) + center_gnd_start = self.rbc_inst.ll().scale(1,0) - vector(2*self.m2_pitch,0) center_gnd_end = vector(center_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch) - center_gnd_pin=self.add_layout_pin_center_segment(text="gnd", - layer="metal2", - start=center_gnd_start, - end=center_gnd_end) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=center_gnd_start, - rotate=90) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=center_gnd_end, - rotate=90) + self.center_gnd_pin=self.add_layout_pin_center_segment(text="gnd", + layer="metal2", + start=center_gnd_start, + end=center_gnd_end) # Gnd line to the right of the replica bitline - right_gnd_start = self.rbc_inst.lr().scale(1,0) + vector(self.m2_pitch,-self.m2_pitch) + right_gnd_start = self.rbc_inst.lr().scale(1,0) + vector(self.m2_pitch,0) right_gnd_end = vector(right_gnd_start.x, self.rbl_inst.uy()+self.m2_pitch) - right_gnd_pin=self.add_layout_pin_center_segment(text="gnd", - layer="metal2", - start=right_gnd_start, - end=right_gnd_end) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=right_gnd_start, - rotate=90) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=right_gnd_end, - rotate=90) + self.right_gnd_pin=self.add_layout_pin_center_segment(text="gnd", + layer="metal2", + start=right_gnd_start, + end=right_gnd_end) @@ -408,8 +353,8 @@ class replica_bitline(design.design): pin = self.rbl_inst.get_pin(wl) if pin.layer != "metal1": continue - start = vector(center_gnd_pin.cx(),pin.cy()) - end = vector(right_gnd_pin.cx(),pin.cy()) + start = vector(self.center_gnd_pin.cx(),pin.cy()) + end = vector(self.right_gnd_pin.cx(),pin.cy()) self.add_segment_center(layer="metal1", start=start, end=end) @@ -426,8 +371,8 @@ class replica_bitline(design.design): for pin in rbl_gnd_pins: if pin.layer != "metal1": continue - start = vector(center_gnd_pin.cx(),pin.cy()) - end = vector(right_gnd_pin.cx(),pin.cy()) + start = vector(self.center_gnd_pin.cx(),pin.cy()) + end = vector(self.right_gnd_pin.cx(),pin.cy()) self.add_segment_center(layer="metal1", start=start, end=end) @@ -445,10 +390,10 @@ class replica_bitline(design.design): for pin in dc_gnd_pins: if pin.layer != "metal1": continue - start = vector(left_gnd_pin.cx(),pin.cy()) + start = vector(self.left_gnd_pin.cx(),pin.cy()) # Note, we don't connect to the center rails because of # via conflicts with the RBL - #end = vector(center_gnd_pin.cx(),pin.cy()) + #end = vector(self.center_gnd_pin.cx(),pin.cy()) end = pin.rc() self.add_segment_center(layer="metal1", start=start, @@ -464,8 +409,8 @@ class replica_bitline(design.design): # Add via for the inverter # pin = self.rbl_inv_inst.get_pin("gnd") - # start = vector(left_gnd_pin.cx(),pin.cy()) - # end = vector(center_gnd_pin.cx(),pin.cy()) + # start = vector(self.left_gnd_pin.cx(),pin.cy()) + # end = vector(self.center_gnd_pin.cx(),pin.cy()) # self.add_segment_center(layer="metal1", # start=start, # end=end) @@ -478,35 +423,18 @@ class replica_bitline(design.design): - # Connect the RBL rails at the top and bottom + # Create RBL rails too rbl_pins = self.rbl_inst.get_pins("gnd") for pin in rbl_pins: if pin.layer != "metal2": continue - end = vector(pin.cx(),right_gnd_pin.uy()) - self.add_segment_center(layer="metal2", - start=pin.uc(), - end=end) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=end, - rotate=90) - - start = vector(pin.cx(),right_gnd_pin.by()) - self.add_segment_center(layer="metal2", - start=pin.bc(), - end=start) - self.add_via_center(layers=("metal1", "via1", "metal2"), - offset=start, - rotate=90) + start = vector(pin.cx(),self.right_gnd_pin.by()) + end = vector(pin.cx(),self.right_gnd_pin.uy()) + self.add_layout_pin_center_segment(text="gnd", + layer="metal2", + start=start, + end=end) - # Connect the rails at the top and bottom - self.add_segment_center(layer="metal1", - start=left_gnd_end, - end=right_gnd_end) - self.add_segment_center(layer="metal1", - start=left_gnd_start, - end=right_gnd_start) - def add_layout_pins(self): diff --git a/compiler/sram.py b/compiler/sram.py index 7e28f18e..977090be 100644 --- a/compiler/sram.py +++ b/compiler/sram.py @@ -16,7 +16,6 @@ class sram(design.design): Dynamically generated SRAM by connecting banks to control logic. The number of banks should be 1 , 2 or 4 """ - def __init__(self, word_size, num_words, num_banks, name): c = reload(__import__(OPTS.control_logic)) @@ -62,6 +61,7 @@ class sram(design.design): self.bank_to_bus_distance = 5*self.m3_width self.compute_sizes() + self.create_modules() self.add_pins() self.create_layout() @@ -146,8 +146,8 @@ class sram(design.design): self.add_pin("ADDR[{0}]".format(i),"INPUT") # These are used to create the physical pins too - self.control_logic_inputs=["CSb", "WEb", "OEb"] - self.control_logic_outputs=["s_en", "w_en", "tri_en", "tri_en_bar", "clk_bar", "clk_buf"] + self.control_logic_inputs=self.control_logic.get_inputs() + self.control_logic_outputs=self.control_logic.get_outputs() self.add_pin_list(self.control_logic_inputs + ["clk"],"INPUT") self.add_pin("vdd","POWER") @@ -156,8 +156,6 @@ class sram(design.design): def create_layout(self): """ Layout creation """ - self.create_modules() - if self.num_banks == 1: self.add_single_bank_modules() self.add_single_bank_pins() @@ -366,7 +364,7 @@ class sram(design.design): """ Add the horizontal and vertical busses """ # Vertical bus # The order of the control signals on the control bus: - self.control_bus_names = ["clk_buf", "tri_en_bar", "tri_en", "clk_bar", "w_en", "s_en"] + self.control_bus_names = ["clk_buf", "tri_en_bar", "tri_en", "clk_buf_bar", "w_en", "s_en"] self.vert_control_bus_positions = self.create_bus(layer="metal2", pitch=self.m2_pitch, offset=self.vertical_bus_offset, @@ -430,7 +428,7 @@ class sram(design.design): def add_two_bank_logic(self): """ Add the control and MSB logic """ - self.add_control_logic(position=self.control_logic_position, rotate=0) + self.add_control_logic(position=self.control_logic_position) self.msb_address_inst = self.add_inst(name="msb_address", mod=self.msb_address, @@ -443,7 +441,7 @@ class sram(design.design): """ Add the control and MSB decode/bank select logic for four banks """ - self.add_control_logic(position=self.control_logic_position, rotate=0) + self.add_control_logic(position=self.control_logic_position) self.msb_address_inst = self.add_inst(name="msb_address", mod=self.msb_address, @@ -797,8 +795,8 @@ class sram(design.design): self.control_logic = self.mod_control_logic(num_rows=self.num_rows) self.add_mod(self.control_logic) - # Create the address and control flops - dff_size = self.addr_size + len(self.control_logic_inputs) + # 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(rows=dff_size, columns=1) self.add_mod(self.addr_ctrl_dff) @@ -859,7 +857,7 @@ class sram(design.design): if(self.num_banks > 1): temp.append("bank_sel[{0}]".format(bank_num)) temp.extend(["s_en", "w_en", "tri_en_bar", "tri_en", - "clk_bar","clk_buf" , "vdd", "gnd"]) + "clk_buf_bar","clk_buf" , "vdd", "gnd"]) self.connect_inst(temp) return bank_inst @@ -904,12 +902,11 @@ class sram(design.design): return line_positions - def add_control_addr_dff(self, position, rotate=0): + 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, - rotate=rotate) + mod=self.addr_ctrl_dff, + offset=position) # inputs, outputs/output/bar inputs = [] outputs = [] @@ -918,18 +915,19 @@ class sram(design.design): 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, rotate): + def add_control_logic(self, position): """ Add and place control logic """ self.control_logic_inst=self.add_inst(name="control", mod=self.control_logic, - offset=position, - rotate=rotate) - self.connect_inst(self.control_logic_inputs + ["clk"] + self.control_logic_outputs + ["vdd", "gnd"]) + offset=position) + self.connect_inst(self.control_logic_inputs + self.control_logic_outputs + ["vdd", "gnd"]) def add_lvs_correspondence_points(self): @@ -961,12 +959,13 @@ class sram(design.design): # 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(-control_gap, - self.bank.height-self.control_logic.width) - self.add_control_logic(position=control_pos, rotate=90) + 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) - addr_pos = vector(self.control_logic_inst.lx(), - 2*self.supply_rail_pitch) + # 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 @@ -981,11 +980,13 @@ 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.bank_inst, "A[{}]".format(i)) + self.copy_layout_pin(self.addr_ctrl_dff_inst, "din[{}]".format(i),"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) + 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.control_logic_inst, "clk") self.copy_layout_pin(self.bank_inst, "vdd") self.copy_layout_pin(self.bank_inst, "gnd") @@ -1046,36 +1047,79 @@ class sram(design.design): dest_pin = self.bank_inst.get_pin(n) self.connect_rail_from_left_m2m3(src_pin, dest_pin) - - # Find the left-most metal2 rails - leftmost_vdd_rail = None - for vdd_pin in self.bank_inst.get_pins("vdd"): - if vdd_pin.layer != "metal2": - continue - if leftmost_vdd_rail == None or vdd_pin.lx() < leftmost_vdd_rail.lx(): - leftmost_vdd_rail = vdd_pin - leftmost_gnd_rail = None - for gnd_pin in self.bank_inst.get_pins("gnd"): - if gnd_pin.layer != "metal2": - continue - if leftmost_gnd_rail == None or gnd_pin.lx() < leftmost_gnd_rail.lx(): - leftmost_gnd_rail = gnd_pin - + # Expand the ring around the bank + bbox_lr = vector(self.control_logic_inst.lx(), self.bank_inst.by() + 2*self.supply_rail_pitch) + bbox_ur = self.bank_inst.ur() - vector(2*self.supply_rail_pitch, 2*self.supply_rail_pitch) + self.add_power_ring([bbox_lr, bbox_ur]) + self.route_single_bank_vdd() + self.route_single_bank_gnd() - src_pins = self.control_logic_inst.get_pins("vdd") - for src_pin in src_pins: - if src_pin.layer != "metal2": - continue - self.connect_rail_from_left_m2m3(src_pin,leftmost_vdd_rail) - - src_pins = self.control_logic_inst.get_pins("gnd") - for src_pin in src_pins: - if src_pin.layer != "metal2": - continue - self.add_path("metal2", [src_pin.rc(), vector(leftmost_gnd_rail.cx(), src_pin.cy())]) - + 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) + bank_pin = self.bank_inst.get_pin(bank_name) + flop_pos = flop_pin.center() + bank_pos = bank_pin.lc() + mid_x_pos = 0.5*(flop_pos.x + bank_pos.x) + mid_pos = vector(mid_x_pos - i*self.m2_pitch, flop_pos.y) + self.add_wire(("metal1","via1","metal2"),[flop_pos, mid_pos, bank_pos]) + # There should be M1 in the flop already, but just in case + self.add_via_center(layers=("metal1","via1","metal2"), + offset=flop_pos, + rotate=90) + 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) + + def route_single_bank_vdd(self): + """ 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] + for inst in modules: + for vdd_pin in inst.get_pins("vdd"): + if vdd_pin.layer != "metal1": + continue + vdd_pos = vdd_pin.rc() + left_rail_pos = vector(self.left_vdd_x_center, vdd_pos.y) + self.add_path("metal1", [left_rail_pos, vdd_pos]) + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=left_rail_pos, + size = (1,3), + rotate=90) + + + def route_single_bank_gnd(self): + """ 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] + for inst in modules: + for gnd_pin in inst.get_pins("gnd"): + if gnd_pin.layer != "metal1": + continue + gnd_pos = gnd_pin.rc() + left_rail_pos = vector(self.left_gnd_x_center, gnd_pos.y) + self.add_path("metal1", [left_rail_pos, gnd_pos]) + self.add_via_center(layers=("metal1", "via1", "metal2"), + offset=left_rail_pos, + size = (1,3), + rotate=90) + + + def sp_write(self, sp_name): # Write the entire spice of the object to the file ############################################################