diff --git a/compiler/modules/port_data.py b/compiler/modules/port_data.py index 9ff99bdd..968b4605 100644 --- a/compiler/modules/port_data.py +++ b/compiler/modules/port_data.py @@ -386,8 +386,10 @@ class port_data(design.design): if self.write_size is not None: for i in range(self.num_wmasks): temp.append("wdriver_sel_{}".format(i)) + for i in range(self.num_spare_cols): + temp.append("spare_wen{}".format(i)) - elif self.num_spare_cols: + elif self.num_spare_cols and not self.write_size: temp.append("w_en") for i in range(self.num_spare_cols): temp.append("spare_wen{}".format(i)) @@ -690,7 +692,7 @@ class port_data(design.design): else: debug.error("Didn't find precharge array.") - # Copy layout pins of spare columns + # Copy bitlines of spare columns for bit in range(self.num_spare_cols): if self.precharge_array_inst: self.copy_layout_pin(self.precharge_array_inst, @@ -718,7 +720,10 @@ class port_data(design.design): 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: + for bit in range(self.num_spare_cols): + # Add spare columns' en_{} pins + self.copy_layout_pin(self.write_driver_array_inst, "en_{}".format(bit + self.num_wmasks), "spare_wen{}".format(bit)) + elif self.num_spare_cols and not self.write_mask_and_array_inst: 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)) diff --git a/compiler/modules/write_driver_array.py b/compiler/modules/write_driver_array.py index 640db97e..48564e86 100644 --- a/compiler/modules/write_driver_array.py +++ b/compiler/modules/write_driver_array.py @@ -85,9 +85,9 @@ class write_driver_array(design.design): 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): + for i in range(self.num_wmasks + self.num_spare_cols): self.add_pin(self.en_name + "_{0}".format(i), "INPUT") - elif self.num_spare_cols: + elif self.num_spare_cols and not self.write_size: for i in range(self.num_spare_cols + 1): self.add_pin(self.en_name + "_{0}".format(i), "INPUT") else: @@ -124,7 +124,7 @@ class write_driver_array(design.design): w = 0 windex+=1 - elif self.num_spare_cols: + elif self.num_spare_cols and not 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), @@ -138,6 +138,10 @@ class write_driver_array(design.design): for i in range(self.num_spare_cols): index = self.word_size + i + if self.write_size: + offset = self.num_wmasks + else: + offset = 1 name = "write_driver{}".format(index) self.driver_insts[index]=self.add_inst(name=name, mod=self.driver) @@ -145,7 +149,7 @@ class write_driver_array(design.design): 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"]) + self.en_name + "_{0}".format(i + offset), "vdd", "gnd"]) def place_write_array(self): @@ -227,8 +231,16 @@ class write_driver_array(design.design): offset=en_pin.ll(), width=wmask_en_len - en_gap, height=en_pin.height()) + + 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 + self.num_wmasks), + layer="m1", + offset=inst.get_pin(inst.mod.en_name).ll(), + width=self.single_col_width - inst.get_pin(inst.mod.en_name).width()) + - elif self.num_spare_cols: + elif self.num_spare_cols and not self.write_size: # 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), diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index ac4b7e33..4af19f98 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -66,7 +66,7 @@ class sram_1bank(sram_base): # So, m3 non-pref pitch means that this is routed on the m2 layer. if self.write_size: self.data_bus_gap = self.m4_nonpref_pitch * 2 - self.data_bus_size = self.m4_nonpref_pitch * (self.word_size) + self.data_bus_gap + self.data_bus_size = self.m4_nonpref_pitch * (self.word_size + self.num_spare_cols) + self.data_bus_gap self.wmask_bus_gap = self.m2_nonpref_pitch * 2 self.wmask_bus_size = self.m2_nonpref_pitch * (max(self.num_wmasks + 1, self.col_addr_size + 1)) + self.wmask_bus_gap else: diff --git a/compiler/tests/10_write_driver_array_wmask_spare_cols_test.py b/compiler/tests/10_write_driver_array_wmask_spare_cols_test.py new file mode 100755 index 00000000..be85665e --- /dev/null +++ b/compiler/tests/10_write_driver_array_wmask_spare_cols_test.py @@ -0,0 +1,47 @@ +#!/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, write_size=4") + a = factory.create(module_type="write_driver_array", columns=8, word_size=8, write_size=4, num_spare_cols=3) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=16, write_size=2") + a = factory.create(module_type="write_driver_array", columns=16, word_size=16, write_size=2, num_spare_cols=2) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=8, write_size=4") + a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4) + 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/20_sram_1bank_2mux_wmask_spare_cols_test.py b/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py new file mode 100755 index 00000000..0e9c74c3 --- /dev/null +++ b/compiler/tests/20_sram_1bank_2mux_wmask_spare_cols_test.py @@ -0,0 +1,56 @@ +#!/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 + + +# @unittest.skip("SKIPPING 20_sram_1bank_2mux_wmask_test") +class sram_1bank_2mux_wmask_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, + write_size=4, + num_spare_cols=3, + num_words=64, + num_banks=1) + + c.words_per_row = 2 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} bit writes, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.write_size, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + 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/20_sram_1bank_nomux_wmask_spare_cols_test.py b/compiler/tests/20_sram_1bank_nomux_wmask_spare_cols_test.py new file mode 100755 index 00000000..dba96ca2 --- /dev/null +++ b/compiler/tests/20_sram_1bank_nomux_wmask_spare_cols_test.py @@ -0,0 +1,56 @@ +#!/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 + + +# @unittest.skip("SKIPPING 20_sram_1bank_nomux_wmask_test") +class sram_1bank_nomux_wmask_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, + write_size=4, + num_spare_cols=3, + num_words=16, + num_banks=1) + + c.words_per_row = 1 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} bit writes, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.write_size, + c.words_per_row, + c.num_banks)) + a = factory.create(module_type="sram", sram_config=c) + self.local_check(a, final_verification=True) + + 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())