diff --git a/compiler/base/custom_cell_properties.py b/compiler/base/custom_cell_properties.py index 45887561..ba671279 100644 --- a/compiler/base/custom_cell_properties.py +++ b/compiler/base/custom_cell_properties.py @@ -116,6 +116,15 @@ 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'}) + self._sense_amp = _cell({'bl' : 'bl', + 'br' : 'br', + 'dout' : 'dout', + 'en' : 'en'}) + @property def bitcell(self): return self._bitcell @@ -132,3 +141,10 @@ class cell_properties(): def dff_buff_array(self): return self._dff_buff_array + @property + def write_driver(self): + return self._write_driver + + @property + def sense_amp(self): + return self._sense_amp diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index d1c2c671..7c37d670 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -8,6 +8,7 @@ from tech import drc, parameter import debug import design from sram_factory import factory +from collections import namedtuple from vector import vector from globals import OPTS @@ -46,7 +47,19 @@ class port_data(design.design): # br lines are connect from the precharger return self.precharge.get_br_names() + def get_bl_name(self, port=0): + bl_name = "bl" + if len(self.all_ports) == 1: + return bl_name + else: + return bl_name + "{}".format(port) + def get_br_name(self, port=0): + br_name = "br" + if len(self.all_ports) == 1: + return br_name + else: + return br_name + "{}".format(port) def create_netlist(self): self.precompute_constants() @@ -94,8 +107,8 @@ class port_data(design.design): self.add_pin("rbl_bl","INOUT") self.add_pin("rbl_br","INOUT") for bit in range(self.num_cols): - bl_name = self.precharge_array.get_bl_name(self.port) - br_name = self.precharge_array.get_br_name(self.port) + bl_name = self.get_bl_name(self.port) + br_name = self.get_br_name(self.port) self.add_pin("{0}_{1}".format(bl_name, bit),"INOUT") self.add_pin("{0}_{1}".format(br_name, bit),"INOUT") if self.port in self.read_ports: @@ -253,8 +266,8 @@ class port_data(design.design): self.precharge_array_inst = self.add_inst(name="precharge_array{}".format(self.port), mod=self.precharge_array) - bl_name = self.precharge_array.get_bl_name(self.port) - br_name = self.precharge_array.get_br_name(self.port) + bl_name = self.get_bl_name(self.port) + br_name = self.get_br_name(self.port) temp = [] # Use left BLs for RBL @@ -285,8 +298,8 @@ class port_data(design.design): self.column_mux_array_inst = self.add_inst(name="column_mux_array{}".format(self.port), mod=self.column_mux_array) - bl_name = self.column_mux_array.get_bl_name(self.port) - br_name = self.column_mux_array.get_br_name(self.port) + bl_name = self.get_bl_name(self.port) + br_name = self.get_br_name(self.port) temp = [] for col in range(self.num_cols): temp.append("{0}_{1}".format(bl_name, col)) @@ -315,8 +328,8 @@ class port_data(design.design): self.sense_amp_array_inst = self.add_inst(name="sense_amp_array{}".format(self.port), mod=self.sense_amp_array) - bl_name = self.sense_amp_array.get_bl_name(self.port) - br_name = self.sense_amp_array.get_br_name(self.port) + bl_name = self.get_bl_name(self.port) + br_name = self.get_br_name(self.port) temp = [] for bit in range(self.word_size): temp.append("dout_{}".format(bit)) @@ -341,8 +354,8 @@ class port_data(design.design): """ Creating Write Driver """ self.write_driver_array_inst = self.add_inst(name="write_driver_array{}".format(self.port), mod=self.write_driver_array) - bl_name = self.write_driver_array.get_bl_name(self.port) - br_name = self.write_driver_array.get_br_name(self.port) + bl_name = self.get_bl_name(self.port) + br_name = self.get_br_name(self.port) temp = [] for bit in range(self.word_size): @@ -523,13 +536,16 @@ class port_data(design.design): # Only do this if we have a column mux! if self.col_addr_size==0: return - + inst1 = self.column_mux_array_inst inst2 = self.precharge_array_inst - if self.port==0: - self.connect_bitlines(inst1, inst2, self.num_cols, inst2_start_bit=1) - else: - self.connect_bitlines(inst1, inst2, self.num_cols) + + insn2_start_bit = 1 if self.port == 0 else 0 + + self.connect_bitlines(inst1=inst1, + inst2=inst2, + num_bits=self.num_cols, + inst2_start_bit=insn2_start_bit) def route_sense_amp_to_column_mux_or_precharge_array(self, port): @@ -539,46 +555,49 @@ class port_data(design.design): if self.col_addr_size>0: # Sense amp is connected to the col mux inst1 = self.column_mux_array_inst - inst1_bl_name = "bl_out_{}" - inst1_br_name = "br_out_{}" + inst1_bls_templ = "{inst}_out_{bit}" start_bit = 0 else: # Sense amp is directly connected to the precharge array inst1 = self.precharge_array_inst - inst1_bl_name = "bl_{}" - inst1_br_name = "br_{}" + inst1_bls_templ="{inst}_{bit}" + if self.port==0: start_bit=1 else: start_bit=0 - - self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, - inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit) + self.channel_route_bitlines(inst1=inst1, + inst1_bls_template=inst1_bls_templ, + inst2=inst2, + num_bits=self.word_size, + inst1_start_bit=start_bit) def route_write_driver_to_column_mux_or_precharge_array(self, port): """ Routing of BL and BR between sense_amp and column mux or precharge array """ inst2 = self.write_driver_array_inst - + inst2_bl_name = inst2.mod.get_bl_name() + inst2_br_name = inst2.mod.get_br_name() + if self.col_addr_size>0: # Write driver is connected to the col mux inst1 = self.column_mux_array_inst - inst1_bl_name = "bl_out_{}" - inst1_br_name = "br_out_{}" + inst1_bls_templ = "{inst}_out_{bit}" start_bit = 0 else: # Sense amp is directly connected to the precharge array inst1 = self.precharge_array_inst - inst1_bl_name = "bl_{}" - inst1_br_name = "br_{}" + inst1_bls_templ="{inst}_{bit}" if self.port==0: start_bit=1 else: start_bit=0 - - self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size, - inst1_bl_name=inst1_bl_name, inst1_br_name=inst1_br_name, inst1_start_bit=start_bit) + + self.channel_route_bitlines(inst1=inst1, inst2=inst2, + num_bits=self.word_size, + inst1_bls_template=inst1_bls_templ, + inst1_start_bit=start_bit) def route_write_driver_to_sense_amp(self, port): @@ -589,7 +608,9 @@ class port_data(design.design): # These should be pitch matched in the cell library, # but just in case, do a channel route. - self.channel_route_bitlines(inst1=inst1, inst2=inst2, num_bits=self.word_size) + self.channel_route_bitlines(inst1=inst1, + inst2=inst2, + num_bits=self.word_size) def route_bitline_pins(self): @@ -635,64 +656,108 @@ class port_data(design.design): if self.write_mask_and_array_inst: self.copy_layout_pin(self.write_mask_and_array_inst, "en", "w_en") - - - def channel_route_bitlines(self, inst1, inst2, num_bits, - inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0, - inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0): + + + def _group_bitline_instances(self, inst1, inst2, num_bits, + inst1_bls_template, + inst1_start_bit, + inst2_bls_template, + inst2_start_bit): """ - Route the bl and br of two modules using the channel router. + Groups all the parameters into a named tuple and seperates them into + top and bottom instances. """ - + inst_group = namedtuple('InstanceGroup', ('inst', 'bls_template', + 'bl_name', 'br_name', 'start_bit')) + + inst1_group = inst_group(inst1, inst1_bls_template, + inst1.mod.get_bl_name(), + inst1.mod.get_br_name(), + inst1_start_bit) + inst2_group = inst_group(inst2, inst2_bls_template, + inst2.mod.get_bl_name(), + inst2.mod.get_br_name(), + inst2_start_bit) # determine top and bottom automatically. # since they don't overlap, we can just check the bottom y coordinate. if inst1.by() < inst2.by(): - (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) - (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) + bot_inst_group = inst1_group + top_inst_group = inst2_group else: - (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) - (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) + bot_inst_group = inst2_group + top_inst_group = inst1_group + return (bot_inst_group, top_inst_group) + + def _get_bitline_pins(self, inst_group, bit): + """ + Extracts bl/br pins from an InstanceGroup based on the bit modifier. + """ + full_bl_name = inst_group.bls_template.format( + **{'inst' : inst_group.bl_name, + 'bit' : inst_group.start_bit + bit} + ) + full_br_name = inst_group.bls_template.format( + **{'inst' : inst_group.br_name, + 'bit' : inst_group.start_bit + bit} + ) + return (inst_group.inst.get_pin(full_bl_name), + inst_group.inst.get_pin(full_br_name)) + + + def channel_route_bitlines(self, inst1, inst2, num_bits, + inst1_bls_template="{inst}_{bit}", + inst1_start_bit=0, + inst2_bls_template="{inst}_{bit}", + inst2_start_bit=0): + """ + Route the bl and br of two modules using the channel router. + """ + + bot_inst_group, top_inst_group = self._group_bitline_instances( + inst1, inst2, num_bits, + inst1_bls_template, inst1_start_bit, + inst2_bls_template, inst2_start_bit) # Channel route each mux separately since we don't minimize the number # of tracks in teh channel router yet. If we did, we could route all the bits at once! - offset = bottom_inst.ul() + vector(0,self.m1_pitch) + offset = bot_inst_group.inst.ul() + vector(0,self.m1_pitch) for bit in range(num_bits): - bottom_names = [bottom_inst.get_pin(bottom_bl_name.format(bit+bottom_start_bit)), bottom_inst.get_pin(bottom_br_name.format(bit+bottom_start_bit))] - top_names = [top_inst.get_pin(top_bl_name.format(bit+top_start_bit)), top_inst.get_pin(top_br_name.format(bit+top_start_bit))] + bottom_names = self._get_bitline_pins(bot_inst_group, bit) + top_names = self._get_bitline_pins(top_inst_group, bit) + route_map = list(zip(bottom_names, top_names)) self.create_horizontal_channel_route(route_map, offset, self.m1_stack) def connect_bitlines(self, inst1, inst2, num_bits, - inst1_bl_name="bl_{}", inst1_br_name="br_{}", inst1_start_bit=0, - inst2_bl_name="bl_{}", inst2_br_name="br_{}", inst2_start_bit=0): - + inst1_bls_template="{inst}_{bit}", + inst1_start_bit=0, + inst2_bls_template="{inst}_{bit}", + inst2_start_bit=0): """ Connect the bl and br of two modules. This assumes that they have sufficient space to create a jog in the middle between the two modules (if needed). """ - # determine top and bottom automatically. - # since they don't overlap, we can just check the bottom y coordinate. - if inst1.by() < inst2.by(): - (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) - (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) - else: - (bottom_inst, bottom_bl_name, bottom_br_name, bottom_start_bit) = (inst2, inst2_bl_name, inst2_br_name, inst2_start_bit) - (top_inst, top_bl_name, top_br_name, top_start_bit) = (inst1, inst1_bl_name, inst1_br_name, inst1_start_bit) + bot_inst_group, top_inst_group = self._group_bitline_instances( + inst1, inst2, num_bits, + inst1_bls_template, inst1_start_bit, + inst2_bls_template, inst2_start_bit) + bottom_inst = bot_inst_group.inst + top_inst = top_inst_group.inst for col in range(num_bits): - bottom_bl = bottom_inst.get_pin(bottom_bl_name.format(col+bottom_start_bit)).uc() - bottom_br = bottom_inst.get_pin(bottom_br_name.format(col+bottom_start_bit)).uc() - top_bl = top_inst.get_pin(top_bl_name.format(col+top_start_bit)).bc() - top_br = top_inst.get_pin(top_br_name.format(col+top_start_bit)).bc() + bot_bl_pin, bot_br_pin = self._get_bitline_pins(bot_inst_group, col) + top_bl_pin, top_br_pin = self._get_bitline_pins(top_inst_group, col) + bot_bl, bot_br = bot_bl_pin.uc(), bot_br_pin.uc() + top_bl, top_br = top_bl_pin.bc(), top_br_pin.bc() - yoffset = 0.5*(top_bl.y+bottom_bl.y) - self.add_path("m2",[bottom_bl, vector(bottom_bl.x,yoffset), + yoffset = 0.5*(top_bl.y+bot_bl.y) + self.add_path("m2",[bot_bl, vector(bot_bl.x,yoffset), vector(top_bl.x,yoffset), top_bl]) - self.add_path("m2",[bottom_br, vector(bottom_br.x,yoffset), + self.add_path("m2",[bot_br, vector(bot_br.x,yoffset), vector(top_br.x,yoffset), top_br]) def graph_exclude_precharge(self): diff --git a/compiler/modules/precharge_array.py b/compiler/modules/precharge_array.py index 5ac97b4d..efc9c4a3 100644 --- a/compiler/modules/precharge_array.py +++ b/compiler/modules/precharge_array.py @@ -32,20 +32,13 @@ class precharge_array(design.design): if not OPTS.netlist_only: self.create_layout() - def get_bl_name(self, port=0): + def get_bl_name(self): bl_name = self.pc_cell.get_bl_names() - if len(self.all_ports) == 1: - return bl_name - else: - return bl_name + "{}".format(port) + return bl_name - def get_br_name(self, port=0): + def get_br_name(self): br_name = self.pc_cell.get_br_names() - if len(self.all_ports) == 1: - return br_name - else: - return br_name + "{}".format(port) - + return br_name def add_pins(self): """Adds pins for spice file""" diff --git a/compiler/modules/sense_amp.py b/compiler/modules/sense_amp.py index eb624111..ff5638ba 100644 --- a/compiler/modules/sense_amp.py +++ b/compiler/modules/sense_amp.py @@ -9,6 +9,7 @@ import design import debug import utils from tech import GDS,layer, parameter,drc +from tech import cell_properties as props from globals import OPTS import logical_effort @@ -19,8 +20,12 @@ class sense_amp(design.design): the technology library. Sense amplifier to read a pair of bit-lines. """ - - pin_names = ["bl", "br", "dout", "en", "vdd", "gnd"] + pin_names = [props.sense_amp.pin.bl, + props.sense_amp.pin.br, + props.sense_amp.pin.dout, + props.sense_amp.pin.en, + props.sense_amp.pin.vdd, + props.sense_amp.pin.gnd] type_list = ["INPUT", "INPUT", "OUTPUT", "INPUT", "POWER", "GROUND"] if not OPTS.netlist_only: (width,height) = utils.get_libcell_size("sense_amp", GDS["unit"], layer["boundary"]) @@ -30,10 +35,18 @@ class sense_amp(design.design): pin_map = [] def get_bl_names(self): - return "bl" + return props.sense_amp.pin.bl def get_br_names(self): - return "br" + return props.sense_amp.pin.br + + @property + def dout_name(self): + return props.sense_amp.pin.dout + + @property + def en_name(self): + return props.sense_amp.pin.en def __init__(self, name): design.design.__init__(self, name) @@ -79,11 +92,10 @@ class sense_amp(design.design): def get_enable_name(self): """Returns name used for enable net""" #FIXME: A better programmatic solution to designate pins - enable_name = "en" + enable_name = self.en_name debug.check(enable_name in self.pin_names, "Enable name {} not found in pin list".format(enable_name)) return enable_name def build_graph(self, graph, inst_name, port_nets): """Adds edges based on inputs/outputs. Overrides base class function.""" self.add_graph_edges(graph, port_nets) - \ No newline at end of file diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 8ac5146c..322cc1b3 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -33,20 +33,21 @@ class sense_amp_array(design.design): if not OPTS.netlist_only: self.create_layout() + def get_bl_name(self): + bl_name = "bl" + return bl_name - def get_bl_name(self, port=0): - bl_name = self.amp.get_bl_names() - if len(self.all_ports) == 1: - return bl_name - else: - return bl_name + "{}".format(port) + def get_br_name(self): + br_name = "br" + return br_name - def get_br_name(self, port=0): - br_name = self.amp.get_br_names() - if len(self.all_ports) == 1: - return br_name - else: - return br_name + "{}".format(port) + @property + def data_name(self): + return "data" + + @property + def en_name(self): + return "en" def create_netlist(self): self.add_modules() @@ -69,10 +70,10 @@ class sense_amp_array(design.design): def add_pins(self): for i in range(0,self.word_size): - self.add_pin("data_{0}".format(i), "OUTPUT") - self.add_pin("bl_{0}".format(i), "INPUT") - self.add_pin("br_{0}".format(i), "INPUT") - self.add_pin("en", "INPUT") + self.add_pin(self.data_name + "_{0}".format(i), "OUTPUT") + self.add_pin(self.get_bl_name() + "_{0}".format(i), "INPUT") + self.add_pin(self.get_br_name() + "_{0}".format(i), "INPUT") + self.add_pin(self.en_name, "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -92,10 +93,10 @@ class sense_amp_array(design.design): name = "sa_d{0}".format(i) self.local_insts.append(self.add_inst(name=name, mod=self.amp)) - self.connect_inst(["bl_{0}".format(i), - "br_{0}".format(i), - "data_{0}".format(i), - "en", "vdd", "gnd"]) + self.connect_inst([self.get_bl_name() + "_{0}".format(i), + self.get_br_name() + "_{0}".format(i), + self.data_name + "_{0}".format(i), + self.en_name, "vdd", "gnd"]) def place_sense_amp_array(self): from tech import cell_properties @@ -135,22 +136,22 @@ class sense_amp_array(design.design): start_layer="m2", vertical=True) - bl_pin = inst.get_pin("bl") - br_pin = inst.get_pin("br") - dout_pin = inst.get_pin("dout") - - self.add_layout_pin(text="bl_{0}".format(i), + bl_pin = inst.get_pin(inst.mod.get_bl_names()) + br_pin = inst.get_pin(inst.mod.get_br_names()) + dout_pin = inst.get_pin(inst.mod.dout_name) + + 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()) - self.add_layout_pin(text="br_{0}".format(i), + 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()) - - self.add_layout_pin(text="data_{0}".format(i), + + self.add_layout_pin(text=self.data_name + "_{0}".format(i), layer="m2", offset=dout_pin.ll(), width=dout_pin.width(), @@ -159,8 +160,8 @@ class sense_amp_array(design.design): def route_rails(self): # add sclk rail across entire array - sclk_offset = self.amp.get_pin("en").ll().scale(0,1) - self.add_layout_pin(text="en", + sclk_offset = self.amp.get_pin(self.amp.en_name).ll().scale(0,1) + self.add_layout_pin(text=self.en_name, layer="m1", offset=sclk_offset, width=self.width, diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 1c181574..324b7415 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -37,20 +37,13 @@ class single_level_column_mux_array(design.design): if not OPTS.netlist_only: self.create_layout() - def get_bl_name(self, port=0): + def get_bl_name(self): bl_name = self.mux.get_bl_names() - if len(self.all_ports) == 1: - return bl_name - else: - return bl_name + "{}".format(port) + return bl_name def get_br_name(self, port=0): br_name = self.mux.get_br_names() - if len(self.all_ports) == 1: - return br_name - else: - return br_name + "{}".format(port) - + return br_name def create_netlist(self): self.add_modules() diff --git a/compiler/modules/write_driver.py b/compiler/modules/write_driver.py index db08bcf4..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,10 +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 props.write_driver.pin.din + + @property + def en_name(self): + 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 dd7430a9..08a2e007 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -37,19 +37,21 @@ class write_driver_array(design.design): if not OPTS.netlist_only: self.create_layout() - def get_bl_name(self, port=0): - bl_name = self.driver.get_bl_names() - if len(self.all_ports) == 1: - return bl_name - else: - return bl_name + "{}".format(port) + def get_bl_name(self): + bl_name = "bl" + return bl_name - def get_br_name(self, port=0): - br_name = self.driver.get_br_names() - if len(self.all_ports) == 1: - return br_name - else: - return br_name + "{}".format(port) + def get_br_name(self): + br_name = "br" + return br_name + + @property + def data_name(self): + return "data" + + @property + def en_name(self): + return "en" def create_netlist(self): self.add_modules() @@ -71,15 +73,15 @@ class write_driver_array(design.design): def add_pins(self): for i in range(self.word_size): - self.add_pin("data_{0}".format(i), "INPUT") - for i in range(self.word_size): - self.add_pin("bl_{0}".format(i), "OUTPUT") - self.add_pin("br_{0}".format(i), "OUTPUT") + 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("en_{0}".format(i), "INPUT") + self.add_pin(self.en_name + "_{0}".format(i), "INPUT") else: - self.add_pin("en", "INPUT") + self.add_pin(self.en_name, "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -102,20 +104,20 @@ class write_driver_array(design.design): mod=self.driver) if self.write_size: - self.connect_inst(["data_{0}".format(index), - "bl_{0}".format(index), - "br_{0}".format(index), - "en_{0}".format(windex), "vdd", "gnd"]) + 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(["data_{0}".format(index), - "bl_{0}".format(index), - "br_{0}".format(index), - "en", "vdd", "gnd"]) + 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): @@ -140,21 +142,22 @@ class write_driver_array(design.design): def add_layout_pins(self): for i in range(self.word_size): - din_pin = self.driver_insts[i].get_pin("din") - self.add_layout_pin(text="data_{0}".format(i), + 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 = self.driver_insts[i].get_pin("bl") - self.add_layout_pin(text="bl_{0}".format(i), + 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 = self.driver_insts[i].get_pin("br") - self.add_layout_pin(text="br_{0}".format(i), + + 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(), @@ -169,7 +172,8 @@ class write_driver_array(design.design): start_layer = "m2") if self.write_size: for bit in range(self.num_wmasks): - en_pin = self.driver_insts[bit*self.write_size].get_pin("en") + 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): @@ -177,15 +181,16 @@ class write_driver_array(design.design): else: en_gap = self.driver_spacing - self.add_layout_pin(text="en_{0}".format(bit), + 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: - self.add_layout_pin(text="en", + inst = self.driver_insts[0] + self.add_layout_pin(text=self.en_name, layer="m1", - offset=self.driver_insts[0].get_pin("en").ll().scale(0,1), + offset=inst.get_pin(inst.mod.en_name).ll().scale(0,1), width=self.width) 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)