From 75bd2b46a548b888eeade14fdfa27895ab337e2f Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Thu, 9 Apr 2020 10:02:15 -0700 Subject: [PATCH 01/28] OpenRAM v1.1.5 --- compiler/globals.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/globals.py b/compiler/globals.py index 3277ab1d..dbb1f962 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -19,7 +19,7 @@ import re import copy import importlib -VERSION = "1.1.4" +VERSION = "1.1.5" NAME = "OpenRAM v{}".format(VERSION) USAGE = "openram.py [options] \nUse -h for help.\n" From fbc6dfdaac3688f3a18283646bd3f1e961a45dcd Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Fri, 17 Apr 2020 12:26:18 -0700 Subject: [PATCH 02/28] split pbitcell tests --- ...4_single_level_column_mux_pbitcell_test.py | 49 +++++++++++++++++ .../tests/04_single_level_column_mux_test.py | 20 +------ ...hierarchical_predecode2x4_pbitcell_test.py | 6 +- .../06_hierarchical_predecode2x4_test.py | 2 +- ...hierarchical_predecode3x8_pbitcell_test.py | 2 +- .../06_hierarchical_predecode3x8_test.py | 2 +- ...le_level_column_mux_array_pbitcell_test.py | 55 +++++++++++++++++++ .../07_single_level_column_mux_array_test.py | 27 +-------- .../tests/08_wordline_driver_pbitcell_test.py | 44 +++++++++++++++ compiler/tests/08_wordline_driver_test.py | 13 +---- compiler/tests/09_sense_amp_array_test.py | 15 ----- .../tests/09_sense_amp_array_test_pbitcell.py | 46 ++++++++++++++++ .../10_write_driver_array_pbitcell_test.py | 46 ++++++++++++++++ compiler/tests/10_write_driver_array_test.py | 15 ----- ..._write_driver_array_wmask_pbitcell_test.py | 49 +++++++++++++++++ .../tests/10_write_driver_array_wmask_test.py | 15 ----- .../10_write_mask_and_array_pbitcell_test.py | 49 +++++++++++++++++ .../tests/10_write_mask_and_array_test.py | 15 ----- .../tests/19_bank_select_pbitcell_test.py | 48 ++++++++++++++++ compiler/tests/19_bank_select_test.py | 19 +------ 20 files changed, 398 insertions(+), 139 deletions(-) create mode 100644 compiler/tests/04_single_level_column_mux_pbitcell_test.py create mode 100644 compiler/tests/07_single_level_column_mux_array_pbitcell_test.py create mode 100644 compiler/tests/08_wordline_driver_pbitcell_test.py create mode 100644 compiler/tests/09_sense_amp_array_test_pbitcell.py create mode 100644 compiler/tests/10_write_driver_array_pbitcell_test.py create mode 100644 compiler/tests/10_write_driver_array_wmask_pbitcell_test.py create mode 100644 compiler/tests/10_write_mask_and_array_pbitcell_test.py create mode 100644 compiler/tests/19_bank_select_pbitcell_test.py diff --git a/compiler/tests/04_single_level_column_mux_pbitcell_test.py b/compiler/tests/04_single_level_column_mux_pbitcell_test.py new file mode 100644 index 00000000..85f909e6 --- /dev/null +++ b/compiler/tests/04_single_level_column_mux_pbitcell_test.py @@ -0,0 +1,49 @@ +#!/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 04_driver_test") + +class single_level_column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + # check single level column mux in multi-port + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 1 + + factory.reset() + debug.info(2, "Checking column mux for pbitcell (innermost connections)") + tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") + self.local_check(tx) + + factory.reset() + debug.info(2, "Checking column mux for pbitcell (outermost connections)") + tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2") + self.local_check(tx) + + 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/04_single_level_column_mux_test.py b/compiler/tests/04_single_level_column_mux_test.py index de5870fc..2b437987 100755 --- a/compiler/tests/04_single_level_column_mux_test.py +++ b/compiler/tests/04_single_level_column_mux_test.py @@ -22,30 +22,14 @@ class single_level_column_mux_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - + # check single level column mux in single port debug.info(2, "Checking column mux") tx = factory.create(module_type="single_level_column_mux", tx_size=8) self.local_check(tx) - - # check single level column mux in multi-port - OPTS.bitcell = "pbitcell" - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 1 - OPTS.num_w_ports = 1 - - factory.reset() - debug.info(2, "Checking column mux for pbitcell (innermost connections)") - tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") - self.local_check(tx) - - factory.reset() - debug.info(2, "Checking column mux for pbitcell (outermost connections)") - tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2") - self.local_check(tx) globals.end_openram() - + # run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() diff --git a/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py b/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py index 8afc45da..bc4a153f 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py @@ -26,13 +26,13 @@ class hierarchical_predecode2x4_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + debug.info(1, "Testing sample for hierarchy_predecode2x4 (multi-port case)") a = factory.create(module_type="hierarchical_predecode2x4") self.local_check(a) - + globals.end_openram() - + # run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() diff --git a/compiler/tests/06_hierarchical_predecode2x4_test.py b/compiler/tests/06_hierarchical_predecode2x4_test.py index 8bb42253..ebb06330 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_test.py @@ -27,7 +27,7 @@ class hierarchical_predecode2x4_test(openram_test): self.local_check(a) globals.end_openram() - + # run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() diff --git a/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py b/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py index 34d38ddf..ffe68102 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py @@ -26,7 +26,7 @@ class hierarchical_predecode3x8_test(openram_test): OPTS.num_rw_ports = 1 OPTS.num_w_ports = 0 OPTS.num_r_ports = 0 - + debug.info(1, "Testing sample for hierarchy_predecode3x8 (multi-port case)") a = factory.create(module_type="hierarchical_predecode3x8") self.local_check(a) diff --git a/compiler/tests/06_hierarchical_predecode3x8_test.py b/compiler/tests/06_hierarchical_predecode3x8_test.py index f01fae03..63acc416 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_test.py @@ -25,7 +25,7 @@ class hierarchical_predecode3x8_test(openram_test): debug.info(1, "Testing sample for hierarchy_predecode3x8") a = factory.create(module_type="hierarchical_predecode3x8") self.local_check(a) - + globals.end_openram() # run the test from the command line diff --git a/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py b/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py new file mode 100644 index 00000000..d929b855 --- /dev/null +++ b/compiler/tests/07_single_level_column_mux_array_pbitcell_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. +# +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 single_level_column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + import single_level_column_mux_array + + # check single level column mux array in multi-port + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 1 + + factory.reset() + debug.info(1, "Testing sample for 2-way column_mux_array in multi-port") + a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") + self.local_check(a) + + debug.info(1, "Testing sample for 4-way column_mux_array in multi-port") + a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + self.local_check(a) + + debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)") + a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") + self.local_check(a) + + debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)") + a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2") + 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/07_single_level_column_mux_array_test.py b/compiler/tests/07_single_level_column_mux_array_test.py index ff6c51eb..c5d48689 100755 --- a/compiler/tests/07_single_level_column_mux_array_test.py +++ b/compiler/tests/07_single_level_column_mux_array_test.py @@ -20,7 +20,7 @@ class single_level_column_mux_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) import single_level_column_mux_array - + # check single level column mux array in single port debug.info(1, "Testing sample for 2-way column_mux_array") a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8) @@ -33,32 +33,9 @@ class single_level_column_mux_test(openram_test): debug.info(1, "Testing sample for 8-way column_mux_array") a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4) self.local_check(a) - - # check single level column mux array in multi-port - OPTS.bitcell = "pbitcell" - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 1 - OPTS.num_w_ports = 1 - - factory.reset() - debug.info(1, "Testing sample for 2-way column_mux_array in multi-port") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") - self.local_check(a) - - debug.info(1, "Testing sample for 4-way column_mux_array in multi-port") - a = factory.create(module_type="single_level_column_mux_array", columns=16, word_size=4, bitcell_bl="bl0", bitcell_br="br0") - self.local_check(a) - - debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (innermost connections)") - a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl0", bitcell_br="br0") - self.local_check(a) - - debug.info(1, "Testing sample for 8-way column_mux_array in multi-port (outermost connections)") - a = factory.create(module_type="single_level_column_mux_array", columns=32, word_size=4, bitcell_bl="bl2", bitcell_br="br2") - self.local_check(a) globals.end_openram() - + # run the test from the command line if __name__ == "__main__": diff --git a/compiler/tests/08_wordline_driver_pbitcell_test.py b/compiler/tests/08_wordline_driver_pbitcell_test.py new file mode 100644 index 00000000..42de5c26 --- /dev/null +++ b/compiler/tests/08_wordline_driver_pbitcell_test.py @@ -0,0 +1,44 @@ +#!/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 04_driver_test") + +class wordline_driver_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + # check wordline driver 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, "Checking driver (multi-port case)") + tx = factory.create(module_type="wordline_driver", rows=8, cols=64) + self.local_check(tx) + + 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/08_wordline_driver_test.py b/compiler/tests/08_wordline_driver_test.py index f64503f8..8a18a59d 100755 --- a/compiler/tests/08_wordline_driver_test.py +++ b/compiler/tests/08_wordline_driver_test.py @@ -28,19 +28,8 @@ class wordline_driver_test(openram_test): tx = factory.create(module_type="wordline_driver", rows=8, cols=32) self.local_check(tx) - # check wordline driver 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, "Checking driver (multi-port case)") - tx = factory.create(module_type="wordline_driver", rows=8, cols=64) - self.local_check(tx) - globals.end_openram() - + # run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() diff --git a/compiler/tests/09_sense_amp_array_test.py b/compiler/tests/09_sense_amp_array_test.py index 88b5a9aa..459113f2 100755 --- a/compiler/tests/09_sense_amp_array_test.py +++ b/compiler/tests/09_sense_amp_array_test.py @@ -34,21 +34,6 @@ class sense_amp_test(openram_test): a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=4) 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) - 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) - self.local_check(a) - globals.end_openram() # run the test from the command line diff --git a/compiler/tests/09_sense_amp_array_test_pbitcell.py b/compiler/tests/09_sense_amp_array_test_pbitcell.py new file mode 100644 index 00000000..7c2fbd2d --- /dev/null +++ b/compiler/tests/09_sense_amp_array_test_pbitcell.py @@ -0,0 +1,46 @@ +#!/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 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) + 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) + 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_pbitcell_test.py b/compiler/tests/10_write_driver_array_pbitcell_test.py new file mode 100644 index 00000000..87849001 --- /dev/null +++ b/compiler/tests/10_write_driver_array_pbitcell_test.py @@ -0,0 +1,46 @@ +#!/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 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) + 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) + 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_test.py b/compiler/tests/10_write_driver_array_test.py index 16e280ed..8db26a5a 100755 --- a/compiler/tests/10_write_driver_array_test.py +++ b/compiler/tests/10_write_driver_array_test.py @@ -29,22 +29,7 @@ class write_driver_test(openram_test): 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) 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) - 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) - self.local_check(a) - globals.end_openram() # run the test from the command line diff --git a/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py b/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py new file mode 100644 index 00000000..046b4d22 --- /dev/null +++ b/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py @@ -0,0 +1,49 @@ +#!/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 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, write_size=4 (multi-port case)") + a = factory.create(module_type="write_driver_array", columns=8, word_size=8, write_size=4) + self.local_check(a) + + debug.info(2, "Testing write_driver_array for columns=16, word_size=8, write_size=4 (multi-port case)") + 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/10_write_driver_array_wmask_test.py b/compiler/tests/10_write_driver_array_wmask_test.py index 743d331a..15e32b19 100755 --- a/compiler/tests/10_write_driver_array_wmask_test.py +++ b/compiler/tests/10_write_driver_array_wmask_test.py @@ -36,21 +36,6 @@ class write_driver_test(openram_test): a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4) 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, write_size=4 (multi-port case)") - a = factory.create(module_type="write_driver_array", columns=8, word_size=8, write_size=4) - self.local_check(a) - - debug.info(2, "Testing write_driver_array for columns=16, word_size=8, write_size=4 (multi-port case)") - a = factory.create(module_type="write_driver_array", columns=16, word_size=8, write_size=4) - self.local_check(a) - globals.end_openram() diff --git a/compiler/tests/10_write_mask_and_array_pbitcell_test.py b/compiler/tests/10_write_mask_and_array_pbitcell_test.py new file mode 100644 index 00000000..5068c119 --- /dev/null +++ b/compiler/tests/10_write_mask_and_array_pbitcell_test.py @@ -0,0 +1,49 @@ +#!/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_mask_and_array_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 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_mask_and_array for columns=8, word_size=8, write_size=4 (multi-port case)") + a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4) + self.local_check(a) + + debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2 (multi-port case)") + a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2) + 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_mask_and_array_test.py b/compiler/tests/10_write_mask_and_array_test.py index 303ce2f4..42d80fa4 100755 --- a/compiler/tests/10_write_mask_and_array_test.py +++ b/compiler/tests/10_write_mask_and_array_test.py @@ -36,21 +36,6 @@ class write_mask_and_array_test(openram_test): a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2) 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_mask_and_array for columns=8, word_size=8, write_size=4 (multi-port case)") - a = factory.create(module_type="write_mask_and_array", columns=8, word_size=8, write_size=4) - self.local_check(a) - - debug.info(2, "Testing write_mask_and_array for columns=16, word_size=8, write_size=2 (multi-port case)") - a = factory.create(module_type="write_mask_and_array", columns=16, word_size=8, write_size=2) - self.local_check(a) - globals.end_openram() diff --git a/compiler/tests/19_bank_select_pbitcell_test.py b/compiler/tests/19_bank_select_pbitcell_test.py new file mode 100644 index 00000000..6bf5929e --- /dev/null +++ b/compiler/tests/19_bank_select_pbitcell_test.py @@ -0,0 +1,48 @@ +#!/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 bank_select_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + OPTS.bitcell = "pbitcell" + debug.info(1, "No column mux, rw control logic") + a = factory.create(module_type="bank_select", port="rw") + self.local_check(a) + + OPTS.num_rw_ports = 0 + OPTS.num_w_ports = 1 + OPTS.num_r_ports = 1 + + debug.info(1, "No column mux, w control logic") + a = factory.create(module_type="bank_select", port="w") + self.local_check(a) + + debug.info(1, "No column mux, r control logic") + a = factory.create(module_type="bank_select", port="r") + 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/19_bank_select_test.py b/compiler/tests/19_bank_select_test.py index adb2523e..afec4c3c 100755 --- a/compiler/tests/19_bank_select_test.py +++ b/compiler/tests/19_bank_select_test.py @@ -24,26 +24,9 @@ class bank_select_test(openram_test): debug.info(1, "No column mux, rw control logic") a = factory.create(module_type="bank_select", port="rw") self.local_check(a) - - OPTS.bitcell = "pbitcell" - debug.info(1, "No column mux, rw control logic") - a = factory.create(module_type="bank_select", port="rw") - self.local_check(a) - - OPTS.num_rw_ports = 0 - OPTS.num_w_ports = 1 - OPTS.num_r_ports = 1 - debug.info(1, "No column mux, w control logic") - a = factory.create(module_type="bank_select", port="w") - self.local_check(a) - - debug.info(1, "No column mux, r control logic") - a = factory.create(module_type="bank_select", port="r") - self.local_check(a) - globals.end_openram() - + # run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() From 7920b0cef99f0ece902a14c47fe5c37e9fa0f263 Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Fri, 17 Apr 2020 12:36:48 -0700 Subject: [PATCH 03/28] m3 min area rounding fix --- compiler/base/hierarchy_layout.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index e67f8d85..14136c9c 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -17,6 +17,7 @@ import os from globals import OPTS from vector import vector from pin_layout import pin_layout +from utils import round_to_grid class layout(): @@ -325,7 +326,7 @@ class layout(): file_name = "non_rectilinear.gds" self.gds_write(file_name) debug.error("Cannot have a non-manhatten layout pin: {}".format(file_name), -1) - + minwidth_layer = drc["minwidth_{}".format(layer)] # one of these will be zero @@ -1213,7 +1214,8 @@ class layout(): else: # Hack for min area if OPTS.tech_name == "s8": - height = width = sqrt(drc["minarea_m3"]) + width = round_to_grid(sqrt(drc["minarea_m3"])) + height = round_to_grid(drc["minarea_m3"]/width) else: width = via.width height = via.height From 7e36cd482855bfa5408ea0fb794be107adb6ada8 Mon Sep 17 00:00:00 2001 From: David Ratchkov Date: Fri, 17 Apr 2020 13:45:57 -0700 Subject: [PATCH 04/28] - Write voltage_map and pg_pin - Remove 'when' condition on leakage power - Remove 'clk*' from 'when' condition on internal_power on the same 'clk*' pin --- compiler/characterizer/lib.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 1e68fc2e..b0668ddc 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -181,17 +181,20 @@ class lib: self.lib.write(" dont_touch : true;\n") self.lib.write(" area : {};\n\n".format(self.sram.width * self.sram.height)) - #Build string of all control signals. + self.write_pg_pin() + + #Build string of all control signals. control_str = 'csb0' #assume at least 1 port for i in range(1, self.total_port_num): control_str += ' & csb{0}'.format(i) # Leakage is included in dynamic when macro is enabled self.lib.write(" leakage_power () {\n") - self.lib.write(" when : \"{0}\";\n".format(control_str)) + # 'when' condition unnecessary when cs pin does not turn power to devices + # self.lib.write(" when : \"{0}\";\n".format(control_str)) self.lib.write(" value : {};\n".format(self.char_sram_results["leakage_power"])) self.lib.write(" }\n") - self.lib.write(" cell_leakage_power : {};\n".format(0)) + self.lib.write(" cell_leakage_power : {};\n".format(self.char_sram_results["leakage_power"])) def write_units(self): @@ -240,6 +243,9 @@ class lib: self.lib.write(" default_max_fanout : 4.0 ;\n") self.lib.write(" default_connection_class : universal ;\n\n") + self.lib.write(" voltage_map ( vdd, {} );\n".format(tech.spice["nom_supply_voltage"])) + self.lib.write(" voltage_map ( gnd, 0 );\n\n") + def create_list(self,values): """ Helper function to create quoted, line wrapped list """ list_values = ", ".join(str(v) for v in values) @@ -518,7 +524,7 @@ class lib: web_name = " & !web{0}".format(port) avg_write_power = np.mean(self.char_port_results[port]["write1_power"] + self.char_port_results[port]["write0_power"]) self.lib.write(" internal_power(){\n") - self.lib.write(" when : \"!csb{0} & clk{0}{1}\"; \n".format(port, web_name)) + self.lib.write(" when : \"!csb{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") self.lib.write(" values(\"{0}\");\n".format(avg_write_power/2.0)) self.lib.write(" }\n") @@ -532,7 +538,7 @@ class lib: web_name = " & web{0}".format(port) avg_read_power = np.mean(self.char_port_results[port]["read1_power"] + self.char_port_results[port]["read0_power"]) self.lib.write(" internal_power(){\n") - self.lib.write(" when : \"!csb{0} & !clk{0}{1}\"; \n".format(port, web_name)) + self.lib.write(" when : \"!csb{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") self.lib.write(" values(\"{0}\");\n".format(avg_read_power/2.0)) self.lib.write(" }\n") @@ -552,6 +558,16 @@ class lib: self.lib.write(" }\n") self.lib.write(" }\n") + def write_pg_pin(self): + self.lib.write(" pg_pin(vdd) {\n") + self.lib.write(" voltage_name : VDD;\n") + self.lib.write(" pg_type : primary_power;\n") + self.lib.write(" }\n\n") + self.lib.write(" pg_pin(gnd) {\n") + self.lib.write(" voltage_name : GND;\n") + self.lib.write(" pg_type : primary_ground;\n") + self.lib.write(" }\n\n") + def compute_delay(self): """Compute SRAM delays for current corner""" self.d = delay(self.sram, self.sp_file, self.corner) From cbb67ad483fd6873d562e1d6f6a90711cf03c8a1 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 17 Apr 2020 13:57:52 -0700 Subject: [PATCH 05/28] Update to run LVS when no DRC errors too. --- compiler/tests/testutils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index eaac38e2..99d534d0 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -51,9 +51,9 @@ class openram_test(unittest.TestCase): drc_result=verify.run_drc(a.name, tempgds, extract=True, final_verification=final_verification) # Always run LVS if we are using magic - if "magic" in OPTS.drc_exe: + if "magic" in OPTS.drc_exe or drc_result == 0: lvs_result=verify.run_lvs(a.name, tempgds, tempspice, final_verification=final_verification) - + # Only allow DRC to fail and LVS to pass if we are using magic if "magic" in OPTS.drc_exe and lvs_result == 0 and drc_result != 0: #zip_file = "/tmp/{0}_{1}".format(a.name,os.getpid()) From 1f816e2823b56c0c3f406d4f7424e7fb6311b236 Mon Sep 17 00:00:00 2001 From: David Ratchkov Date: Fri, 17 Apr 2020 14:55:17 -0700 Subject: [PATCH 06/28] - Characterize actual disabled power (read mode only) - Report rise/fall power individually --- .gitignore | 2 ++ compiler/characterizer/delay.py | 15 +++++++++++++-- compiler/characterizer/lib.py | 22 +++++++++++++--------- compiler/characterizer/simulation.py | 16 ++++++++++++++++ 4 files changed, 44 insertions(+), 11 deletions(-) diff --git a/.gitignore b/.gitignore index 948e7d19..3d6e4f92 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,5 @@ *.toc *.synctex.gz **/model_data +outputs +technology/freepdk45/ncsu_basekit diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index a9f9542c..2823a415 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -59,7 +59,7 @@ class delay(simulation): """ Create measurement names. The names themselves currently define the type of measurement """ self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"] - self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power"] + self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power", "disabled_read0_power", "disabled_read1_power"] # self.voltage_when_names = ["volt_bl", "volt_br"] # self.bitline_delay_names = ["delay_bl", "delay_br"] @@ -108,6 +108,11 @@ class delay(simulation): self.read_lib_meas.append(power_measure("read0_power", "FALL", measure_scale=1e3)) self.read_lib_meas[-1].meta_str = sram_op.READ_ZERO + self.read_lib_meas.append(power_measure("disabled_read1_power", "RISE", measure_scale=1e3)) + self.read_lib_meas[-1].meta_str = "disabled_read1" + self.read_lib_meas.append(power_measure("disabled_read0_power", "FALL", measure_scale=1e3)) + self.read_lib_meas[-1].meta_str = "disabled_read0" + # This will later add a half-period to the spice time delay. Only for reading 0. for obj in self.read_lib_meas: if obj.meta_str is sram_op.READ_ZERO: @@ -665,7 +670,7 @@ class delay(simulation): if not success: feasible_period = 2 * feasible_period continue - + # Positions of measurements currently hardcoded. First 2 are delays, next 2 are slews feasible_delays = [results[port][mname] for mname in self.delay_meas_names if "delay" in mname] feasible_slews = [results[port][mname] for mname in self.delay_meas_names if "slew" in mname] @@ -1208,6 +1213,9 @@ class delay(simulation): read_port) self.measure_cycles[read_port][sram_op.READ_ZERO] = len(self.cycle_times)-1 + self.add_nop(self.probe_address, data_zeros, read_port) + self.measure_cycles[write_port]["disabled_read0"] = len(self.cycle_times) - 1 + self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)") self.add_write("W data 1 address {} to write value".format(self.probe_address), @@ -1223,6 +1231,9 @@ class delay(simulation): wmask_ones, write_port) + self.add_nop(self.probe_address, data_zeros, read_port) + self.measure_cycles[write_port]["disabled_read1"] = len(self.cycle_times) - 1 + # This also ensures we will have a L->H transition on the next read self.add_read("R data 0 address {} to clear dout caps".format(inverse_address), inverse_address, diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index b0668ddc..9f3c12d3 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -522,39 +522,43 @@ class lib: if port in self.write_ports: if port in self.read_ports: web_name = " & !web{0}".format(port) - avg_write_power = np.mean(self.char_port_results[port]["write1_power"] + self.char_port_results[port]["write0_power"]) + write1_power = np.mean(self.char_port_results[port]["write1_power"]) + write0_power = np.mean(self.char_port_results[port]["write0_power"]) self.lib.write(" internal_power(){\n") self.lib.write(" when : \"!csb{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") - self.lib.write(" values(\"{0}\");\n".format(avg_write_power/2.0)) + self.lib.write(" values(\"{0:.6e}\");\n".format(write1_power)) self.lib.write(" }\n") self.lib.write(" fall_power(scalar){\n") - self.lib.write(" values(\"{0}\");\n".format(avg_write_power/2.0)) + self.lib.write(" values(\"{0:.6e}\");\n".format(write0_power)) self.lib.write(" }\n") self.lib.write(" }\n") if port in self.read_ports: if port in self.write_ports: web_name = " & web{0}".format(port) - avg_read_power = np.mean(self.char_port_results[port]["read1_power"] + self.char_port_results[port]["read0_power"]) + read1_power = np.mean(self.char_port_results[port]["read1_power"]) + read0_power = np.mean(self.char_port_results[port]["read0_power"]) self.lib.write(" internal_power(){\n") self.lib.write(" when : \"!csb{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") - self.lib.write(" values(\"{0}\");\n".format(avg_read_power/2.0)) + self.lib.write(" values(\"{0:.6e}\");\n".format(read1_power)) self.lib.write(" }\n") self.lib.write(" fall_power(scalar){\n") - self.lib.write(" values(\"{0}\");\n".format(avg_read_power/2.0)) + self.lib.write(" values(\"{0:.6e}\");\n".format(read0_power)) self.lib.write(" }\n") self.lib.write(" }\n") - # Have 0 internal power when disabled, this will be represented as leakage power. + # Disabled power. + disabled_read1_power = np.mean(self.char_port_results[port]["disabled_read1_power"]) + disabled_read0_power = np.mean(self.char_port_results[port]["disabled_read0_power"]) self.lib.write(" internal_power(){\n") self.lib.write(" when : \"csb{0}\"; \n".format(port)) self.lib.write(" rise_power(scalar){\n") - self.lib.write(" values(\"0\");\n") + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read1_power)) self.lib.write(" }\n") self.lib.write(" fall_power(scalar){\n") - self.lib.write(" values(\"0\");\n") + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read0_power)) self.lib.write(" }\n") self.lib.write(" }\n") diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index adbe5f5f..0cfc860f 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -210,6 +210,22 @@ class simulation(): if unselected_port != port: self.add_noop_one_port(unselected_port) + def add_nop(self, address, din_data, port): + """ Add the control values for a cycle with clock only. Does not increment the period. """ + debug.check(port in self.read_ports or port in self.write_ports, + "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports)) + debug.info(2, 'Clock only on port {}'.format(port)) + self.fn_cycle_comments.append('Clock only on port {}'.format(port)) + self.append_cycle_comment(port, 'Clock only on port {}'.format(port)) + + self.cycle_times.append(self.t_current) + self.t_current += self.period + self.add_control_one_port(port, "noop") + # If the port is also a readwrite then add data. + if port in self.write_ports: + self.add_data(din_data, port) + self.add_address(address, port) + def add_noop_all_ports(self, comment): """ Add the control values for a noop to all ports. """ debug.info(2, comment) From 123cc371beabe50a21bdf4382ce332198cd20255 Mon Sep 17 00:00:00 2001 From: David Ratchkov Date: Fri, 17 Apr 2020 16:09:58 -0700 Subject: [PATCH 07/28] - Fix disabled power char --- compiler/characterizer/delay.py | 24 ++++++++++++++---- compiler/characterizer/lib.py | 37 +++++++++++++++++++--------- compiler/characterizer/simulation.py | 33 +++++++++++++------------ 3 files changed, 61 insertions(+), 33 deletions(-) diff --git a/compiler/characterizer/delay.py b/compiler/characterizer/delay.py index 2823a415..62367d72 100644 --- a/compiler/characterizer/delay.py +++ b/compiler/characterizer/delay.py @@ -59,7 +59,8 @@ class delay(simulation): """ Create measurement names. The names themselves currently define the type of measurement """ self.delay_meas_names = ["delay_lh", "delay_hl", "slew_lh", "slew_hl"] - self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power", "disabled_read0_power", "disabled_read1_power"] + self.power_meas_names = ["read0_power", "read1_power", "write0_power", "write1_power", + "disabled_read0_power", "disabled_read1_power", "disabled_write0_power", "disabled_write1_power"] # self.voltage_when_names = ["volt_bl", "volt_br"] # self.bitline_delay_names = ["delay_bl", "delay_br"] @@ -161,6 +162,11 @@ class delay(simulation): self.write_lib_meas.append(power_measure("write0_power", "FALL", measure_scale=1e3)) self.write_lib_meas[-1].meta_str = sram_op.WRITE_ZERO + self.write_lib_meas.append(power_measure("disabled_write1_power", "RISE", measure_scale=1e3)) + self.write_lib_meas[-1].meta_str = "disabled_write1" + self.write_lib_meas.append(power_measure("disabled_write0_power", "FALL", measure_scale=1e3)) + self.write_lib_meas[-1].meta_str = "disabled_write0" + write_measures = [] write_measures.append(self.write_lib_meas) write_measures.append(self.create_write_bit_measures()) @@ -1203,6 +1209,9 @@ class delay(simulation): write_port) self.measure_cycles[write_port][sram_op.WRITE_ZERO] = len(self.cycle_times)-1 + self.add_noop_clock_one_port(write_port) + self.measure_cycles[write_port]["disabled_write0"] = len(self.cycle_times)-1 + # This also ensures we will have a H->L transition on the next read self.add_read("R data 1 address {} to set dout caps".format(inverse_address), inverse_address, @@ -1213,8 +1222,9 @@ class delay(simulation): read_port) self.measure_cycles[read_port][sram_op.READ_ZERO] = len(self.cycle_times)-1 - self.add_nop(self.probe_address, data_zeros, read_port) - self.measure_cycles[write_port]["disabled_read0"] = len(self.cycle_times) - 1 + self.add_noop_clock_one_port(read_port) + self.measure_cycles[read_port]["disabled_read0"] = len(self.cycle_times) - 1 + self.add_noop_all_ports("Idle cycle (if read takes >1 cycle)") @@ -1225,14 +1235,18 @@ class delay(simulation): write_port) self.measure_cycles[write_port][sram_op.WRITE_ONE] = len(self.cycle_times)-1 + self.add_noop_clock_one_port(write_port) + self.measure_cycles[write_port]["disabled_write1"] = len(self.cycle_times)-1 + self.add_write("W data 0 address {} to clear din caps".format(inverse_address), inverse_address, data_zeros, wmask_ones, write_port) - self.add_nop(self.probe_address, data_zeros, read_port) - self.measure_cycles[write_port]["disabled_read1"] = len(self.cycle_times) - 1 + self.add_noop_clock_one_port(read_port) + self.measure_cycles[read_port]["disabled_read1"] = len(self.cycle_times) - 1 + # This also ensures we will have a L->H transition on the next read self.add_read("R data 0 address {} to clear dout caps".format(inverse_address), diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 9f3c12d3..57e21763 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -534,6 +534,19 @@ class lib: self.lib.write(" }\n") self.lib.write(" }\n") + # Disabled power. + disabled_read1_power = np.mean(self.char_port_results[port]["disabled_read1_power"]) + disabled_read0_power = np.mean(self.char_port_results[port]["disabled_raed0_power"]) + self.lib.write(" internal_power(){\n") + self.lib.write(" when : \"csb{0}{1}\"; \n".format(port, web_name)) + self.lib.write(" rise_power(scalar){\n") + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read1_power)) + self.lib.write(" }\n") + self.lib.write(" fall_power(scalar){\n") + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read0_power)) + self.lib.write(" }\n") + self.lib.write(" }\n") + if port in self.read_ports: if port in self.write_ports: web_name = " & web{0}".format(port) @@ -549,18 +562,18 @@ class lib: self.lib.write(" }\n") self.lib.write(" }\n") - # Disabled power. - disabled_read1_power = np.mean(self.char_port_results[port]["disabled_read1_power"]) - disabled_read0_power = np.mean(self.char_port_results[port]["disabled_read0_power"]) - self.lib.write(" internal_power(){\n") - self.lib.write(" when : \"csb{0}\"; \n".format(port)) - self.lib.write(" rise_power(scalar){\n") - self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read1_power)) - self.lib.write(" }\n") - self.lib.write(" fall_power(scalar){\n") - self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read0_power)) - self.lib.write(" }\n") - self.lib.write(" }\n") + # Disabled power. + disabled_write1_power = np.mean(self.char_port_results[port]["disabled_write1_power"]) + disabled_write0_power = np.mean(self.char_port_results[port]["disabled_write0_power"]) + self.lib.write(" internal_power(){\n") + self.lib.write(" when : \"csb{0}{1}\"; \n".format(port, web_name)) + self.lib.write(" rise_power(scalar){\n") + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_write1_power)) + self.lib.write(" }\n") + self.lib.write(" fall_power(scalar){\n") + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_write0_power)) + self.lib.write(" }\n") + self.lib.write(" }\n") def write_pg_pin(self): self.lib.write(" pg_pin(vdd) {\n") diff --git a/compiler/characterizer/simulation.py b/compiler/characterizer/simulation.py index 0cfc860f..0d5cfb25 100644 --- a/compiler/characterizer/simulation.py +++ b/compiler/characterizer/simulation.py @@ -210,22 +210,6 @@ class simulation(): if unselected_port != port: self.add_noop_one_port(unselected_port) - def add_nop(self, address, din_data, port): - """ Add the control values for a cycle with clock only. Does not increment the period. """ - debug.check(port in self.read_ports or port in self.write_ports, - "Cannot add read cycle to a write port. Port {0}, Read Ports {1}".format(port, self.read_ports)) - debug.info(2, 'Clock only on port {}'.format(port)) - self.fn_cycle_comments.append('Clock only on port {}'.format(port)) - self.append_cycle_comment(port, 'Clock only on port {}'.format(port)) - - self.cycle_times.append(self.t_current) - self.t_current += self.period - self.add_control_one_port(port, "noop") - # If the port is also a readwrite then add data. - if port in self.write_ports: - self.add_data(din_data, port) - self.add_address(address, port) - def add_noop_all_ports(self, comment): """ Add the control values for a noop to all ports. """ debug.info(2, comment) @@ -295,6 +279,23 @@ class simulation(): except: self.add_wmask("0"*self.num_wmasks, port) + def add_noop_clock_one_port(self, port): + """ Add the control values for a noop to a single port. Increments the period. """ + debug.info(2, 'Clock only on port {}'.format(port)) + self.fn_cycle_comments.append('Clock only on port {}'.format(port)) + self.append_cycle_comment(port, 'Clock only on port {}'.format(port)) + + self.cycle_times.append(self.t_current) + self.t_current += self.period + + self.add_noop_one_port(port) + + #Add noops to all other ports. + for unselected_port in self.all_ports: + if unselected_port != port: + self.add_noop_one_port(unselected_port) + + def append_cycle_comment(self, port, comment): """Add comment to list to be printed in stimulus file""" #Clean up time before appending. Make spacing dynamic as well. From 5aea45ed690593e4e9b965f84639e12ea29731e9 Mon Sep 17 00:00:00 2001 From: David Ratchkov Date: Fri, 17 Apr 2020 16:23:06 -0700 Subject: [PATCH 08/28] - Fix switched disabled powers --- compiler/characterizer/lib.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 57e21763..276ea767 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -535,15 +535,15 @@ class lib: self.lib.write(" }\n") # Disabled power. - disabled_read1_power = np.mean(self.char_port_results[port]["disabled_read1_power"]) - disabled_read0_power = np.mean(self.char_port_results[port]["disabled_raed0_power"]) + disabled_write1_power = np.mean(self.char_port_results[port]["disabled_write1_power"]) + disabled_write0_power = np.mean(self.char_port_results[port]["disabled_write0_power"]) self.lib.write(" internal_power(){\n") self.lib.write(" when : \"csb{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") - self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read1_power)) + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_write1_power)) self.lib.write(" }\n") self.lib.write(" fall_power(scalar){\n") - self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read0_power)) + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_write0_power)) self.lib.write(" }\n") self.lib.write(" }\n") @@ -563,18 +563,18 @@ class lib: self.lib.write(" }\n") # Disabled power. - disabled_write1_power = np.mean(self.char_port_results[port]["disabled_write1_power"]) - disabled_write0_power = np.mean(self.char_port_results[port]["disabled_write0_power"]) + disabled_read1_power = np.mean(self.char_port_results[port]["disabled_read1_power"]) + disabled_read0_power = np.mean(self.char_port_results[port]["disabled_read0_power"]) self.lib.write(" internal_power(){\n") self.lib.write(" when : \"csb{0}{1}\"; \n".format(port, web_name)) self.lib.write(" rise_power(scalar){\n") - self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_write1_power)) + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read1_power)) self.lib.write(" }\n") self.lib.write(" fall_power(scalar){\n") - self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_write0_power)) + self.lib.write(" values(\"{0:.6e}\");\n".format(disabled_read0_power)) self.lib.write(" }\n") self.lib.write(" }\n") - + def write_pg_pin(self): self.lib.write(" pg_pin(vdd) {\n") self.lib.write(" voltage_name : VDD;\n") From 7f65176908ec460b3229c897a3cfd93bb7100e64 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Apr 2020 14:23:40 -0700 Subject: [PATCH 09/28] Configured bitline directions into prot_data --- compiler/base/hierarchy_layout.py | 36 +++++++++++++++++++++---------- compiler/modules/bitcell_array.py | 24 ++++++++++----------- compiler/modules/port_data.py | 7 +++++- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index e67f8d85..3cf3e727 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -974,6 +974,7 @@ class layout(): def create_channel_route(self, netlist, offset, layer_stack, + layer_dirs=None, vertical=False): """ The net list is a list of the nets. Each net is a list of pins @@ -1012,25 +1013,38 @@ class layout(): def vcg_pin_overlap(pin1, pin2, vertical, pitch): """ Check for vertical or horizontal overlap of the two pins """ + # FIXME: If the pins are not in a row, this may break. # However, a top pin shouldn't overlap another top pin, # for example, so the # extra comparison *shouldn't* matter. # Pin 1 must be in the "BOTTOM" set - x_overlap = pin1.by() < pin2.by() and abs(pin1.center().x-pin2.center().x) Date: Mon, 20 Apr 2020 14:26:44 -0700 Subject: [PATCH 10/28] Split port data test into single and multi-port. --- compiler/tests/18_port_data_1rw_1r_test.py | 78 ++++++++++++++++++++++ compiler/tests/18_port_data_test.py | 46 ------------- 2 files changed, 78 insertions(+), 46 deletions(-) create mode 100755 compiler/tests/18_port_data_1rw_1r_test.py diff --git a/compiler/tests/18_port_data_1rw_1r_test.py b/compiler/tests/18_port_data_1rw_1r_test.py new file mode 100755 index 00000000..3e1dbded --- /dev/null +++ b/compiler/tests/18_port_data_1rw_1r_test.py @@ -0,0 +1,78 @@ +#!/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_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.num_rw_ports = 0 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 1 + + c = sram_config(word_size=4, + 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()) diff --git a/compiler/tests/18_port_data_test.py b/compiler/tests/18_port_data_test.py index 71681056..57e19846 100755 --- a/compiler/tests/18_port_data_test.py +++ b/compiler/tests/18_port_data_test.py @@ -55,52 +55,6 @@ class port_data_test(openram_test): 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 From 7995451cbb669cd346fca33cb8f4a9889e5434ce Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Apr 2020 14:45:18 -0700 Subject: [PATCH 11/28] PEP8 formatting --- .../modules/single_level_column_mux_array.py | 63 ++++++++----------- 1 file changed, 26 insertions(+), 37 deletions(-) diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 324b7415..d1c08e18 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -5,17 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from math import log import design -import contact -from tech import drc import debug -import math from vector import vector from sram_factory import factory from globals import OPTS import logical_effort + class single_level_column_mux_array(design.design): """ Dynamically generated column mux array. @@ -56,7 +53,7 @@ class single_level_column_mux_array(design.design): self.add_routing() # Find the highest shapes to determine height before adding well highest = self.find_highest_coords() - self.height = highest.y + self.height = highest.y self.add_layout_pins() self.add_enclosure(self.mux_inst, "pwell") @@ -74,22 +71,18 @@ class single_level_column_mux_array(design.design): self.add_pin("br_out_{}".format(i)) self.add_pin("gnd") - def add_modules(self): self.mux = factory.create(module_type="single_level_column_mux", bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) self.add_mod(self.mux) - def setup_layout_constants(self): - self.column_addr_size = num_of_inputs = int(self.words_per_row / 2) + self.column_addr_size = int(self.words_per_row / 2) self.width = self.columns * self.mux.width # one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br # one extra route pitch is to space from the sense amp - self.route_height = (self.words_per_row + 3)*self.m1_pitch - - + self.route_height = (self.words_per_row + 3) * self.m1_pitch def create_array(self): self.mux_inst = [] @@ -101,8 +94,8 @@ class single_level_column_mux_array(design.design): self.connect_inst(["bl_{}".format(col_num), "br_{}".format(col_num), - "bl_out_{}".format(int(col_num/self.words_per_row)), - "br_out_{}".format(int(col_num/self.words_per_row)), + "bl_out_{}".format(int(col_num / self.words_per_row)), + "br_out_{}".format(int(col_num / self.words_per_row)), "sel_{}".format(col_num % self.words_per_row), "gnd"]) @@ -117,11 +110,9 @@ class single_level_column_mux_array(design.design): else: mirror = "" - name = "XMUX{0}".format(col_num) offset = vector(xoffset, self.route_height) self.mux_inst[col_num].place(offset=offset, mirror=mirror) - def add_layout_pins(self): """ Add the pins after we determine the height. """ # For every column, add a pass gate @@ -131,18 +122,17 @@ class single_level_column_mux_array(design.design): self.add_layout_pin(text="bl_{}".format(col_num), layer="m2", offset=offset, - height=self.height-offset.y) + height=self.height - offset.y) offset = mux_inst.get_pin("br").ll() self.add_layout_pin(text="br_{}".format(col_num), layer="m2", offset=offset, - height=self.height-offset.y) + height=self.height - offset.y) for inst in self.mux_inst: self.copy_layout_pin(inst, "gnd") - def add_routing(self): self.add_horizontal_input_rail() self.add_vertical_poly_rail() @@ -151,7 +141,7 @@ class single_level_column_mux_array(design.design): def add_horizontal_input_rail(self): """ Create address input rails on M1 below the mux transistors """ for j in range(self.words_per_row): - offset = vector(0, self.route_height + (j-self.words_per_row)*self.m1_pitch) + offset = vector(0, self.route_height + (j - self.words_per_row) * self.m1_pitch) self.add_layout_pin(text="sel_{}".format(j), layer="m1", offset=offset, @@ -167,9 +157,10 @@ class single_level_column_mux_array(design.design): # Add the column x offset to find the right select bit gate_offset = self.mux_inst[col].get_pin("sel").bc() # height to connect the gate to the correct horizontal row - sel_height = self.get_pin("sel_{}".format(sel_index)).by() + # sel_height = self.get_pin("sel_{}".format(sel_index)).by() # use the y offset from the sel pin and the x offset from the gate - offset = vector(gate_offset.x,self.get_pin("sel_{}".format(sel_index)).cy()) + offset = vector(gate_offset.x, + self.get_pin("sel_{}".format(sel_index)).cy()) # Add the poly contact with a shift to account for the rotation self.add_via_center(layers=("m1", "contact", "poly"), offset=offset) @@ -182,11 +173,11 @@ class single_level_column_mux_array(design.design): bl_offset = self.mux_inst[j].get_pin("bl_out").bc() br_offset = self.mux_inst[j].get_pin("br_out").bc() - bl_out_offset = bl_offset - vector(0,(self.words_per_row+1)*self.m1_pitch) - br_out_offset = br_offset - vector(0,(self.words_per_row+2)*self.m1_pitch) + bl_out_offset = bl_offset - vector(0, (self.words_per_row + 1) * self.m1_pitch) + br_out_offset = br_offset - vector(0, (self.words_per_row + 2) * self.m1_pitch) - bl_out_offset_end = bl_out_offset + vector(0,self.route_height) - br_out_offset_end = br_out_offset + vector(0,self.route_height) + bl_out_offset_end = bl_out_offset + vector(0, self.route_height) + br_out_offset_end = br_out_offset + vector(0, self.route_height) if cell_properties.bitcell.mirror.y and j % 2: tmp_bl_out_end = br_out_offset_end @@ -208,21 +199,20 @@ class single_level_column_mux_array(design.design): else: dist = 0 - self.add_path("m1", [bl_out_offset, bl_out_offset+vector(width+dist,0)]) - self.add_path("m1", [br_out_offset, br_out_offset+vector(width-dist,0)]) + self.add_path("m1", [bl_out_offset, bl_out_offset + vector(width + dist, 0)]) + self.add_path("m1", [br_out_offset, br_out_offset + vector(width - dist, 0)]) # Extend the bitline output rails and gnd downward on the first bit of each n-way mux - self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j/self.words_per_row)), + self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j / self.words_per_row)), layer="m2", start=bl_out_offset, end=tmp_bl_out_end) - self.add_layout_pin_segment_center(text="br_out_{}".format(int(j/self.words_per_row)), + self.add_layout_pin_segment_center(text="br_out_{}".format(int(j / self.words_per_row)), layer="m2", start=br_out_offset, end=tmp_br_out_end) - - # This via is on the right of the wire + # This via is on the right of the wire self.add_via_center(layers=self.m1_stack, offset=bl_out_offset) @@ -231,20 +221,19 @@ class single_level_column_mux_array(design.design): offset=br_out_offset) else: - - self.add_path("m2", [ bl_out_offset, tmp_bl_out_end]) - self.add_path("m2", [ br_out_offset, tmp_br_out_end]) + self.add_path("m2", [bl_out_offset, tmp_bl_out_end]) + self.add_path("m2", [br_out_offset, tmp_br_out_end]) # This via is on the right of the wire self.add_via_center(layers=self.m1_stack, offset=bl_out_offset) - # This via is on the left of the wire + # This via is on the left of the wire self.add_via_center(layers=self.m1_stack, offset=br_out_offset) def get_drain_cin(self): """Get the relative capacitance of the drain of the NMOS pass TX""" from tech import parameter - #Bitcell drain load being used to estimate mux NMOS drain load + # Bitcell drain load being used to estimate mux NMOS drain load drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap']) - return drain_load + return drain_load From 8c177f9947e6c1f98977cad5b8a6ab87ddfa0ea7 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Apr 2020 15:03:32 -0700 Subject: [PATCH 12/28] Split col mux test --- ...4_single_level_column_mux_pbitcell_test.py | 49 +++++++++++++++++++ .../tests/04_single_level_column_mux_test.py | 16 ------ compiler/tests/18_port_data_1rw_1r_test.py | 2 +- 3 files changed, 50 insertions(+), 17 deletions(-) create mode 100755 compiler/tests/04_single_level_column_mux_pbitcell_test.py diff --git a/compiler/tests/04_single_level_column_mux_pbitcell_test.py b/compiler/tests/04_single_level_column_mux_pbitcell_test.py new file mode 100755 index 00000000..6fe55736 --- /dev/null +++ b/compiler/tests/04_single_level_column_mux_pbitcell_test.py @@ -0,0 +1,49 @@ +#!/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 04_driver_test") + +class single_level_column_mux_pbitcell_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + # check single level column mux in multi-port + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 1 + OPTS.num_w_ports = 1 + + factory.reset() + debug.info(2, "Checking column mux for pbitcell (innermost connections)") + tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") + self.local_check(tx) + + factory.reset() + debug.info(2, "Checking column mux for pbitcell (outermost connections)") + tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2") + self.local_check(tx) + + 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/04_single_level_column_mux_test.py b/compiler/tests/04_single_level_column_mux_test.py index de5870fc..9f1d03f9 100755 --- a/compiler/tests/04_single_level_column_mux_test.py +++ b/compiler/tests/04_single_level_column_mux_test.py @@ -28,22 +28,6 @@ class single_level_column_mux_test(openram_test): tx = factory.create(module_type="single_level_column_mux", tx_size=8) self.local_check(tx) - # check single level column mux in multi-port - OPTS.bitcell = "pbitcell" - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 1 - OPTS.num_w_ports = 1 - - factory.reset() - debug.info(2, "Checking column mux for pbitcell (innermost connections)") - tx = factory.create(module_type="single_level_column_mux", tx_size=8, bitcell_bl="bl0", bitcell_br="br0") - self.local_check(tx) - - factory.reset() - debug.info(2, "Checking column mux for pbitcell (outermost connections)") - tx = factory.create(module_type="single_level_column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2") - self.local_check(tx) - globals.end_openram() # run the test from the command line diff --git a/compiler/tests/18_port_data_1rw_1r_test.py b/compiler/tests/18_port_data_1rw_1r_test.py index 3e1dbded..6201de6a 100755 --- a/compiler/tests/18_port_data_1rw_1r_test.py +++ b/compiler/tests/18_port_data_1rw_1r_test.py @@ -13,7 +13,7 @@ from globals import OPTS from sram_factory import factory import debug -class port_data_test(openram_test): +class port_data_1rw_1r_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) From dfbf6fe45c4115ec79b96a9880433c51ac1ca770 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Apr 2020 15:33:53 -0700 Subject: [PATCH 13/28] Default is to use preferred layer directions --- compiler/base/hierarchy_layout.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 3cf3e727..b970666d 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1127,13 +1127,13 @@ class layout(): self.horizontal_pitch) offset += vector(0, self.horizontal_pitch) - def create_vertical_channel_route(self, netlist, offset, layer_stack, layer_dirs): + def create_vertical_channel_route(self, netlist, offset, layer_stack, layer_dirs=None): """ Wrapper to create a vertical channel route """ self.create_channel_route(netlist, offset, layer_stack, layer_dirs, vertical=True) - def create_horizontal_channel_route(self, netlist, offset, layer_stack, layer_dirs): + def create_horizontal_channel_route(self, netlist, offset, layer_stack, layer_dirs=None): """ Wrapper to create a horizontal channel route """ From f6135f34711e755ab80c6a3891506a3fc8e380f0 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 20 Apr 2020 16:38:30 -0700 Subject: [PATCH 14/28] PEP8 formatting --- compiler/modules/dff_buf_array.py | 96 +++++++++++++++---------------- 1 file changed, 46 insertions(+), 50 deletions(-) diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index 1735a7a1..f95bf576 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -7,13 +7,12 @@ # import debug import design -from tech import drc from tech import cell_properties as props -from math import log from vector import vector from globals import OPTS from sram_factory import factory + class dff_buf_array(design.design): """ This is a simple row (or multiple rows) of flops. @@ -54,13 +53,13 @@ class dff_buf_array(design.design): self.DRC_LVS() def add_pins(self): - for row in range(self.rows): + for row in range(self.rows): for col in range(self.columns): - self.add_pin(self.get_din_name(row,col), "INPUT") - for row in range(self.rows): + self.add_pin(self.get_din_name(row, col), "INPUT") + for row in range(self.rows): for col in range(self.columns): - self.add_pin(self.get_dout_name(row,col), "OUTPUT") - self.add_pin(self.get_dout_bar_name(row,col), "OUTPUT") + self.add_pin(self.get_dout_name(row, col), "OUTPUT") + self.add_pin(self.get_dout_bar_name(row, col), "OUTPUT") self.add_pin("clk", "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -75,17 +74,16 @@ class dff_buf_array(design.design): inv2_size=self.inv2_size) self.add_mod(self.dff) - def create_dff_array(self): self.dff_insts={} - for row in range(self.rows): + for row in range(self.rows): for col in range(self.columns): - name = "dff_r{0}_c{1}".format(row,col) - self.dff_insts[row,col]=self.add_inst(name=name, - mod=self.dff) - inst_ports = [self.get_din_name(row,col), - self.get_dout_name(row,col), - self.get_dout_bar_name(row,col), + name = "dff_r{0}_c{1}".format(row, col) + self.dff_insts[row, col]=self.add_inst(name=name, + mod=self.dff) + inst_ports = [self.get_din_name(row, col), + self.get_dout_name(row, col), + self.get_dout_bar_name(row, col), "clk", "vdd", "gnd"] @@ -102,17 +100,17 @@ class dff_buf_array(design.design): dff_pitch = self.dff.width + well_spacing + self.well_extend_active - for row in range(self.rows): + for row in range(self.rows): for col in range(self.columns): - name = "Xdff_r{0}_c{1}".format(row,col) + name = "Xdff_r{0}_c{1}".format(row, col) if (row % 2 == 0): - base = vector(col*dff_pitch,row*self.dff.height) + base = vector(col * dff_pitch, row * self.dff.height) mirror = "R0" else: - base = vector(col*dff_pitch,(row+1)*self.dff.height) + base = vector(col * dff_pitch, (row + 1) * self.dff.height) mirror = "MX" - self.dff_insts[row,col].place(offset=base, - mirror=mirror) + self.dff_insts[row, col].place(offset=base, + mirror=mirror) def get_din_name(self, row, col): if self.columns == 1: @@ -120,7 +118,7 @@ class dff_buf_array(design.design): elif self.rows == 1: din_name = "din_{0}".format(col) else: - din_name = "din_{0}_{1}".format(row,col) + din_name = "din_{0}_{1}".format(row, col) return din_name @@ -130,7 +128,7 @@ class dff_buf_array(design.design): elif self.rows == 1: dout_name = "dout_{0}".format(col) else: - dout_name = "dout_{0}_{1}".format(row,col) + dout_name = "dout_{0}_{1}".format(row, col) return dout_name @@ -140,75 +138,73 @@ class dff_buf_array(design.design): elif self.rows == 1: dout_bar_name = "dout_bar_{0}".format(col) else: - dout_bar_name = "dout_bar_{0}_{1}".format(row,col) + dout_bar_name = "dout_bar_{0}_{1}".format(row, col) return dout_bar_name def add_layout_pins(self): for row in range(self.rows): - for col in range(self.columns): + for col in range(self.columns): # Continous vdd rail along with label. - vdd_pin=self.dff_insts[row,col].get_pin("vdd") + vdd_pin=self.dff_insts[row, col].get_pin("vdd") self.add_power_pin("vdd", vdd_pin.lc()) # Continous gnd rail along with label. - gnd_pin=self.dff_insts[row,col].get_pin("gnd") + gnd_pin=self.dff_insts[row, col].get_pin("gnd") self.add_power_pin("gnd", gnd_pin.lc()) - - for row in range(self.rows): - for col in range(self.columns): - din_pin = self.dff_insts[row,col].get_pin("D") - debug.check(din_pin.layer=="m2","DFF D pin not on metal2") - self.add_layout_pin(text=self.get_din_name(row,col), + for row in range(self.rows): + for col in range(self.columns): + din_pin = self.dff_insts[row, col].get_pin("D") + debug.check(din_pin.layer=="m2", "DFF D pin not on metal2") + self.add_layout_pin(text=self.get_din_name(row, col), layer=din_pin.layer, offset=din_pin.ll(), width=din_pin.width(), height=din_pin.height()) - dout_pin = self.dff_insts[row,col].get_pin("Q") - debug.check(dout_pin.layer=="m2","DFF Q pin not on metal2") - self.add_layout_pin(text=self.get_dout_name(row,col), + dout_pin = self.dff_insts[row, col].get_pin("Q") + debug.check(dout_pin.layer=="m2", "DFF Q pin not on metal2") + self.add_layout_pin(text=self.get_dout_name(row, col), layer=dout_pin.layer, offset=dout_pin.ll(), width=dout_pin.width(), height=dout_pin.height()) - dout_bar_pin = self.dff_insts[row,col].get_pin("Qb") - debug.check(dout_bar_pin.layer=="m2","DFF Qb pin not on metal2") - self.add_layout_pin(text=self.get_dout_bar_name(row,col), + dout_bar_pin = self.dff_insts[row, col].get_pin("Qb") + debug.check(dout_bar_pin.layer=="m2", "DFF Qb pin not on metal2") + self.add_layout_pin(text=self.get_dout_bar_name(row, col), layer=dout_bar_pin.layer, offset=dout_bar_pin.ll(), width=dout_bar_pin.width(), height=dout_bar_pin.height()) - # Create vertical spines to a single horizontal rail - clk_pin = self.dff_insts[0,0].get_pin("clk") - clk_ypos = 2*self.m3_pitch+self.m3_width - debug.check(clk_pin.layer=="m2","DFF clk pin not on metal2") + clk_pin = self.dff_insts[0, 0].get_pin("clk") + clk_ypos = 2 * self.m3_pitch + self.m3_width + debug.check(clk_pin.layer=="m2", "DFF clk pin not on metal2") if self.columns==1: self.add_layout_pin(text="clk", layer="m2", - offset=clk_pin.ll().scale(1,0), + offset=clk_pin.ll().scale(1, 0), width=self.m2_width, height=self.height) else: self.add_layout_pin_segment_center(text="clk", - layer="m3", - start=vector(0,clk_ypos), - end=vector(self.width,clk_ypos)) + layer="m3", + start=vector(0, clk_ypos), + end=vector(self.width, clk_ypos)) for col in range(self.columns): - clk_pin = self.dff_insts[0,col].get_pin("clk") + clk_pin = self.dff_insts[0, col].get_pin("clk") # Make a vertical strip for each column self.add_rect(layer="m2", - offset=clk_pin.ll().scale(1,0), + offset=clk_pin.ll().scale(1, 0), width=self.m2_width, height=self.height) # Drop a via to the M3 pin self.add_via_center(layers=self.m2_stack, - offset=vector(clk_pin.cx(),clk_ypos)) + offset=vector(clk_pin.cx(), clk_ypos)) def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff array""" From 63bea67fb5700f5a7110ceab4faae542e07d00e5 Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Mon, 20 Apr 2020 20:22:46 -0700 Subject: [PATCH 15/28] col_mux.py changes --- compiler/pgates/single_level_column_mux.py | 86 ++++++++++++---------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index 90645326..9d21211e 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -7,7 +7,7 @@ # import pgate import debug -from tech import drc +from tech import drc, layer from vector import vector from sram_factory import factory import logical_effort @@ -22,13 +22,13 @@ class single_level_column_mux(pgate.pgate): for optimal speed """ def __init__(self, name, tx_size=8, bitcell_bl="bl", bitcell_br="br"): - + debug.info(2, "creating single column mux cell: {0}".format(name)) self.tx_size = int(tx_size) self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br - + pgate.pgate.__init__(self, name) def get_bl_names(self): @@ -41,9 +41,9 @@ class single_level_column_mux(pgate.pgate): self.add_modules() self.add_pins() self.add_ptx() - + def create_layout(self): - + self.pin_height = 2 * self.m2_width self.width = self.bitcell.width self.height = self.nmos_upper.uy() + self.pin_height @@ -59,39 +59,42 @@ class single_level_column_mux(pgate.pgate): self.ptx_width = self.tx_size * drc("minwidth_tx") self.nmos = factory.create(module_type="ptx", width=self.ptx_width) self.add_mod(self.nmos) - + def add_pins(self): self.add_pin_list(["bl", "br", "bl_out", "br_out", "sel", "gnd"]) def add_bitline_pins(self): """ Add the top and bottom pins to this cell """ - bl_pos = vector(self.bitcell.get_pin(self.bitcell_bl).lx(), 0) - br_pos = vector(self.bitcell.get_pin(self.bitcell_br).lx(), 0) + bl_pin=self.bitcell.get_pin(self.bitcell_bl) + br_pin=self.bitcell.get_pin(self.bitcell_br) + + bl_pos = vector(bl_pin.lx(), 0) + br_pos = vector(br_pin.lx(), 0) # bl and br self.add_layout_pin(text="bl", - layer="m2", + layer=bl_pin.layer, offset=bl_pos + vector(0, self.height - self.pin_height), height=self.pin_height) self.add_layout_pin(text="br", - layer="m2", + layer=br_pin.layer, offset=br_pos + vector(0, self.height - self.pin_height), height=self.pin_height) - + # bl_out and br_out self.add_layout_pin(text="bl_out", - layer="m2", + layer=bl_pin.layer, offset=bl_pos, height=self.pin_height) self.add_layout_pin(text="br_out", - layer="m2", + layer=br_pin.layer, offset=br_pos, height=self.pin_height) def add_ptx(self): """ Create the two pass gate NMOS transistors to switch the bitlines""" - + # Space it in the center nmos_lower_position = self.nmos.active_offset.scale(0,1) \ + vector(0.5 * self.bitcell.width- 0.5 * self.nmos.active_width, 0) @@ -102,7 +105,7 @@ class single_level_column_mux(pgate.pgate): # This aligns it directly above the other tx with gates abutting nmos_upper_position = nmos_lower_position \ - + vector(0, self.nmos.active_height + self.poly_space) + + vector(0, self.nmos.active_height + self.active_space) self.nmos_upper = self.add_inst(name="mux_tx2", mod=self.nmos, offset=nmos_upper_position) @@ -110,12 +113,11 @@ class single_level_column_mux(pgate.pgate): def connect_poly(self): """ Connect the poly gate of the two pass transistors """ - - height = self.nmos_upper.get_pin("G").uy() - self.nmos_lower.get_pin("G").by() + self.add_layout_pin(text="sel", layer="poly", - offset=self.nmos_lower.get_pin("G").ll(), - height=height) + offset=self.nmos_lower.get_pin("G").ul() - vector(0,self.poly_extend_active), + height=self.active_space) def connect_bitlines(self): """ Connect the bitlines to the mux transistors """ @@ -131,36 +133,42 @@ class single_level_column_mux(pgate.pgate): nmos_upper_s_pin = self.nmos_upper.get_pin("S") nmos_upper_d_pin = self.nmos_upper.get_pin("D") + # If li exists, use li and m1 for the mux, otherwise use m1 and m2 + if "li" in layer: + col_mux_stack = self.li_stack + else: + col_mux_stack = self.m1_stack + # Add vias to bl, br_out, nmos_upper/S, nmos_lower/D - self.add_via_center(layers=self.m1_stack, + self.add_via_center(layers=col_mux_stack, offset=bl_pin.bc(), directions=("V", "V")) - self.add_via_center(layers=self.m1_stack, + self.add_via_center(layers=col_mux_stack, offset=br_out_pin.uc(), directions=("V", "V")) - self.add_via_center(layers=self.m1_stack, + self.add_via_center(layers=col_mux_stack, offset=nmos_upper_s_pin.center(), directions=("V", "V")) - self.add_via_center(layers=self.m1_stack, + self.add_via_center(layers=col_mux_stack, offset=nmos_lower_d_pin.center(), directions=("V", "V")) - + # bl -> nmos_upper/D on metal1 # bl_out -> nmos_upper/S on metal2 - self.add_path("m1", + self.add_path(col_mux_stack[0], [bl_pin.ll(), vector(nmos_upper_d_pin.cx(), bl_pin.by()), nmos_upper_d_pin.center()]) # halfway up, move over mid1 = bl_out_pin.uc().scale(1, 0.4) \ + nmos_upper_s_pin.bc().scale(0, 0.4) mid2 = bl_out_pin.uc().scale(0, 0.4) \ - + nmos_upper_s_pin.bc().scale(1, 0.4) - self.add_path("m2", - [bl_out_pin.uc(), mid1, mid2, nmos_upper_s_pin.bc()]) - + + nmos_upper_s_pin.bc().scale(1, 0.4) + self.add_path(col_mux_stack[2], + [bl_out_pin.uc(), mid1, mid2, nmos_upper_s_pin.center()]) + # br -> nmos_lower/D on metal2 # br_out -> nmos_lower/S on metal1 - self.add_path("m1", + self.add_path(col_mux_stack[0], [br_out_pin.uc(), vector(nmos_lower_s_pin.cx(), br_out_pin.uy()), nmos_lower_s_pin.center()]) @@ -169,9 +177,9 @@ class single_level_column_mux(pgate.pgate): + nmos_lower_d_pin.uc().scale(0,0.5) mid2 = br_pin.bc().scale(0,0.5) \ + nmos_lower_d_pin.uc().scale(1,0.5) - self.add_path("m2", - [br_pin.bc(), mid1, mid2, nmos_lower_d_pin.uc()]) - + self.add_path(col_mux_stack[2], + [br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()]) + def add_wells(self): """ Add a well and implant over the whole cell. Also, add the @@ -192,11 +200,12 @@ class single_level_column_mux(pgate.pgate): start_layer="m1") # Add well enclosure over all the tx and contact - self.add_rect(layer="pwell", - offset=vector(0, 0), - width=self.bitcell.width, - height=self.height) - + if "pwell" in layer: + self.add_rect(layer="pwell", + offset=vector(0, 0), + width=self.bitcell.width, + height=self.height) + def get_stage_effort(self, corner, slew, load): """ Returns relative delay that the column mux. @@ -211,4 +220,3 @@ class single_level_column_mux(pgate.pgate): load, parasitic_delay, False) - From 829f3e03fa08da37cfdfb22d01018237bbe753f5 Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Mon, 20 Apr 2020 22:08:29 -0700 Subject: [PATCH 16/28] col_mux.py update with correct contacts --- compiler/pgates/single_level_column_mux.py | 29 +++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index 9d21211e..e84469db 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -57,7 +57,10 @@ class single_level_column_mux(pgate.pgate): # Adds nmos_lower,nmos_upper to the module self.ptx_width = self.tx_size * drc("minwidth_tx") - self.nmos = factory.create(module_type="ptx", width=self.ptx_width) + self.nmos = factory.create(module_type="ptx", + width=self.ptx_width, + add_source_contact=False, + add_drain_contact=False) self.add_mod(self.nmos) def add_pins(self): @@ -153,6 +156,30 @@ class single_level_column_mux(pgate.pgate): offset=nmos_lower_d_pin.center(), directions=("V", "V")) + # Add diffusion contacts + # These were previously omitted with the options: add_source_contact=False, add_drain_contact=False + # They are added now and not previously due to a s8 tech special case in which the contacts intersected the mux intraconnect + self.add_via_center(layers=self.active_stack, + offset=nmos_upper_d_pin.center(), + directions=("V", "V"), + implant_type="n", + well_type="nwell") + self.add_via_center(layers=self.active_stack, + offset=nmos_lower_s_pin.center(), + directions=("V", "V"), + implant_type="n", + well_type="nwell") + self.add_via_center(layers=self.active_stack, + offset=nmos_upper_s_pin.center(), + directions=("V", "V"), + implant_type="n", + well_type="nwell") + self.add_via_center(layers=self.active_stack, + offset=nmos_lower_d_pin.center(), + directions=("V", "V"), + implant_type="n", + well_type="nwell") + # bl -> nmos_upper/D on metal1 # bl_out -> nmos_upper/S on metal2 self.add_path(col_mux_stack[0], From ab91d0ab1d86afb4d9f73b22c613cbe6cc7c0853 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 21 Apr 2020 15:20:30 -0700 Subject: [PATCH 17/28] Add purpose to string output --- compiler/base/geometry.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/base/geometry.py b/compiler/base/geometry.py index 5d7f8d76..cfcfa73a 100644 --- a/compiler/base/geometry.py +++ b/compiler/base/geometry.py @@ -296,11 +296,11 @@ class path(geometry): def __str__(self): """ override print function output """ - return "path: layer=" + self.layerNumber + " w=" + self.width + return "path: layer=" + self.layerNumber + " purpose=" + str(self.layerPurpose) + " w=" + self.width def __repr__(self): """ override print function output """ - return "( path: layer=" + self.layerNumber + " w=" + self.width + " coords=" + str(self.coordinates) + " )" + return "( path: layer=" + self.layerNumber + " purpose=" + str(self.layerPurpose) + " w=" + self.width + " coords=" + str(self.coordinates) + " )" class label(geometry): @@ -340,11 +340,11 @@ class label(geometry): def __str__(self): """ override print function output """ - return "label: " + self.text + " layer=" + str(self.layerNumber) + return "label: " + self.text + " layer=" + str(self.layerNumber) + " purpose=" + str(self.layerPurpose) def __repr__(self): """ override print function output """ - return "( label: " + self.text + " @" + str(self.offset) + " layer=" + str(self.layerNumber) + " )" + return "( label: " + self.text + " @" + str(self.offset) + " layer=" + str(self.layerNumber) + " purpose=" + str(self.layerPurpose) + " )" class rectangle(geometry): @@ -391,4 +391,4 @@ class rectangle(geometry): def __repr__(self): """ override print function output """ - return "( rect: @" + str(self.offset) + " WxH=" + str(self.width) + "x" + str(self.height) + " layer=" + str(self.layerNumber) + " )" + return "( rect: @" + str(self.offset) + " WxH=" + str(self.width) + "x" + str(self.height) + " layer=" + str(self.layerNumber) + " purpose=" + str(self.layerPurpose) + " )" From 5f76514cf09844936e3929106cc089c3317e1f9c Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 21 Apr 2020 15:20:51 -0700 Subject: [PATCH 18/28] Remove end of line whitespace --- technology/scn4m_subm/tech/tech.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/technology/scn4m_subm/tech/tech.py b/technology/scn4m_subm/tech/tech.py index 7c360d38..d8384d7f 100644 --- a/technology/scn4m_subm/tech/tech.py +++ b/technology/scn4m_subm/tech/tech.py @@ -89,7 +89,7 @@ power_grid = m3_stack ################################################### # create the GDS layer map -layer={} +layer={} layer["pwell"] = (41, 0) layer["nwell"] = (42, 0) layer["active"] = (43, 0) @@ -98,9 +98,9 @@ layer["nimplant"] = (45, 0) layer["poly"] = (46, 0) layer["poly_contact"] = (47, 0) layer["active_contact"] = (48, 0) -layer["m1"] = (49, 0) +layer["m1"] = (49, 0) layer["via1"] = (50, 0) -layer["m2"] = (51, 0) +layer["m2"] = (51, 0) layer["via2"] = (61, 0) layer["m3"] = (62, 0) layer["via3"] = (30, 0) From cd66ddb37c9af43e56a679aadb3ff0b1805d92d1 Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 21 Apr 2020 15:21:29 -0700 Subject: [PATCH 19/28] Add supply rails to dff array. PEP8 cleanup. --- compiler/modules/dff_buf.py | 33 +++++++++++++++--------------- compiler/modules/dff_buf_array.py | 34 +++++++++++++++++++++++++------ 2 files changed, 44 insertions(+), 23 deletions(-) diff --git a/compiler/modules/dff_buf.py b/compiler/modules/dff_buf.py index c30f15b6..500767d8 100644 --- a/compiler/modules/dff_buf.py +++ b/compiler/modules/dff_buf.py @@ -35,7 +35,7 @@ class dff_buf(design.design): # This causes a DRC in the pinv which assumes min width rails. This ensures the output # contact does not violate spacing to the rail in the NMOS. debug.check(inv1_size>=2, "Inverter must be greater than two for rail spacing DRC rules.") - debug.check(inv2_size>=2, "Inverter must be greater than two for rail spacing DRC rules.") + debug.check(inv2_size>=2, "Inverter must be greater than two for rail spacing DRC rules.") self.inv1_size=inv1_size self.inv2_size=inv2_size @@ -52,14 +52,13 @@ class dff_buf(design.design): def create_layout(self): self.place_instances() self.width = self.inv2_inst.rx() + self.height = self.dff.height - - self.route_wires() self.add_layout_pins() self.add_boundary() self.DRC_LVS() - + def add_modules(self): self.dff = factory.create(module_type="dff") self.add_mod(self.dff) @@ -73,8 +72,6 @@ class dff_buf(design.design): size=self.inv2_size, height=self.dff.height) self.add_mod(self.inv2) - - def add_pins(self): self.add_pin("D", "INPUT") @@ -96,17 +93,19 @@ class dff_buf(design.design): self.inv1_inst=self.add_inst(name="dff_buf_inv1", mod=self.inv1) - self.connect_inst(["qint", "Qb", "vdd", "gnd"]) + self.connect_inst(["qint", "Qb", "vdd", "gnd"]) self.inv2_inst=self.add_inst(name="dff_buf_inv2", mod=self.inv2) - self.connect_inst(["Qb", "Q", "vdd", "gnd"]) + self.connect_inst(["Qb", "Q", "vdd", "gnd"]) def place_instances(self): # Add the DFF - self.dff_inst.place(vector(0,0)) + self.dff_inst.place(vector(0, 0)) # Add INV1 to the right + # The INV needs well spacing because the DFF is likely from a library + # with different well construction rules well_spacing = 0 try: well_spacing = max(well_spacing, self.nwell_space) @@ -129,7 +128,7 @@ class dff_buf(design.design): # Route dff q to inv1 a q_pin = self.dff_inst.get_pin("Q") a1_pin = self.inv1_inst.get_pin("A") - mid_x_offset = 0.5*(a1_pin.cx() + q_pin.cx()) + mid_x_offset = 0.5 * (a1_pin.cx() + q_pin.cx()) mid1 = vector(mid_x_offset, q_pin.cy()) mid2 = vector(mid_x_offset, a1_pin.cy()) self.add_path("m3", [q_pin.center(), mid1, mid2, a1_pin.center()]) @@ -143,7 +142,7 @@ class dff_buf(design.design): # Route inv1 z to inv2 a z1_pin = self.inv1_inst.get_pin("Z") a2_pin = self.inv2_inst.get_pin("A") - mid_x_offset = 0.5*(z1_pin.cx() + a2_pin.cx()) + mid_x_offset = 0.5 * (z1_pin.cx() + a2_pin.cx()) self.mid_qb_pos = vector(mid_x_offset, z1_pin.cy()) mid2 = vector(mid_x_offset, a2_pin.cy()) self.add_path("m1", [z1_pin.center(), self.mid_qb_pos, mid2, a2_pin.center()]) @@ -181,8 +180,8 @@ class dff_buf(design.design): height=din_pin.height()) dout_pin = self.inv2_inst.get_pin("Z") - mid_pos = dout_pin.center() + vector(self.m1_pitch,0) - q_pos = mid_pos - vector(0,self.m2_pitch) + mid_pos = dout_pin.center() + vector(self.m1_pitch, 0) + q_pos = mid_pos - vector(0, self.m2_pitch) self.add_layout_pin_rect_center(text="Q", layer="m2", offset=q_pos) @@ -190,7 +189,7 @@ class dff_buf(design.design): self.add_via_center(layers=self.m1_stack, offset=q_pos) - qb_pos = self.mid_qb_pos + vector(0,self.m2_pitch) + qb_pos = self.mid_qb_pos + vector(0, self.m2_pitch) self.add_layout_pin_rect_center(text="Qb", layer="m2", offset=qb_pos) @@ -200,7 +199,7 @@ class dff_buf(design.design): def get_clk_cin(self): """Return the total capacitance (in relative units) that the clock is loaded by in the dff""" - #This is a handmade cell so the value must be entered in the tech.py file or estimated. - #Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. - #FIXME: Dff changed in a past commit. The parameter need to be updated. + # This is a handmade cell so the value must be entered in the tech.py file or estimated. + # Calculated in the tech file by summing the widths of all the gates and dividing by the minimum width. + # FIXME: Dff changed in a past commit. The parameter need to be updated. return parameter["dff_clk_cin"] diff --git a/compiler/modules/dff_buf_array.py b/compiler/modules/dff_buf_array.py index f95bf576..b608cdeb 100644 --- a/compiler/modules/dff_buf_array.py +++ b/compiler/modules/dff_buf_array.py @@ -48,6 +48,7 @@ class dff_buf_array(design.design): self.width = self.columns * self.dff.width self.height = self.rows * self.dff.height self.place_dff_array() + self.route_supplies() self.add_layout_pins() self.add_boundary() self.DRC_LVS() @@ -94,15 +95,25 @@ class dff_buf_array(design.design): def place_dff_array(self): - well_spacing = max(self.nwell_space, - self.pwell_space, - self.pwell_to_nwell) + well_spacing = 0 + try: + well_spacing = max(self.nwell_space, well_spacing) + except AttributeError: + pass + try: + well_spacing = max(self.pwell_space, well_spacing) + except AttributeError: + pass + try: + well_spacing = max(self.pwell_to_nwell, well_spacing) + except AttributeError: + pass dff_pitch = self.dff.width + well_spacing + self.well_extend_active for row in range(self.rows): for col in range(self.columns): - name = "Xdff_r{0}_c{1}".format(row, col) + # name = "Xdff_r{0}_c{1}".format(row, col) if (row % 2 == 0): base = vector(col * dff_pitch, row * self.dff.height) mirror = "R0" @@ -141,8 +152,17 @@ class dff_buf_array(design.design): dout_bar_name = "dout_bar_{0}_{1}".format(row, col) return dout_bar_name - - def add_layout_pins(self): + + def route_supplies(self): + for row in range(self.rows): + vdd0_pin=self.dff_insts[row, 0].get_pin("vdd") + vddn_pin=self.dff_insts[row, self.columns - 1].get_pin("vdd") + self.add_path(vdd0_pin.layer, [vdd0_pin.lc(), vddn_pin.rc()], width=vdd0_pin.height()) + + gnd0_pin=self.dff_insts[row, 0].get_pin("gnd") + gndn_pin=self.dff_insts[row, self.columns - 1].get_pin("gnd") + self.add_path(gnd0_pin.layer, [gnd0_pin.lc(), gndn_pin.rc()], width=gnd0_pin.height()) + for row in range(self.rows): for col in range(self.columns): # Continous vdd rail along with label. @@ -152,6 +172,8 @@ class dff_buf_array(design.design): # Continous gnd rail along with label. gnd_pin=self.dff_insts[row, col].get_pin("gnd") self.add_power_pin("gnd", gnd_pin.lc()) + + def add_layout_pins(self): for row in range(self.rows): for col in range(self.columns): From fc85dfe29fd27b02b19a3c6d37631297abf6bf5b Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 21 Apr 2020 15:21:57 -0700 Subject: [PATCH 20/28] Add boundary to all pgates --- compiler/pgates/pand2.py | 1 + compiler/pgates/pand3.py | 1 + compiler/pgates/pbuf.py | 1 + compiler/pgates/pdriver.py | 1 + compiler/pgates/pinv.py | 1 + compiler/pgates/pinvbuf.py | 1 + compiler/pgates/pnand2.py | 3 ++- compiler/pgates/pnand3.py | 1 + compiler/pgates/pnor2.py | 1 + compiler/pgates/precharge.py | 3 ++- compiler/pgates/ptristate_inv.py | 1 + compiler/pgates/pwrite_driver.py | 1 + 12 files changed, 14 insertions(+), 2 deletions(-) diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 23fd5e5b..995296b6 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -45,6 +45,7 @@ class pand2(pgate.pgate): self.place_insts() self.add_wires() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() def add_pins(self): diff --git a/compiler/pgates/pand3.py b/compiler/pgates/pand3.py index dd1d87f7..f8cc2ac3 100644 --- a/compiler/pgates/pand3.py +++ b/compiler/pgates/pand3.py @@ -44,6 +44,7 @@ class pand3(pgate.pgate): self.place_insts() self.add_wires() self.add_layout_pins() + self.add_boundary() self.DRC_LVS() def add_pins(self): diff --git a/compiler/pgates/pbuf.py b/compiler/pgates/pbuf.py index 3171324b..6f9719eb 100644 --- a/compiler/pgates/pbuf.py +++ b/compiler/pgates/pbuf.py @@ -37,6 +37,7 @@ class pbuf(pgate.pgate): self.place_insts() self.add_wires() self.add_layout_pins() + self.add_boundary() def add_pins(self): self.add_pin("A", "INPUT") diff --git a/compiler/pgates/pdriver.py b/compiler/pgates/pdriver.py index 5aa5393e..4bf654a4 100644 --- a/compiler/pgates/pdriver.py +++ b/compiler/pgates/pdriver.py @@ -76,6 +76,7 @@ class pdriver(pgate.pgate): self.width = self.inv_inst_list[-1].rx() self.height = self.inv_inst_list[0].height + self.add_boundary() def add_pins(self): self.add_pin("A", "INPUT") diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 3ec3e23e..d5a26a7a 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -64,6 +64,7 @@ class pinv(pgate.pgate): "A", position="farleft") self.route_outputs() + self.add_boundary() def add_pins(self): """ Adds pins for spice netlist """ diff --git a/compiler/pgates/pinvbuf.py b/compiler/pgates/pinvbuf.py index b8ecb3bf..fe376bc4 100644 --- a/compiler/pgates/pinvbuf.py +++ b/compiler/pgates/pinvbuf.py @@ -47,6 +47,7 @@ class pinvbuf(pgate.pgate): self.place_modules() self.route_wires() self.add_layout_pins() + self.add_boundary() self.offset_all_coordinates() diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 2f21c0bb..8398abbc 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -57,7 +57,8 @@ class pnand2(pgate.pgate): self.extend_wells() self.route_inputs() self.route_output() - + self.add_boundary() + def add_pins(self): """ Adds pins for spice netlist """ pin_list = ["A", "B", "Z", "vdd", "gnd"] diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index 83e57c0a..fd563145 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -67,6 +67,7 @@ class pnand3(pgate.pgate): self.extend_wells() self.route_inputs() self.route_output() + self.add_boundary() def add_ptx(self): """ Create the PMOS and NMOS transistors. """ diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 75840f26..9dbc0c52 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -56,6 +56,7 @@ class pnor2(pgate.pgate): self.extend_wells() self.route_inputs() self.route_output() + self.add_boundary() def add_pins(self): """ Adds pins for spice netlist """ diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index afe14a05..7adec605 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -68,7 +68,8 @@ class precharge(design.design): self.route_vdd_rail() self.route_bitlines() self.connect_to_bitlines() - + self.add_boundary() + def add_pins(self): self.add_pin_list(["bl", "br", "en_bar", "vdd"], ["OUTPUT", "OUTPUT", "INPUT", "POWER"]) diff --git a/compiler/pgates/ptristate_inv.py b/compiler/pgates/ptristate_inv.py index 9586e72b..22f6b164 100644 --- a/compiler/pgates/ptristate_inv.py +++ b/compiler/pgates/ptristate_inv.py @@ -56,6 +56,7 @@ class ptristate_inv(pgate.pgate): self.connect_rails() self.route_inputs() self.route_outputs() + self.add_boundary() def add_pins(self): """ Adds pins for spice netlist """ diff --git a/compiler/pgates/pwrite_driver.py b/compiler/pgates/pwrite_driver.py index 16830e62..da5eacdc 100644 --- a/compiler/pgates/pwrite_driver.py +++ b/compiler/pgates/pwrite_driver.py @@ -52,6 +52,7 @@ class pwrite_driver(design.design): self.place_modules() self.route_wires() self.route_supplies() + self.add_boundary() def add_pins(self): self.add_pin("din", "INPUT") From 0f6998a1c5dca33abb6b0604b84709688d0ae6bf Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 21 Apr 2020 15:36:38 -0700 Subject: [PATCH 21/28] PEP8 cleanup --- compiler/modules/delay_chain.py | 72 +++++++++++++++------------------ 1 file changed, 33 insertions(+), 39 deletions(-) diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index a07576d4..4e421d0a 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -7,12 +7,11 @@ # import debug import design -from tech import drc -from contact import contact from vector import vector from globals import OPTS from sram_factory import factory + class delay_chain(design.design): """ Generate a delay chain with the given number of stages and fanout. @@ -28,7 +27,7 @@ class delay_chain(design.design): # Two fanouts are needed so that we can route the vdd/gnd connections for f in fanout_list: - debug.check(f>=2,"Must have >=2 fanouts for each stage.") + debug.check(f>=2, "Must have >=2 fanouts for each stage.") # number of inverters including any fanout loads. self.fanout_list = fanout_list @@ -36,7 +35,6 @@ class delay_chain(design.design): self.create_netlist() if not OPTS.netlist_only: self.create_layout() - def create_netlist(self): self.add_modules() @@ -45,9 +43,9 @@ class delay_chain(design.design): def create_layout(self): # Each stage is a a row - self.height = len(self.fanout_list)*self.inv.height + self.height = len(self.fanout_list) * self.inv.height # The width is determined by the largest fanout plus the driver - self.width = (max(self.fanout_list)+1) * self.inv.width + self.width = (max(self.fanout_list) + 1) * self.inv.width self.place_inverters() self.route_inverters() @@ -71,7 +69,7 @@ class delay_chain(design.design): self.driver_inst_list = [] self.rightest_load_inst = {} self.load_inst_map = {} - for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_list): + for stage_num, fanout_size in zip(range(len(self.fanout_list)), self.fanout_list): # Add the inverter cur_driver=self.add_inst(name="dinv{}".format(stage_num), mod=self.inv) @@ -79,23 +77,23 @@ class delay_chain(design.design): self.driver_inst_list.append(cur_driver) # Hook up the driver - if stage_num+1==len(self.fanout_list): + if stage_num + 1 == len(self.fanout_list): stageout_name = "out" else: - stageout_name = "dout_{}".format(stage_num+1) + stageout_name = "dout_{}".format(stage_num + 1) if stage_num == 0: stagein_name = "in" else: - stagein_name = "dout_{}".format(stage_num) + stagein_name = "dout_{}".format(stage_num) self.connect_inst([stagein_name, stageout_name, "vdd", "gnd"]) # Now add the dummy loads to the right self.load_inst_map[cur_driver]=[] for i in range(fanout_size): - cur_load=self.add_inst(name="dload_{0}_{1}".format(stage_num,i), + cur_load=self.add_inst(name="dload_{0}_{1}".format(stage_num, i), mod=self.inv) # Fanout stage is always driven by driver and output is disconnected - disconnect_name = "n_{0}_{1}".format(stage_num,i) + disconnect_name = "n_{0}_{1}".format(stage_num, i) self.connect_inst([stageout_name, disconnect_name, "vdd", "gnd"]) # Keep track of all the loads to connect their inputs as a load @@ -106,13 +104,13 @@ class delay_chain(design.design): def place_inverters(self): """ Place the inverters and connect them based on the stage list """ - for stage_num,fanout_size in zip(range(len(self.fanout_list)),self.fanout_list): + for stage_num, fanout_size in zip(range(len(self.fanout_list)), self.fanout_list): if stage_num % 2: inv_mirror = "MX" - inv_offset = vector(0, (stage_num+1)* self.inv.height) + inv_offset = vector(0, (stage_num + 1) * self.inv.height) else: inv_mirror = "R0" - inv_offset = vector(0, stage_num * self.inv.height) + inv_offset = vector(0, stage_num * self.inv.height) # Add the inverter cur_driver=self.driver_inst_list[stage_num] @@ -122,10 +120,9 @@ class delay_chain(design.design): # Now add the dummy loads to the right load_list = self.load_inst_map[cur_driver] for i in range(fanout_size): - inv_offset += vector(self.inv.width,0) + inv_offset += vector(self.inv.width, 0) load_list[i].place(offset=inv_offset, mirror=inv_mirror) - def add_route(self, pin1, pin2): """ This guarantees that we route from the top to bottom row correctly. """ @@ -134,9 +131,9 @@ class delay_chain(design.design): if pin1_pos.y == pin2_pos.y: self.add_path("m2", [pin1_pos, pin2_pos]) else: - mid_point = vector(pin2_pos.x, 0.5*(pin1_pos.y+pin2_pos.y)) + mid_point = vector(pin2_pos.x, 0.5 * (pin1_pos.y + pin2_pos.y)) # Written this way to guarantee it goes right first if we are switching rows - self.add_path("m2", [pin1_pos, vector(pin1_pos.x,mid_point.y), mid_point, vector(mid_point.x,pin2_pos.y), pin2_pos]) + self.add_path("m2", [pin1_pos, vector(pin1_pos.x, mid_point.y), mid_point, vector(mid_point.x, pin2_pos.y), pin2_pos]) def route_inverters(self): """ Add metal routing for each of the fanout stages """ @@ -145,7 +142,7 @@ class delay_chain(design.design): inv = self.driver_inst_list[i] for load in self.load_inst_map[inv]: # Drop a via on each A pin - a_pin = load.get_pin("A") + a_pin = load.get_pin("A") self.add_via_center(layers=self.m1_stack, offset=a_pin.center()) self.add_via_center(layers=self.m2_stack, @@ -161,19 +158,17 @@ class delay_chain(design.design): offset=z_pin.center()) self.add_via_center(layers=self.m2_stack, offset=z_pin.center()) - self.add_path("m3",[z_pin.center(), a_max.center()]) + self.add_path("m3", [z_pin.center(), a_max.center()]) - # Route Z to the A of the next stage - if i+1 < len(self.driver_inst_list): + if i + 1 < len(self.driver_inst_list): z_pin = inv.get_pin("Z") - next_inv = self.driver_inst_list[i+1] + next_inv = self.driver_inst_list[i + 1] next_a_pin = next_inv.get_pin("A") - y_mid = (z_pin.cy() + next_a_pin.cy())/2 + y_mid = (z_pin.cy() + next_a_pin.cy()) / 2 mid1_point = vector(z_pin.cx(), y_mid) mid2_point = vector(next_a_pin.cx(), y_mid) - self.add_path("m2",[z_pin.center(), mid1_point, mid2_point, next_a_pin.center()]) - + self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()]) def add_layout_pins(self): """ Add vdd and gnd rails and the input/output. Connect the gnd rails internally on @@ -184,7 +179,7 @@ class delay_chain(design.design): # The routing to connect the loads is over the first and last cells # We have an even number of drivers and must only do every other # supply rail - for i in range(0,len(self.driver_inst_list),2): + for i in range(0, len(self.driver_inst_list), 2): inv = self.driver_inst_list[i] for load in self.load_inst_map[inv]: if load==self.rightest_load_inst[inv]: @@ -202,43 +197,42 @@ class delay_chain(design.design): pin = load.get_pin(pin_name) self.add_power_pin(pin_name, pin.rc()) - # input is A pin of first inverter a_pin = self.driver_inst_list[0].get_pin("A") self.add_via_center(layers=self.m1_stack, offset=a_pin.center()) self.add_layout_pin(text="in", layer="m2", - offset=a_pin.ll().scale(1,0), + offset=a_pin.ll().scale(1, 0), height=a_pin.cy()) - # output is A pin of last load inverter last_driver_inst = self.driver_inst_list[-1] a_pin = self.rightest_load_inst[last_driver_inst].get_pin("A") self.add_via_center(layers=self.m1_stack, offset=a_pin.center()) - mid_point = vector(a_pin.cx()+3*self.m2_width,a_pin.cy()) - self.add_path("m2",[a_pin.center(), mid_point, mid_point.scale(1,0)]) + mid_point = vector(a_pin.cx() + 3 * self.m2_width, a_pin.cy()) + self.add_path("m2", [a_pin.center(), mid_point, mid_point.scale(1, 0)]) self.add_layout_pin_segment_center(text="out", layer="m2", start=mid_point, - end=mid_point.scale(1,0)) + end=mid_point.scale(1, 0)) def get_cin(self): """Get the enable input ralative capacitance""" - #Only 1 input to the delay chain which is connected to an inverter. + # Only 1 input to the delay chain which is connected to an inverter. dc_cin = self.inv.get_cin() - return dc_cin + return dc_cin def determine_delayed_en_stage_efforts(self, ext_delayed_en_cout, inp_is_rise=True): """Get the stage efforts from the en to s_en. Does not compute the delay for the bitline load.""" stage_effort_list = [] - #Add a stage to the list for every stage in delay chain. Stages only differ in fanout except the last which has an external cout. + # Add a stage to the list for every stage in delay chain. + # Stages only differ in fanout except the last which has an external cout. last_stage_is_rise = inp_is_rise for stage_fanout in self.fanout_list: - stage_cout = self.inv.get_cin()*(stage_fanout+1) - if len(stage_effort_list) == len(self.fanout_list)-1: #last stage + stage_cout = self.inv.get_cin() * (stage_fanout + 1) + if len(stage_effort_list) == len(self.fanout_list) - 1: stage_cout+=ext_delayed_en_cout stage = self.inv.get_stage_effort(stage_cout, last_stage_is_rise) stage_effort_list.append(stage) From 3d4a40b338f2cc196cb48f780e15b776db5b3e4c Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Tue, 21 Apr 2020 15:38:19 -0700 Subject: [PATCH 22/28] freepdk45 col_mux fix --- compiler/pgates/single_level_column_mux.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index e84469db..288894aa 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -108,7 +108,7 @@ class single_level_column_mux(pgate.pgate): # This aligns it directly above the other tx with gates abutting nmos_upper_position = nmos_lower_position \ - + vector(0, self.nmos.active_height + self.active_space) + + vector(0, self.nmos.active_height + max(self.active_space,self.poly_space)) self.nmos_upper = self.add_inst(name="mux_tx2", mod=self.nmos, offset=nmos_upper_position) @@ -117,10 +117,14 @@ class single_level_column_mux(pgate.pgate): def connect_poly(self): """ Connect the poly gate of the two pass transistors """ + # offset is the top of the lower nmos' diffusion + # height is the distance between the nmos' diffusions, which depends on max(self.active_space,self.poly_space) + offset = self.nmos_lower.get_pin("G").ul() - vector(0,self.poly_extend_active) + height = self.nmos_upper.get_pin("G").by() + self.poly_extend_active - offset.y self.add_layout_pin(text="sel", layer="poly", - offset=self.nmos_lower.get_pin("G").ul() - vector(0,self.poly_extend_active), - height=self.active_space) + offset=offset, + height=height) def connect_bitlines(self): """ Connect the bitlines to the mux transistors """ From f1c1adc9bd0aeac481d8cf011ad018971b469c6e Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 21 Apr 2020 16:12:54 -0700 Subject: [PATCH 23/28] Simplify supply contacts in delay chain. --- compiler/modules/delay_chain.py | 42 ++++++++++++--------------------- 1 file changed, 15 insertions(+), 27 deletions(-) diff --git a/compiler/modules/delay_chain.py b/compiler/modules/delay_chain.py index 4e421d0a..b34974e5 100644 --- a/compiler/modules/delay_chain.py +++ b/compiler/modules/delay_chain.py @@ -49,6 +49,7 @@ class delay_chain(design.design): self.place_inverters() self.route_inverters() + self.route_supplies() self.add_layout_pins() self.add_boundary() self.DRC_LVS() @@ -67,7 +68,6 @@ class delay_chain(design.design): def create_inverters(self): """ Create the inverters and connect them based on the stage list """ self.driver_inst_list = [] - self.rightest_load_inst = {} self.load_inst_map = {} for stage_num, fanout_size in zip(range(len(self.fanout_list)), self.fanout_list): # Add the inverter @@ -98,9 +98,6 @@ class delay_chain(design.design): # Keep track of all the loads to connect their inputs as a load self.load_inst_map[cur_driver].append(cur_load) - else: - # Keep track of the last one so we can add the the wire later - self.rightest_load_inst[cur_driver]=cur_load def place_inverters(self): """ Place the inverters and connect them based on the stage list """ @@ -151,7 +148,7 @@ class delay_chain(design.design): # Route an M3 horizontal wire to the furthest z_pin = inv.get_pin("Z") a_pin = inv.get_pin("A") - a_max = self.rightest_load_inst[inv].get_pin("A") + a_max = self.load_inst_map[inv][-1].get_pin("A") self.add_via_center(layers=self.m1_stack, offset=a_pin.center()) self.add_via_center(layers=self.m1_stack, @@ -169,33 +166,24 @@ class delay_chain(design.design): mid1_point = vector(z_pin.cx(), y_mid) mid2_point = vector(next_a_pin.cx(), y_mid) self.add_path("m2", [z_pin.center(), mid1_point, mid2_point, next_a_pin.center()]) - - def add_layout_pins(self): - """ Add vdd and gnd rails and the input/output. Connect the gnd rails internally on - the top end with no input/output to obstruct. """ + def route_supplies(self): # Add power and ground to all the cells except: # the fanout driver, the right-most load # The routing to connect the loads is over the first and last cells # We have an even number of drivers and must only do every other # supply rail - for i in range(0, len(self.driver_inst_list), 2): - inv = self.driver_inst_list[i] - for load in self.load_inst_map[inv]: - if load==self.rightest_load_inst[inv]: - continue - for pin_name in ["vdd", "gnd"]: - pin = load.get_pin(pin_name) - self.add_power_pin(pin_name, pin.rc()) - else: - # We have an even number of rows, so need to get the last gnd rail - inv = self.driver_inst_list[-1] - for load in self.load_inst_map[inv]: - if load==self.rightest_load_inst[inv]: - continue - pin_name = "gnd" - pin = load.get_pin(pin_name) - self.add_power_pin(pin_name, pin.rc()) + + for inst in self.driver_inst_list: + load_list = self.load_inst_map[inst] + for pin_name in ["vdd", "gnd"]: + pin = load_list[0].get_pin(pin_name) + self.add_power_pin(pin_name, pin.rc() - vector(self.m1_pitch, 0)) + + pin = load_list[-1].get_pin(pin_name) + self.add_power_pin(pin_name, pin.rc() - vector(0.5 * self.m1_pitch, 0)) + + def add_layout_pins(self): # input is A pin of first inverter a_pin = self.driver_inst_list[0].get_pin("A") @@ -208,7 +196,7 @@ class delay_chain(design.design): # output is A pin of last load inverter last_driver_inst = self.driver_inst_list[-1] - a_pin = self.rightest_load_inst[last_driver_inst].get_pin("A") + a_pin = self.load_inst_map[last_driver_inst][-1].get_pin("A") self.add_via_center(layers=self.m1_stack, offset=a_pin.center()) mid_point = vector(a_pin.cx() + 3 * self.m2_width, a_pin.cy()) From 60ba2c1aa55ebf664deeaec919530d2ab6917e64 Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Tue, 21 Apr 2020 17:20:29 -0700 Subject: [PATCH 24/28] updated pbitcell test names --- compiler/tests/04_precharge_pbitcell_test.py | 8 ++++---- .../tests/04_single_level_column_mux_pbitcell_test.py | 2 +- compiler/tests/05_replica_pbitcell_array_test.py | 6 +++--- compiler/tests/06_hierarchical_decoder_pbitcell_test.py | 4 ++-- .../tests/06_hierarchical_predecode2x4_pbitcell_test.py | 2 +- .../tests/06_hierarchical_predecode3x8_pbitcell_test.py | 2 +- .../07_single_level_column_mux_array_pbitcell_test.py | 2 +- compiler/tests/08_wordline_driver_pbitcell_test.py | 2 +- compiler/tests/09_sense_amp_array_test_pbitcell.py | 2 +- compiler/tests/10_write_driver_array_pbitcell_test.py | 2 +- .../tests/10_write_driver_array_wmask_pbitcell_test.py | 2 +- compiler/tests/10_write_mask_and_array_pbitcell_test.py | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/tests/04_precharge_pbitcell_test.py b/compiler/tests/04_precharge_pbitcell_test.py index fd2f8283..3eb7628d 100755 --- a/compiler/tests/04_precharge_pbitcell_test.py +++ b/compiler/tests/04_precharge_pbitcell_test.py @@ -15,12 +15,12 @@ from globals import OPTS from sram_factory import factory import debug -class precharge_test(openram_test): +class precharge_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) globals.init_openram(config_file) - + # check precharge in multi-port OPTS.bitcell = "pbitcell" OPTS.num_rw_ports = 1 @@ -36,14 +36,14 @@ class precharge_test(openram_test): debug.info(2, "Checking precharge for pbitcell (innermost connections)") tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl1", bitcell_br="br1") self.local_check(tx) - + factory.reset() debug.info(2, "Checking precharge for pbitcell (outermost connections)") tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl2", bitcell_br="br2") self.local_check(tx) globals.end_openram() - + # run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() diff --git a/compiler/tests/04_single_level_column_mux_pbitcell_test.py b/compiler/tests/04_single_level_column_mux_pbitcell_test.py index 85f909e6..18ab631f 100644 --- a/compiler/tests/04_single_level_column_mux_pbitcell_test.py +++ b/compiler/tests/04_single_level_column_mux_pbitcell_test.py @@ -17,7 +17,7 @@ import debug #@unittest.skip("SKIPPING 04_driver_test") -class single_level_column_mux_test(openram_test): +class single_level_column_mux_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) diff --git a/compiler/tests/05_replica_pbitcell_array_test.py b/compiler/tests/05_replica_pbitcell_array_test.py index 34bdbee7..6a87f408 100755 --- a/compiler/tests/05_replica_pbitcell_array_test.py +++ b/compiler/tests/05_replica_pbitcell_array_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2019 Regents of the University of California +# Copyright (c) 2016-2019 Regents of the University of California # All rights reserved. # import unittest @@ -13,7 +13,7 @@ from globals import OPTS from sram_factory import factory import debug -class replica_bitcell_array_test(openram_test): +class replica_pbitcell_array_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -41,7 +41,7 @@ class replica_bitcell_array_test(openram_test): debug.info(2, "Testing 4x4 array for pbitcell") a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, left_rbl=1, right_rbl=0, bitcell_ports=[0]) self.local_check(a) - + globals.end_openram() # run the test from the command line diff --git a/compiler/tests/06_hierarchical_decoder_pbitcell_test.py b/compiler/tests/06_hierarchical_decoder_pbitcell_test.py index ec8f4efe..094e8b2e 100755 --- a/compiler/tests/06_hierarchical_decoder_pbitcell_test.py +++ b/compiler/tests/06_hierarchical_decoder_pbitcell_test.py @@ -15,7 +15,7 @@ from globals import OPTS from sram_factory import factory import debug -class hierarchical_decoder_test(openram_test): +class hierarchical_decoder_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) @@ -64,7 +64,7 @@ class hierarchical_decoder_test(openram_test): self.local_check(a) globals.end_openram() - + # run the test from the command line if __name__ == "__main__": (OPTS, args) = globals.parse_args() diff --git a/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py b/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py index bc4a153f..b5532891 100755 --- a/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py +++ b/compiler/tests/06_hierarchical_predecode2x4_pbitcell_test.py @@ -15,7 +15,7 @@ from globals import OPTS from sram_factory import factory import debug -class hierarchical_predecode2x4_test(openram_test): +class hierarchical_predecode2x4_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) diff --git a/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py b/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py index ffe68102..1d5ab41b 100755 --- a/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py +++ b/compiler/tests/06_hierarchical_predecode3x8_pbitcell_test.py @@ -15,7 +15,7 @@ from globals import OPTS from sram_factory import factory import debug -class hierarchical_predecode3x8_test(openram_test): +class hierarchical_predecode3x8_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) diff --git a/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py b/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py index d929b855..84e62a96 100644 --- a/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py +++ b/compiler/tests/07_single_level_column_mux_array_pbitcell_test.py @@ -14,7 +14,7 @@ from globals import OPTS from sram_factory import factory import debug -class single_level_column_mux_test(openram_test): +class single_level_column_mux_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) diff --git a/compiler/tests/08_wordline_driver_pbitcell_test.py b/compiler/tests/08_wordline_driver_pbitcell_test.py index 42de5c26..3dd5933d 100644 --- a/compiler/tests/08_wordline_driver_pbitcell_test.py +++ b/compiler/tests/08_wordline_driver_pbitcell_test.py @@ -17,7 +17,7 @@ import debug #@unittest.skip("SKIPPING 04_driver_test") -class wordline_driver_test(openram_test): +class wordline_driver_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) diff --git a/compiler/tests/09_sense_amp_array_test_pbitcell.py b/compiler/tests/09_sense_amp_array_test_pbitcell.py index 7c2fbd2d..a0fe256f 100644 --- a/compiler/tests/09_sense_amp_array_test_pbitcell.py +++ b/compiler/tests/09_sense_amp_array_test_pbitcell.py @@ -15,7 +15,7 @@ from globals import OPTS from sram_factory import factory import debug -class sense_amp_test(openram_test): +class sense_amp_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) diff --git a/compiler/tests/10_write_driver_array_pbitcell_test.py b/compiler/tests/10_write_driver_array_pbitcell_test.py index 87849001..397b3762 100644 --- a/compiler/tests/10_write_driver_array_pbitcell_test.py +++ b/compiler/tests/10_write_driver_array_pbitcell_test.py @@ -15,7 +15,7 @@ from globals import OPTS from sram_factory import factory import debug -class write_driver_test(openram_test): +class write_driver_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) diff --git a/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py b/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py index 046b4d22..b6593eb0 100644 --- a/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py +++ b/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py @@ -17,7 +17,7 @@ from sram_factory import factory import debug -class write_driver_test(openram_test): +class write_driver_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) diff --git a/compiler/tests/10_write_mask_and_array_pbitcell_test.py b/compiler/tests/10_write_mask_and_array_pbitcell_test.py index 5068c119..448ee8b1 100644 --- a/compiler/tests/10_write_mask_and_array_pbitcell_test.py +++ b/compiler/tests/10_write_mask_and_array_pbitcell_test.py @@ -17,7 +17,7 @@ from sram_factory import factory import debug -class write_mask_and_array_test(openram_test): +class write_mask_and_array_pbitcell_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) From c2419af2e2a61e4caa821ca04abcb90007a0ca0e Mon Sep 17 00:00:00 2001 From: David Ratchkov Date: Mon, 20 Apr 2020 13:36:47 -0700 Subject: [PATCH 25/28] Fix voltage_map names (these do not need to match pg_pin names) --- compiler/characterizer/lib.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/characterizer/lib.py b/compiler/characterizer/lib.py index 276ea767..e6befc2b 100644 --- a/compiler/characterizer/lib.py +++ b/compiler/characterizer/lib.py @@ -243,8 +243,8 @@ class lib: self.lib.write(" default_max_fanout : 4.0 ;\n") self.lib.write(" default_connection_class : universal ;\n\n") - self.lib.write(" voltage_map ( vdd, {} );\n".format(tech.spice["nom_supply_voltage"])) - self.lib.write(" voltage_map ( gnd, 0 );\n\n") + self.lib.write(" voltage_map ( VDD, {} );\n".format(tech.spice["nom_supply_voltage"])) + self.lib.write(" voltage_map ( GND, 0 );\n\n") def create_list(self,values): """ Helper function to create quoted, line wrapped list """ From 14f440df7360f3b799b3ba1448fac9ccb580097e Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Wed, 22 Apr 2020 10:40:04 -0700 Subject: [PATCH 26/28] Update golden results with new lib syntax --- compiler/tests/21_hspice_delay_test.py | 47 +++-- compiler/tests/21_ngspice_delay_test.py | 44 ++-- ..._16_1_freepdk45_FF_1p0V_25C_analytical.lib | 83 +++++--- ..._16_1_freepdk45_SS_1p0V_25C_analytical.lib | 83 +++++--- .../sram_2_16_1_freepdk45_TT_1p0V_25C.lib | 167 ++++++++------- ..._16_1_freepdk45_TT_1p0V_25C_analytical.lib | 83 +++++--- ...16_1_scn4m_subm_FF_5p0V_25C_analytical.lib | 95 +++++---- ...16_1_scn4m_subm_SS_5p0V_25C_analytical.lib | 95 +++++---- .../sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib | 191 ++++++++++-------- ...16_1_scn4m_subm_TT_5p0V_25C_analytical.lib | 95 +++++---- 10 files changed, 583 insertions(+), 400 deletions(-) diff --git a/compiler/tests/21_hspice_delay_test.py b/compiler/tests/21_hspice_delay_test.py index 832a6308..a602f9d2 100755 --- a/compiler/tests/21_hspice_delay_test.py +++ b/compiler/tests/21_hspice_delay_test.py @@ -60,29 +60,36 @@ class timing_sram_test(openram_test): data, port_data = d.analyze(probe_address, probe_data, slews, loads) #Combine info about port into all data data.update(port_data[0]) - + if OPTS.tech_name == "freepdk45": - golden_data = {'delay_hl': [0.2383338], - 'delay_lh': [0.2383338], - 'leakage_power': 0.0014532999999999998, - 'min_period': 0.898, - 'read0_power': [0.30059800000000003], - 'read1_power': [0.30061810000000005], - 'slew_hl': [0.25358420000000004], - 'slew_lh': [0.25358420000000004], - 'write0_power': [0.34616749999999996], - 'write1_power': [0.2792924]} + golden_data = {'min_period': 0.898, + 'write1_power': [0.2659137999999999], + 'disabled_write0_power': [0.1782495], + 'disabled_read0_power': [0.14490679999999997], + 'write0_power': [0.3330119], + 'disabled_write1_power': [0.1865223], + 'leakage_power': 0.0014532, + 'disabled_read1_power': [0.1627516], + 'slew_lh': [0.25367799999999996], + 'slew_hl': [0.25367799999999996], + 'delay_lh': [0.23820930000000004], + 'delay_hl': [0.23820930000000004], + 'read1_power': [0.3005756], + 'read0_power': [0.3005888]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.7448], - 'delay_lh': [1.7448], - 'leakage_power': 0.0006356744000000001, + golden_data = {'leakage_power': 0.0006356576000000001, + 'write1_power': [11.292700000000002], + 'read0_power': [12.98], + 'disabled_write1_power': [8.3707], + 'write0_power': [14.4447], 'delay_hl': [1.7445000000000002], + 'disabled_read0_power': [6.4325], + 'slew_hl': [1.7437], + 'disabled_write0_power': [8.1307], + 'slew_lh': [1.7437], + 'read1_power': [12.9869], + 'disabled_read1_power': [7.706], 'min_period': 6.25, - 'read0_power': [12.9846], - 'read1_power': [12.9722], - 'slew_hl': [1.7433], - 'slew_lh': [1.7433], - 'write0_power': [14.8772], - 'write1_power': [11.7217]} + 'delay_lh': [1.7445000000000002]} else: self.assertTrue(False) # other techs fail # Check if no too many or too few results diff --git a/compiler/tests/21_ngspice_delay_test.py b/compiler/tests/21_ngspice_delay_test.py index fb72a57d..c944b3ce 100755 --- a/compiler/tests/21_ngspice_delay_test.py +++ b/compiler/tests/21_ngspice_delay_test.py @@ -55,27 +55,35 @@ class timing_sram_test(openram_test): data.update(port_data[0]) if OPTS.tech_name == "freepdk45": - golden_data = {'delay_hl': [0.2264205], - 'delay_lh': [0.2264205], - 'leakage_power': 0.0021017429999999997, - 'min_period': 0.859, - 'read0_power': [0.3339161], - 'read1_power': [0.31329440000000003], - 'slew_hl': [0.2590786], - 'slew_lh': [0.2590786], - 'write0_power': [0.36360849999999995], - 'write1_power': [0.3486931]} + golden_data = {'slew_lh': [0.2592187], + 'slew_hl': [0.2592187], + 'delay_lh': [0.2465583], + 'disabled_write0_power': [0.1924678], + 'disabled_read0_power': [0.152483], + 'write0_power': [0.3409064], + 'disabled_read1_power': [0.1737818], + 'read0_power': [0.3096708], + 'read1_power': [0.3107916], + 'delay_hl': [0.2465583], + 'write1_power': [0.26915849999999997], + 'leakage_power': 0.002044307, + 'min_period': 0.898, + 'disabled_write1_power': [0.201411]} elif OPTS.tech_name == "scn4m_subm": - golden_data = {'delay_hl': [1.85985], - 'delay_lh': [1.85985], + golden_data = {'read1_power': [12.11658], + 'write1_power': [10.52653], + 'read0_power': [11.956710000000001], + 'disabled_write0_power': [7.673665], + 'disabled_write1_power': [7.981922000000001], + 'slew_lh': [1.868836], + 'slew_hl': [1.868836], + 'delay_hl': [1.8598510000000001], + 'delay_lh': [1.8598510000000001], 'leakage_power': 0.008613619, + 'disabled_read0_power': [5.904712], 'min_period': 6.875, - 'read0_power': [12.656310000000001], - 'read1_power': [12.11682], - 'slew_hl': [1.868942], - 'slew_lh': [1.868942], - 'write0_power': [13.978110000000001], - 'write1_power': [11.437930000000001]} + 'disabled_read1_power': [7.132159], + 'write0_power': [13.406400000000001]} else: self.assertTrue(False) # other techs fail diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib index a1c5a04b..b3ef0e0a 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_FF_1p0V_25C_analytical.lib @@ -35,11 +35,14 @@ library (sram_2_16_1_freepdk45_FF_1p0V_25C_lib){ default_max_fanout : 4.0 ; default_connection_class : universal ; + voltage_map ( VDD, 1.0 ); + voltage_map ( GND, 0 ); + lu_table_template(CELL_TABLE){ variable_1 : input_net_transition; variable_2 : total_output_net_capacitance; index_1("0.00125, 0.005, 0.04"); - index_2("0.052275, 0.2091, 1.6728"); + index_2("5.2275e-05, 0.0002091, 0.0008364"); } lu_table_template(CONSTRAINT_TABLE){ @@ -78,17 +81,26 @@ cell (sram_2_16_1_freepdk45){ dont_use : true; map_only : true; dont_touch : true; - area : 1124.88; + area : 0; + + pg_pin(vdd) { + voltage_name : VDD; + pg_type : primary_power; + } + + pg_pin(gnd) { + voltage_name : GND; + pg_type : primary_ground; + } leakage_power () { - when : "csb0"; - value : 0.000167; + value : 0.000198; } - cell_leakage_power : 0; + cell_leakage_power : 0.000198; bus(din0){ bus_type : data; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; memory_write(){ address : addr0; clocked_on : clk0; @@ -127,8 +139,8 @@ cell (sram_2_16_1_freepdk45){ bus(dout0){ bus_type : data; direction : output; - max_capacitance : 1.6728; - min_capacitance : 0.052275; + max_capacitance : 0.0008364000000000001; + min_capacitance : 5.2275000000000003e-05; memory_read(){ address : addr0; } @@ -138,14 +150,14 @@ cell (sram_2_16_1_freepdk45){ related_pin : "clk0"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.088, 0.088, 0.088",\ - "0.088, 0.088, 0.088",\ - "0.088, 0.088, 0.088"); + values("0.193, 0.193, 0.194",\ + "0.193, 0.193, 0.194",\ + "0.193, 0.193, 0.194"); } cell_fall(CELL_TABLE) { - values("0.088, 0.088, 0.088",\ - "0.088, 0.088, 0.088",\ - "0.088, 0.088, 0.088"); + values("0.193, 0.193, 0.194",\ + "0.193, 0.193, 0.194",\ + "0.193, 0.193, 0.194"); } rise_transition(CELL_TABLE) { values("0.001, 0.001, 0.001",\ @@ -164,7 +176,7 @@ cell (sram_2_16_1_freepdk45){ bus(addr0){ bus_type : addr; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; max_transition : 0.04; pin(addr0[3:0]){ timing(){ @@ -200,7 +212,7 @@ cell (sram_2_16_1_freepdk45){ pin(csb0){ direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -233,7 +245,7 @@ cell (sram_2_16_1_freepdk45){ pin(web0){ direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -267,52 +279,61 @@ cell (sram_2_16_1_freepdk45){ pin(clk0){ clock : true; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; internal_power(){ - when : "!csb0 & clk0 & !web0"; + when : "!csb0 & !web0"; rise_power(scalar){ - values("0.033101244168888884"); + values("9.240667e-02"); } fall_power(scalar){ - values("0.033101244168888884"); + values("9.240667e-02"); } } internal_power(){ - when : "!csb0 & !clk0 & web0"; + when : "csb0 & !web0"; rise_power(scalar){ - values("0.033101244168888884"); + values("9.240667e-02"); } fall_power(scalar){ - values("0.033101244168888884"); + values("9.240667e-02"); } } internal_power(){ - when : "csb0"; + when : "!csb0 & web0"; rise_power(scalar){ - values("0"); + values("9.240667e-02"); } fall_power(scalar){ - values("0"); + values("9.240667e-02"); + } + } + internal_power(){ + when : "csb0 & web0"; + rise_power(scalar){ + values("9.240667e-02"); + } + fall_power(scalar){ + values("9.240667e-02"); } } timing(){ timing_type :"min_pulse_width"; related_pin : clk0; rise_constraint(scalar) { - values("0.009"); + values("0.0195"); } fall_constraint(scalar) { - values("0.009"); + values("0.0195"); } } timing(){ timing_type :"minimum_period"; related_pin : clk0; rise_constraint(scalar) { - values("0.018"); + values("0.039"); } fall_constraint(scalar) { - values("0.018"); + values("0.039"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib index 865daada..34be4fe4 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_SS_1p0V_25C_analytical.lib @@ -35,11 +35,14 @@ library (sram_2_16_1_freepdk45_SS_1p0V_25C_lib){ default_max_fanout : 4.0 ; default_connection_class : universal ; + voltage_map ( VDD, 1.0 ); + voltage_map ( GND, 0 ); + lu_table_template(CELL_TABLE){ variable_1 : input_net_transition; variable_2 : total_output_net_capacitance; index_1("0.00125, 0.005, 0.04"); - index_2("0.052275, 0.2091, 1.6728"); + index_2("5.2275e-05, 0.0002091, 0.0008364"); } lu_table_template(CONSTRAINT_TABLE){ @@ -78,17 +81,26 @@ cell (sram_2_16_1_freepdk45){ dont_use : true; map_only : true; dont_touch : true; - area : 1124.88; + area : 0; + + pg_pin(vdd) { + voltage_name : VDD; + pg_type : primary_power; + } + + pg_pin(gnd) { + voltage_name : GND; + pg_type : primary_ground; + } leakage_power () { - when : "csb0"; - value : 0.000167; + value : 0.000198; } - cell_leakage_power : 0; + cell_leakage_power : 0.000198; bus(din0){ bus_type : data; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; memory_write(){ address : addr0; clocked_on : clk0; @@ -127,8 +139,8 @@ cell (sram_2_16_1_freepdk45){ bus(dout0){ bus_type : data; direction : output; - max_capacitance : 1.6728; - min_capacitance : 0.052275; + max_capacitance : 0.0008364000000000001; + min_capacitance : 5.2275000000000003e-05; memory_read(){ address : addr0; } @@ -138,14 +150,14 @@ cell (sram_2_16_1_freepdk45){ related_pin : "clk0"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.107, 0.107, 0.107",\ - "0.107, 0.107, 0.107",\ - "0.107, 0.107, 0.107"); + values("0.236, 0.236, 0.237",\ + "0.236, 0.236, 0.237",\ + "0.236, 0.236, 0.237"); } cell_fall(CELL_TABLE) { - values("0.107, 0.107, 0.107",\ - "0.107, 0.107, 0.107",\ - "0.107, 0.107, 0.107"); + values("0.236, 0.236, 0.237",\ + "0.236, 0.236, 0.237",\ + "0.236, 0.236, 0.237"); } rise_transition(CELL_TABLE) { values("0.001, 0.001, 0.001",\ @@ -164,7 +176,7 @@ cell (sram_2_16_1_freepdk45){ bus(addr0){ bus_type : addr; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; max_transition : 0.04; pin(addr0[3:0]){ timing(){ @@ -200,7 +212,7 @@ cell (sram_2_16_1_freepdk45){ pin(csb0){ direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -233,7 +245,7 @@ cell (sram_2_16_1_freepdk45){ pin(web0){ direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -267,52 +279,61 @@ cell (sram_2_16_1_freepdk45){ pin(clk0){ clock : true; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; internal_power(){ - when : "!csb0 & clk0 & !web0"; + when : "!csb0 & !web0"; rise_power(scalar){ - values("0.033101244168888884"); + values("7.560546e-02"); } fall_power(scalar){ - values("0.033101244168888884"); + values("7.560546e-02"); } } internal_power(){ - when : "!csb0 & !clk0 & web0"; + when : "csb0 & !web0"; rise_power(scalar){ - values("0.033101244168888884"); + values("7.560546e-02"); } fall_power(scalar){ - values("0.033101244168888884"); + values("7.560546e-02"); } } internal_power(){ - when : "csb0"; + when : "!csb0 & web0"; rise_power(scalar){ - values("0"); + values("7.560546e-02"); } fall_power(scalar){ - values("0"); + values("7.560546e-02"); + } + } + internal_power(){ + when : "csb0 & web0"; + rise_power(scalar){ + values("7.560546e-02"); + } + fall_power(scalar){ + values("7.560546e-02"); } } timing(){ timing_type :"min_pulse_width"; related_pin : clk0; rise_constraint(scalar) { - values("0.0105"); + values("0.0235"); } fall_constraint(scalar) { - values("0.0105"); + values("0.0235"); } } timing(){ timing_type :"minimum_period"; related_pin : clk0; rise_constraint(scalar) { - values("0.021"); + values("0.047"); } fall_constraint(scalar) { - values("0.021"); + values("0.047"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib index 72d01a0f..cca9c1ed 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C.lib @@ -35,11 +35,14 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ default_max_fanout : 4.0 ; default_connection_class : universal ; + voltage_map ( VDD, 1.0 ); + voltage_map ( GND, 0 ); + lu_table_template(CELL_TABLE){ variable_1 : input_net_transition; variable_2 : total_output_net_capacitance; index_1("0.00125, 0.005, 0.04"); - index_2("0.052275, 0.2091, 1.6728"); + index_2("5.2275e-05, 0.0002091, 0.0008364"); } lu_table_template(CONSTRAINT_TABLE){ @@ -78,17 +81,26 @@ cell (sram_2_16_1_freepdk45){ dont_use : true; map_only : true; dont_touch : true; - area : 977.4951374999999; + area : 0; + + pg_pin(vdd) { + voltage_name : VDD; + pg_type : primary_power; + } + + pg_pin(gnd) { + voltage_name : GND; + pg_type : primary_ground; + } leakage_power () { - when : "csb0"; - value : 0.0011164579999999999; + value : 0.00163; } - cell_leakage_power : 0; + cell_leakage_power : 0.00163; bus(din0){ bus_type : data; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; memory_write(){ address : addr0; clocked_on : clk0; @@ -98,9 +110,9 @@ cell (sram_2_16_1_freepdk45){ timing_type : setup_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.033, 0.033, 0.039",\ - "0.033, 0.033, 0.039",\ - "0.033, 0.033, 0.039"); + values("0.033, 0.033, 0.033",\ + "0.033, 0.033, 0.033",\ + "0.033, 0.033, 0.033"); } fall_constraint(CONSTRAINT_TABLE) { values("0.027, 0.027, 0.033",\ @@ -112,14 +124,14 @@ cell (sram_2_16_1_freepdk45){ timing_type : hold_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("-0.01, -0.016, -0.022",\ - "-0.01, -0.016, -0.022",\ - "-0.01, -0.016, -0.022"); + values("-0.01, -0.01, 0.021",\ + "-0.01, -0.01, 0.021",\ + "-0.01, -0.01, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.016, -0.016, -0.016",\ - "-0.016, -0.016, -0.016",\ - "-0.016, -0.016, -0.016"); + values("-0.016, -0.01, -0.016",\ + "-0.016, -0.01, -0.016",\ + "-0.016, -0.01, -0.016"); } } } @@ -127,8 +139,8 @@ cell (sram_2_16_1_freepdk45){ bus(dout0){ bus_type : data; direction : output; - max_capacitance : 1.6728; - min_capacitance : 0.052275; + max_capacitance : 0.0008364000000000001; + min_capacitance : 5.2275000000000003e-05; memory_read(){ address : addr0; } @@ -138,24 +150,24 @@ cell (sram_2_16_1_freepdk45){ related_pin : "clk0"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.235, 0.235, 0.239",\ - "0.235, 0.236, 0.24",\ - "0.241, 0.242, 0.246"); + values("0.226, 0.227, 0.232",\ + "0.227, 0.228, 0.233",\ + "0.232, 0.234, 0.238"); } cell_fall(CELL_TABLE) { - values("2.583, 2.585, 2.612",\ - "2.584, 2.585, 2.613",\ - "2.59, 2.592, 2.62"); + values("0.226, 0.227, 0.232",\ + "0.227, 0.228, 0.233",\ + "0.232, 0.234, 0.238"); } rise_transition(CELL_TABLE) { - values("0.022, 0.022, 0.03",\ - "0.022, 0.023, 0.03",\ - "0.022, 0.022, 0.03"); + values("0.256, 0.256, 0.257",\ + "0.256, 0.256, 0.257",\ + "0.256, 0.256, 0.257"); } fall_transition(CELL_TABLE) { - values("0.078, 0.079, 0.083",\ - "0.078, 0.079, 0.083",\ - "0.079, 0.079, 0.083"); + values("0.256, 0.256, 0.257",\ + "0.256, 0.256, 0.257",\ + "0.256, 0.256, 0.257"); } } } @@ -164,16 +176,16 @@ cell (sram_2_16_1_freepdk45){ bus(addr0){ bus_type : addr; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; max_transition : 0.04; pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.033, 0.033, 0.039",\ - "0.033, 0.033, 0.039",\ - "0.033, 0.033, 0.039"); + values("0.033, 0.033, 0.033",\ + "0.033, 0.033, 0.033",\ + "0.033, 0.033, 0.033"); } fall_constraint(CONSTRAINT_TABLE) { values("0.027, 0.027, 0.033",\ @@ -185,14 +197,14 @@ cell (sram_2_16_1_freepdk45){ timing_type : hold_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("-0.01, -0.016, -0.022",\ - "-0.01, -0.016, -0.022",\ - "-0.01, -0.016, -0.022"); + values("-0.01, -0.01, 0.021",\ + "-0.01, -0.01, 0.021",\ + "-0.01, -0.01, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.016, -0.016, -0.016",\ - "-0.016, -0.016, -0.016",\ - "-0.016, -0.016, -0.016"); + values("-0.016, -0.01, -0.016",\ + "-0.016, -0.01, -0.016",\ + "-0.016, -0.01, -0.016"); } } } @@ -200,14 +212,14 @@ cell (sram_2_16_1_freepdk45){ pin(csb0){ direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; timing(){ timing_type : setup_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.033, 0.033, 0.039",\ - "0.033, 0.033, 0.039",\ - "0.033, 0.033, 0.039"); + values("0.033, 0.033, 0.033",\ + "0.033, 0.033, 0.033",\ + "0.033, 0.033, 0.033"); } fall_constraint(CONSTRAINT_TABLE) { values("0.027, 0.027, 0.033",\ @@ -219,28 +231,28 @@ cell (sram_2_16_1_freepdk45){ timing_type : hold_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("-0.01, -0.016, -0.022",\ - "-0.01, -0.016, -0.022",\ - "-0.01, -0.016, -0.022"); + values("-0.01, -0.01, 0.021",\ + "-0.01, -0.01, 0.021",\ + "-0.01, -0.01, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.016, -0.016, -0.016",\ - "-0.016, -0.016, -0.016",\ - "-0.016, -0.016, -0.016"); + values("-0.016, -0.01, -0.016",\ + "-0.016, -0.01, -0.016",\ + "-0.016, -0.01, -0.016"); } } } pin(web0){ direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; timing(){ timing_type : setup_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.033, 0.033, 0.039",\ - "0.033, 0.033, 0.039",\ - "0.033, 0.033, 0.039"); + values("0.033, 0.033, 0.033",\ + "0.033, 0.033, 0.033",\ + "0.033, 0.033, 0.033"); } fall_constraint(CONSTRAINT_TABLE) { values("0.027, 0.027, 0.033",\ @@ -252,14 +264,14 @@ cell (sram_2_16_1_freepdk45){ timing_type : hold_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("-0.01, -0.016, -0.022",\ - "-0.01, -0.016, -0.022",\ - "-0.01, -0.016, -0.022"); + values("-0.01, -0.01, 0.021",\ + "-0.01, -0.01, 0.021",\ + "-0.01, -0.01, 0.021"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.016, -0.016, -0.016",\ - "-0.016, -0.016, -0.016",\ - "-0.016, -0.016, -0.016"); + values("-0.016, -0.01, -0.016",\ + "-0.016, -0.01, -0.016",\ + "-0.016, -0.01, -0.016"); } } } @@ -267,52 +279,61 @@ cell (sram_2_16_1_freepdk45){ pin(clk0){ clock : true; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; internal_power(){ - when : "!csb0 & clk0 & !web0"; + when : "!csb0 & !web0"; rise_power(scalar){ - values("0.03599689694444445"); + values("3.069977e-01"); } fall_power(scalar){ - values("0.03599689694444445"); + values("3.686680e-01"); } } internal_power(){ - when : "!csb0 & !clk0 & web0"; + when : "csb0 & !web0"; rise_power(scalar){ - values("0.029906643888888886"); + values("2.055845e-01"); } fall_power(scalar){ - values("0.029906643888888886"); + values("1.933561e-01"); } } internal_power(){ - when : "csb0"; + when : "!csb0 & web0"; rise_power(scalar){ - values("0"); + values("3.315565e-01"); } fall_power(scalar){ - values("0"); + values("3.314553e-01"); + } + } + internal_power(){ + when : "csb0 & web0"; + rise_power(scalar){ + values("1.777355e-01"); + } + fall_power(scalar){ + values("1.615044e-01"); } } timing(){ timing_type :"min_pulse_width"; related_pin : clk0; rise_constraint(scalar) { - values("2.422"); + values("0.449"); } fall_constraint(scalar) { - values("2.422"); + values("0.449"); } } timing(){ timing_type :"minimum_period"; related_pin : clk0; rise_constraint(scalar) { - values("4.844"); + values("0.898"); } fall_constraint(scalar) { - values("4.844"); + values("0.898"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib index 33587063..26028892 100644 --- a/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_freepdk45_TT_1p0V_25C_analytical.lib @@ -35,11 +35,14 @@ library (sram_2_16_1_freepdk45_TT_1p0V_25C_lib){ default_max_fanout : 4.0 ; default_connection_class : universal ; + voltage_map ( VDD, 1.0 ); + voltage_map ( GND, 0 ); + lu_table_template(CELL_TABLE){ variable_1 : input_net_transition; variable_2 : total_output_net_capacitance; index_1("0.00125, 0.005, 0.04"); - index_2("0.052275, 0.2091, 1.6728"); + index_2("5.2275e-05, 0.0002091, 0.0008364"); } lu_table_template(CONSTRAINT_TABLE){ @@ -78,17 +81,26 @@ cell (sram_2_16_1_freepdk45){ dont_use : true; map_only : true; dont_touch : true; - area : 977.4951374999999; + area : 0; + + pg_pin(vdd) { + voltage_name : VDD; + pg_type : primary_power; + } + + pg_pin(gnd) { + voltage_name : GND; + pg_type : primary_ground; + } leakage_power () { - when : "csb0"; - value : 0.000179; + value : 0.000198; } - cell_leakage_power : 0; + cell_leakage_power : 0.000198; bus(din0){ bus_type : data; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; memory_write(){ address : addr0; clocked_on : clk0; @@ -127,8 +139,8 @@ cell (sram_2_16_1_freepdk45){ bus(dout0){ bus_type : data; direction : output; - max_capacitance : 1.6728; - min_capacitance : 0.052275; + max_capacitance : 0.0008364000000000001; + min_capacitance : 5.2275000000000003e-05; memory_read(){ address : addr0; } @@ -138,14 +150,14 @@ cell (sram_2_16_1_freepdk45){ related_pin : "clk0"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.098, 0.098, 0.098",\ - "0.098, 0.098, 0.098",\ - "0.098, 0.098, 0.098"); + values("0.215, 0.215, 0.216",\ + "0.215, 0.215, 0.216",\ + "0.215, 0.215, 0.216"); } cell_fall(CELL_TABLE) { - values("0.098, 0.098, 0.098",\ - "0.098, 0.098, 0.098",\ - "0.098, 0.098, 0.098"); + values("0.215, 0.215, 0.216",\ + "0.215, 0.215, 0.216",\ + "0.215, 0.215, 0.216"); } rise_transition(CELL_TABLE) { values("0.001, 0.001, 0.001",\ @@ -164,7 +176,7 @@ cell (sram_2_16_1_freepdk45){ bus(addr0){ bus_type : addr; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; max_transition : 0.04; pin(addr0[3:0]){ timing(){ @@ -200,7 +212,7 @@ cell (sram_2_16_1_freepdk45){ pin(csb0){ direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -233,7 +245,7 @@ cell (sram_2_16_1_freepdk45){ pin(web0){ direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -267,52 +279,61 @@ cell (sram_2_16_1_freepdk45){ pin(clk0){ clock : true; direction : input; - capacitance : 0.2091; + capacitance : 0.00020910000000000001; internal_power(){ - when : "!csb0 & clk0 & !web0"; + when : "!csb0 & !web0"; rise_power(scalar){ - values("0.0747594982142222"); + values("8.316600e-02"); } fall_power(scalar){ - values("0.0747594982142222"); + values("8.316600e-02"); } } internal_power(){ - when : "!csb0 & !clk0 & web0"; + when : "csb0 & !web0"; rise_power(scalar){ - values("0.0747594982142222"); + values("8.316600e-02"); } fall_power(scalar){ - values("0.0747594982142222"); + values("8.316600e-02"); } } internal_power(){ - when : "csb0"; + when : "!csb0 & web0"; rise_power(scalar){ - values("0"); + values("8.316600e-02"); } fall_power(scalar){ - values("0"); + values("8.316600e-02"); + } + } + internal_power(){ + when : "csb0 & web0"; + rise_power(scalar){ + values("8.316600e-02"); + } + fall_power(scalar){ + values("8.316600e-02"); } } timing(){ timing_type :"min_pulse_width"; related_pin : clk0; rise_constraint(scalar) { - values("0.0"); + values("0.0215"); } fall_constraint(scalar) { - values("0.0"); + values("0.0215"); } } timing(){ timing_type :"minimum_period"; related_pin : clk0; rise_constraint(scalar) { - values("0"); + values("0.043"); } fall_constraint(scalar) { - values("0"); + values("0.043"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib index c370f993..6912aec7 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_FF_5p0V_25C_analytical.lib @@ -35,11 +35,14 @@ library (sram_2_16_1_scn4m_subm_FF_5p0V_25C_lib){ default_max_fanout : 4.0 ; default_connection_class : universal ; + voltage_map ( VDD, 5.0 ); + voltage_map ( GND, 0 ); + lu_table_template(CELL_TABLE){ variable_1 : input_net_transition; variable_2 : total_output_net_capacitance; index_1("0.0125, 0.05, 0.4"); - index_2("2.45605, 9.8242, 78.5936"); + index_2("0.00245605, 0.0098242, 0.0392968"); } lu_table_template(CONSTRAINT_TABLE){ @@ -78,17 +81,26 @@ cell (sram_2_16_1_scn4m_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 73068.14000000001; + area : 0; + + pg_pin(vdd) { + voltage_name : VDD; + pg_type : primary_power; + } + + pg_pin(gnd) { + voltage_name : GND; + pg_type : primary_ground; + } leakage_power () { - when : "csb0"; - value : 0.000167; + value : 0.000198; } - cell_leakage_power : 0; + cell_leakage_power : 0.000198; bus(din0){ bus_type : data; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; memory_write(){ address : addr0; clocked_on : clk0; @@ -127,8 +139,8 @@ cell (sram_2_16_1_scn4m_subm){ bus(dout0){ bus_type : data; direction : output; - max_capacitance : 78.5936; - min_capacitance : 2.45605; + max_capacitance : 0.0392968; + min_capacitance : 0.00245605; memory_read(){ address : addr0; } @@ -138,24 +150,24 @@ cell (sram_2_16_1_scn4m_subm){ related_pin : "clk0"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.241, 0.241, 0.241",\ - "0.241, 0.241, 0.241",\ - "0.241, 0.241, 0.241"); + values("1.183, 1.199, 1.264",\ + "1.183, 1.199, 1.264",\ + "1.183, 1.199, 1.264"); } cell_fall(CELL_TABLE) { - values("0.241, 0.241, 0.241",\ - "0.241, 0.241, 0.241",\ - "0.241, 0.241, 0.241"); + values("1.183, 1.199, 1.264",\ + "1.183, 1.199, 1.264",\ + "1.183, 1.199, 1.264"); } rise_transition(CELL_TABLE) { - values("0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004"); + values("0.006, 0.007, 0.014",\ + "0.006, 0.007, 0.014",\ + "0.006, 0.007, 0.014"); } fall_transition(CELL_TABLE) { - values("0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004"); + values("0.006, 0.007, 0.014",\ + "0.006, 0.007, 0.014",\ + "0.006, 0.007, 0.014"); } } } @@ -164,7 +176,7 @@ cell (sram_2_16_1_scn4m_subm){ bus(addr0){ bus_type : addr; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; max_transition : 0.4; pin(addr0[3:0]){ timing(){ @@ -200,7 +212,7 @@ cell (sram_2_16_1_scn4m_subm){ pin(csb0){ direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -233,7 +245,7 @@ cell (sram_2_16_1_scn4m_subm){ pin(web0){ direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -267,52 +279,61 @@ cell (sram_2_16_1_scn4m_subm){ pin(clk0){ clock : true; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; internal_power(){ - when : "!csb0 & clk0 & !web0"; + when : "!csb0 & !web0"; rise_power(scalar){ - values("4.99880645"); + values("7.797263e+00"); } fall_power(scalar){ - values("4.99880645"); + values("7.797263e+00"); } } internal_power(){ - when : "!csb0 & !clk0 & web0"; + when : "csb0 & !web0"; rise_power(scalar){ - values("4.99880645"); + values("7.797263e+00"); } fall_power(scalar){ - values("4.99880645"); + values("7.797263e+00"); } } internal_power(){ - when : "csb0"; + when : "!csb0 & web0"; rise_power(scalar){ - values("0"); + values("7.797263e+00"); } fall_power(scalar){ - values("0"); + values("7.797263e+00"); + } + } + internal_power(){ + when : "csb0 & web0"; + rise_power(scalar){ + values("7.797263e+00"); + } + fall_power(scalar){ + values("7.797263e+00"); } } timing(){ timing_type :"min_pulse_width"; related_pin : clk0; rise_constraint(scalar) { - values("0.024"); + values("0.1265"); } fall_constraint(scalar) { - values("0.024"); + values("0.1265"); } } timing(){ timing_type :"minimum_period"; related_pin : clk0; rise_constraint(scalar) { - values("0.048"); + values("0.253"); } fall_constraint(scalar) { - values("0.048"); + values("0.253"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib index f52de676..a7605cb3 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_SS_5p0V_25C_analytical.lib @@ -35,11 +35,14 @@ library (sram_2_16_1_scn4m_subm_SS_5p0V_25C_lib){ default_max_fanout : 4.0 ; default_connection_class : universal ; + voltage_map ( VDD, 5.0 ); + voltage_map ( GND, 0 ); + lu_table_template(CELL_TABLE){ variable_1 : input_net_transition; variable_2 : total_output_net_capacitance; index_1("0.0125, 0.05, 0.4"); - index_2("2.45605, 9.8242, 78.5936"); + index_2("0.00245605, 0.0098242, 0.0392968"); } lu_table_template(CONSTRAINT_TABLE){ @@ -78,17 +81,26 @@ cell (sram_2_16_1_scn4m_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 73068.14000000001; + area : 0; + + pg_pin(vdd) { + voltage_name : VDD; + pg_type : primary_power; + } + + pg_pin(gnd) { + voltage_name : GND; + pg_type : primary_ground; + } leakage_power () { - when : "csb0"; - value : 0.000167; + value : 0.000198; } - cell_leakage_power : 0; + cell_leakage_power : 0.000198; bus(din0){ bus_type : data; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; memory_write(){ address : addr0; clocked_on : clk0; @@ -127,8 +139,8 @@ cell (sram_2_16_1_scn4m_subm){ bus(dout0){ bus_type : data; direction : output; - max_capacitance : 78.5936; - min_capacitance : 2.45605; + max_capacitance : 0.0392968; + min_capacitance : 0.00245605; memory_read(){ address : addr0; } @@ -138,24 +150,24 @@ cell (sram_2_16_1_scn4m_subm){ related_pin : "clk0"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.294, 0.294, 0.294",\ - "0.294, 0.294, 0.294",\ - "0.294, 0.294, 0.294"); + values("1.446, 1.466, 1.545",\ + "1.446, 1.466, 1.545",\ + "1.446, 1.466, 1.545"); } cell_fall(CELL_TABLE) { - values("0.294, 0.294, 0.294",\ - "0.294, 0.294, 0.294",\ - "0.294, 0.294, 0.294"); + values("1.446, 1.466, 1.545",\ + "1.446, 1.466, 1.545",\ + "1.446, 1.466, 1.545"); } rise_transition(CELL_TABLE) { - values("0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004"); + values("0.007, 0.009, 0.017",\ + "0.007, 0.009, 0.017",\ + "0.007, 0.009, 0.017"); } fall_transition(CELL_TABLE) { - values("0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004"); + values("0.007, 0.009, 0.017",\ + "0.007, 0.009, 0.017",\ + "0.007, 0.009, 0.017"); } } } @@ -164,7 +176,7 @@ cell (sram_2_16_1_scn4m_subm){ bus(addr0){ bus_type : addr; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; max_transition : 0.4; pin(addr0[3:0]){ timing(){ @@ -200,7 +212,7 @@ cell (sram_2_16_1_scn4m_subm){ pin(csb0){ direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -233,7 +245,7 @@ cell (sram_2_16_1_scn4m_subm){ pin(web0){ direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -267,52 +279,61 @@ cell (sram_2_16_1_scn4m_subm){ pin(clk0){ clock : true; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; internal_power(){ - when : "!csb0 & clk0 & !web0"; + when : "!csb0 & !web0"; rise_power(scalar){ - values("4.99880645"); + values("6.379579e+00"); } fall_power(scalar){ - values("4.99880645"); + values("6.379579e+00"); } } internal_power(){ - when : "!csb0 & !clk0 & web0"; + when : "csb0 & !web0"; rise_power(scalar){ - values("4.99880645"); + values("6.379579e+00"); } fall_power(scalar){ - values("4.99880645"); + values("6.379579e+00"); } } internal_power(){ - when : "csb0"; + when : "!csb0 & web0"; rise_power(scalar){ - values("0"); + values("6.379579e+00"); } fall_power(scalar){ - values("0"); + values("6.379579e+00"); + } + } + internal_power(){ + when : "csb0 & web0"; + rise_power(scalar){ + values("6.379579e+00"); + } + fall_power(scalar){ + values("6.379579e+00"); } } timing(){ timing_type :"min_pulse_width"; related_pin : clk0; rise_constraint(scalar) { - values("0.0295"); + values("0.1545"); } fall_constraint(scalar) { - values("0.0295"); + values("0.1545"); } } timing(){ timing_type :"minimum_period"; related_pin : clk0; rise_constraint(scalar) { - values("0.059"); + values("0.309"); } fall_constraint(scalar) { - values("0.059"); + values("0.309"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib index 7447a1e2..8bec74c3 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C.lib @@ -35,11 +35,14 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ default_max_fanout : 4.0 ; default_connection_class : universal ; + voltage_map ( VDD, 5.0 ); + voltage_map ( GND, 0 ); + lu_table_template(CELL_TABLE){ variable_1 : input_net_transition; variable_2 : total_output_net_capacitance; index_1("0.0125, 0.05, 0.4"); - index_2("2.45605, 9.8242, 78.5936"); + index_2("0.00245605, 0.0098242, 0.0392968"); } lu_table_template(CONSTRAINT_TABLE){ @@ -78,17 +81,26 @@ cell (sram_2_16_1_scn4m_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 60774.3; + area : 0; + + pg_pin(vdd) { + voltage_name : VDD; + pg_type : primary_power; + } + + pg_pin(gnd) { + voltage_name : GND; + pg_type : primary_ground; + } leakage_power () { - when : "csb0"; - value : 0.0009813788999999999; + value : 0.000198; } - cell_leakage_power : 0; + cell_leakage_power : 0.000198; bus(din0){ bus_type : data; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; memory_write(){ address : addr0; clocked_on : clk0; @@ -98,28 +110,28 @@ cell (sram_2_16_1_scn4m_subm){ timing_type : setup_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.167, 0.167, 0.228",\ - "0.167, 0.167, 0.228",\ - "0.167, 0.167, 0.228"); + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.131, 0.125, 0.137",\ - "0.131, 0.125, 0.137",\ - "0.131, 0.125, 0.137"); + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); } } timing(){ timing_type : hold_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.089, -0.089, -0.089",\ - "-0.089, -0.089, -0.089",\ - "-0.089, -0.089, -0.089"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } } } @@ -127,8 +139,8 @@ cell (sram_2_16_1_scn4m_subm){ bus(dout0){ bus_type : data; direction : output; - max_capacitance : 78.5936; - min_capacitance : 2.45605; + max_capacitance : 0.0392968; + min_capacitance : 0.00245605; memory_read(){ address : addr0; } @@ -138,24 +150,24 @@ cell (sram_2_16_1_scn4m_subm){ related_pin : "clk0"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("1.556, 1.576, 1.751",\ - "1.559, 1.579, 1.754",\ - "1.624, 1.643, 1.819"); + values("1.314, 1.332, 1.404",\ + "1.314, 1.332, 1.404",\ + "1.314, 1.332, 1.404"); } cell_fall(CELL_TABLE) { - values("3.445, 3.504, 3.926",\ - "3.448, 3.507, 3.93",\ - "3.49, 3.549, 3.972"); + values("1.314, 1.332, 1.404",\ + "1.314, 1.332, 1.404",\ + "1.314, 1.332, 1.404"); } rise_transition(CELL_TABLE) { - values("0.13, 0.169, 0.574",\ - "0.13, 0.169, 0.574",\ - "0.13, 0.169, 0.574"); + values("0.006, 0.008, 0.015",\ + "0.006, 0.008, 0.015",\ + "0.006, 0.008, 0.015"); } fall_transition(CELL_TABLE) { - values("0.467, 0.49, 0.959",\ - "0.467, 0.49, 0.959",\ - "0.47, 0.493, 0.96"); + values("0.006, 0.008, 0.015",\ + "0.006, 0.008, 0.015",\ + "0.006, 0.008, 0.015"); } } } @@ -164,35 +176,35 @@ cell (sram_2_16_1_scn4m_subm){ bus(addr0){ bus_type : addr; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; max_transition : 0.4; pin(addr0[3:0]){ timing(){ timing_type : setup_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.167, 0.167, 0.228",\ - "0.167, 0.167, 0.228",\ - "0.167, 0.167, 0.228"); + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.131, 0.125, 0.137",\ - "0.131, 0.125, 0.137",\ - "0.131, 0.125, 0.137"); + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); } } timing(){ timing_type : hold_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.089, -0.089, -0.089",\ - "-0.089, -0.089, -0.089",\ - "-0.089, -0.089, -0.089"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } } } @@ -200,66 +212,66 @@ cell (sram_2_16_1_scn4m_subm){ pin(csb0){ direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; timing(){ timing_type : setup_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.167, 0.167, 0.228",\ - "0.167, 0.167, 0.228",\ - "0.167, 0.167, 0.228"); + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.131, 0.125, 0.137",\ - "0.131, 0.125, 0.137",\ - "0.131, 0.125, 0.137"); + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); } } timing(){ timing_type : hold_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.089, -0.089, -0.089",\ - "-0.089, -0.089, -0.089",\ - "-0.089, -0.089, -0.089"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } } } pin(web0){ direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; timing(){ timing_type : setup_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("0.167, 0.167, 0.228",\ - "0.167, 0.167, 0.228",\ - "0.167, 0.167, 0.228"); + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); } fall_constraint(CONSTRAINT_TABLE) { - values("0.131, 0.125, 0.137",\ - "0.131, 0.125, 0.137",\ - "0.131, 0.125, 0.137"); + values("0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009",\ + "0.009, 0.009, 0.009"); } } timing(){ timing_type : hold_rising; related_pin : "clk0"; rise_constraint(CONSTRAINT_TABLE) { - values("-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114",\ - "-0.065, -0.071, -0.114"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } fall_constraint(CONSTRAINT_TABLE) { - values("-0.089, -0.089, -0.089",\ - "-0.089, -0.089, -0.089",\ - "-0.089, -0.089, -0.089"); + values("0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001",\ + "0.001, 0.001, 0.001"); } } } @@ -267,52 +279,61 @@ cell (sram_2_16_1_scn4m_subm){ pin(clk0){ clock : true; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; internal_power(){ - when : "!csb0 & clk0 & !web0"; + when : "!csb0 & !web0"; rise_power(scalar){ - values("9.972790277777777"); + values("7.017537e+00"); } fall_power(scalar){ - values("9.972790277777777"); + values("7.017537e+00"); } } internal_power(){ - when : "!csb0 & !clk0 & web0"; + when : "csb0 & !web0"; rise_power(scalar){ - values("8.899322499999998"); + values("7.017537e+00"); } fall_power(scalar){ - values("8.899322499999998"); + values("7.017537e+00"); } } internal_power(){ - when : "csb0"; + when : "!csb0 & web0"; rise_power(scalar){ - values("0"); + values("7.017537e+00"); } fall_power(scalar){ - values("0"); + values("7.017537e+00"); + } + } + internal_power(){ + when : "csb0 & web0"; + rise_power(scalar){ + values("7.017537e+00"); + } + fall_power(scalar){ + values("7.017537e+00"); } } timing(){ timing_type :"min_pulse_width"; related_pin : clk0; rise_constraint(scalar) { - values("2.344"); + values("0.1405"); } fall_constraint(scalar) { - values("2.344"); + values("0.1405"); } } timing(){ timing_type :"minimum_period"; related_pin : clk0; rise_constraint(scalar) { - values("4.688"); + values("0.281"); } fall_constraint(scalar) { - values("4.688"); + values("0.281"); } } } diff --git a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib index 4248b986..8bec74c3 100644 --- a/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib +++ b/compiler/tests/golden/sram_2_16_1_scn4m_subm_TT_5p0V_25C_analytical.lib @@ -35,11 +35,14 @@ library (sram_2_16_1_scn4m_subm_TT_5p0V_25C_lib){ default_max_fanout : 4.0 ; default_connection_class : universal ; + voltage_map ( VDD, 5.0 ); + voltage_map ( GND, 0 ); + lu_table_template(CELL_TABLE){ variable_1 : input_net_transition; variable_2 : total_output_net_capacitance; index_1("0.0125, 0.05, 0.4"); - index_2("2.45605, 9.8242, 78.5936"); + index_2("0.00245605, 0.0098242, 0.0392968"); } lu_table_template(CONSTRAINT_TABLE){ @@ -78,17 +81,26 @@ cell (sram_2_16_1_scn4m_subm){ dont_use : true; map_only : true; dont_touch : true; - area : 60774.3; + area : 0; + + pg_pin(vdd) { + voltage_name : VDD; + pg_type : primary_power; + } + + pg_pin(gnd) { + voltage_name : GND; + pg_type : primary_ground; + } leakage_power () { - when : "csb0"; - value : 0.000179; + value : 0.000198; } - cell_leakage_power : 0; + cell_leakage_power : 0.000198; bus(din0){ bus_type : data; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; memory_write(){ address : addr0; clocked_on : clk0; @@ -127,8 +139,8 @@ cell (sram_2_16_1_scn4m_subm){ bus(dout0){ bus_type : data; direction : output; - max_capacitance : 78.5936; - min_capacitance : 2.45605; + max_capacitance : 0.0392968; + min_capacitance : 0.00245605; memory_read(){ address : addr0; } @@ -138,24 +150,24 @@ cell (sram_2_16_1_scn4m_subm){ related_pin : "clk0"; timing_type : falling_edge; cell_rise(CELL_TABLE) { - values("0.268, 0.268, 0.268",\ - "0.268, 0.268, 0.268",\ - "0.268, 0.268, 0.268"); + values("1.314, 1.332, 1.404",\ + "1.314, 1.332, 1.404",\ + "1.314, 1.332, 1.404"); } cell_fall(CELL_TABLE) { - values("0.268, 0.268, 0.268",\ - "0.268, 0.268, 0.268",\ - "0.268, 0.268, 0.268"); + values("1.314, 1.332, 1.404",\ + "1.314, 1.332, 1.404",\ + "1.314, 1.332, 1.404"); } rise_transition(CELL_TABLE) { - values("0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004"); + values("0.006, 0.008, 0.015",\ + "0.006, 0.008, 0.015",\ + "0.006, 0.008, 0.015"); } fall_transition(CELL_TABLE) { - values("0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004",\ - "0.004, 0.004, 0.004"); + values("0.006, 0.008, 0.015",\ + "0.006, 0.008, 0.015",\ + "0.006, 0.008, 0.015"); } } } @@ -164,7 +176,7 @@ cell (sram_2_16_1_scn4m_subm){ bus(addr0){ bus_type : addr; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; max_transition : 0.4; pin(addr0[3:0]){ timing(){ @@ -200,7 +212,7 @@ cell (sram_2_16_1_scn4m_subm){ pin(csb0){ direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -233,7 +245,7 @@ cell (sram_2_16_1_scn4m_subm){ pin(web0){ direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; timing(){ timing_type : setup_rising; related_pin : "clk0"; @@ -267,52 +279,61 @@ cell (sram_2_16_1_scn4m_subm){ pin(clk0){ clock : true; direction : input; - capacitance : 9.8242; + capacitance : 0.0098242; internal_power(){ - when : "!csb0 & clk0 & !web0"; + when : "!csb0 & !web0"; rise_power(scalar){ - values("11.3049604371"); + values("7.017537e+00"); } fall_power(scalar){ - values("11.3049604371"); + values("7.017537e+00"); } } internal_power(){ - when : "!csb0 & !clk0 & web0"; + when : "csb0 & !web0"; rise_power(scalar){ - values("11.3049604371"); + values("7.017537e+00"); } fall_power(scalar){ - values("11.3049604371"); + values("7.017537e+00"); } } internal_power(){ - when : "csb0"; + when : "!csb0 & web0"; rise_power(scalar){ - values("0"); + values("7.017537e+00"); } fall_power(scalar){ - values("0"); + values("7.017537e+00"); + } + } + internal_power(){ + when : "csb0 & web0"; + rise_power(scalar){ + values("7.017537e+00"); + } + fall_power(scalar){ + values("7.017537e+00"); } } timing(){ timing_type :"min_pulse_width"; related_pin : clk0; rise_constraint(scalar) { - values("0.0"); + values("0.1405"); } fall_constraint(scalar) { - values("0.0"); + values("0.1405"); } } timing(){ timing_type :"minimum_period"; related_pin : clk0; rise_constraint(scalar) { - values("0"); + values("0.281"); } fall_constraint(scalar) { - values("0"); + values("0.281"); } } } From 32576fb62c9ac7a69518f7fe1714eeb1de42d912 Mon Sep 17 00:00:00 2001 From: mrg Date: Wed, 22 Apr 2020 13:27:50 -0700 Subject: [PATCH 27/28] Convert wordline driver to pand2 rather than pnand2+pdriver --- compiler/modules/control_logic.py | 2 +- compiler/modules/hierarchical_decoder.py | 1 - compiler/modules/wordline_driver.py | 119 ++++++++++------------- compiler/pgates/pand2.py | 3 +- 4 files changed, 54 insertions(+), 71 deletions(-) diff --git a/compiler/modules/control_logic.py b/compiler/modules/control_logic.py index b4c7402e..5dd8182e 100644 --- a/compiler/modules/control_logic.py +++ b/compiler/modules/control_logic.py @@ -90,7 +90,7 @@ class control_logic(design.design): self.add_mod(self.ctrl_dff_array) self.and2 = factory.create(module_type="pand2", - size=4, + size=12, height=dff_height) self.add_mod(self.and2) diff --git a/compiler/modules/hierarchical_decoder.py b/compiler/modules/hierarchical_decoder.py index f46849c6..69822149 100644 --- a/compiler/modules/hierarchical_decoder.py +++ b/compiler/modules/hierarchical_decoder.py @@ -32,7 +32,6 @@ class hierarchical_decoder(design.design): self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple except AttributeError: self.cell_multiple = 1 - # For debugging self.cell_height = self.cell_multiple * b.height self.num_outputs = num_outputs diff --git a/compiler/modules/wordline_driver.py b/compiler/modules/wordline_driver.py index d84457ba..76a31074 100644 --- a/compiler/modules/wordline_driver.py +++ b/compiler/modules/wordline_driver.py @@ -7,10 +7,12 @@ # import debug import design +import math import contact from vector import vector from sram_factory import factory from globals import OPTS +from tech import cell_properties class wordline_driver(design.design): @@ -26,6 +28,13 @@ class wordline_driver(design.design): self.rows = rows self.cols = cols + + b = factory.create(module_type="bitcell") + try: + self.cell_multiple = cell_properties.bitcell.decoder_bitcell_multiple + except AttributeError: + self.cell_multiple = 1 + self.cell_height = self.cell_multiple * b.height self.create_netlist() if not OPTS.netlist_only: @@ -37,6 +46,7 @@ class wordline_driver(design.design): self.create_drivers() def create_layout(self): + self.setup_layout_constants() self.place_drivers() self.route_layout() self.route_vdd_gnd() @@ -56,17 +66,10 @@ class wordline_driver(design.design): self.add_pin("gnd", "GROUND") def add_modules(self): - b = factory.create(module_type="bitcell") - - self.inv = factory.create(module_type="pdriver", - fanout=self.cols, - neg_polarity=True, - height=b.height) - self.add_mod(self.inv) - - self.nand2 = factory.create(module_type="pnand2", - height=b.height) - self.add_mod(self.nand2) + self.and2 = factory.create(module_type="pand2", + height=self.cell_height, + size=self.cols) + self.add_mod(self.and2) def route_vdd_gnd(self): """ @@ -75,68 +78,64 @@ class wordline_driver(design.design): """ # Find the x offsets for where the vias/pins should be placed - a_xoffset = self.nand_inst[0].lx() + xoffset_list = [self.and_inst[0].lx()] for num in range(self.rows): # this will result in duplicate polygons for rails, but who cares - # use the inverter offset even though it will be the nand's too + # use the inverter offset even though it will be the and's too (gate_offset, y_dir) = self.get_gate_offset(0, - self.inv.height, + self.and2.height, num) - # Route both supplies for name in ["vdd", "gnd"]: - supply_pin = self.inv2_inst[num].get_pin(name) + supply_pin = self.and_inst[num].get_pin(name) # Add pins in two locations - for xoffset in [a_xoffset]: + for xoffset in xoffset_list: pin_pos = vector(xoffset, supply_pin.cy()) self.add_power_pin(name, pin_pos) def create_drivers(self): - self.nand_inst = [] - self.inv2_inst = [] + self.and_inst = [] for row in range(self.rows): - name_nand = "wl_driver_nand{}".format(row) - name_inv2 = "wl_driver_inv{}".format(row) + name_and = "wl_driver_and{}".format(row) - # add nand 2 - self.nand_inst.append(self.add_inst(name=name_nand, - mod=self.nand2)) + # add and2 + self.and_inst.append(self.add_inst(name=name_and, + mod=self.and2)) self.connect_inst(["en", "in_{0}".format(row), - "wl_bar_{0}".format(row), - "vdd", "gnd"]) - # add inv2 - self.inv2_inst.append(self.add_inst(name=name_inv2, - mod=self.inv)) - self.connect_inst(["wl_bar_{0}".format(row), "wl_{0}".format(row), "vdd", "gnd"]) + + def setup_layout_constants(self): + # We may have more than one bitcell per decoder row + self.num_rows = math.ceil(self.rows / self.cell_multiple) + # We will place this many final decoders per row + self.decoders_per_row = math.ceil(self.rows / self.num_rows) def place_drivers(self): - nand2_xoffset = 2 * self.m1_width + 5 * self.m1_space - inv2_xoffset = nand2_xoffset + self.nand2.width + and2_xoffset = 2 * self.m1_width + 5 * self.m1_space - self.width = inv2_xoffset + self.inv.width - self.height = self.inv.height * self.rows + self.width = and2_xoffset + self.and2.width + self.height = self.and2.height * self.num_rows for row in range(self.rows): + #row = math.floor(inst_index / self.decoders_per_row) + #dec = inst_index % self.decoders_per_row + if (row % 2): - y_offset = self.inv.height * (row + 1) + y_offset = self.and2.height * (row + 1) inst_mirror = "MX" else: - y_offset = self.inv.height * row + y_offset = self.and2.height * row inst_mirror = "R0" - nand2_offset = [nand2_xoffset, y_offset] - inv2_offset = [inv2_xoffset, y_offset] + # x_off = self.internal_routing_width + dec * and_mod.width + and2_offset = [and2_xoffset, y_offset] - # add nand 2 - self.nand_inst[row].place(offset=nand2_offset, - mirror=inst_mirror) - # add inv2 - self.inv2_inst[row].place(offset=inv2_offset, + # add and2 + self.and_inst[row].place(offset=and2_offset, mirror=inst_mirror) def route_layout(self): @@ -151,11 +150,10 @@ class wordline_driver(design.design): height=self.height) for row in range(self.rows): - nand_inst = self.nand_inst[row] - inv2_inst = self.inv2_inst[row] + and_inst = self.and_inst[row] # en connection - a_pin = nand_inst.get_pin("A") + a_pin = and_inst.get_pin("A") a_pos = a_pin.lc() clk_offset = vector(en_pin.bc().x, a_pos.y) self.add_segment_center(layer="m1", @@ -164,18 +162,10 @@ class wordline_driver(design.design): self.add_via_center(layers=self.m1_stack, offset=clk_offset) - # Nand2 out to 2nd inv - zr_pos = nand_inst.get_pin("Z").rc() - al_pos = inv2_inst.get_pin("A").lc() - # ensure the bend is in the middle - mid1_pos = vector(0.5 * (zr_pos.x + al_pos.x), zr_pos.y) - mid2_pos = vector(0.5 * (zr_pos.x + al_pos.x), al_pos.y) - self.add_path("m1", [zr_pos, mid1_pos, mid2_pos, al_pos]) - - # connect the decoder input pin to nand2 B - b_pin = nand_inst.get_pin("B") + # connect the decoder input pin to and2 B + b_pin = and_inst.get_pin("B") b_pos = b_pin.lc() - # needs to move down since B nand input is + # needs to move down since B and input is # nearly aligned with A inv input up_or_down = self.m2_space if row % 2 else -self.m2_space input_offset = vector(0, b_pos.y + up_or_down) @@ -192,7 +182,7 @@ class wordline_driver(design.design): offset=mid_via_offset, directions=("V", "V")) - # now connect to the nand2 B + # now connect to the and2 B self.add_path("m2", [mid_via_offset, b_pos]) contact_offset = b_pos - vector(0.5 * contact.m1_via.height, 0) self.add_via_center(layers=self.m1_stack, @@ -200,7 +190,7 @@ class wordline_driver(design.design): directions=("H", "H")) # output each WL on the right - wl_offset = inv2_inst.get_pin("Z").rc() + wl_offset = and_inst.get_pin("Z").rc() self.add_layout_pin_segment_center(text="wl_{0}".format(row), layer="m1", start=wl_offset, @@ -213,13 +203,8 @@ class wordline_driver(design.design): """ stage_effort_list = [] - stage1_cout = self.inv.get_cin() - stage1 = self.nand2.get_stage_effort(stage1_cout, inp_is_rise) + stage1 = self.and2.get_stage_effort(external_cout, inp_is_rise) stage_effort_list.append(stage1) - last_stage_is_rise = stage1.is_rise - - stage2 = self.inv.get_stage_efforts(external_cout, last_stage_is_rise) - stage_effort_list.extend(stage2) return stage_effort_list @@ -228,6 +213,6 @@ class wordline_driver(design.design): Get the relative capacitance of all the enable connections in the bank """ - # The enable is connected to a nand2 for every row. - total_cin = self.nand2.get_cin() * self.rows + # The enable is connected to a and2 for every row. + total_cin = self.and2.get_cin() * self.rows return total_cin diff --git a/compiler/pgates/pand2.py b/compiler/pgates/pand2.py index 995296b6..4c044f1c 100644 --- a/compiler/pgates/pand2.py +++ b/compiler/pgates/pand2.py @@ -30,13 +30,12 @@ class pand2(pgate.pgate): self.create_insts() def create_modules(self): - # Shield the cap, but have at least a stage effort of 4 self.nand = factory.create(module_type="pnand2", height=self.height) self.add_mod(self.nand) self.inv = factory.create(module_type="pdriver", neg_polarity=True, - fanout=3*self.size, + fanout=self.size, height=self.height) self.add_mod(self.inv) From fed1c0bbe10c43425bae1dd46c16775c1714e1e3 Mon Sep 17 00:00:00 2001 From: Joey Kunzler Date: Wed, 22 Apr 2020 16:22:34 -0700 Subject: [PATCH 28/28] s8 col mux array --- .../modules/single_level_column_mux_array.py | 115 +++++++++--------- compiler/pgates/single_level_column_mux.py | 45 ++++--- 2 files changed, 85 insertions(+), 75 deletions(-) diff --git a/compiler/modules/single_level_column_mux_array.py b/compiler/modules/single_level_column_mux_array.py index 324b7415..581e20b0 100644 --- a/compiler/modules/single_level_column_mux_array.py +++ b/compiler/modules/single_level_column_mux_array.py @@ -5,17 +5,15 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # -from math import log import design -import contact -from tech import drc import debug -import math +from tech import layer from vector import vector from sram_factory import factory from globals import OPTS import logical_effort + class single_level_column_mux_array(design.design): """ Dynamically generated column mux array. @@ -26,13 +24,20 @@ class single_level_column_mux_array(design.design): design.design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} word_size: {1} bl: {2} br: {3}".format(columns, word_size, bitcell_bl, bitcell_br)) - + self.columns = columns self.word_size = word_size self.words_per_row = int(self.columns / self.word_size) self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br - + + if "li" in layer: + self.col_mux_stack = self.li_stack + self.col_mux_stack_pitch = self.li_pitch + else: + self.col_mux_stack = self.m1_stack + self.col_mux_stack_pitch = self.m1_pitch + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -49,20 +54,20 @@ class single_level_column_mux_array(design.design): self.add_modules() self.add_pins() self.create_array() - + def create_layout(self): self.setup_layout_constants() self.place_array() self.add_routing() # Find the highest shapes to determine height before adding well highest = self.find_highest_coords() - self.height = highest.y + self.height = highest.y self.add_layout_pins() - self.add_enclosure(self.mux_inst, "pwell") - + if "pwell" in layer: + self.add_enclosure(self.mux_inst, "pwell") self.add_boundary() self.DRC_LVS() - + def add_pins(self): for i in range(self.columns): self.add_pin("bl_{}".format(i)) @@ -74,23 +79,19 @@ class single_level_column_mux_array(design.design): self.add_pin("br_out_{}".format(i)) self.add_pin("gnd") - def add_modules(self): self.mux = factory.create(module_type="single_level_column_mux", bitcell_bl=self.bitcell_bl, bitcell_br=self.bitcell_br) self.add_mod(self.mux) - def setup_layout_constants(self): - self.column_addr_size = num_of_inputs = int(self.words_per_row / 2) + self.column_addr_size = int(self.words_per_row / 2) self.width = self.columns * self.mux.width # one set of metal1 routes for select signals and a pair to interconnect the mux outputs bl/br # one extra route pitch is to space from the sense amp - self.route_height = (self.words_per_row + 3)*self.m1_pitch - + self.route_height = (self.words_per_row + 3) * self.col_mux_stack_pitch - def create_array(self): self.mux_inst = [] # For every column, add a pass gate @@ -98,11 +99,11 @@ class single_level_column_mux_array(design.design): name = "XMUX{0}".format(col_num) self.mux_inst.append(self.add_inst(name=name, mod=self.mux)) - + self.connect_inst(["bl_{}".format(col_num), "br_{}".format(col_num), - "bl_out_{}".format(int(col_num/self.words_per_row)), - "br_out_{}".format(int(col_num/self.words_per_row)), + "bl_out_{}".format(int(col_num / self.words_per_row)), + "br_out_{}".format(int(col_num / self.words_per_row)), "sel_{}".format(col_num % self.words_per_row), "gnd"]) @@ -117,32 +118,31 @@ class single_level_column_mux_array(design.design): else: mirror = "" - name = "XMUX{0}".format(col_num) offset = vector(xoffset, self.route_height) self.mux_inst[col_num].place(offset=offset, mirror=mirror) - def add_layout_pins(self): """ Add the pins after we determine the height. """ # For every column, add a pass gate for col_num in range(self.columns): mux_inst = self.mux_inst[col_num] - offset = mux_inst.get_pin("bl").ll() + bl_pin = mux_inst.get_pin("bl") + offset = bl_pin.ll() self.add_layout_pin(text="bl_{}".format(col_num), - layer="m2", + layer=bl_pin.layer, offset=offset, - height=self.height-offset.y) + height=self.height - offset.y) - offset = mux_inst.get_pin("br").ll() + br_pin = mux_inst.get_pin("br") + offset = br_pin.ll() self.add_layout_pin(text="br_{}".format(col_num), - layer="m2", + layer=br_pin.layer, offset=offset, - height=self.height-offset.y) + height=self.height - offset.y) for inst in self.mux_inst: self.copy_layout_pin(inst, "gnd") - def add_routing(self): self.add_horizontal_input_rail() self.add_vertical_poly_rail() @@ -151,15 +151,15 @@ class single_level_column_mux_array(design.design): def add_horizontal_input_rail(self): """ Create address input rails on M1 below the mux transistors """ for j in range(self.words_per_row): - offset = vector(0, self.route_height + (j-self.words_per_row)*self.m1_pitch) + offset = vector(0, self.route_height + (j - self.words_per_row) * self.col_mux_stack_pitch) #edit self.add_layout_pin(text="sel_{}".format(j), - layer="m1", + layer=self.col_mux_stack[0], offset=offset, width=self.mux.width * self.columns) def add_vertical_poly_rail(self): """ Connect the poly to the address rails """ - + # Offset to the first transistor gate in the pass gate for col in range(self.columns): # which select bit should this column connect to depends on the position in the word @@ -167,11 +167,12 @@ class single_level_column_mux_array(design.design): # Add the column x offset to find the right select bit gate_offset = self.mux_inst[col].get_pin("sel").bc() # height to connect the gate to the correct horizontal row - sel_height = self.get_pin("sel_{}".format(sel_index)).by() + # sel_height = self.get_pin("sel_{}".format(sel_index)).by() # use the y offset from the sel pin and the x offset from the gate - offset = vector(gate_offset.x,self.get_pin("sel_{}".format(sel_index)).cy()) + offset = vector(gate_offset.x, + self.get_pin("sel_{}".format(sel_index)).cy()) # Add the poly contact with a shift to account for the rotation - self.add_via_center(layers=("m1", "contact", "poly"), + self.add_via_center(layers=self.poly_stack, offset=offset) self.add_path("poly", [offset, gate_offset]) @@ -182,11 +183,11 @@ class single_level_column_mux_array(design.design): bl_offset = self.mux_inst[j].get_pin("bl_out").bc() br_offset = self.mux_inst[j].get_pin("br_out").bc() - bl_out_offset = bl_offset - vector(0,(self.words_per_row+1)*self.m1_pitch) - br_out_offset = br_offset - vector(0,(self.words_per_row+2)*self.m1_pitch) + bl_out_offset = bl_offset - vector(0, (self.words_per_row + 1) * self.col_mux_stack_pitch) + br_out_offset = br_offset - vector(0, (self.words_per_row + 2) * self.col_mux_stack_pitch) - bl_out_offset_end = bl_out_offset + vector(0,self.route_height) - br_out_offset_end = br_out_offset + vector(0,self.route_height) + bl_out_offset_end = bl_out_offset + vector(0, self.route_height) + br_out_offset_end = br_out_offset + vector(0, self.route_height) if cell_properties.bitcell.mirror.y and j % 2: tmp_bl_out_end = br_out_offset_end @@ -208,43 +209,41 @@ class single_level_column_mux_array(design.design): else: dist = 0 - self.add_path("m1", [bl_out_offset, bl_out_offset+vector(width+dist,0)]) - self.add_path("m1", [br_out_offset, br_out_offset+vector(width-dist,0)]) + self.add_path(self.col_mux_stack[0], [bl_out_offset, bl_out_offset + vector(width + dist, 0)]) + self.add_path(self.col_mux_stack[0], [br_out_offset, br_out_offset + vector(width - dist, 0)]) # Extend the bitline output rails and gnd downward on the first bit of each n-way mux - self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j/self.words_per_row)), - layer="m2", + self.add_layout_pin_segment_center(text="bl_out_{}".format(int(j / self.words_per_row)), + layer=self.col_mux_stack[2], start=bl_out_offset, end=tmp_bl_out_end) - self.add_layout_pin_segment_center(text="br_out_{}".format(int(j/self.words_per_row)), - layer="m2", + self.add_layout_pin_segment_center(text="br_out_{}".format(int(j / self.words_per_row)), + layer=self.col_mux_stack[2], start=br_out_offset, end=tmp_br_out_end) - - # This via is on the right of the wire - self.add_via_center(layers=self.m1_stack, + # This via is on the right of the wire + self.add_via_center(layers=self.col_mux_stack, offset=bl_out_offset) # This via is on the left of the wire - self.add_via_center(layers=self.m1_stack, + self.add_via_center(layers=self.col_mux_stack, offset=br_out_offset) else: - - self.add_path("m2", [ bl_out_offset, tmp_bl_out_end]) - self.add_path("m2", [ br_out_offset, tmp_br_out_end]) - + self.add_path(self.col_mux_stack[2], [bl_out_offset, bl_offset]) + self.add_path(self.col_mux_stack[2], [br_out_offset, br_offset]) + # This via is on the right of the wire - self.add_via_center(layers=self.m1_stack, + self.add_via_center(layers=self.col_mux_stack, offset=bl_out_offset) - # This via is on the left of the wire - self.add_via_center(layers=self.m1_stack, + # This via is on the left of the wire + self.add_via_center(layers=self.col_mux_stack, offset=br_out_offset) def get_drain_cin(self): """Get the relative capacitance of the drain of the NMOS pass TX""" from tech import parameter - #Bitcell drain load being used to estimate mux NMOS drain load + # Bitcell drain load being used to estimate mux NMOS drain load drain_load = logical_effort.convert_farad_to_relative_c(parameter['bitcell_drain_cap']) - return drain_load + return drain_load diff --git a/compiler/pgates/single_level_column_mux.py b/compiler/pgates/single_level_column_mux.py index 288894aa..9e38287f 100644 --- a/compiler/pgates/single_level_column_mux.py +++ b/compiler/pgates/single_level_column_mux.py @@ -121,13 +121,25 @@ class single_level_column_mux(pgate.pgate): # height is the distance between the nmos' diffusions, which depends on max(self.active_space,self.poly_space) offset = self.nmos_lower.get_pin("G").ul() - vector(0,self.poly_extend_active) height = self.nmos_upper.get_pin("G").by() + self.poly_extend_active - offset.y - self.add_layout_pin(text="sel", - layer="poly", + self.add_rect(layer="poly", offset=offset, height=height) + # Add the sel pin to the bottom of the mux + self.add_layout_pin(text="sel", + layer="poly", + offset=self.nmos_lower.get_pin("G").ll(), + height=self.poly_extend_active) + def connect_bitlines(self): """ Connect the bitlines to the mux transistors """ + + # If li exists, use li and m1 for the mux, otherwise use m1 and m2 + if "li" in layer: + self.col_mux_stack = self.li_stack + else: + self.col_mux_stack = self.m1_stack + # These are on metal2 bl_pin = self.get_pin("bl") br_pin = self.get_pin("br") @@ -140,29 +152,24 @@ class single_level_column_mux(pgate.pgate): nmos_upper_s_pin = self.nmos_upper.get_pin("S") nmos_upper_d_pin = self.nmos_upper.get_pin("D") - # If li exists, use li and m1 for the mux, otherwise use m1 and m2 - if "li" in layer: - col_mux_stack = self.li_stack - else: - col_mux_stack = self.m1_stack - # Add vias to bl, br_out, nmos_upper/S, nmos_lower/D - self.add_via_center(layers=col_mux_stack, + self.add_via_center(layers=self.col_mux_stack, offset=bl_pin.bc(), directions=("V", "V")) - self.add_via_center(layers=col_mux_stack, + self.add_via_center(layers=self.col_mux_stack, offset=br_out_pin.uc(), directions=("V", "V")) - self.add_via_center(layers=col_mux_stack, + self.add_via_center(layers=self.col_mux_stack, offset=nmos_upper_s_pin.center(), directions=("V", "V")) - self.add_via_center(layers=col_mux_stack, + self.add_via_center(layers=self.col_mux_stack, offset=nmos_lower_d_pin.center(), directions=("V", "V")) # Add diffusion contacts # These were previously omitted with the options: add_source_contact=False, add_drain_contact=False - # They are added now and not previously due to a s8 tech special case in which the contacts intersected the mux intraconnect + # They are added now and not previously so that they do not include m1 (which is usually included by default) + # This is only a concern when the local interconnect (li) layer is being used self.add_via_center(layers=self.active_stack, offset=nmos_upper_d_pin.center(), directions=("V", "V"), @@ -186,7 +193,7 @@ class single_level_column_mux(pgate.pgate): # bl -> nmos_upper/D on metal1 # bl_out -> nmos_upper/S on metal2 - self.add_path(col_mux_stack[0], + self.add_path(self.col_mux_stack[0], [bl_pin.ll(), vector(nmos_upper_d_pin.cx(), bl_pin.by()), nmos_upper_d_pin.center()]) # halfway up, move over @@ -194,12 +201,12 @@ class single_level_column_mux(pgate.pgate): + nmos_upper_s_pin.bc().scale(0, 0.4) mid2 = bl_out_pin.uc().scale(0, 0.4) \ + nmos_upper_s_pin.bc().scale(1, 0.4) - self.add_path(col_mux_stack[2], + self.add_path(self.col_mux_stack[2], [bl_out_pin.uc(), mid1, mid2, nmos_upper_s_pin.center()]) # br -> nmos_lower/D on metal2 # br_out -> nmos_lower/S on metal1 - self.add_path(col_mux_stack[0], + self.add_path(self.col_mux_stack[0], [br_out_pin.uc(), vector(nmos_lower_s_pin.cx(), br_out_pin.uy()), nmos_lower_s_pin.center()]) @@ -208,7 +215,7 @@ class single_level_column_mux(pgate.pgate): + nmos_lower_d_pin.uc().scale(0,0.5) mid2 = br_pin.bc().scale(0,0.5) \ + nmos_lower_d_pin.uc().scale(1,0.5) - self.add_path(col_mux_stack[2], + self.add_path(self.col_mux_stack[2], [br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()]) def add_wells(self): @@ -225,6 +232,10 @@ class single_level_column_mux(pgate.pgate): implant_type="p", well_type="p") + # If there is a li layer, include it in the power stack + self.add_via_center(layers=self.col_mux_stack, + offset=active_pos) + # Add the M1->..->power_grid_layer stack self.add_power_pin(name = "gnd", loc = active_pos,