From 7505fa5aef116220975e3670091e927cdd93ca37 Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Wed, 27 May 2020 20:03:11 -0700 Subject: [PATCH] update for end caps --- compiler/bitcells/col_cap_bitcell_1rw_1r.py | 43 ++++++ compiler/bitcells/row_cap_bitcell_1rw_1r.py | 43 ++++++ compiler/modules/bitcell_base_array.py | 15 +- compiler/modules/col_cap_array.py | 103 +++++++++++++ compiler/modules/replica_bitcell_array.py | 138 ++++++++++-------- compiler/modules/replica_column.py | 84 ++++++++--- compiler/modules/row_cap_array.py | 128 ++++++++++++++++ compiler/options.py | 21 +-- .../14_replica_bitcell_1rw_1r_array_test.py | 12 +- 9 files changed, 486 insertions(+), 101 deletions(-) create mode 100644 compiler/bitcells/col_cap_bitcell_1rw_1r.py create mode 100644 compiler/bitcells/row_cap_bitcell_1rw_1r.py create mode 100644 compiler/modules/col_cap_array.py create mode 100644 compiler/modules/row_cap_array.py diff --git a/compiler/bitcells/col_cap_bitcell_1rw_1r.py b/compiler/bitcells/col_cap_bitcell_1rw_1r.py new file mode 100644 index 00000000..315ad23f --- /dev/null +++ b/compiler/bitcells/col_cap_bitcell_1rw_1r.py @@ -0,0 +1,43 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import debug +import utils +from tech import GDS, layer +from tech import cell_properties as props +import bitcell_base + + +class col_cap_bitcell_1rw_1r(bitcell_base.bitcell_base): + """ + todo""" + + pin_names = [props.bitcell.cell_1rw1r.pin.bl0, + props.bitcell.cell_1rw1r.pin.br0, + props.bitcell.cell_1rw1r.pin.bl1, + props.bitcell.cell_1rw1r.pin.br1, + props.bitcell.cell_1rw1r.pin.vdd] + + type_list = ["OUTPUT", "OUTPUT", "OUTPUT", "OUTPUT", + "POWER", "GROUND"] + + (width, height) = utils.get_libcell_size("col_cap_cell_1rw_1r", + GDS["unit"], + layer["boundary"]) + pin_map = utils.get_libcell_pins(pin_names, + "col_cap_cell_1rw_1r", + GDS["unit"]) + + def __init__(self, name=""): + # Ignore the name argument + bitcell_base.bitcell_base.__init__(self, "col_cap_cell_1rw_1r") + debug.info(2, "Create col_cap bitcell 1rw+1r object") + + self.width = col_cap_bitcell_1rw_1r.width + self.height = col_cap_bitcell_1rw_1r.height + self.pin_map = col_cap_bitcell_1rw_1r.pin_map + self.add_pin_types(self.type_list) diff --git a/compiler/bitcells/row_cap_bitcell_1rw_1r.py b/compiler/bitcells/row_cap_bitcell_1rw_1r.py new file mode 100644 index 00000000..b50629f0 --- /dev/null +++ b/compiler/bitcells/row_cap_bitcell_1rw_1r.py @@ -0,0 +1,43 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# +import debug +import utils +from tech import GDS, layer +from tech import cell_properties as props +import bitcell_base + + +class row_cap_bitcell_1rw_1r(bitcell_base.bitcell_base): + """ + A single bit cell which is forced to store a 0. + This module implements the single memory cell used in the design. It + is a hand-made cell, so the layout and netlist should be available in + the technology library. """ + + pin_names = [props.bitcell.cell_1rw1r.pin.wl0, + props.bitcell.cell_1rw1r.pin.wl1, + props.bitcell.cell_1rw1r.pin.gnd] + + type_list = ["INPUT", "INPUT", "GROUND"] + + (width, height) = utils.get_libcell_size("row_cap_cell_1rw_1r", + GDS["unit"], + layer["boundary"]) + pin_map = utils.get_libcell_pins(pin_names, + "row_cap_cell_1rw_1r", + GDS["unit"]) + + def __init__(self, name=""): + # Ignore the name argument + bitcell_base.bitcell_base.__init__(self, "row_cap_cell_1rw_1r") + debug.info(2, "Create row_cap bitcell 1rw+1r object") + + self.width = row_cap_bitcell_1rw_1r.width + self.height = row_cap_bitcell_1rw_1r.height + self.pin_map = row_cap_bitcell_1rw_1r.pin_map + self.add_pin_types(self.type_list) diff --git a/compiler/modules/bitcell_base_array.py b/compiler/modules/bitcell_base_array.py index a8829fc3..9b46a192 100644 --- a/compiler/modules/bitcell_base_array.py +++ b/compiler/modules/bitcell_base_array.py @@ -108,16 +108,23 @@ class bitcell_base_array(design.design): except AttributeError: bitcell_power_pin_directions = None + # For specific technologies, there is no vdd via within the bitcell. Instead vdd is connect via end caps. + try: + bitcell_no_vdd_pin = cell_properties.bitcell.no_vdd_via + except AttributeError: + bitcell_no_vdd_pin = False + # Add vdd/gnd via stacks for row in range(self.row_size): for col in range(self.column_size): inst = self.cell_inst[row,col] for pin_name in ["vdd", "gnd"]: for pin in inst.get_pins(pin_name): - self.add_power_pin(name=pin_name, - loc=pin.center(), - directions=bitcell_power_pin_directions, - start_layer=pin.layer) + if not (pin_name == "vdd" and bitcell_no_vdd_pin): + self.add_power_pin(name=pin_name, + loc=pin.center(), + directions=bitcell_power_pin_directions, + start_layer=pin.layer) def _adjust_x_offset(self, xoffset, col, col_offset): tempx = xoffset diff --git a/compiler/modules/col_cap_array.py b/compiler/modules/col_cap_array.py new file mode 100644 index 00000000..3119f4e5 --- /dev/null +++ b/compiler/modules/col_cap_array.py @@ -0,0 +1,103 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# All rights reserved. +# +from bitcell_base_array import bitcell_base_array +from sram_factory import factory +from globals import OPTS +from tech import cell_properties + +class col_cap_array(bitcell_base_array): + """ + Generate a dummy row/column for the replica array. + """ + def __init__(self, cols, rows, column_offset=0, mirror=0, name=""): + super().__init__(cols, rows, name, column_offset) + self.mirror = mirror + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + """ Create and connect the netlist """ + self.add_modules() + self.add_pins() + self.create_instances() + + def create_layout(self): + + self.place_array("dummy_r{0}_c{1}", self.mirror) + self.add_layout_pins() + self.add_boundary() + self.DRC_LVS() + + def add_modules(self): + """ Add the modules used in this design """ + # self.dummy_cell = factory.create(module_type="col_cap_bitcell_1rw_1r") # TODO: make module_type generic + self.dummy_cell = factory.create(module_type="col_cap_bitcell") + self.add_mod(self.dummy_cell) + + self.cell = factory.create(module_type="bitcell") + + def create_instances(self): + """ Create the module instances used in this design """ + self.cell_inst = {} + for col in range(self.column_size): + for row in range(self.row_size): + name = "bit_r{0}_c{1}".format(row, col) + self.cell_inst[row,col]=self.add_inst(name=name, + mod=self.dummy_cell) + self.connect_inst(self.get_bitcell_pins(col, row)) + + def get_bitcell_pins(self, col, row): + """ + Creates a list of connections in the bitcell, + indexed by column and row, for instance use in bitcell_array + """ + + pin_name = cell_properties.bitcell.cell_1rw1r.pin + bitcell_pins = ["{0}_{1}".format(pin_name.bl0, col), + "{0}_{1}".format(pin_name.br0, col), + "{0}_{1}".format(pin_name.bl1, col), + "{0}_{1}".format(pin_name.br1, col), + "vdd"] + + return bitcell_pins + + def add_layout_pins(self): + """ Add the layout pins """ + + column_list = self.cell.get_all_bitline_names() + + for col in range(self.column_size): + for cell_column in column_list: + bl_pin = self.cell_inst[0,col].get_pin(cell_column) + self.add_layout_pin(text=cell_column+"_{0}".format(col), + layer=bl_pin.layer, + offset=bl_pin.ll().scale(1,0), + width=bl_pin.width(), + height=self.height) + + # Add vdd/gnd via stacks + for row in range(self.row_size): + for col in range(self.column_size): + inst = self.cell_inst[row,col] + for pin_name in ["vdd", "gnd"]: + for pin in inst.get_pins(pin_name): + self.add_power_pin(name=pin.name, + loc=pin.center(), + start_layer=pin.layer) + + + # def input_load(self): + # wl_wire = self.gen_wl_wire() + # return wl_wire.return_input_cap() + # + # def get_wordline_cin(self): + # """Get the relative input capacitance from the wordline connections in all the bitcell""" + # #A single wordline is connected to all the bitcells in a single row meaning the capacitance depends on the # of columns + # bitcell_wl_cin = self.cell.get_wl_cin() + # total_cin = bitcell_wl_cin * self.column_size + # return total_cin diff --git a/compiler/modules/replica_bitcell_array.py b/compiler/modules/replica_bitcell_array.py index c88dbe6d..ff91f7fd 100644 --- a/compiler/modules/replica_bitcell_array.py +++ b/compiler/modules/replica_bitcell_array.py @@ -1,12 +1,12 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2019 Regents of the University of California +# Copyright (c) 2016-2019 Regents of the University of California # All rights reserved. # import debug import design -from tech import drc, spice +from tech import drc, spice, cell_properties from vector import vector from globals import OPTS from sram_factory import factory @@ -34,11 +34,11 @@ class replica_bitcell_array(design.design): debug.check(left_rbl+right_rbl==len(self.all_ports),"Invalid number of RBLs for port configuration.") debug.check(left_rbl+right_rbl==len(self.bitcell_ports),"Bitcell ports must match total RBLs.") - + # Two dummy rows/cols plus replica for each port self.extra_rows = 2 + left_rbl + right_rbl self.extra_cols = 2 + left_rbl + right_rbl - + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -46,8 +46,8 @@ class replica_bitcell_array(design.design): # We don't offset this because we need to align # the replica bitcell in the control logic #self.offset_all_coordinates() - - + + def create_netlist(self): """ Create and connect the netlist """ self.add_modules() @@ -55,15 +55,15 @@ class replica_bitcell_array(design.design): self.create_instances() def add_modules(self): - """ Array and dummy/replica columns + """ Array and dummy/replica columns d or D = dummy cell (caps to distinguish grouping) r or R = replica cell (caps to distinguish grouping) - b or B = bitcell - replica columns 1 + b or B = bitcell + replica columns 1 v v - bdDDDDDDDDDDDDDDdb <- Dummy row - bdDDDDDDDDDDDDDDrb <- Dummy row + bdDDDDDDDDDDDDDDdb <- Dummy row + bdDDDDDDDDDDDDDDrb <- Dummy row br--------------rb br| Array |rb br| row x col |rb @@ -106,7 +106,7 @@ class replica_bitcell_array(design.design): column_offset=column_offset, replica_bit=replica_bit) self.add_mod(self.replica_columns[bit]) - + # Dummy row self.dummy_row = factory.create(module_type="dummy_array", cols=self.column_size, @@ -116,15 +116,35 @@ class replica_bitcell_array(design.design): mirror=0) self.add_mod(self.dummy_row) - # Dummy col (mirror starting at first if odd replica+dummy rows) - self.dummy_col_left = factory.create(module_type="dummy_array", + + # If there are bitcell end caps, replace the dummy cells on the edge of the bitcell array with end caps. + try: + end_caps_enabled = cell_properties.bitcell.end_caps + except AttributeError: + end_caps_enabled = False + + # Dummy Row or Col Cap, depending on bitcell array properties + edge_row_module_type = ("col_cap_array" if end_caps_enabled else "dummy_array") + + self.edge_row = factory.create(module_type=edge_row_module_type, + cols=self.column_size, + rows=1, + # dummy column + left replica column + column_offset=1 + self.left_rbl, + mirror=0) + self.add_mod(self.edge_row) + + # Dummy Col or Row Cap, depending on bitcell array properties + edge_col_module_type = ("row_cap_array" if end_caps_enabled else "dummy_array") + + self.edge_col_left = factory.create(module_type=edge_col_module_type, cols=1, column_offset=0, rows=self.row_size + self.extra_rows, mirror=(self.left_rbl+1)%2) - self.add_mod(self.dummy_col_left) + self.add_mod(self.edge_col_left) - self.dummy_col_right = factory.create(module_type="dummy_array", + self.edge_col_right = factory.create(module_type=edge_col_module_type, cols=1, # dummy column # + left replica column @@ -133,9 +153,7 @@ class replica_bitcell_array(design.design): column_offset=1 + self.left_rbl + self.column_size + self.right_rbl, rows=self.row_size + self.extra_rows, mirror=(self.left_rbl+1)%2) - self.add_mod(self.dummy_col_right) - - + self.add_mod(self.edge_col_right) def add_pins(self): self.bitcell_array_wl_names = self.bitcell_array.get_all_wordline_names() @@ -150,7 +168,7 @@ class replica_bitcell_array(design.design): self.rbl_bl_names = {} self.rbl_br_names = {} self.rbl_wl_names = {} - + # Create the full WL names include dummy, replica, and regular bit cells self.replica_col_wl_names = [] self.replica_col_wl_names.extend(["{0}_bot".format(x) for x in self.dummy_cell_wl_names]) @@ -193,7 +211,7 @@ class replica_bitcell_array(design.design): wl_names = ["rbl_{0}_{1}".format(x,port) for x in self.cell.get_all_wl_names()] #wl_names[port] = "rbl_wl{}".format(port) self.replica_wl_names[port] = wl_names - + # External pins self.add_pin_list(self.bitcell_array_bl_names, "INOUT") @@ -204,22 +222,22 @@ class replica_bitcell_array(design.design): self.add_pin(bl_name,"OUTPUT") self.add_pin(br_name,"OUTPUT") self.add_pin_list(self.bitcell_array_wl_names, "INPUT") - # Need to sort by port order since dictionary values may not be in order + # Need to sort by port order since dictionary values may not be in order wl_names = [self.rbl_wl_names[x] for x in sorted(self.rbl_wl_names.keys())] for pin_name in wl_names: self.add_pin(pin_name,"INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") - + def create_instances(self): """ Create the module instances used in this design """ supplies = ["vdd", "gnd"] - + # Used for names/dimensions only self.cell = factory.create(module_type="bitcell") - + # Main array self.bitcell_array_inst=self.add_inst(name="bitcell_array", mod=self.bitcell_array) @@ -231,35 +249,33 @@ class replica_bitcell_array(design.design): self.replica_col_inst[port]=self.add_inst(name="replica_col_{}".format(port), mod=self.replica_columns[port]) self.connect_inst(self.replica_bl_names[port] + self.replica_col_wl_names + supplies) - - + + # Dummy rows under the bitcell array (connected with with the replica cell wl) self.dummy_row_replica_inst = {} for port in range(self.left_rbl+self.right_rbl): self.dummy_row_replica_inst[port]=self.add_inst(name="dummy_row_{}".format(port), mod=self.dummy_row) self.connect_inst(self.dummy_row_bl_names + self.replica_wl_names[port] + supplies) - - - # Top/bottom dummy rows + + + # Top/bottom dummy rows or col caps self.dummy_row_bot_inst=self.add_inst(name="dummy_row_bot", - mod=self.dummy_row) + mod=self.edge_row) self.connect_inst(self.dummy_row_bl_names + [x+"_bot" for x in self.dummy_cell_wl_names] + supplies) self.dummy_row_top_inst=self.add_inst(name="dummy_row_top", - mod=self.dummy_row) + mod=self.edge_row) self.connect_inst(self.dummy_row_bl_names + [x+"_top" for x in self.dummy_cell_wl_names] + supplies) # Left/right Dummy columns self.dummy_col_left_inst=self.add_inst(name="dummy_col_left", - mod=self.dummy_col_left) + mod=self.edge_col_left) self.connect_inst([x+"_left" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies) self.dummy_col_right_inst=self.add_inst(name="dummy_col_right", - mod=self.dummy_col_right) + mod=self.edge_col_right) self.connect_inst([x+"_right" for x in self.dummy_cell_bl_names] + self.dummy_col_wl_names + supplies) - - def create_layout(self): self.height = (self.row_size+self.extra_rows)*self.dummy_row.height @@ -267,7 +283,7 @@ class replica_bitcell_array(design.design): # This is a bitcell x bitcell offset to scale offset = vector(self.cell.width, self.cell.height) - + self.bitcell_array_inst.place(offset=[0,0]) # To the left of the bitcell array @@ -276,7 +292,6 @@ class replica_bitcell_array(design.design): # To the right of the bitcell array for bit in range(self.right_rbl): self.replica_col_inst[self.left_rbl+bit].place(offset=offset.scale(bit,-self.left_rbl-1)+self.bitcell_array_inst.lr()) - # Far top dummy row (first row above array is NOT flipped) flip_dummy = self.right_rbl%2 @@ -298,17 +313,17 @@ class replica_bitcell_array(design.design): for bit in range(self.right_rbl): self.dummy_row_replica_inst[self.left_rbl+bit].place(offset=offset.scale(0,bit+bit%2)+self.bitcell_array_inst.ul(), mirror="MX" if bit%2 else "R0") - + self.translate_all(offset.scale(-1-self.left_rbl,-1-self.left_rbl)) - + self.add_layout_pins() - + self.add_boundary() - + self.DRC_LVS() - + def add_layout_pins(self): """ Add the layout pins """ @@ -341,10 +356,10 @@ class replica_bitcell_array(design.design): for (pin_name,wl_name) in zip(self.cell.get_all_wl_names(),self.replica_wl_names[port]): # +1 for dummy row pin_bit = port+1 - # +row_size if above the array + # +row_size if above the array if port>=self.left_rbl: pin_bit += self.row_size - + pin_name += "_{}".format(pin_bit) pin = inst.get_pin(pin_name) if wl_name in self.rbl_wl_names.values(): @@ -368,20 +383,27 @@ class replica_bitcell_array(design.design): offset=pin.ll().scale(1, 0), width=pin.width(), height=self.height) - + + # For specific technologies, there is no vdd via within the bitcell. Instead vdd is connect via end caps. + try: + bitcell_no_vdd_pin = cell_properties.bitcell.no_vdd_via + except AttributeError: + bitcell_no_vdd_pin = False + for pin_name in ["vdd", "gnd"]: for inst in self.insts: pin_list = inst.get_pins(pin_name) for pin in pin_list: - self.add_power_pin(name=pin_name, - loc=pin.center(), - directions=("V", "V"), - start_layer=pin.layer) + if not (pin_name == "vdd" and bitcell_no_vdd_pin): + self.add_power_pin(name=pin_name, + loc=pin.center(), + directions=("V", "V"), + start_layer=pin.layer) def get_rbl_wl_name(self, port): """ Return the WL for the given RBL port """ return self.rbl_wl_names[port] - + def get_rbl_bl_name(self, port): """ Return the BL for the given RBL port """ return self.rbl_bl_names[port] @@ -393,17 +415,17 @@ class replica_bitcell_array(design.design): def analytical_power(self, corner, load): """Power of Bitcell array and bitline in nW.""" from tech import drc, parameter - + # Dynamic Power from Bitline bl_wire = self.gen_bl_wire() cell_load = 2 * bl_wire.return_input_cap() bl_swing = OPTS.rbl_delay_percentage freq = spice["default_event_frequency"] bitline_dynamic = self.calc_dynamic_power(corner, cell_load, freq, swing=bl_swing) - - #Calculate the bitcell power which currently only includes leakage + + #Calculate the bitcell power which currently only includes leakage cell_power = self.cell.analytical_power(corner, load) - + #Leakage power grows with entire array and bitlines. total_power = self.return_power(cell_power.dynamic + bitline_dynamic * self.column_size, cell_power.leakage * self.column_size * self.row_size) @@ -429,13 +451,13 @@ class replica_bitcell_array(design.design): def graph_exclude_bits(self, targ_row, targ_col): """Excludes bits in column from being added to graph except target""" self.bitcell_array.graph_exclude_bits(targ_row, targ_col) - + def graph_exclude_replica_col_bits(self): """Exclude all replica/dummy cells in the replica columns except the replica bit.""" - + for port in range(self.left_rbl+self.right_rbl): self.replica_columns[port].exclude_all_but_replica() def get_cell_name(self, inst_name, row, col): """Gets the spice name of the target bitcell.""" - return self.bitcell_array.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col) + return self.bitcell_array.get_cell_name(inst_name+'.x'+self.bitcell_array_inst.name, row, col) diff --git a/compiler/modules/replica_column.py b/compiler/modules/replica_column.py index d874ba8c..2e3d207e 100644 --- a/compiler/modules/replica_column.py +++ b/compiler/modules/replica_column.py @@ -1,11 +1,11 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2019 Regents of the University of California +# Copyright (c) 2016-2019 Regents of the University of California # All rights reserved. # import debug import design -from tech import drc +from tech import drc, cell_properties import contact from sram_factory import factory from vector import vector @@ -16,7 +16,7 @@ class replica_column(design.design): Generate a replica bitline column for the replica array. Rows is the total number of rows i the main array. Left_rbl and right_rbl are the number of left and right replica bitlines. - Replica bit specifies which replica column this is (to determine where to put the + Replica bit specifies which replica column this is (to determine where to put the replica cell. """ @@ -31,15 +31,15 @@ class replica_column(design.design): # left, right, regular rows plus top/bottom dummy cells self.total_size = self.left_rbl+rows+self.right_rbl+2 self.column_offset = column_offset - + debug.check(replica_bit!=0 and replica_bit!=rows,"Replica bit cannot be the dummy row.") debug.check(replica_bit<=left_rbl or replica_bit>=self.total_size-right_rbl-1, - "Replica bit cannot be in the regular array.") + "Replica bit cannot be in the regular array.") self.create_netlist() if not OPTS.netlist_only: self.create_layout() - + def create_netlist(self): self.add_modules() self.add_pins() @@ -47,7 +47,7 @@ class replica_column(design.design): def create_layout(self): self.height = self.total_size*self.cell.height - self.width = self.cell.width + self.width = self.cell.width self.place_instances() self.add_layout_pins() @@ -55,7 +55,7 @@ class replica_column(design.design): self.DRC_LVS() def add_pins(self): - + for bl_name in self.cell.get_all_bitline_names(): # In the replica column, these are only outputs! self.add_pin("{0}_{1}".format(bl_name,0), "OUTPUT") @@ -63,7 +63,7 @@ class replica_column(design.design): for row in range(self.total_size): for wl_name in self.cell.get_all_wl_names(): self.add_pin("{0}_{1}".format(wl_name,row), "INPUT") - + self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -72,27 +72,49 @@ class replica_column(design.design): self.add_mod(self.replica_cell) self.dummy_cell = factory.create(module_type="dummy_bitcell") self.add_mod(self.dummy_cell) + try: + edge_module_type = ("col_cap_bitcell" if cell_properties.bitcell.end_caps else "dummy_bitcell") + except AttributeError: + edge_module_type = "dummy_bitcell" + self.edge_cell = factory.create(module_type=edge_module_type) + self.add_mod(self.edge_cell) # Used for pin names only self.cell = factory.create(module_type="bitcell") - + def create_instances(self): + + try: + end_caps_enabled = cell_properties.bitcell.end_caps + except AttributeError: + end_caps_enabled = False + self.cell_inst = {} for row in range(self.total_size): name="rbc_{0}".format(row) # Top/bottom cell are always dummy cells. # Regular array cells are replica cells (>left_rbl and self.left_rbl and row