diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index 078dc3ae..c8805049 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -20,7 +20,7 @@ class control_logic(design.design): Dynamically generated Control logic for the total SRAM circuit. """ - def __init__(self, num_rows, words_per_row, word_size, sram=None, port_type="rw", name=""): + def __init__(self, num_rows, words_per_row, word_size, spare_columns=None, sram=None, port_type="rw", name=""): """ Constructor """ name = "control_logic_" + port_type design.design.__init__(self, name) @@ -35,7 +35,12 @@ class control_logic(design.design): self.word_size = word_size self.port_type = port_type - self.num_cols = word_size * words_per_row + if not spare_columns: + self.num_spare_cols = spare_columns + else: + self.num_spare_cols = 0 + + self.num_cols = word_size * words_per_row + self.num_spare_cols self.num_words = num_rows * words_per_row self.enable_delay_chain_resizing = False diff --git a/compiler/sram/sram_1bank.py b/compiler/sram/sram_1bank.py index 8dbcfaf4..ac4b7e33 100644 --- a/compiler/sram/sram_1bank.py +++ b/compiler/sram/sram_1bank.py @@ -71,7 +71,7 @@ class sram_1bank(sram_base): self.wmask_bus_size = self.m2_nonpref_pitch * (max(self.num_wmasks + 1, self.col_addr_size + 1)) + self.wmask_bus_gap else: self.data_bus_gap = self.m3_nonpref_pitch * 2 - self.data_bus_size = self.m3_nonpref_pitch * (max(self.word_size + 1, self.col_addr_size + 1)) + self.data_bus_gap + self.data_bus_size = self.m3_nonpref_pitch * (max(self.word_size + self.num_spare_cols + 1, self.col_addr_size + 1)) + self.data_bus_gap self.col_addr_bus_gap = self.m2_nonpref_pitch * 2 self.col_addr_bus_size = self.m2_nonpref_pitch * (self.col_addr_size) + self.col_addr_bus_gap @@ -191,7 +191,7 @@ class sram_1bank(sram_base): signal + "{}".format(port)) if port in self.read_ports: - for bit in range(self.word_size): + for bit in range(self.word_size + self.num_spare_cols): self.copy_layout_pin(self.bank_inst, "dout{0}_{1}".format(port, bit), "dout{0}[{1}]".format(port, bit)) @@ -208,7 +208,7 @@ class sram_1bank(sram_base): "addr{0}[{1}]".format(port, bit + self.col_addr_size)) if port in self.write_ports: - for bit in range(self.word_size): + for bit in range(self.word_size + self.num_spare_cols): self.copy_layout_pin(self.data_dff_insts[port], "din_{}".format(bit), "din{0}[{1}]".format(port, bit)) @@ -218,6 +218,10 @@ class sram_1bank(sram_base): self.copy_layout_pin(self.wmask_dff_insts[port], "din_{}".format(bit), "wmask{0}[{1}]".format(port, bit)) + for bit in range(self.num_spare_cols): + self.copy_layout_pin(self.bank_inst, + "spare_wen{0}_{1}".format(port, bit), + "spare_wen{0}[{1}]".format(port, bit)) def route_layout(self): """ Route a single bank SRAM """ @@ -380,7 +384,7 @@ class sram_1bank(sram_base): else: offset = self.data_dff_insts[port].ul() + vector(0, self.data_bus_gap) - dff_names = ["dout_{}".format(x) for x in range(self.word_size)] + dff_names = ["dout_{}".format(x) for x in range(self.word_size + self.num_spare_cols)] dff_pins = [self.data_dff_insts[port].get_pin(x) for x in dff_names] if self.write_size: for x in dff_names: @@ -393,7 +397,7 @@ class sram_1bank(sram_base): to_layer="m4", offset=pin_offset) - bank_names = ["din{0}_{1}".format(port, x) for x in range(self.word_size)] + bank_names = ["din{0}_{1}".format(port, x) for x in range(self.word_size + self.num_spare_cols)] bank_pins = [self.bank_inst.get_pin(x) for x in bank_names] if self.write_size: for x in bank_names: diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index bcb85308..0ca569af 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -37,6 +37,9 @@ class sram_base(design, verilog, lef): else: self.num_wmasks = 0 + if not self.num_spare_cols: + self.num_spare_cols = 0 + # For logical effort delay calculations. self.all_mods_except_control_done = False @@ -44,7 +47,7 @@ class sram_base(design, verilog, lef): """ Add pins for entire SRAM. """ for 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{0}[{1}]".format(port, bit), "INPUT") for port in self.all_ports: @@ -75,8 +78,10 @@ class sram_base(design, verilog, lef): for port in self.write_ports: for bit in range(self.num_wmasks): self.add_pin("wmask{0}[{1}]".format(port, bit), "INPUT") + for bit in range(self.num_spare_cols): + self.add_pin("spare_wen{0}[{1}]".format(port, bit), "INPUT") for 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{0}[{1}]".format(port, bit), "OUTPUT") self.add_pin("vdd", "POWER") @@ -274,7 +279,7 @@ class sram_base(design, verilog, lef): else: self.col_addr_dff = None - self.data_dff = factory.create("dff_array", module_name="data_dff", rows=1, columns=self.word_size) + self.data_dff = factory.create("dff_array", module_name="data_dff", rows=1, columns=self.word_size + self.num_spare_cols) self.add_mod(self.data_dff) if self.write_size: @@ -303,6 +308,7 @@ class sram_base(design, verilog, lef): self.control_logic_rw = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, + spare_columns=self.num_spare_cols, sram=self, port_type="rw") self.add_mod(self.control_logic_rw) @@ -310,6 +316,7 @@ class sram_base(design, verilog, lef): self.control_logic_w = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, + spare_columns=self.num_spare_cols, sram=self, port_type="w") self.add_mod(self.control_logic_w) @@ -317,6 +324,7 @@ class sram_base(design, verilog, lef): self.control_logic_r = self.mod_control_logic(num_rows=self.num_rows, words_per_row=self.words_per_row, word_size=self.word_size, + spare_columns=self.num_spare_cols, sram=self, port_type="r") self.add_mod(self.control_logic_r) @@ -328,12 +336,12 @@ class sram_base(design, verilog, lef): temp = [] for port in self.read_ports: - for bit in range(self.word_size): + for bit in range(self.word_size + self.num_spare_cols): temp.append("dout{0}[{1}]".format(port, bit)) for port in self.all_ports: temp.append("rbl_bl{0}".format(port)) for port in self.write_ports: - for bit in range(self.word_size): + for bit in range(self.word_size + self.num_spare_cols): temp.append("bank_din{0}[{1}]".format(port, bit)) for port in self.all_ports: for bit in range(self.bank_addr_size): @@ -349,6 +357,8 @@ class sram_base(design, verilog, lef): temp.append("w_en{0}".format(port)) for bit in range(self.num_wmasks): temp.append("bank_wmask{}[{}]".format(port, bit)) + for bit in range(self.num_spare_cols): + temp.append("spare_wen{0}[{1}]".format(port, bit)) for port in self.all_ports: temp.append("wl_en{0}".format(port)) temp.extend(["vdd", "gnd"]) @@ -436,7 +446,7 @@ class sram_base(design, verilog, lef): # inputs, outputs/output/bar inputs = [] outputs = [] - for bit in range(self.word_size): + for bit in range(self.word_size + self.num_spare_cols): inputs.append("din{}[{}]".format(port, bit)) outputs.append("bank_din{}[{}]".format(port, bit)) diff --git a/compiler/tests/20_sram_1bank_2mux_1rw_1r_spare_cols_test.py b/compiler/tests/20_sram_1bank_2mux_1rw_1r_spare_cols_test.py new file mode 100755 index 00000000..d087a47b --- /dev/null +++ b/compiler/tests/20_sram_1bank_2mux_1rw_1r_spare_cols_test.py @@ -0,0 +1,58 @@ +#!/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 sram_1bank_2mux_1rw_1r_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 + + OPTS.bitcell = "bitcell_1rw_1r" + OPTS.replica_bitcell = "replica_bitcell_1rw_1r" + OPTS.dummy_bitcell="dummy_bitcell_1rw_1r" + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + + c = sram_config(word_size=4, + num_words=32, + num_spare_cols=3, + 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, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + 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_2mux_1w_1r_spare_cols_test.py b/compiler/tests/20_sram_1bank_2mux_1w_1r_spare_cols_test.py new file mode 100755 index 00000000..349f5374 --- /dev/null +++ b/compiler/tests/20_sram_1bank_2mux_1w_1r_spare_cols_test.py @@ -0,0 +1,59 @@ +#!/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_psram_1bank_2mux_1w_1r_test, odd supply routing error") +class psram_1bank_2mux_1w_1r_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 + + OPTS.bitcell = "bitcell_1w_1r" + OPTS.replica_bitcell="replica_bitcell_1w_1r" + OPTS.dummy_bitcell="dummy_bitcell_1w_1r" + OPTS.num_rw_ports = 0 + OPTS.num_w_ports = 1 + OPTS.num_r_ports = 1 + + c = sram_config(word_size=4, + num_words=32, + num_spare_cols=3, + num_banks=1) + c.num_words=32 + c.words_per_row=2 + c.recompute_sizes() + debug.info(1, "Layout test for {}rw,{}r,{}w sram " + "with {} bit words, {} words, {} words per " + "row, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + 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_1rw_1r_spare_cols_test.py b/compiler/tests/20_sram_1bank_nomux_1rw_1r_spare_cols_test.py new file mode 100755 index 00000000..d2df2aef --- /dev/null +++ b/compiler/tests/20_sram_1bank_nomux_1rw_1r_spare_cols_test.py @@ -0,0 +1,59 @@ +#!/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 sram_1bank_nomux_1rw_1r_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 + + OPTS.bitcell = "bitcell_1rw_1r" + OPTS.replica_bitcell = "replica_bitcell_1rw_1r" + OPTS.dummy_bitcell = "dummy_bitcell_1rw_1r" + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 0 + + c = sram_config(word_size=4, + num_words=16, + num_spare_cols=4, + 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, {} words per " + "row, {} spare columns, {} banks".format(OPTS.num_rw_ports, + OPTS.num_r_ports, + OPTS.num_w_ports, + c.word_size, + c.num_words, + c.words_per_row, + c.num_spare_cols, + 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())