diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index fbf5223a..5fad35ae 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -27,6 +27,10 @@ class port_data(design.design): else: self.num_wmasks = 0 + if self.num_spare_cols is None: + self.num_spare_cols = 0 + + if name == "": name = "port_data_{0}".format(self.port) design.design.__init__(self, name) @@ -102,7 +106,7 @@ class port_data(design.design): self.DRC_LVS() def add_pins(self): - """ Adding pins for port address module""" + """ Adding pins for port data module""" self.add_pin("rbl_bl", "INOUT") self.add_pin("rbl_br", "INOUT") @@ -111,11 +115,18 @@ class port_data(design.design): 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") + + for bit in range(self.num_spare_cols): + bl_name = self.get_bl_name(self.port) + br_name = self.get_br_name(self.port) + self.add_pin("spare{0}_{1}".format(bl_name, bit), "INOUT") + self.add_pin("spare{0}_{1}".format(br_name, bit), "INOUT") + if self.port in self.read_ports: - for bit in range(self.word_size): + for bit in range(self.word_size + self.num_spare_cols): self.add_pin("dout_{}".format(bit), "OUTPUT") if self.port in self.write_ports: - for bit in range(self.word_size): + for bit in range(self.word_size + self.num_spare_cols): self.add_pin("din_{}".format(bit), "INPUT") # Will be empty if no col addr lines sel_names = ["sel_{}".format(x) for x in range(self.num_col_addr_lines)] @@ -128,6 +139,8 @@ class port_data(design.design): self.add_pin("w_en", "INPUT") for bit in range(self.num_wmasks): self.add_pin("bank_wmask_{}".format(bit), "INPUT") + for bit in range(self.num_spare_cols): + self.add_pin("spare_wen{}".format(bit), "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -179,7 +192,7 @@ class port_data(design.design): # Extra column +1 is for RBL # Precharge will be shifted left if needed self.precharge_array = factory.create(module_type="precharge_array", - columns=self.num_cols + 1, + columns=self.num_cols + self.num_spare_cols + 1, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port]) self.add_mod(self.precharge_array) @@ -187,7 +200,8 @@ class port_data(design.design): if self.port in self.read_ports: self.sense_amp_array = factory.create(module_type="sense_amp_array", word_size=self.word_size, - words_per_row=self.words_per_row) + words_per_row=self.words_per_row, + num_spare_cols=self.num_spare_cols) self.add_mod(self.sense_amp_array) else: self.sense_amp_array = None @@ -206,7 +220,8 @@ class port_data(design.design): self.write_driver_array = factory.create(module_type="write_driver_array", columns=self.num_cols, word_size=self.word_size, - write_size=self.write_size) + write_size=self.write_size, + num_spare_cols=self.num_spare_cols) self.add_mod(self.write_driver_array) if self.write_size is not None: self.write_mask_and_array = factory.create(module_type="write_mask_and_array", @@ -249,7 +264,7 @@ class port_data(design.design): # We create a dummy here to get bl/br names to add those pins to this # module, which happens before we create the real precharge_array self.precharge_array = factory.create(module_type="precharge_array", - columns=self.num_cols + 1, + columns=self.num_cols + self.num_spare_cols + 1, bitcell_bl=self.bl_names[self.port], bitcell_br=self.br_names[self.port]) @@ -272,6 +287,10 @@ class port_data(design.design): for bit in range(self.num_cols): temp.append("{0}_{1}".format(bl_name, bit)) temp.append("{0}_{1}".format(br_name, bit)) + + for bit in range(self.num_spare_cols): + temp.append("sparebl{0}_{1}".format(self.port, bit)) + temp.append("sparebr{0}_{1}".format(self.port, bit)) # Use right BLs for RBL if self.port==1: @@ -297,7 +316,6 @@ class port_data(design.design): for col in range(self.num_cols): temp.append("{0}_{1}".format(bl_name, col)) temp.append("{0}_{1}".format(br_name, col)) - for word in range(self.words_per_row): temp.append("sel_{}".format(word)) for bit in range(self.word_size): @@ -330,8 +348,14 @@ class port_data(design.design): else: temp.append("{0}_out_{1}".format(bl_name, bit)) temp.append("{0}_out_{1}".format(br_name, bit)) - - temp.extend(["s_en", "vdd", "gnd"]) + + for bit in range(self.num_spare_cols): + temp.append("dout_{}".format(self.word_size + bit)) + temp.append("sparebl{0}_{1}".format(self.port, bit)) + temp.append("sparebr{0}_{1}".format(self.port, bit)) + + temp.append("s_en") + temp.extend(["vdd", "gnd"]) self.connect_inst(temp) def place_sense_amp_array(self, offset): @@ -346,7 +370,7 @@ class port_data(design.design): br_name = self.get_br_name(self.port) temp = [] - for bit in range(self.word_size): + for bit in range(self.word_size + self.num_spare_cols): temp.append("din_{}".format(bit)) for bit in range(self.word_size): @@ -355,11 +379,20 @@ class port_data(design.design): temp.append("{0}_{1}".format(br_name, bit)) else: temp.append("{0}_out_{1}".format(bl_name, bit)) - temp.append("{0}_out_{1}".format(br_name, bit)) + temp.append("{0}_out_{1}".format(br_name, bit)) + + for bit in range(self.num_spare_cols): + temp.append("sparebl{0}_{1}".format(self.port, bit)) + temp.append("sparebr{0}_{1}".format(self.port, bit)) if self.write_size is not None: for i in range(self.num_wmasks): temp.append("wdriver_sel_{}".format(i)) + + elif self.num_spare_cols: + temp.append("w_en") + for i in range(self.num_spare_cols): + temp.append("spare_wen{}".format(i)) else: temp.append("w_en") temp.extend(["vdd", "gnd"]) @@ -445,7 +478,7 @@ class port_data(design.design): def route_sense_amp_out(self, port): """ Add pins for the sense amp output """ - for bit in range(self.word_size): + for bit in range(self.word_size + self.num_spare_cols): data_pin = self.sense_amp_array_inst.get_pin("data_{}".format(bit)) self.add_layout_pin_rect_center(text="dout_{0}".format(bit), layer=data_pin.layer, @@ -456,7 +489,7 @@ class port_data(design.design): def route_write_driver_in(self, port): """ Connecting write driver """ - for row in range(self.word_size): + for row in range(self.word_size + self.num_spare_cols): data_name = "data_{}".format(row) din_name = "din_{}".format(row) self.copy_layout_pin(self.write_driver_array_inst, data_name, din_name) @@ -545,12 +578,36 @@ class port_data(design.design): else: start_bit=0 - self.channel_route_bitlines(inst1=inst1, - inst1_bls_template=inst1_bls_templ, - inst2=inst2, - num_bits=self.word_size, - inst1_start_bit=start_bit) + if self.port==0: + off = 1 + else: + off = 0 + + if self.num_spare_cols != 0 and self.col_addr_size>0: + self.channel_route_bitlines(inst1=self.column_mux_array_inst, + inst1_bls_template="{inst}_out_{bit}", + inst2=inst2, + num_bits=self.word_size, + inst1_start_bit=start_bit) + + self.channel_route_bitlines(inst1=self.precharge_array_inst, + inst1_bls_template="{inst}_{bit}", + inst2=inst2, + num_bits=self.num_spare_cols, + inst1_start_bit=self.num_cols + off, + inst2_start_bit=self.word_size) + + else: + self.channel_route_bitlines(inst1=inst1, + inst1_bls_template=inst1_bls_templ, + inst2=inst2, + num_bits=self.word_size + self.num_spare_cols, + inst1_start_bit=start_bit) + + + # spare cols connected to precharge array since they are read independently + 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 @@ -569,10 +626,33 @@ class port_data(design.design): else: start_bit=0 - self.channel_route_bitlines(inst1=inst1, inst2=inst2, - num_bits=self.word_size, - inst1_bls_template=inst1_bls_templ, - inst1_start_bit=start_bit) + if self.port==0: + off=1 + else: + off=0 + + + if self.num_spare_cols != 0 and self.col_addr_size>0: + self.channel_route_bitlines(inst1=self.column_mux_array_inst, + inst1_bls_template="{inst}_out_{bit}", + inst2=inst2, + num_bits=self.word_size, + inst1_start_bit=start_bit) + + self.channel_route_bitlines(inst1=self.precharge_array_inst, + inst1_bls_template="{inst}_{bit}", + inst2=inst2, + num_bits=self.num_spare_cols, + inst1_start_bit=self.num_cols + off, + inst2_start_bit=self.word_size) + + else: + self.channel_route_bitlines(inst1=inst1, + inst1_bls_template=inst1_bls_templ, + inst2=inst2, + num_bits=self.word_size + self.num_spare_cols, + inst1_start_bit=start_bit) + def route_write_driver_to_sense_amp(self, port): """ Routing of BL and BR between write driver and sense amp """ @@ -584,7 +664,7 @@ class port_data(design.design): # but just in case, do a channel route. self.channel_route_bitlines(inst1=inst1, inst2=inst2, - num_bits=self.word_size) + num_bits=self.word_size + self.num_spare_cols) def route_bitline_pins(self): """ Add the bitline pins for the given port """ @@ -595,13 +675,13 @@ class port_data(design.design): self.copy_layout_pin(self.precharge_array_inst, "br_0", "rbl_br") bit_offset=1 elif self.port==1: - self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols), "rbl_bl") - self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols), "rbl_br") + self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(self.num_cols + self.num_spare_cols), "rbl_bl") + self.copy_layout_pin(self.precharge_array_inst, "br_{}".format(self.num_cols + self.num_spare_cols), "rbl_br") bit_offset=0 else: bit_offset=0 - for bit in range(self.num_cols): + for bit in range(self.num_cols + self.num_spare_cols): if self.precharge_array_inst: self.copy_layout_pin(self.precharge_array_inst, "bl_{}".format(bit + bit_offset), @@ -621,12 +701,16 @@ class port_data(design.design): for pin_name in sel_names: self.copy_layout_pin(self.column_mux_array_inst, pin_name) if self.sense_amp_array_inst: - self.copy_layout_pin(self.sense_amp_array_inst, "en", "s_en") + self.copy_layout_pin(self.sense_amp_array_inst, "en", "s_en") if self.write_driver_array_inst: if self.write_mask_and_array_inst: for bit in range(self.num_wmasks): # Add write driver's en_{} pins self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit), "wdriver_sel_{}".format(bit)) + elif self.num_spare_cols: + self.copy_layout_pin(self.write_driver_array_inst, "en_0", "w_en") + for bit in range(self.num_spare_cols): + self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit + 1), "spare_wen{}".format(bit)) else: self.copy_layout_pin(self.write_driver_array_inst, "en", "w_en") if self.write_mask_and_array_inst: diff --git a/compiler/modules/sense_amp_array.py b/compiler/modules/sense_amp_array.py index 322cc1b3..8640e033 100644 --- a/compiler/modules/sense_amp_array.py +++ b/compiler/modules/sense_amp_array.py @@ -19,7 +19,7 @@ class sense_amp_array(design.design): Dynamically generated sense amp array for all bitlines. """ - def __init__(self, name, word_size, words_per_row): + def __init__(self, name, word_size, words_per_row, num_spare_cols=None): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("word_size {0}".format(word_size)) @@ -27,8 +27,12 @@ class sense_amp_array(design.design): self.word_size = word_size self.words_per_row = words_per_row - self.row_size = self.word_size * self.words_per_row - + + if not num_spare_cols: + self.num_spare_cols = 0 + else: + self.num_spare_cols = num_spare_cols + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -58,9 +62,9 @@ class sense_amp_array(design.design): self.height = self.amp.height if self.bitcell.width > self.amp.width: - self.width = self.bitcell.width * self.word_size * self.words_per_row + self.width = self.bitcell.width * (self.word_size * self.words_per_row + self.num_spare_cols) else: - self.width = self.amp.width * self.word_size * self.words_per_row + self.width = self.amp.width * (self.word_size * self.words_per_row + self.num_spare_cols) self.place_sense_amp_array() self.add_layout_pins() @@ -69,7 +73,7 @@ class sense_amp_array(design.design): self.DRC_LVS() def add_pins(self): - for i in range(0,self.word_size): + for i in range(0,self.word_size + self.num_spare_cols): 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") @@ -88,8 +92,7 @@ class sense_amp_array(design.design): def create_sense_amp_array(self): self.local_insts = [] - for i in range(0,self.word_size): - + for i in range(0,self.word_size + self.num_spare_cols): name = "sa_d{0}".format(i) self.local_insts.append(self.add_inst(name=name, mod=self.amp)) @@ -102,13 +105,14 @@ class sense_amp_array(design.design): from tech import cell_properties if self.bitcell.width > self.amp.width: amp_spacing = self.bitcell.width * self.words_per_row + spare_cols_spacing = self.bitcell.width else: amp_spacing = self.amp.width * self.words_per_row + spare_cols_spacing = self.amp.width for i in range(0,self.word_size): xoffset = amp_spacing * i - - # align the xoffset to the grid of bitcells. This way we + # align the xoffset to the grid of bitcells. This way we # know when to do the mirroring. grid_x = int(xoffset / self.amp.width) @@ -120,6 +124,23 @@ class sense_amp_array(design.design): amp_position = vector(xoffset, 0) self.local_insts[i].place(offset=amp_position,mirror=mirror) + + # place spare sense amps (will share the same enable as regular sense amps) + for i in range(0,self.num_spare_cols): + index = self.word_size + i + xoffset = ((self.word_size * self.words_per_row) + i) * spare_cols_spacing + # align the xoffset to the grid of bitcells. This way we + # know when to do the mirroring. + grid_x = int(xoffset / self.amp.width) + + if cell_properties.bitcell.mirror.y and grid_x % 2: + mirror = "MY" + xoffset = xoffset + self.amp.width + else: + mirror = "" + + amp_position = vector(xoffset, 0) + self.local_insts[index].place(offset=amp_position,mirror=mirror) def add_layout_pins(self): @@ -173,7 +194,7 @@ class sense_amp_array(design.design): def get_en_cin(self): """Get the relative capacitance of all the sense amp enable connections in the array""" sense_amp_en_cin = self.amp.get_en_cin() - return sense_amp_en_cin * self.word_size + return sense_amp_en_cin * (self.word_size + self.num_spare_cols) def get_drain_cin(self): """Get the relative capacitance of the drain of the PMOS isolation TX""" diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 08a2e007..f56c5e49 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -19,7 +19,7 @@ class write_driver_array(design.design): Dynamically generated write driver array of all bitlines. """ - def __init__(self, name, columns, word_size,write_size=None): + def __init__(self, name, columns, word_size, num_spare_cols=None, write_size=None): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("columns: {0}".format(columns)) @@ -29,6 +29,10 @@ class write_driver_array(design.design): self.word_size = word_size self.write_size = write_size self.words_per_row = int(columns / word_size) + if not num_spare_cols: + self.num_spare_cols = 0 + else: + self.num_spare_cols = num_spare_cols if self.write_size: self.num_wmasks = int(self.word_size/self.write_size) @@ -61,9 +65,13 @@ class write_driver_array(design.design): def create_layout(self): if self.bitcell.width > self.driver.width: - self.width = self.columns * self.bitcell.width + self.width = (self.columns + self.num_spare_cols) * self.bitcell.width + self.width_regular_cols = self.columns * self.bitcell.width + self.single_col_width = self.bitcell.width else: - self.width = self.columns * self.driver.width + self.width = (self.columns + self.num_spare_cols) * self.driver.width + self.width_regular_cols = self.columns * self.driver.width + self.single_col_width = self.driver.width self.height = self.driver.height self.place_write_array() @@ -72,14 +80,17 @@ class write_driver_array(design.design): self.DRC_LVS() def add_pins(self): - for i in range(self.word_size): + for i in range(self.word_size + self.num_spare_cols): self.add_pin(self.data_name + "_{0}".format(i), "INPUT") - for i in range(self.word_size): + for i in range(self.word_size + self.num_spare_cols): 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") + elif self.num_spare_cols: + for i in range(self.num_spare_cols + 1): + self.add_pin(self.en_name + "_{0}".format(i), "INPUT") else: self.add_pin(self.en_name, "INPUT") self.add_pin("vdd", "POWER") @@ -113,12 +124,30 @@ class write_driver_array(design.design): if w == self.write_size: w = 0 windex+=1 + + elif self.num_spare_cols: + 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(0), "vdd", "gnd"]) + 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"]) + for i in range(self.num_spare_cols): + index = self.word_size + i + name = "write_driver{}".format(index) + self.driver_insts[index]=self.add_inst(name=name, + mod=self.driver) + + 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(i + 1), "vdd", "gnd"]) + def place_write_array(self): from tech import cell_properties @@ -139,9 +168,23 @@ class write_driver_array(design.design): base = vector(xoffset, 0) self.driver_insts[index].place(offset=base, mirror=mirror) + # place spare write drivers (if spare columns are specified) + for i in range(self.num_spare_cols): + index = self.word_size + i + xoffset = (self.columns + 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): + for i in range(self.word_size + self.num_spare_cols): 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), @@ -186,14 +229,29 @@ class write_driver_array(design.design): offset=en_pin.ll(), width=wmask_en_len-en_gap, height=en_pin.height()) + + elif self.num_spare_cols: + # shorten enable rail to accomodate those for spare write drivers + inst = self.driver_insts[0] + self.add_layout_pin(text=self.en_name + "_{0}".format(0), + layer="m1", + offset=inst.get_pin(inst.mod.en_name).ll(), + width=self.width_regular_cols - (self.words_per_row * inst.get_pin(inst.mod.en_name).width())) + + # individual enables for every spare write driver + for i in range(self.num_spare_cols): + inst = self.driver_insts[self.word_size + i] + self.add_layout_pin(text=self.en_name + "_{0}".format(i + 1), + layer="m1", + offset=inst.get_pin(inst.mod.en_name).ll(), + width=self.single_col_width - inst.get_pin(inst.mod.en_name).width()) + 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): diff --git a/compiler/options.py b/compiler/options.py index 1c5d3e6a..5a35b173 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -45,6 +45,7 @@ class options(optparse.Values): # You can manually specify banks, but it is better to auto-detect it. num_banks = 1 num_spare_rows = 0 + # num_spare_cols = 0 ################### # Optimization options diff --git a/compiler/sram/sram_config.py b/compiler/sram/sram_config.py index e5d9c8dc..3af2fd9c 100644 --- a/compiler/sram/sram_config.py +++ b/compiler/sram/sram_config.py @@ -14,19 +14,18 @@ from sram_factory import factory class sram_config: """ This is a structure that is used to hold the SRAM configuration options. """ - def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0): + def __init__(self, word_size, num_words, write_size = None, num_banks=1, words_per_row=None, num_spare_rows=0, num_spare_cols=None): self.word_size = word_size self.num_words = num_words self.write_size = write_size self.num_banks = num_banks self.num_spare_rows = num_spare_rows + self.num_spare_cols = num_spare_cols # This will get over-written when we determine the organization self.words_per_row = words_per_row - self.compute_sizes() - - + self.compute_sizes() def set_local_config(self, module): """ Copy all of the member variables to the given module for convenience """ diff --git a/compiler/tests/09_sense_amp_array_spare_cols_test.py b/compiler/tests/09_sense_amp_array_spare_cols_test.py new file mode 100755 index 00000000..1eabe196 --- /dev/null +++ b/compiler/tests/09_sense_amp_array_spare_cols_test.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# 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 unittest +from testutils import * +import sys,os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + +class sense_amp_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + # check sense amp array for single port + debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2") + a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=1, num_spare_cols=3) + self.local_check(a) + + debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4") + a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4, num_spare_cols=2) + self.local_check(a) + + # check sense amp array for multi-port + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 0 + OPTS.num_r_ports = 0 + + factory.reset() + debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=2 (multi-port case)") + a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2, num_spare_cols=2) + self.local_check(a) + + debug.info(2, "Testing sense_amp_array for word_size=4, words_per_row=4 (multi-port case)") + a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4, num_spare_cols=3) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/10_write_driver_array_spare_cols_test.py b/compiler/tests/10_write_driver_array_spare_cols_test.py new file mode 100755 index 00000000..c5e7132f --- /dev/null +++ b/compiler/tests/10_write_driver_array_spare_cols_test.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +# 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 unittest +from testutils import * +import sys,os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + +class write_driver_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + # check write driver array for single port + debug.info(2, "Testing write_driver_array for columns=8, word_size=8") + a = factory.create(module_type="write_driver_array", columns=8, word_size=8, num_spare_cols=3) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=8") + a = factory.create(module_type="write_driver_array", columns=16, word_size=8, num_spare_cols=3) + self.local_check(a) + + # check write driver array for multi-port + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_w_ports = 0 + OPTS.num_r_ports = 0 + + factory.reset() + debug.info(2, "Testing write_driver_array for columns=8, word_size=8 (multi-port case)") + a = factory.create(module_type="write_driver_array", columns=8, word_size=8, num_spare_cols=3) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=8 (multi-port case)") + a = factory.create(module_type="write_driver_array", columns=16, word_size=8, num_spare_cols=3) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/18_port_data_spare_cols_test.py b/compiler/tests/18_port_data_spare_cols_test.py new file mode 100755 index 00000000..1695f861 --- /dev/null +++ b/compiler/tests/18_port_data_spare_cols_test.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2019 Regents of the University of California +# All rights reserved. +# +import unittest +from testutils import * +import sys,os +sys.path.append(os.getenv("OPENRAM_HOME")) +import globals +from globals import OPTS +from sram_factory import factory +import debug + +class port_data_spare_cols_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + from sram_config import sram_config + + c = sram_config(word_size=8, + num_words=16, + num_spare_rows=1, + num_spare_cols=1) + + c.words_per_row=1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + c.num_words=64 + c.words_per_row=4 + c.num_spare_cols=3 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + c.word_size=2 + c.num_words=128 + c.words_per_row=8 + c.num_spare_cols=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + + OPTS.bitcell = "bitcell_1w_1r" + OPTS.num_rw_ports = 0 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 1 + + c.num_words=16 + c.words_per_row=1 + factory.reset() + c.recompute_sizes() + debug.info(1, "No column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + c.num_words=32 + c.words_per_row=2 + factory.reset() + c.recompute_sizes() + debug.info(1, "Two way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + c.num_words=64 + c.words_per_row=4 + factory.reset() + c.recompute_sizes() + debug.info(1, "Four way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + c.word_size=2 + c.num_words=128 + c.words_per_row=8 + factory.reset() + c.recompute_sizes() + debug.info(1, "Eight way column mux") + a = factory.create("port_data", sram_config=c, port=0) + self.local_check(a) + a = factory.create("port_data", sram_config=c, port=1) + self.local_check(a) + + globals.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = globals.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner())