From 9a12b68680167d7277ca64ba5c7496640393cacf Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Mon, 17 Feb 2020 14:25:00 +0100 Subject: [PATCH] write_driver: Allow custom pin names we don't want to propagate the write driver bl/br names out of the write_driver_array. Thus the write_driver_array gets them named as "bl"/"br" again. Signed-off-by: Bastian Koppelmann --- compiler/base/custom_cell_properties.py | 9 + compiler/modules/write_driver.py | 17 +- compiler/modules/write_driver_array.py | 4 +- compiler/modules/write_driver_array.py.orig | 202 ++++++++++++++++++++ 4 files changed, 225 insertions(+), 7 deletions(-) create mode 100644 compiler/modules/write_driver_array.py.orig diff --git a/compiler/base/custom_cell_properties.py b/compiler/base/custom_cell_properties.py index 45887561..04d27379 100644 --- a/compiler/base/custom_cell_properties.py +++ b/compiler/base/custom_cell_properties.py @@ -116,6 +116,12 @@ class cell_properties(): self._dff_buff_array = _dff_buff_array(use_custom_ports = False, add_body_contacts = False) + self._write_driver = _cell({'din': 'din', + 'bl' : 'bl', + 'br' : 'br', + 'en' : 'en'}) + + @property def bitcell(self): return self._bitcell @@ -132,3 +138,6 @@ class cell_properties(): def dff_buff_array(self): return self._dff_buff_array + @property + def write_driver(self): + return self._write_driver diff --git a/compiler/modules/write_driver.py b/compiler/modules/write_driver.py index 78920a10..9afac81b 100644 --- a/compiler/modules/write_driver.py +++ b/compiler/modules/write_driver.py @@ -10,6 +10,7 @@ import design import utils from globals import OPTS from tech import GDS,layer +from tech import cell_properties as props class write_driver(design.design): """ @@ -19,7 +20,13 @@ class write_driver(design.design): the technology library. """ - pin_names = ["din", "bl", "br", "en", "vdd", "gnd"] + pin_names = [props.write_driver.pin.din, + props.write_driver.pin.bl, + props.write_driver.pin.br, + props.write_driver.pin.en, + props.write_driver.pin.vdd, + props.write_driver.pin.gnd] + type_list = ["INPUT", "OUTPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] if not OPTS.netlist_only: (width,height) = utils.get_libcell_size("write_driver", GDS["unit"], layer["boundary"]) @@ -38,18 +45,18 @@ class write_driver(design.design): self.add_pin_types(self.type_list) def get_bl_names(self): - return "bl" + return props.write_driver.pin.bl def get_br_names(self): - return "br" + return props.write_driver.pin.br @property def din_name(self): - return "din" + return props.write_driver.pin.din @property def en_name(self): - return "en" + return props.write_driver.pin.en def get_w_en_cin(self): """Get the relative capacitance of a single input""" diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 16233c88..08a2e007 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -38,11 +38,11 @@ class write_driver_array(design.design): self.create_layout() def get_bl_name(self): - bl_name = self.driver.get_bl_names() + bl_name = "bl" return bl_name def get_br_name(self): - br_name = self.driver.get_br_names() + br_name = "br" return br_name @property diff --git a/compiler/modules/write_driver_array.py.orig b/compiler/modules/write_driver_array.py.orig new file mode 100644 index 00000000..16233c88 --- /dev/null +++ b/compiler/modules/write_driver_array.py.orig @@ -0,0 +1,202 @@ +# 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. +# +from math import log +import design +from tech import drc +import debug +from sram_factory import factory +from vector import vector +from globals import OPTS + +class write_driver_array(design.design): + """ + Array of tristate drivers to write to the bitlines through the column mux. + Dynamically generated write driver array of all bitlines. + """ + + def __init__(self, name, columns, word_size,write_size=None): + design.design.__init__(self, name) + debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("columns: {0}".format(columns)) + self.add_comment("word_size {0}".format(word_size)) + + self.columns = columns + self.word_size = word_size + self.write_size = write_size + self.words_per_row = int(columns / word_size) + + if self.write_size: + self.num_wmasks = int(self.word_size/self.write_size) + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def get_bl_name(self): + bl_name = self.driver.get_bl_names() + return bl_name + + def get_br_name(self): + br_name = self.driver.get_br_names() + return br_name + + @property + def data_name(self): + return "data" + + @property + def en_name(self): + return "en" + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_write_array() + + def create_layout(self): + + if self.bitcell.width > self.driver.width: + self.width = self.columns * self.bitcell.width + else: + self.width = self.columns * self.driver.width + self.height = self.driver.height + + self.place_write_array() + self.add_layout_pins() + self.add_boundary() + self.DRC_LVS() + + def add_pins(self): + for i in range(self.word_size): + self.add_pin(self.data_name + "_{0}".format(i), "INPUT") + for i in range(self.word_size): + self.add_pin(self.get_bl_name() + "_{0}".format(i), "OUTPUT") + self.add_pin(self.get_br_name() + "_{0}".format(i), "OUTPUT") + if self.write_size: + for i in range(self.num_wmasks): + self.add_pin(self.en_name + "_{0}".format(i), "INPUT") + else: + self.add_pin(self.en_name, "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def add_modules(self): + self.driver = factory.create(module_type="write_driver") + self.add_mod(self.driver) + + # This is just used for measurements, + # so don't add the module + self.bitcell = factory.create(module_type="bitcell") + + def create_write_array(self): + self.driver_insts = {} + w = 0 + windex=0 + for i in range(0,self.columns,self.words_per_row): + name = "write_driver{}".format(i) + index = int(i/self.words_per_row) + self.driver_insts[index]=self.add_inst(name=name, + mod=self.driver) + + if self.write_size: + self.connect_inst([self.data_name + "_{0}".format(index), + self.get_bl_name() + "_{0}".format(index), + self.get_br_name() + "_{0}".format(index), + self.en_name + "_{0}".format(windex), "vdd", "gnd"]) + w+=1 + # when w equals write size, the next en pin can be connected since we are now at the next wmask bit + if w == self.write_size: + w = 0 + windex+=1 + else: + self.connect_inst([self.data_name + "_{0}".format(index), + self.get_bl_name() + "_{0}".format(index), + self.get_br_name() + "_{0}".format(index), + self.en_name, "vdd", "gnd"]) + + + def place_write_array(self): + from tech import cell_properties + if self.bitcell.width > self.driver.width: + self.driver_spacing = self.bitcell.width + else: + self.driver_spacing = self.driver.width + for i in range(0,self.columns,self.words_per_row): + index = int(i/self.words_per_row) + xoffset = i * self.driver_spacing + + if cell_properties.bitcell.mirror.y and i % 2: + mirror = "MY" + xoffset = xoffset + self.driver.width + else: + mirror = "" + + base = vector(xoffset, 0) + self.driver_insts[index].place(offset=base, mirror=mirror) + + + def add_layout_pins(self): + for i in range(self.word_size): + inst = self.driver_insts[i] + din_pin = inst.get_pin(inst.mod.din_name) + self.add_layout_pin(text=self.data_name + "_{0}".format(i), + layer="m2", + offset=din_pin.ll(), + width=din_pin.width(), + height=din_pin.height()) + bl_pin = inst.get_pin(inst.mod.get_bl_names()) + self.add_layout_pin(text=self.get_bl_name() + "_{0}".format(i), + layer="m2", + offset=bl_pin.ll(), + width=bl_pin.width(), + height=bl_pin.height()) + + br_pin = inst.get_pin(inst.mod.get_br_names()) + self.add_layout_pin(text=self.get_br_name() + "_{0}".format(i), + layer="m2", + offset=br_pin.ll(), + width=br_pin.width(), + height=br_pin.height()) + + for n in ["vdd", "gnd"]: + pin_list = self.driver_insts[i].get_pins(n) + for pin in pin_list: + self.add_power_pin(name = n, + loc = pin.center(), + vertical=True, + start_layer = "m2") + if self.write_size: + for bit in range(self.num_wmasks): + inst = self.driver_insts[bit*self.write_size] + en_pin = inst.get_pin(inst.mod.en_name) + # Determine width of wmask modified en_pin with/without col mux + wmask_en_len = self.words_per_row*(self.write_size * self.driver_spacing) + if (self.words_per_row == 1): + en_gap = self.driver_spacing - en_pin.width() + else: + en_gap = self.driver_spacing + + self.add_layout_pin(text=self.en_name + "_{0}".format(bit), + layer=en_pin.layer, + offset=en_pin.ll(), + width=wmask_en_len-en_gap, + height=en_pin.height()) + else: + inst = self.driver_insts[0] + self.add_layout_pin(text=self.en_name, + layer="m1", + offset=inst.get_pin(inst.mod.en_name).ll().scale(0,1), + width=self.width) + + + + + def get_w_en_cin(self): + """Get the relative capacitance of all the enable connections in the bank""" + #The enable is connected to a nand2 for every row. + return self.driver.get_w_en_cin() * len(self.driver_insts)