From 5b86c76f1d5399787a1c4a5faf274f3892563161 Mon Sep 17 00:00:00 2001 From: Daniel Bovensiepen Li Date: Thu, 23 Feb 2023 11:21:22 +0800 Subject: [PATCH 01/98] docs(usage): fix minor typo --- docs/source/basic_usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/basic_usage.md b/docs/source/basic_usage.md index b9f5f468..25010d2f 100644 --- a/docs/source/basic_usage.md +++ b/docs/source/basic_usage.md @@ -40,7 +40,7 @@ from openram import tech ... ``` -Note that you need to initalize OpenRAM so that the modules are imported properly. You can also look +Note that you need to initialize OpenRAM so that the modules are imported properly. You can also look at [sram_compiler.py](../../sram_compiler.py) as an example on how to use "openram." If you want to pass custom configuration when generating an SRAM, you can use the `sram_config` class. From 5c173551ec0a5eb86c4557c47fe542a149c15c35 Mon Sep 17 00:00:00 2001 From: mrg Date: Thu, 2 Mar 2023 12:44:52 -0800 Subject: [PATCH 02/98] Remove regress.py and skip_tests for Makefile option instead. --- compiler/tests/Makefile | 57 ++++++------ compiler/tests/regress.py | 113 ----------------------- compiler/tests/skip_tests_freepdk45.txt | 1 - compiler/tests/skip_tests_scn4m_subm.txt | 2 - compiler/tests/skip_tests_sky130.txt | 86 ----------------- 5 files changed, 31 insertions(+), 228 deletions(-) delete mode 100755 compiler/tests/regress.py delete mode 100644 compiler/tests/skip_tests_freepdk45.txt delete mode 100644 compiler/tests/skip_tests_scn4m_subm.txt delete mode 100644 compiler/tests/skip_tests_sky130.txt diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 7351a424..bfa2ab8e 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -15,28 +15,14 @@ TEST_STAMPS= $(addsuffix .ok,$(TEST_BASES)) OPENRAM_DIR = $(OPENRAM_HOME)/tests RESULTS_DIR = $(OPENRAM_DIR)/results + + # Use % for all techs: # %/test.py # or a specific tech: # freepdk45/test.py BROKEN_STAMPS = \ - sky130/01_library_test.ok \ - sky130/04_column_mux_pbitcell_test.ok \ - sky130/04_dummy_pbitcell_test.ok \ - sky130/04_pbitcell_test.ok \ - sky130/04_pnand4_test.ok \ - sky130/04_pand4_test.ok \ - sky130/04_precharge_pbitcell_test.ok \ - sky130/04_replica_pbitcell_test.ok \ - sky130/05_pbitcell_array_test.ok \ - sky130/05_bitcell_array_test.ok \ - sky130/05_bitcell_array_1rw_1r_test.ok \ - sky130/05_dummy_array_test.ok \ %/06_hierarchical_decoder_4096row_test.ok \ - sky130/07_column_mux_array_pbitcell_test.ok \ - sky130/19_pmulti_bank_test.ok \ - sky130/19_psingle_bank_test.ok \ - sky130/19_bank_select_pbitcell_test.ok \ %/19_single_bank_16mux_1rw_1r_test.ok \ %/19_single_bank_16mux_test.ok \ %/20_sram_1bank_16mux_1rw_1r_test.ok \ @@ -47,11 +33,6 @@ BROKEN_STAMPS = \ %/20_psram_1bank_2mux_test.ok \ %/21_hspice_delay_test.ok \ %/21_hspice_setuphold_test.ok \ - sky130/20_psram_1bank_4mux_1rw_1r_test.ok \ - sky130/22_psram_1bank_2mux_func_test.ok \ - sky130/22_psram_1bank_4mux_func_test.ok \ - sky130/22_psram_1bank_8mux_func_test.ok \ - sky130/22_psram_1bank_nomux_func_test.ok \ %/22_psram_1bank_2mux_func_test.ok \ %/22_psram_1bank_4mux_func_test.ok \ %/22_psram_1bank_8mux_func_test.ok \ @@ -66,11 +47,6 @@ BROKEN_STAMPS = \ %/22_sram_1bank_nomux_sparecols_func_test.ok \ %/22_sram_1bank_wmask_1rw_1r_func_test.ok \ %/22_sram_wmask_func_test.ok \ - sky130/23_lib_sram_linear_regression_test.ok \ - sky130/23_lib_sram_model_corners_test.ok \ - sky130/23_lib_sram_model_test.ok \ - sky130/23_lib_sram_prune_test.ok \ - sky131/23_lib_sram_test.ok \ %/26_hspice_pex_pinv_test.ok \ %/27_verilog_multibank_test.ok \ %/50_riscv_1k_1rw1r_func_test.ok \ @@ -87,6 +63,35 @@ BROKEN_STAMPS = \ %/50_riscv_512b_1rw_func_test.ok \ %/50_riscv_8k_1rw1r_func_test.ok \ %/50_riscv_8k_1rw_func_test.ok \ + freepdk45/21_xyce_delay_test.ok \ + scn4m_subm/19_single_bank_global_bitline_test.ok \ + scn4m_subm/21_xyce_delay_test.ok \ + sky130/01_library_test.ok \ + sky130/04_column_mux_pbitcell_test.ok \ + sky130/04_dummy_pbitcell_test.ok \ + sky130/04_pbitcell_test.ok \ + sky130/04_pnand4_test.ok \ + sky130/04_pand4_test.ok \ + sky130/04_precharge_pbitcell_test.ok \ + sky130/04_replica_pbitcell_test.ok \ + sky130/05_pbitcell_array_test.ok \ + sky130/05_bitcell_array_test.ok \ + sky130/05_bitcell_array_1rw_1r_test.ok \ + sky130/05_dummy_array_test.ok \ + sky130/07_column_mux_array_pbitcell_test.ok \ + sky130/19_pmulti_bank_test.ok \ + sky130/19_psingle_bank_test.ok \ + sky130/19_bank_select_pbitcell_test.ok \ + sky130/20_psram_1bank_4mux_1rw_1r_test.ok \ + sky130/22_psram_1bank_2mux_func_test.ok \ + sky130/22_psram_1bank_4mux_func_test.ok \ + sky130/22_psram_1bank_8mux_func_test.ok \ + sky130/22_psram_1bank_nomux_func_test.ok \ + sky130/23_lib_sram_linear_regression_test.ok \ + sky130/23_lib_sram_model_corners_test.ok \ + sky130/23_lib_sram_model_test.ok \ + sky130/23_lib_sram_prune_test.ok \ + sky131/23_lib_sram_test.ok gettech = $(word 1,$(subst /, ,$*)) getfile = $(word 2,$(subst /, ,$*)) diff --git a/compiler/tests/regress.py b/compiler/tests/regress.py deleted file mode 100755 index 4df495df..00000000 --- a/compiler/tests/regress.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2023 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 re -import unittest -import sys, os -from openram import globals -from subunit import ProtocolTestCase, TestProtocolClient -from testtools import ConcurrentTestSuite - -(OPTS, args) = globals.parse_args() -del sys.argv[1:] - -from testutils import * -header(__file__, OPTS.tech_name) - -# get a list of all files in the tests directory -files = os.listdir(sys.path[0]) - -# load a file with all tests to skip in a given technology -# since tech_name is dynamically loaded, we can't use @skip directives -try: - skip_file_name = "{0}/tests/skip_tests_{1}.txt".format(os.getenv("OPENRAM_HOME"), OPTS.tech_name) - skip_file = open(skip_file_name, "r") - skip_tests = skip_file.read().splitlines() - for st in skip_tests: - debug.warning("Skipping: " + st) -except FileNotFoundError: - skip_tests = [] - -# assume any file that ends in "test.py" in it is a regression test -nametest = re.compile("test\.py$", re.IGNORECASE) -all_tests = list(filter(nametest.search, files)) -filtered_tests = list(filter(lambda i: i not in skip_tests, all_tests)) -filtered_tests.sort() - -num_threads = OPTS.num_threads - - -def partition_unit_tests(suite, num_threads): - partitions = [list() for x in range(num_threads)] - for index, test in enumerate(suite): - partitions[index % num_threads].append(test) - return partitions - - -def fork_tests(num_threads): - results = [] - test_partitions = partition_unit_tests(suite, num_threads) - suite._tests[:] = [] - - def do_fork(suite): - - for test_partition in test_partitions: - test_suite = unittest.TestSuite(test_partition) - test_partition[:] = [] - c2pread, c2pwrite = os.pipe() - pid = os.fork() - if pid == 0: - # PID of 0 is a child - try: - # Open a stream to write to the parent - stream = os.fdopen(c2pwrite, 'wb', 0) - os.close(c2pread) - sys.stdin.close() - test_suite_result = TestProtocolClient(stream) - test_suite.run(test_suite_result) - except EBADF: - try: - stream.write(traceback.format_exc()) - finally: - os._exit(1) - os._exit(0) - else: - # PID >0 is the parent - # Collect all of the child streams and append to the results - os.close(c2pwrite) - stream = os.fdopen(c2pread, 'rb', 0) - test = ProtocolTestCase(stream) - results.append(test) - return results - return do_fork - - -# import all of the modules -filenameToModuleName = lambda f: os.path.splitext(f)[0] -moduleNames = map(filenameToModuleName, filtered_tests) -modules = map(__import__, moduleNames) - -suite = unittest.TestSuite() -load = unittest.defaultTestLoader.loadTestsFromModule -suite.addTests(map(load, modules)) - -test_runner = unittest.TextTestRunner(verbosity=2, stream=sys.stderr) -if num_threads == 1: - final_suite = suite -else: - final_suite = ConcurrentTestSuite(suite, fork_tests(num_threads)) - -test_result = test_runner.run(final_suite) - -# import verify -# verify.print_drc_stats() -# verify.print_lvs_stats() -# verify.print_pex_stats() - -sys.exit(not test_result.wasSuccessful()) diff --git a/compiler/tests/skip_tests_freepdk45.txt b/compiler/tests/skip_tests_freepdk45.txt deleted file mode 100644 index 145cf857..00000000 --- a/compiler/tests/skip_tests_freepdk45.txt +++ /dev/null @@ -1 +0,0 @@ -21_xyce_delay_test.py diff --git a/compiler/tests/skip_tests_scn4m_subm.txt b/compiler/tests/skip_tests_scn4m_subm.txt deleted file mode 100644 index c3fb3138..00000000 --- a/compiler/tests/skip_tests_scn4m_subm.txt +++ /dev/null @@ -1,2 +0,0 @@ -19_single_bank_global_bitline_test.py -21_xyce_delay_test.py diff --git a/compiler/tests/skip_tests_sky130.txt b/compiler/tests/skip_tests_sky130.txt deleted file mode 100644 index b0cba8aa..00000000 --- a/compiler/tests/skip_tests_sky130.txt +++ /dev/null @@ -1,86 +0,0 @@ -04_dummy_pbitcell_test.py -04_pbitcell_test.py -04_precharge_pbitcell_test.py -04_replica_pbitcell_test.py -04_column_mux_pbitcell_test.py -05_bitcell_array_test.py -05_dummy_array_test.py -05_pbitcell_array_test.py -06_hierarchical_decoder_pbitcell_test.py -06_hierarchical_decoder_test.py -06_hierarchical_predecode2x4_pbitcell_test.py -06_hierarchical_predecode2x4_test.py -06_hierarchical_predecode3x8_pbitcell_test.py -06_hierarchical_predecode3x8_test.py -06_hierarchical_predecode4x16_test.py -07_column_mux_array_pbitcell_test.py -08_wordline_driver_array_pbitcell_test.py -08_wordline_driver_array_test.py -09_sense_amp_array_test_pbitcell.py -09_sense_amp_array_test.py -10_write_driver_array_pbitcell_test.py -10_write_driver_array_test.py -10_write_driver_array_wmask_pbitcell_test.py -10_write_driver_array_wmask_test.py -10_write_mask_and_array_pbitcell_test.py -10_write_mask_and_array_test.py -12_tri_gate_array_test.py -14_replica_pbitcell_array_test.py -14_replica_bitcell_array_test.py -14_replica_column_test.py -14_replica_column_1rw_1r_test.py -18_port_address_test.py -18_port_data_test.py -18_port_data_wmask_test.py -19_bank_select_pbitcell_test.py -19_bank_select_test.py -19_psingle_bank_test.py -19_bank_select_pbitcell_test.py -19_pmulti_bank_test.py -19_multi_bank_test.py -19_psingle_bank_test.py -19_single_bank_1w_1r_test.py -19_single_bank_wmask_1rw_1r_test.py -19_single_bank_1rw_1r_test.py -19_single_bank_test.py -19_single_bank_wmask_test.py -20_psram_1bank_2mux_1rw_1w_test.py -20_psram_1bank_2mux_1rw_1w_wmask_test.py -20_psram_1bank_2mux_1w_1r_test.py -20_psram_1bank_2mux_test.py -20_psram_1bank_4mux_1rw_1r_test.py -20_sram_1bank_2mux_1w_1r_test.py -20_sram_1bank_2mux_test.py -20_sram_1bank_2mux_wmask_test.py -20_sram_1bank_32b_1024_wmask_test.py -20_sram_1bank_4mux_test.py -20_sram_1bank_8mux_test.py -20_sram_1bank_nomux_test.py -20_sram_1bank_nomux_wmask_test.py -20_sram_2bank_test.py -21_hspice_delay_test.py -21_hspice_setuphold_test.py -21_model_delay_test.py -21_ngspice_delay_test.py -21_ngspice_setuphold_test.py -22_psram_1bank_2mux_func_test.py -22_psram_1bank_4mux_func_test.py -22_psram_1bank_8mux_func_test.py -22_psram_1bank_nomux_func_test.py -22_sram_1bank_2mux_func_test.py -22_sram_1bank_4mux_func_test.py -22_sram_1bank_8mux_func_test.py -22_sram_1bank_nomux_func_test.py -22_sram_1rw_1r_1bank_nomux_func_test.py -22_sram_wmask_func_test.py -23_lib_sram_model_corners_test.py -23_lib_sram_model_test.py -23_lib_sram_prune_test.py -23_lib_sram_test.py -24_lef_sram_test.py -25_verilog_sram_test.py -26_hspice_pex_pinv_test.py -26_ngspice_pex_pinv_test.py -26_pex_test.py -30_openram_back_end_test.py -30_openram_front_end_test.py From 83a644c0d5691af3f0c9658810bf5011c1c45f35 Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Thu, 2 Mar 2023 22:12:14 +0000 Subject: [PATCH 03/98] Bump version: 1.2.1 -> 1.2.2 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 6085e946..23aa8390 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.1 +1.2.2 From c8f05e241d7b077c7476fbd497c3836f5ee7b6a9 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Thu, 2 Mar 2023 15:37:02 -0800 Subject: [PATCH 04/98] Fix twine error for PyPI --- setup.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8f3fd9f2..7e2c53a2 100644 --- a/setup.py +++ b/setup.py @@ -52,14 +52,26 @@ with open("requirements.txt") as f: version = open("VERSION", "r").read().rstrip() +with open("README.md") as f: + long_description = f.read() + + # Call the setup to create the package setup( name="openram", version=version, description="An open-source static random access memory (SRAM) compiler", + long_description=long_description, + long_description_content_type="text/markdown", url="https://openram.org/", + download_url="https://github.com/VLSIDA/OpenRAM/releases", + project_urls={ + "Bug Tracker": "https://github.com/VLSIDA/OpenRAM/issues", + "Documentation": "https://github.com/VLSIDA/OpenRAM/blob/stable/docs/source/index.md", + "Source Code": "https://github.com/VLSIDA/OpenRAM", + }, author="Matthew Guthaus", - author_email="mrg@ucsc.edu", + author_email="mrg+vlsida@ucsc.edu", keywords=[ "sram", "magic", "gds", "netgen", "ngspice", "netlist" ], readme="README.md", license="BSD-3", From 0fe1c05e511aaa3f5773106bf4563b02068aebab Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Thu, 2 Mar 2023 15:50:35 -0800 Subject: [PATCH 05/98] Use links for images in README --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 46d43290..adebb381 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ -![](./images/OpenRAM_logo_yellow_transparent.svg) +![](https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/OpenRAM_logo_yellow_transparent.svg) # OpenRAM [![Python 3.5](https://img.shields.io/badge/Python-3.5-green.svg)](https://www.python.org/) -[![License: BSD 3-clause](./images/license_badge.svg)](./LICENSE) -[![Download](./images/download-stable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/stable.zip) -[![Download](./images/download-unstable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/dev.zip) +[![License: BSD 3-clause](https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/license_badge.svg)](./LICENSE) +[![Download](https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/download-stable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/stable.zip) +[![Download](https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/download-unstable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/dev.zip) An open-source static random access memory (SRAM) compiler. # What is OpenRAM? - + OpenRAM is an award winning open-source Python framework to create the layout, netlists, timing and power models, placement and routing models, and From 257ba70a0308e9c4ffebf18c0993d8effffba17d Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Fri, 3 Mar 2023 10:16:11 -0800 Subject: [PATCH 06/98] Remove readme argument from setup --- setup.py | 1 - 1 file changed, 1 deletion(-) diff --git a/setup.py b/setup.py index 7e2c53a2..09152d92 100644 --- a/setup.py +++ b/setup.py @@ -73,7 +73,6 @@ setup( author="Matthew Guthaus", author_email="mrg+vlsida@ucsc.edu", keywords=[ "sram", "magic", "gds", "netgen", "ngspice", "netlist" ], - readme="README.md", license="BSD-3", packages=packages, package_dir=package_dir, From 18d2d68e83099a30e3fe3a2b52bc4cc8da71c03d Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Fri, 3 Mar 2023 19:50:59 +0000 Subject: [PATCH 07/98] Bump version: 1.2.2 -> 1.2.3 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 23aa8390..0495c4a8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.2 +1.2.3 From 68330b4085cf902ea0c2639a2b5ac4c78baf96ce Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Sun, 5 Mar 2023 20:37:53 -0800 Subject: [PATCH 08/98] Add more meta data for PyPI --- setup.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 09152d92..b47d7096 100644 --- a/setup.py +++ b/setup.py @@ -73,7 +73,22 @@ setup( author="Matthew Guthaus", author_email="mrg+vlsida@ucsc.edu", keywords=[ "sram", "magic", "gds", "netgen", "ngspice", "netlist" ], - license="BSD-3", + license="BSD 3-Clause", + python_requires=">=3.6", + classifiers=[ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Operating System :: Unix", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3 :: Only", + "Topic :: Scientific/Engineering", + "Topic :: Software Development", + "Topic :: System :: Hardware", + ], packages=packages, package_dir=package_dir, include_package_data=True, From 5ee42ee6d34a87e80bd9c15aa7450c94feea0f2b Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Sun, 5 Mar 2023 20:41:27 -0800 Subject: [PATCH 09/98] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index adebb381..9f47a75e 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ updating. # License -OpenRAM is licensed under the [BSD 3-clause License](./LICENSE). +OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE). # Publications From f5fcbc2a7cfe058a3c592ebb378cb6111a759df8 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Sun, 5 Mar 2023 21:08:07 -0800 Subject: [PATCH 10/98] Update documentation for workflows --- .github/workflows/README.md | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index b0e9ddf7..a4d19df1 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -8,7 +8,6 @@ commit" means. 1. If `regress` workflow fails on 'private/dev', `sync` workflow gets triggered and it pushes the latest changes to the public repo's 'dev' branch (public/dev). -After this push, `regress` workflow will also run on 'public/dev'. 1. If `regress` workflow successfully passes on 'private/dev', `version` workflow gets triggered. It creates a new version commit and tag, and pushes to @@ -18,16 +17,6 @@ workflow gets triggered. It creates a new version commit and tag, and pushes to workflow runs. It deploys the PyPI package of OpenRAM and creates a new GitHub release on that repo. -1. If there is a pull request on either repo, `regress` workflow runs on that -pull request. - -1. If there is a push to 'public/dev', `regress` workflow runs (it also happens -when pull requests are merged). - -1. If `regress` workflow successfully passes on 'public/dev', `version` -workflow gets triggered. It creates a new version commit and tag, and pushes to -'private/dev', 'public/dev', and 'public/stable'. - ## Important Notes @@ -54,7 +43,7 @@ automatically. That means, you don't have to tag that commit manually. this commit was automatically generated after a previous commit passed `regress` workflow or was manually generated with caution. -1. `regress` workflow doesn't run on branches named 'stable'. +1. `regress` workflow doesn't run on the public repo. 1. `deploy` workflow only runs on branches named 'stable'. @@ -63,17 +52,14 @@ workflow or was manually generated with caution. 1. `sync` workflow only runs on the private repo. -1. Pull requests merged on to 'public/dev' will also trigger `regress` and it -can create a new version. - -1. Merging pull requests that don't pass `regress` workflow on the public repo -should be avoided since it won't update the private repo automatically. To -prevent merging by mistake, the dev branch can be protected in the GitHub -settings. +1. `sync_tag` workflow only runs on the private repo. 1. Merging pull requests on the private repo should be safe in any case. They are treated the same as commit pushes. +> **Warning**: `regress` workflow is currently disabled on the public repo +> manually. This was done because of a security risk on our private server. +> Enabling it on GitHub will run `regress` workflow on the public repo. ## Flowchart From 49af00313dac04357f537ae563e04985ab8b9669 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Sun, 5 Mar 2023 21:22:03 -0800 Subject: [PATCH 11/98] Add pip installation to documentation --- docs/source/basic_setup.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/source/basic_setup.md b/docs/source/basic_setup.md index 83f2c544..78edc352 100644 --- a/docs/source/basic_setup.md +++ b/docs/source/basic_setup.md @@ -30,11 +30,9 @@ In general, the OpenRAM compiler has very few dependencies: ## OpenRAM Library OpenRAM is available as a Python library. There are a few ways to install it: -+ Install using Makefile (you need to clone the repo): ++ Install the latest _stable_ version with pip: ``` -git clone git@github.com:VLSIDA/OpenRAM.git -cd OpenRAM -make library +pip3 install openram ``` + Install the latest _dev_ version: @@ -42,6 +40,13 @@ make library pip3 install git+https://git@github.com/VLSIDA/OpenRAM.git@dev ``` ++ Install using Makefile (you need to clone the repo): +``` +git clone git@github.com:VLSIDA/OpenRAM.git +cd OpenRAM +make library +``` + ## Anaconda @@ -52,7 +57,8 @@ worry about updating/installing these tools. OpenRAM installs Anaconda silently OpenRAM uses Anaconda by default, but you can turn this feature off by setting `use_conda = False` in your config file. Then, OpenRAM will use the tools you have installed on your system. -If you want to install Anaconda without running OpenRAM (for example to run unit tests, which do not install Anaconda), you can run: +If you want to install Anaconda without running OpenRAM (for example to run unit tests, which do +not install Anaconda), you can run: ``` cd OpenRAM ./install_conda.sh @@ -87,15 +93,15 @@ needed if you have the library. You can add these environment variables to your `.bashrc`: ``` - export OPENRAM_HOME="$HOME/OpenRAM/compiler" - export OPENRAM_TECH="$HOME/OpenRAM/technology" - export PYTHONPATH=$OPENRAM_HOME +export OPENRAM_HOME="$HOME/OpenRAM/compiler" +export OPENRAM_TECH="$HOME/OpenRAM/technology" +export PYTHONPATH=$OPENRAM_HOME ``` Note that if you want symbols to resolve in your editor, you may also want to add the specific technology directory that you use and any custom technology modules as well. For example: ``` - export PYTHONPATH="$OPENRAM_HOME:$OPENRAM_TECH/sky130:$OPENRAM_TECH/sky130/custom" +export PYTHONPATH="$OPENRAM_HOME:$OPENRAM_TECH/sky130:$OPENRAM_TECH/sky130/custom" ``` We include the tech files necessary for [SCMOS] SCN4M\_SUBM, From ec6ec22a2999d658f2f1b15701ba2a9a5d20bd51 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Mon, 6 Mar 2023 11:39:34 -0800 Subject: [PATCH 12/98] Don't use docker to install pdk --- Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 467277cf..fb0e8e6c 100644 --- a/Makefile +++ b/Makefile @@ -69,12 +69,12 @@ $(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) $(SKY130_PDK): $(OPEN_PDKS_DIR) $(SKY130_PDKS_DIR) @echo "Installing open_pdks..." - $(DOCKER_CMD) sh -c ". /home/cad-user/.bashrc && cd /pdk/open_pdks && \ - ./configure --enable-sky130-pdk=/pdk/skywater-pdk/libraries --with-sky130-local-path=/pdk && \ - cd sky130 && \ - make veryclean && \ - make && \ - make SHARED_PDKS_PATH=/pdk install" + @cd $(PDK_ROOT)/open_pdks && \ + ./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) && \ + cd sky130 && \ + make veryclean && \ + make && \ + make SHARED_PDKS_PATH=$(PDK_ROOT) install $(SRAM_LIB_DIR): check-pdk-root @echo "Cloning SRAM library..." From 5dea8e5b971d2d573d172431705fa29618e63775 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Mon, 6 Mar 2023 11:55:18 -0800 Subject: [PATCH 13/98] Add note for using conda to install pdk --- docs/source/basic_setup.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/source/basic_setup.md b/docs/source/basic_setup.md index 78edc352..a1f70e0c 100644 --- a/docs/source/basic_setup.md +++ b/docs/source/basic_setup.md @@ -120,6 +120,13 @@ To install this automatically, you can run: cd $HOME/OpenRAM make pdk ``` +> **Note**: If you don't have Magic installed, you need to install and activate the conda environment before running this command. +> You can install conda with: +> +> ``` +> source miniconda/bin/activate +> ``` + Then you must also install the [Sky130] SRAM build space with the appropriate cell views into the OpenRAM technology directory by running: From 4ec8733378f648d93575b6247c3f594cc0efa089 Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Mon, 6 Mar 2023 22:45:57 +0000 Subject: [PATCH 14/98] Bump version: 1.2.3 -> 1.2.4 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 0495c4a8..e8ea05db 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.3 +1.2.4 From 22517b7921f9742fbd9aaf23a695846aded68a5e Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Wed, 8 Mar 2023 14:35:03 -0800 Subject: [PATCH 15/98] Add badge for PyPI --- README.md | 3 +-- images/download-stable-blue.svg | 1 - images/download-unstable-blue.svg | 1 - images/download.svg | 2 -- 4 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 images/download-stable-blue.svg delete mode 100644 images/download-unstable-blue.svg delete mode 100644 images/download.svg diff --git a/README.md b/README.md index 9f47a75e..78eae437 100644 --- a/README.md +++ b/README.md @@ -3,8 +3,7 @@ [![Python 3.5](https://img.shields.io/badge/Python-3.5-green.svg)](https://www.python.org/) [![License: BSD 3-clause](https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/license_badge.svg)](./LICENSE) -[![Download](https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/download-stable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/stable.zip) -[![Download](https://raw.githubusercontent.com/VLSIDA/OpenRAM/stable/images/download-unstable-blue.svg)](https://github.com/VLSIDA/OpenRAM/archive/dev.zip) +[![PyPI - Downloads](https://img.shields.io/pypi/dm/openram?color=brightgreen&label=PyPI)](https://pypi.org/project/openram/) An open-source static random access memory (SRAM) compiler. diff --git a/images/download-stable-blue.svg b/images/download-stable-blue.svg deleted file mode 100644 index 2fbc3649..00000000 --- a/images/download-stable-blue.svg +++ /dev/null @@ -1 +0,0 @@ - downloaddownloadstablestable \ No newline at end of file diff --git a/images/download-unstable-blue.svg b/images/download-unstable-blue.svg deleted file mode 100644 index a233df6b..00000000 --- a/images/download-unstable-blue.svg +++ /dev/null @@ -1 +0,0 @@ - downloaddownloadunstableunstable \ No newline at end of file diff --git a/images/download.svg b/images/download.svg deleted file mode 100644 index 95d978ed..00000000 --- a/images/download.svg +++ /dev/null @@ -1,2 +0,0 @@ - -download download latestlatest From c9bf3c126194fce9f073a91e34454588041adb41 Mon Sep 17 00:00:00 2001 From: mrg Date: Fri, 10 Mar 2023 10:44:54 -0800 Subject: [PATCH 16/98] Remove factory.reset from all unit tests as we no longer use regress.py. --- compiler/tests/04_column_mux_pbitcell_test.py | 2 -- compiler/tests/04_dummy_pbitcell_test.py | 2 -- compiler/tests/04_pbitcell_test.py | 10 ---------- compiler/tests/04_precharge_1rw_1r_test.py | 1 - compiler/tests/04_precharge_pbitcell_test.py | 3 --- compiler/tests/04_replica_pbitcell_test.py | 2 -- .../tests/06_hierarchical_decoder_pbitcell_test.py | 5 ----- compiler/tests/07_column_mux_array_pbitcell_test.py | 1 - compiler/tests/08_precharge_array_1rw_1r_test.py | 1 - .../tests/08_wordline_driver_array_pbitcell_test.py | 1 - compiler/tests/09_sense_amp_array_pbitcell_test.py | 1 - compiler/tests/09_sense_amp_array_spare_cols_test.py | 1 - compiler/tests/10_write_driver_array_pbitcell_test.py | 1 - .../tests/10_write_driver_array_spare_cols_test.py | 1 - .../tests/10_write_driver_array_wmask_pbitcell_test.py | 1 - .../tests/10_write_mask_and_array_pbitcell_test.py | 1 - ...14_capped_replica_bitcell_array_leftrbl_1rw_test.py | 1 - .../14_capped_replica_bitcell_array_norbl_1rw_test.py | 1 - .../tests/14_replica_bitcell_array_leftrbl_1rw_test.py | 1 - .../tests/14_replica_bitcell_array_norbl_1rw_test.py | 1 - compiler/tests/14_replica_pbitcell_array_test.py | 1 - compiler/tests/18_port_data_16mux_1rw_1r_test.py | 1 - compiler/tests/18_port_data_16mux_test.py | 1 - compiler/tests/18_port_data_2mux_1rw_1r_test.py | 1 - compiler/tests/18_port_data_2mux_test.py | 1 - compiler/tests/18_port_data_4mux_1rw_1r_test.py | 1 - compiler/tests/18_port_data_4mux_test.py | 1 - compiler/tests/18_port_data_8mux_1rw_1r_test.py | 1 - compiler/tests/18_port_data_8mux_test.py | 1 - compiler/tests/18_port_data_nomux_1rw_1r_test.py | 1 - compiler/tests/18_port_data_nomux_test.py | 1 - compiler/tests/18_port_data_spare_cols_test.py | 8 -------- compiler/tests/18_port_data_wmask_1rw_1r_test.py | 8 -------- compiler/tests/18_port_data_wmask_test.py | 8 -------- compiler/tests/19_multi_bank_test.py | 4 ---- compiler/tests/19_pmulti_bank_test.py | 4 ---- compiler/tests/19_psingle_bank_test.py | 4 ---- compiler/tests/19_single_bank_16mux_1rw_1r_test.py | 1 - compiler/tests/19_single_bank_16mux_test.py | 1 - compiler/tests/19_single_bank_1w_1r_test.py | 4 ---- compiler/tests/19_single_bank_2mux_1rw_1r_test.py | 1 - compiler/tests/19_single_bank_2mux_test.py | 1 - compiler/tests/19_single_bank_4mux_1rw_1r_test.py | 1 - compiler/tests/19_single_bank_4mux_test.py | 1 - compiler/tests/19_single_bank_8mux_1rw_1r_test.py | 1 - compiler/tests/19_single_bank_8mux_test.py | 1 - compiler/tests/19_single_bank_global_bitline_test.py | 4 ---- compiler/tests/19_single_bank_nomux_1rw_1r_test.py | 1 - compiler/tests/19_single_bank_nomux_test.py | 1 - compiler/tests/19_single_bank_spare_cols_test.py | 4 ---- compiler/tests/19_single_bank_wmask_1rw_1r_test.py | 4 ---- compiler/tests/19_single_bank_wmask_test.py | 4 ---- compiler/tests/20_sram_2bank_test.py | 4 ---- 53 files changed, 119 deletions(-) diff --git a/compiler/tests/04_column_mux_pbitcell_test.py b/compiler/tests/04_column_mux_pbitcell_test.py index e8d5038b..177f1eba 100755 --- a/compiler/tests/04_column_mux_pbitcell_test.py +++ b/compiler/tests/04_column_mux_pbitcell_test.py @@ -28,12 +28,10 @@ class column_mux_pbitcell_test(openram_test): 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="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="column_mux",tx_size=8, bitcell_bl="bl2", bitcell_br="br2") self.local_check(tx) diff --git a/compiler/tests/04_dummy_pbitcell_test.py b/compiler/tests/04_dummy_pbitcell_test.py index 9043dbc6..981270ed 100755 --- a/compiler/tests/04_dummy_pbitcell_test.py +++ b/compiler/tests/04_dummy_pbitcell_test.py @@ -28,7 +28,6 @@ class replica_pbitcell_test(openram_test): OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 - factory.reset() debug.info(2, "Checking dummy bitcell using pbitcell (small cell)") tx = dummy_pbitcell(name="rpbc") self.local_check(tx) @@ -37,7 +36,6 @@ class replica_pbitcell_test(openram_test): OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - factory.reset() debug.info(2, "Checking dummy bitcell using pbitcell (large cell)") tx = dummy_pbitcell(name="rpbc") self.local_check(tx) diff --git a/compiler/tests/04_pbitcell_test.py b/compiler/tests/04_pbitcell_test.py index d1ab4168..c0338015 100755 --- a/compiler/tests/04_pbitcell_test.py +++ b/compiler/tests/04_pbitcell_test.py @@ -26,7 +26,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=1 OPTS.num_w_ports=1 OPTS.num_r_ports=1 - factory.reset() debug.info(2, "Bitcell with 1 of each port: read/write, write, and read") tx = factory.create(module_type="pbitcell") self.local_check(tx) @@ -34,7 +33,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=0 OPTS.num_w_ports=1 OPTS.num_r_ports=1 - factory.reset() debug.info(2, "Bitcell with 0 read/write ports") tx = factory.create(module_type="pbitcell") self.local_check(tx) @@ -42,7 +40,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=1 OPTS.num_w_ports=0 OPTS.num_r_ports=1 - factory.reset() debug.info(2, "Bitcell with 0 write ports") tx = factory.create(module_type="pbitcell") self.local_check(tx) @@ -50,7 +47,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=1 OPTS.num_w_ports=1 OPTS.num_r_ports=0 - factory.reset() debug.info(2, "Bitcell with 0 read ports") tx = factory.create(module_type="pbitcell") self.local_check(tx) @@ -58,7 +54,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=1 OPTS.num_w_ports=0 OPTS.num_r_ports=0 - factory.reset() debug.info(2, "Bitcell with 0 read ports and 0 write ports") tx = factory.create(module_type="pbitcell") self.local_check(tx) @@ -66,7 +61,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=2 OPTS.num_w_ports=2 OPTS.num_r_ports=2 - factory.reset() debug.info(2, "Bitcell with 2 of each port: read/write, write, and read") tx = factory.create(module_type="pbitcell") self.local_check(tx) @@ -74,7 +68,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=0 OPTS.num_w_ports=2 OPTS.num_r_ports=2 - factory.reset() debug.info(2, "Bitcell with 0 read/write ports") tx = factory.create(module_type="pbitcell") self.local_check(tx) @@ -82,7 +75,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=2 OPTS.num_w_ports=0 OPTS.num_r_ports=2 - factory.reset() debug.info(2, "Bitcell with 0 write ports") tx = factory.create(module_type="pbitcell") self.local_check(tx) @@ -90,7 +82,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=2 OPTS.num_w_ports=2 OPTS.num_r_ports=0 - factory.reset() debug.info(2, "Bitcell with 0 read ports") tx = factory.create(module_type="pbitcell") self.local_check(tx) @@ -98,7 +89,6 @@ class pbitcell_test(openram_test): OPTS.num_rw_ports=2 OPTS.num_w_ports=0 OPTS.num_r_ports=0 - factory.reset() debug.info(2, "Bitcell with 0 read ports and 0 write ports") tx = factory.create(module_type="pbitcell") self.local_check(tx) diff --git a/compiler/tests/04_precharge_1rw_1r_test.py b/compiler/tests/04_precharge_1rw_1r_test.py index 59f01a73..9b422ca5 100755 --- a/compiler/tests/04_precharge_1rw_1r_test.py +++ b/compiler/tests/04_precharge_1rw_1r_test.py @@ -32,7 +32,6 @@ class precharge_test(openram_test): tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl0", bitcell_br="br0") self.local_check(tx) - factory.reset() debug.info(2, "Checking precharge for 1rw1r port 1") tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl1", bitcell_br="br1") self.local_check(tx) diff --git a/compiler/tests/04_precharge_pbitcell_test.py b/compiler/tests/04_precharge_pbitcell_test.py index 4a228b6e..71024200 100755 --- a/compiler/tests/04_precharge_pbitcell_test.py +++ b/compiler/tests/04_precharge_pbitcell_test.py @@ -28,17 +28,14 @@ class precharge_pbitcell_test(openram_test): OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - factory.reset() debug.info(2, "Checking precharge for pbitcell (innermost connections)") tx = factory.create(module_type="precharge", size=1, bitcell_bl="bl0", bitcell_br="br0") self.local_check(tx) - factory.reset() 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) diff --git a/compiler/tests/04_replica_pbitcell_test.py b/compiler/tests/04_replica_pbitcell_test.py index 00252a84..73d94039 100755 --- a/compiler/tests/04_replica_pbitcell_test.py +++ b/compiler/tests/04_replica_pbitcell_test.py @@ -28,7 +28,6 @@ class replica_pbitcell_test(openram_test): OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 - factory.reset() debug.info(2, "Checking replica bitcell using pbitcell (small cell)") tx = replica_pbitcell(name="rpbc") self.local_check(tx) @@ -37,7 +36,6 @@ class replica_pbitcell_test(openram_test): OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 - factory.reset() debug.info(2, "Checking replica bitcell using pbitcell (large cell)") tx = replica_pbitcell(name="rpbc") self.local_check(tx) diff --git a/compiler/tests/06_hierarchical_decoder_pbitcell_test.py b/compiler/tests/06_hierarchical_decoder_pbitcell_test.py index 3b731b31..e77922f6 100755 --- a/compiler/tests/06_hierarchical_decoder_pbitcell_test.py +++ b/compiler/tests/06_hierarchical_decoder_pbitcell_test.py @@ -27,17 +27,14 @@ class hierarchical_decoder_pbitcell_test(openram_test): OPTS.num_r_ports = 0 openram.setup_bitcell() - factory.reset() debug.info(1, "Testing 16 row sample for hierarchical_decoder (multi-port case)") a = factory.create(module_type="hierarchical_decoder", num_outputs=16) self.local_check(a) - factory.reset() debug.info(1, "Testing 17 row sample for hierarchical_decoder (multi-port case)") a = factory.create(module_type="hierarchical_decoder", num_outputs=17) self.local_check(a) - factory.reset() debug.info(1, "Testing 23 row sample for hierarchical_decoder (multi-port case)") a = factory.create(module_type="hierarchical_decoder", num_outputs=23) self.local_check(a) @@ -46,7 +43,6 @@ class hierarchical_decoder_pbitcell_test(openram_test): a = factory.create(module_type="hierarchical_decoder", num_outputs=32) self.local_check(a) - factory.reset() debug.info(1, "Testing 65 row sample for hierarchical_decoder (multi-port case)") a = factory.create(module_type="hierarchical_decoder", num_outputs=65) self.local_check(a) @@ -55,7 +51,6 @@ class hierarchical_decoder_pbitcell_test(openram_test): a = factory.create(module_type="hierarchical_decoder", num_outputs=128) self.local_check(a) - factory.reset() debug.info(1, "Testing 341 row sample for hierarchical_decoder (multi-port case)") a = factory.create(module_type="hierarchical_decoder", num_outputs=341) self.local_check(a) diff --git a/compiler/tests/07_column_mux_array_pbitcell_test.py b/compiler/tests/07_column_mux_array_pbitcell_test.py index 020696fa..9f082218 100755 --- a/compiler/tests/07_column_mux_array_pbitcell_test.py +++ b/compiler/tests/07_column_mux_array_pbitcell_test.py @@ -27,7 +27,6 @@ class column_mux_pbitcell_test(openram_test): 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="column_mux_array", columns=16, word_size=8, bitcell_bl="bl0", bitcell_br="br0") self.local_check(a) diff --git a/compiler/tests/08_precharge_array_1rw_1r_test.py b/compiler/tests/08_precharge_array_1rw_1r_test.py index e9b2bce4..739d8006 100755 --- a/compiler/tests/08_precharge_array_1rw_1r_test.py +++ b/compiler/tests/08_precharge_array_1rw_1r_test.py @@ -28,7 +28,6 @@ class precharge_1rw_1r_test(openram_test): OPTS.num_w_ports = 0 openram.setup_bitcell() - factory.reset() debug.info(2, "Checking 3 column precharge array for 1RW/1R bitcell (port 0)") pc = factory.create(module_type="precharge_array", columns=3, bitcell_bl="bl0", bitcell_br="br0") self.local_check(pc) diff --git a/compiler/tests/08_wordline_driver_array_pbitcell_test.py b/compiler/tests/08_wordline_driver_array_pbitcell_test.py index 5162bf1f..9eb3bdfd 100755 --- a/compiler/tests/08_wordline_driver_array_pbitcell_test.py +++ b/compiler/tests/08_wordline_driver_array_pbitcell_test.py @@ -28,7 +28,6 @@ class wordline_driver_array_pbitcell_test(openram_test): 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_array", rows=8, cols=64) self.local_check(tx) diff --git a/compiler/tests/09_sense_amp_array_pbitcell_test.py b/compiler/tests/09_sense_amp_array_pbitcell_test.py index ae1186b7..2040b4b2 100755 --- a/compiler/tests/09_sense_amp_array_pbitcell_test.py +++ b/compiler/tests/09_sense_amp_array_pbitcell_test.py @@ -28,7 +28,6 @@ class sense_amp_pbitcell_test(openram_test): 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) diff --git a/compiler/tests/09_sense_amp_array_spare_cols_test.py b/compiler/tests/09_sense_amp_array_spare_cols_test.py index c39fd094..981cc6ae 100755 --- a/compiler/tests/09_sense_amp_array_spare_cols_test.py +++ b/compiler/tests/09_sense_amp_array_spare_cols_test.py @@ -37,7 +37,6 @@ class sense_amp_array_spare_cols_test(openram_test): 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, num_spare_cols=2 (multi-port case)") a = factory.create(module_type="sense_amp_array", word_size=4, words_per_row=2, num_spare_cols=2) self.local_check(a) diff --git a/compiler/tests/10_write_driver_array_pbitcell_test.py b/compiler/tests/10_write_driver_array_pbitcell_test.py index 1a72989b..e5914935 100755 --- a/compiler/tests/10_write_driver_array_pbitcell_test.py +++ b/compiler/tests/10_write_driver_array_pbitcell_test.py @@ -28,7 +28,6 @@ class write_driver_pbitcell_test(openram_test): 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) diff --git a/compiler/tests/10_write_driver_array_spare_cols_test.py b/compiler/tests/10_write_driver_array_spare_cols_test.py index ef0c3596..a1926a90 100755 --- a/compiler/tests/10_write_driver_array_spare_cols_test.py +++ b/compiler/tests/10_write_driver_array_spare_cols_test.py @@ -37,7 +37,6 @@ class write_driver_array_spare_cols_test(openram_test): 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 and num_spare_cols=3") a = factory.create(module_type="write_driver_array", columns=8, word_size=8, num_spare_cols=3) self.local_check(a) 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 69054586..7bc6704d 100755 --- a/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py +++ b/compiler/tests/10_write_driver_array_wmask_pbitcell_test.py @@ -28,7 +28,6 @@ class write_driver_pbitcell_test(openram_test): 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) 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 3d79d4dd..e19bfd27 100755 --- a/compiler/tests/10_write_mask_and_array_pbitcell_test.py +++ b/compiler/tests/10_write_mask_and_array_pbitcell_test.py @@ -28,7 +28,6 @@ class write_mask_and_array_pbitcell_test(openram_test): 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) diff --git a/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_test.py b/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_test.py index b4ba91d1..61464b9b 100755 --- a/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_test.py +++ b/compiler/tests/14_capped_replica_bitcell_array_leftrbl_1rw_test.py @@ -24,7 +24,6 @@ class capped_replica_bitcell_array_test(openram_test): OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 - factory.reset() debug.info(2, "Testing 4x4 array for bitcell") a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[1, 0], left_rbl=[0]) self.local_check(a) diff --git a/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_test.py b/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_test.py index 175689c3..070404ac 100755 --- a/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_test.py +++ b/compiler/tests/14_capped_replica_bitcell_array_norbl_1rw_test.py @@ -24,7 +24,6 @@ class capped_replica_bitcell_array_test(openram_test): OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 - factory.reset() debug.info(2, "Testing 4x4 array for bitcell") a = factory.create(module_type="capped_replica_bitcell_array", cols=7, rows=5, rbl=[1, 0]) self.local_check(a) diff --git a/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_test.py b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_test.py index f77a571d..b8d5e5ed 100755 --- a/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_test.py +++ b/compiler/tests/14_replica_bitcell_array_leftrbl_1rw_test.py @@ -24,7 +24,6 @@ class replica_bitcell_array_test(openram_test): OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 - factory.reset() debug.info(2, "Testing 4x4 array for bitcell") a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[1, 0], left_rbl=[0]) self.local_check(a) diff --git a/compiler/tests/14_replica_bitcell_array_norbl_1rw_test.py b/compiler/tests/14_replica_bitcell_array_norbl_1rw_test.py index e893c3ca..219bd680 100755 --- a/compiler/tests/14_replica_bitcell_array_norbl_1rw_test.py +++ b/compiler/tests/14_replica_bitcell_array_norbl_1rw_test.py @@ -24,7 +24,6 @@ class replica_bitcell_array_test(openram_test): OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 - factory.reset() debug.info(2, "Testing 4x4 array for bitcell") a = factory.create(module_type="replica_bitcell_array", cols=7, rows=5, rbl=[1, 0]) self.local_check(a) diff --git a/compiler/tests/14_replica_pbitcell_array_test.py b/compiler/tests/14_replica_pbitcell_array_test.py index cb143c40..a7d0f077 100755 --- a/compiler/tests/14_replica_pbitcell_array_test.py +++ b/compiler/tests/14_replica_pbitcell_array_test.py @@ -38,7 +38,6 @@ class replica_pbitcell_array_test(openram_test): OPTS.num_r_ports = 0 OPTS.num_w_ports = 0 - factory.reset() debug.info(2, "Testing 4x4 array for pbitcell") a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 0], left_rbl=[0]) self.local_check(a) diff --git a/compiler/tests/18_port_data_16mux_1rw_1r_test.py b/compiler/tests/18_port_data_16mux_1rw_1r_test.py index 57947481..b4b50323 100755 --- a/compiler/tests/18_port_data_16mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_16mux_1rw_1r_test.py @@ -32,7 +32,6 @@ class port_data_1rw_1r_test(openram_test): c.word_size=2 c.num_words=128 c.words_per_row=16 - factory.reset() c.recompute_sizes() debug.info(1, "Sixteen way column mux") a = factory.create("port_data", sram_config=c, port=0) diff --git a/compiler/tests/18_port_data_16mux_test.py b/compiler/tests/18_port_data_16mux_test.py index 0b1859e4..66d4c4bf 100755 --- a/compiler/tests/18_port_data_16mux_test.py +++ b/compiler/tests/18_port_data_16mux_test.py @@ -36,7 +36,6 @@ class port_data_test(openram_test): c.word_size=2 c.num_words=128 c.words_per_row=16 - factory.reset() c.recompute_sizes() debug.info(1, "Sixteen way column mux") a = factory.create("port_data", sram_config=c, port=0) diff --git a/compiler/tests/18_port_data_2mux_1rw_1r_test.py b/compiler/tests/18_port_data_2mux_1rw_1r_test.py index d9ca31ea..fc0d9243 100755 --- a/compiler/tests/18_port_data_2mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_2mux_1rw_1r_test.py @@ -31,7 +31,6 @@ class port_data_1rw_1r_test(openram_test): 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) diff --git a/compiler/tests/18_port_data_2mux_test.py b/compiler/tests/18_port_data_2mux_test.py index 469d3e34..8eb29615 100755 --- a/compiler/tests/18_port_data_2mux_test.py +++ b/compiler/tests/18_port_data_2mux_test.py @@ -35,7 +35,6 @@ class port_data_test(openram_test): 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) diff --git a/compiler/tests/18_port_data_4mux_1rw_1r_test.py b/compiler/tests/18_port_data_4mux_1rw_1r_test.py index edd2336b..ac81e561 100755 --- a/compiler/tests/18_port_data_4mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_4mux_1rw_1r_test.py @@ -31,7 +31,6 @@ class port_data_1rw_1r_test(openram_test): 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) diff --git a/compiler/tests/18_port_data_4mux_test.py b/compiler/tests/18_port_data_4mux_test.py index 12ef31d2..c3eae434 100755 --- a/compiler/tests/18_port_data_4mux_test.py +++ b/compiler/tests/18_port_data_4mux_test.py @@ -35,7 +35,6 @@ class port_data_test(openram_test): 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) diff --git a/compiler/tests/18_port_data_8mux_1rw_1r_test.py b/compiler/tests/18_port_data_8mux_1rw_1r_test.py index 683a086f..e57d12ef 100755 --- a/compiler/tests/18_port_data_8mux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_8mux_1rw_1r_test.py @@ -32,7 +32,6 @@ class port_data_1rw_1r_test(openram_test): 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) diff --git a/compiler/tests/18_port_data_8mux_test.py b/compiler/tests/18_port_data_8mux_test.py index ae067163..a8f82489 100755 --- a/compiler/tests/18_port_data_8mux_test.py +++ b/compiler/tests/18_port_data_8mux_test.py @@ -36,7 +36,6 @@ class port_data_test(openram_test): 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) diff --git a/compiler/tests/18_port_data_nomux_1rw_1r_test.py b/compiler/tests/18_port_data_nomux_1rw_1r_test.py index 04cbddd8..8b887d9b 100755 --- a/compiler/tests/18_port_data_nomux_1rw_1r_test.py +++ b/compiler/tests/18_port_data_nomux_1rw_1r_test.py @@ -30,7 +30,6 @@ class port_data_1rw_1r_test(openram_test): 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) diff --git a/compiler/tests/18_port_data_nomux_test.py b/compiler/tests/18_port_data_nomux_test.py index 07836e3d..e479de1f 100755 --- a/compiler/tests/18_port_data_nomux_test.py +++ b/compiler/tests/18_port_data_nomux_test.py @@ -34,7 +34,6 @@ class port_data_test(openram_test): num_spare_rows=num_spare_rows) 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) diff --git a/compiler/tests/18_port_data_spare_cols_test.py b/compiler/tests/18_port_data_spare_cols_test.py index c511dc5c..0db34da0 100755 --- a/compiler/tests/18_port_data_spare_cols_test.py +++ b/compiler/tests/18_port_data_spare_cols_test.py @@ -26,7 +26,6 @@ class port_data_spare_cols_test(openram_test): num_spare_cols=3) 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) @@ -34,7 +33,6 @@ class port_data_spare_cols_test(openram_test): 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) @@ -43,7 +41,6 @@ class port_data_spare_cols_test(openram_test): c.num_words=64 c.words_per_row=4 c.num_spare_cols=3 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create("port_data", sram_config=c, port=0) @@ -53,7 +50,6 @@ class port_data_spare_cols_test(openram_test): c.num_words=128 c.words_per_row=8 c.num_spare_cols=4 - factory.reset() c.recompute_sizes() debug.info(1, "Eight way column mux") a = factory.create("port_data", sram_config=c, port=0) @@ -66,7 +62,6 @@ class port_data_spare_cols_test(openram_test): 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) @@ -76,7 +71,6 @@ class port_data_spare_cols_test(openram_test): 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) @@ -86,7 +80,6 @@ class port_data_spare_cols_test(openram_test): 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) @@ -97,7 +90,6 @@ class port_data_spare_cols_test(openram_test): 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) diff --git a/compiler/tests/18_port_data_wmask_1rw_1r_test.py b/compiler/tests/18_port_data_wmask_1rw_1r_test.py index ee3278d2..b731a1d0 100755 --- a/compiler/tests/18_port_data_wmask_1rw_1r_test.py +++ b/compiler/tests/18_port_data_wmask_1rw_1r_test.py @@ -31,7 +31,6 @@ class port_data_wmask_1rw_1r_test(openram_test): 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) @@ -39,7 +38,6 @@ class port_data_wmask_1rw_1r_test(openram_test): 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) @@ -47,7 +45,6 @@ class port_data_wmask_1rw_1r_test(openram_test): 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) @@ -55,7 +52,6 @@ class port_data_wmask_1rw_1r_test(openram_test): 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) @@ -68,7 +64,6 @@ class port_data_wmask_1rw_1r_test(openram_test): 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) @@ -78,7 +73,6 @@ class port_data_wmask_1rw_1r_test(openram_test): # 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) @@ -88,7 +82,6 @@ class port_data_wmask_1rw_1r_test(openram_test): 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) @@ -99,7 +92,6 @@ class port_data_wmask_1rw_1r_test(openram_test): c.word_size = 8 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) diff --git a/compiler/tests/18_port_data_wmask_test.py b/compiler/tests/18_port_data_wmask_test.py index e1860e6e..3db910c1 100755 --- a/compiler/tests/18_port_data_wmask_test.py +++ b/compiler/tests/18_port_data_wmask_test.py @@ -35,7 +35,6 @@ class port_data_wmask_test(openram_test): num_spare_rows=num_spare_rows) 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) @@ -43,7 +42,6 @@ class port_data_wmask_test(openram_test): 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) @@ -51,7 +49,6 @@ class port_data_wmask_test(openram_test): 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) @@ -59,7 +56,6 @@ class port_data_wmask_test(openram_test): 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) @@ -72,7 +68,6 @@ class port_data_wmask_test(openram_test): 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) @@ -82,7 +77,6 @@ class port_data_wmask_test(openram_test): # 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) @@ -92,7 +86,6 @@ class port_data_wmask_test(openram_test): 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) @@ -103,7 +96,6 @@ class port_data_wmask_test(openram_test): c.word_size = 8 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) diff --git a/compiler/tests/19_multi_bank_test.py b/compiler/tests/19_multi_bank_test.py index a1fb9b57..c1f408e0 100755 --- a/compiler/tests/19_multi_bank_test.py +++ b/compiler/tests/19_multi_bank_test.py @@ -29,7 +29,6 @@ class multi_bank_test(openram_test): c.num_banks=2 c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create("bank", sram_config=c) @@ -37,7 +36,6 @@ class multi_bank_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create("bank", sram_config=c) @@ -45,7 +43,6 @@ class multi_bank_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create("bank", sram_config=c) @@ -54,7 +51,6 @@ class multi_bank_test(openram_test): 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("bank", sram_config=c) diff --git a/compiler/tests/19_pmulti_bank_test.py b/compiler/tests/19_pmulti_bank_test.py index 4e39a32c..378ff837 100755 --- a/compiler/tests/19_pmulti_bank_test.py +++ b/compiler/tests/19_pmulti_bank_test.py @@ -34,7 +34,6 @@ class multi_bank_test(openram_test): c.num_banks=2 c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create("bank", sram_config=c) @@ -42,7 +41,6 @@ class multi_bank_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create("bank", sram_config=c) @@ -50,7 +48,6 @@ class multi_bank_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create("bank", sram_config=c) @@ -59,7 +56,6 @@ class multi_bank_test(openram_test): 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("bank", sram_config=c) diff --git a/compiler/tests/19_psingle_bank_test.py b/compiler/tests/19_psingle_bank_test.py index 205b6bff..cf38b68b 100755 --- a/compiler/tests/19_psingle_bank_test.py +++ b/compiler/tests/19_psingle_bank_test.py @@ -36,7 +36,6 @@ class psingle_bank_test(openram_test): num_words=16) c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create(module_type="bank", sram_config=c) @@ -44,7 +43,6 @@ class psingle_bank_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create(module_type="bank", sram_config=c) @@ -52,7 +50,6 @@ class psingle_bank_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create(module_type="bank", sram_config=c) @@ -61,7 +58,6 @@ class psingle_bank_test(openram_test): c.word_size=2 c.num_words=128 c.words_per_row=8 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create(module_type="bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_16mux_1rw_1r_test.py b/compiler/tests/19_single_bank_16mux_1rw_1r_test.py index 9ce9ee22..4d31ea38 100755 --- a/compiler/tests/19_single_bank_16mux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_16mux_1rw_1r_test.py @@ -32,7 +32,6 @@ class single_bank_1rw_1r_test(openram_test): num_words=128) c.words_per_row=16 - factory.reset() c.recompute_sizes() debug.info(1, "Sixteen way column mux") a = factory.create(module_type="bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_16mux_test.py b/compiler/tests/19_single_bank_16mux_test.py index 889d6e95..2bc53ace 100755 --- a/compiler/tests/19_single_bank_16mux_test.py +++ b/compiler/tests/19_single_bank_16mux_test.py @@ -38,7 +38,6 @@ class single_bank_test(openram_test): c.word_size=2 c.num_words=128 c.words_per_row=16 - factory.reset() c.recompute_sizes() debug.info(1, "Sixteen way column mux") a = factory.create("bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_1w_1r_test.py b/compiler/tests/19_single_bank_1w_1r_test.py index ed3594e6..428f6dc6 100755 --- a/compiler/tests/19_single_bank_1w_1r_test.py +++ b/compiler/tests/19_single_bank_1w_1r_test.py @@ -32,7 +32,6 @@ class single_bank_1w_1r_test(openram_test): num_words=16) c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create(module_type="bank", sram_config=c) @@ -40,7 +39,6 @@ class single_bank_1w_1r_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create(module_type="bank", sram_config=c) @@ -48,7 +46,6 @@ class single_bank_1w_1r_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create(module_type="bank", sram_config=c) @@ -57,7 +54,6 @@ class single_bank_1w_1r_test(openram_test): 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(module_type="bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_2mux_1rw_1r_test.py b/compiler/tests/19_single_bank_2mux_1rw_1r_test.py index 14400ece..e81d1bbc 100755 --- a/compiler/tests/19_single_bank_2mux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_2mux_1rw_1r_test.py @@ -33,7 +33,6 @@ class single_bank_1rw_1r_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create(module_type="bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_2mux_test.py b/compiler/tests/19_single_bank_2mux_test.py index 897ad100..a1679f5c 100755 --- a/compiler/tests/19_single_bank_2mux_test.py +++ b/compiler/tests/19_single_bank_2mux_test.py @@ -28,7 +28,6 @@ class single_bank_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create("bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_4mux_1rw_1r_test.py b/compiler/tests/19_single_bank_4mux_1rw_1r_test.py index 588055ec..0c1f3439 100755 --- a/compiler/tests/19_single_bank_4mux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_4mux_1rw_1r_test.py @@ -33,7 +33,6 @@ class single_bank_1rw_1r_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create(module_type="bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_4mux_test.py b/compiler/tests/19_single_bank_4mux_test.py index def5a5bc..94219f97 100755 --- a/compiler/tests/19_single_bank_4mux_test.py +++ b/compiler/tests/19_single_bank_4mux_test.py @@ -28,7 +28,6 @@ class single_bank_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create("bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_8mux_1rw_1r_test.py b/compiler/tests/19_single_bank_8mux_1rw_1r_test.py index 7e1c9bb4..2a12397c 100755 --- a/compiler/tests/19_single_bank_8mux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_8mux_1rw_1r_test.py @@ -34,7 +34,6 @@ class single_bank_1rw_1r_test(openram_test): 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(module_type="bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_8mux_test.py b/compiler/tests/19_single_bank_8mux_test.py index 626746b2..bee204a5 100755 --- a/compiler/tests/19_single_bank_8mux_test.py +++ b/compiler/tests/19_single_bank_8mux_test.py @@ -38,7 +38,6 @@ class single_bank_test(openram_test): 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("bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_global_bitline_test.py b/compiler/tests/19_single_bank_global_bitline_test.py index 5501e485..3649dea4 100755 --- a/compiler/tests/19_single_bank_global_bitline_test.py +++ b/compiler/tests/19_single_bank_global_bitline_test.py @@ -33,7 +33,6 @@ class single_bank_1rw_1r_test(openram_test): num_words=16) c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create(module_type="bank", sram_config=c) @@ -41,7 +40,6 @@ class single_bank_1rw_1r_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create(module_type="bank", sram_config=c) @@ -49,7 +47,6 @@ class single_bank_1rw_1r_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create(module_type="bank", sram_config=c) @@ -58,7 +55,6 @@ class single_bank_1rw_1r_test(openram_test): 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(module_type="bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_nomux_1rw_1r_test.py b/compiler/tests/19_single_bank_nomux_1rw_1r_test.py index 3926df30..14c998ae 100755 --- a/compiler/tests/19_single_bank_nomux_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_nomux_1rw_1r_test.py @@ -32,7 +32,6 @@ class single_bank_1rw_1r_test(openram_test): num_words=16) c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create(module_type="bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_nomux_test.py b/compiler/tests/19_single_bank_nomux_test.py index 3c49f975..f7c9b72d 100755 --- a/compiler/tests/19_single_bank_nomux_test.py +++ b/compiler/tests/19_single_bank_nomux_test.py @@ -36,7 +36,6 @@ class single_bank_test(openram_test): num_spare_rows=num_spare_rows) c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create("bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_spare_cols_test.py b/compiler/tests/19_single_bank_spare_cols_test.py index 68b71b51..1e3280de 100755 --- a/compiler/tests/19_single_bank_spare_cols_test.py +++ b/compiler/tests/19_single_bank_spare_cols_test.py @@ -28,7 +28,6 @@ class single_bank_spare_cols_test(openram_test): num_spare_cols=3) c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create("bank", sram_config=c) @@ -36,7 +35,6 @@ class single_bank_spare_cols_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create("bank", sram_config=c) @@ -44,7 +42,6 @@ class single_bank_spare_cols_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create("bank", sram_config=c) @@ -53,7 +50,6 @@ class single_bank_spare_cols_test(openram_test): 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("bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_wmask_1rw_1r_test.py b/compiler/tests/19_single_bank_wmask_1rw_1r_test.py index 8d810d91..20410bc8 100755 --- a/compiler/tests/19_single_bank_wmask_1rw_1r_test.py +++ b/compiler/tests/19_single_bank_wmask_1rw_1r_test.py @@ -34,7 +34,6 @@ class single_bank_wmask_1rw_1r_test(openram_test): num_banks=1) c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create("bank", sram_config=c) @@ -42,7 +41,6 @@ class single_bank_wmask_1rw_1r_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create("bank", sram_config=c) @@ -50,7 +48,6 @@ class single_bank_wmask_1rw_1r_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create("bank", sram_config=c) @@ -58,7 +55,6 @@ class single_bank_wmask_1rw_1r_test(openram_test): c.num_words=128 c.words_per_row=8 - factory.reset() c.recompute_sizes() debug.info(1, "Eight way column mux") a = factory.create("bank", sram_config=c) diff --git a/compiler/tests/19_single_bank_wmask_test.py b/compiler/tests/19_single_bank_wmask_test.py index 19b01e61..16a14c6f 100755 --- a/compiler/tests/19_single_bank_wmask_test.py +++ b/compiler/tests/19_single_bank_wmask_test.py @@ -29,7 +29,6 @@ class single_bank_wmask_test(openram_test): num_banks=1) c.words_per_row=1 - factory.reset() c.recompute_sizes() debug.info(1, "No column mux") a = factory.create("bank", sram_config=c) @@ -37,7 +36,6 @@ class single_bank_wmask_test(openram_test): c.num_words=32 c.words_per_row=2 - factory.reset() c.recompute_sizes() debug.info(1, "Two way column mux") a = factory.create("bank", sram_config=c) @@ -45,7 +43,6 @@ class single_bank_wmask_test(openram_test): c.num_words=64 c.words_per_row=4 - factory.reset() c.recompute_sizes() debug.info(1, "Four way column mux") a = factory.create("bank", sram_config=c) @@ -53,7 +50,6 @@ class single_bank_wmask_test(openram_test): c.num_words=128 c.words_per_row=8 - factory.reset() c.recompute_sizes() debug.info(1, "Eight way column mux") a = factory.create("bank", sram_config=c) diff --git a/compiler/tests/20_sram_2bank_test.py b/compiler/tests/20_sram_2bank_test.py index c2d2c412..52031166 100755 --- a/compiler/tests/20_sram_2bank_test.py +++ b/compiler/tests/20_sram_2bank_test.py @@ -38,7 +38,6 @@ class sram_2bank_test(openram_test): c.num_words, c.words_per_row, c.num_banks)) - factory.reset() a = factory.create(module_type="sram", sram_config=c) self.local_check(a, final_verification=True) @@ -54,7 +53,6 @@ class sram_2bank_test(openram_test): c.num_words, c.words_per_row, c.num_banks)) - factory.reset() a = factory.create(module_type="sram", sram_config=c) self.local_check(a, final_verification=True) @@ -70,7 +68,6 @@ class sram_2bank_test(openram_test): c.num_words, c.words_per_row, c.num_banks)) - factory.reset() a = factory.create(module_type="sram", sram_config=c) self.local_check(a, final_verification=True) @@ -87,7 +84,6 @@ class sram_2bank_test(openram_test): c.num_words, c.words_per_row, c.num_banks)) - factory.reset() a = factory.create(module_type="sram", sram_config=c) self.local_check(a, final_verification=True) From 650b6e513c39593ac8dec9c9c3388414c9ebe29f Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Fri, 10 Mar 2023 16:35:22 -0800 Subject: [PATCH 17/98] Remove the hack used for unit tests running on docker --- compiler/tests/testutils.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/compiler/tests/testutils.py b/compiler/tests/testutils.py index fcb9a776..a41620c3 100644 --- a/compiler/tests/testutils.py +++ b/compiler/tests/testutils.py @@ -10,21 +10,6 @@ import sys, os, glob import pdb import traceback import time -# FIXME: This is a hack for unit tests running on docker. -try: - import openram -except: - # If openram library isn't found as a python package, - # import it from the $OPENRAM_HOME path. - import importlib.util - OPENRAM_HOME = os.getenv("OPENRAM_HOME") - # Import using spec since the directory can be named something - # other than "openram". - spec = importlib.util.spec_from_file_location("openram", "{}/../__init__.py".format(OPENRAM_HOME)) - module = importlib.util.module_from_spec(spec) - sys.modules["openram"] = module - spec.loader.exec_module(module) - import openram from openram import debug from openram import OPTS From 8ea100b52e7ebe812df95427a1653a437a98cfcf Mon Sep 17 00:00:00 2001 From: mrg Date: Tue, 14 Mar 2023 08:50:00 -0700 Subject: [PATCH 18/98] Split pbitcell tests to fix factory.reset() bug. --- ...t.py => 04_dummy_pbitcell_1rw1r1w_test.py} | 8 ---- compiler/tests/04_dummy_pbitcell_1rw_test.py | 43 +++++++++++++++++++ ...py => 04_replica_pbitcell_1rw1r1w_test.py} | 8 ---- .../tests/04_replica_pbitcell_1rw_test.py | 43 +++++++++++++++++++ ...> 14_replica_pbitcell_1rw1r_array_test.py} | 11 ----- .../14_replica_pbitcell_1rw_array_test.py | 42 ++++++++++++++++++ 6 files changed, 128 insertions(+), 27 deletions(-) rename compiler/tests/{04_dummy_pbitcell_test.py => 04_dummy_pbitcell_1rw1r1w_test.py} (83%) create mode 100755 compiler/tests/04_dummy_pbitcell_1rw_test.py rename compiler/tests/{04_replica_pbitcell_test.py => 04_replica_pbitcell_1rw1r1w_test.py} (83%) create mode 100755 compiler/tests/04_replica_pbitcell_1rw_test.py rename compiler/tests/{14_replica_pbitcell_array_test.py => 14_replica_pbitcell_1rw1r_array_test.py} (74%) create mode 100755 compiler/tests/14_replica_pbitcell_1rw_array_test.py diff --git a/compiler/tests/04_dummy_pbitcell_test.py b/compiler/tests/04_dummy_pbitcell_1rw1r1w_test.py similarity index 83% rename from compiler/tests/04_dummy_pbitcell_test.py rename to compiler/tests/04_dummy_pbitcell_1rw1r1w_test.py index 981270ed..a5d038ca 100755 --- a/compiler/tests/04_dummy_pbitcell_test.py +++ b/compiler/tests/04_dummy_pbitcell_1rw1r1w_test.py @@ -24,14 +24,6 @@ class replica_pbitcell_test(openram_test): from openram.modules import dummy_pbitcell OPTS.bitcell = "pbitcell" - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 0 - OPTS.num_w_ports = 0 - - debug.info(2, "Checking dummy bitcell using pbitcell (small cell)") - tx = dummy_pbitcell(name="rpbc") - self.local_check(tx) - OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 diff --git a/compiler/tests/04_dummy_pbitcell_1rw_test.py b/compiler/tests/04_dummy_pbitcell_1rw_test.py new file mode 100755 index 00000000..000856a5 --- /dev/null +++ b/compiler/tests/04_dummy_pbitcell_1rw_test.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 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 sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class dummy_pbitcell_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + from openram.modules import dummy_pbitcell + + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + + debug.info(2, "Checking dummy bitcell using pbitcell (small cell)") + tx = dummy_pbitcell(name="rpbc") + self.local_check(tx) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/04_replica_pbitcell_test.py b/compiler/tests/04_replica_pbitcell_1rw1r1w_test.py similarity index 83% rename from compiler/tests/04_replica_pbitcell_test.py rename to compiler/tests/04_replica_pbitcell_1rw1r1w_test.py index 73d94039..5af89b43 100755 --- a/compiler/tests/04_replica_pbitcell_test.py +++ b/compiler/tests/04_replica_pbitcell_1rw1r1w_test.py @@ -24,14 +24,6 @@ class replica_pbitcell_test(openram_test): from openram.modules import replica_pbitcell OPTS.bitcell = "pbitcell" - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 0 - OPTS.num_w_ports = 0 - - debug.info(2, "Checking replica bitcell using pbitcell (small cell)") - tx = replica_pbitcell(name="rpbc") - self.local_check(tx) - OPTS.num_rw_ports = 1 OPTS.num_r_ports = 1 OPTS.num_w_ports = 1 diff --git a/compiler/tests/04_replica_pbitcell_1rw_test.py b/compiler/tests/04_replica_pbitcell_1rw_test.py new file mode 100755 index 00000000..ef6a1cd9 --- /dev/null +++ b/compiler/tests/04_replica_pbitcell_1rw_test.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 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 sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class replica_pbitcell_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + from openram.modules import replica_pbitcell + + OPTS.bitcell = "pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + + debug.info(2, "Checking replica bitcell using pbitcell (small cell)") + tx = replica_pbitcell(name="rpbc") + self.local_check(tx) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/14_replica_pbitcell_array_test.py b/compiler/tests/14_replica_pbitcell_1rw1r_array_test.py similarity index 74% rename from compiler/tests/14_replica_pbitcell_array_test.py rename to compiler/tests/14_replica_pbitcell_1rw1r_array_test.py index a7d0f077..6ef53ed3 100755 --- a/compiler/tests/14_replica_pbitcell_array_test.py +++ b/compiler/tests/14_replica_pbitcell_1rw1r_array_test.py @@ -31,17 +31,6 @@ class replica_pbitcell_array_test(openram_test): a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 1], left_rbl=[0], right_rbl=[1]) self.local_check(a) - OPTS.bitcell = "pbitcell" - OPTS.replica_bitcell = "replica_pbitcell" - OPTS.dummy_bitcell = "dummy_pbitcell" - OPTS.num_rw_ports = 1 - OPTS.num_r_ports = 0 - OPTS.num_w_ports = 0 - - debug.info(2, "Testing 4x4 array for pbitcell") - a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 0], left_rbl=[0]) - self.local_check(a) - openram.end_openram() diff --git a/compiler/tests/14_replica_pbitcell_1rw_array_test.py b/compiler/tests/14_replica_pbitcell_1rw_array_test.py new file mode 100755 index 00000000..154fc914 --- /dev/null +++ b/compiler/tests/14_replica_pbitcell_1rw_array_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California, Santa Cruz +# All rights reserved. +# +import sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class replica_pbitcell_array_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + OPTS.bitcell = "pbitcell" + OPTS.replica_bitcell = "replica_pbitcell" + OPTS.dummy_bitcell = "dummy_pbitcell" + OPTS.num_rw_ports = 1 + OPTS.num_r_ports = 0 + OPTS.num_w_ports = 0 + + debug.info(2, "Testing 4x4 array for pbitcell") + a = factory.create(module_type="replica_bitcell_array", cols=4, rows=4, rbl=[1, 0], left_rbl=[0]) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 56b65da727069d9699791c3f9c5d27c2bcfcf5cd Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Tue, 14 Mar 2023 18:30:42 +0000 Subject: [PATCH 19/98] Bump version: 1.2.4 -> 1.2.5 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index e8ea05db..c813fe11 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.4 +1.2.5 From c0d9941985007c9388c97bbaa4f9b7b9e928f3ea Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Tue, 14 Mar 2023 21:38:35 -0700 Subject: [PATCH 20/98] Cleanup README --- README.md | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 78eae437..0bee4049 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ An open-source static random access memory (SRAM) compiler. + + # What is OpenRAM? @@ -16,20 +18,26 @@ other views necessary to use SRAMs in ASIC design. OpenRAM supports integration in both commercial and open-source flows with both predictive and fabricable technologies. + + # Documentation Please see our [documentation][documentation] and let us know if anything needs updating. + + # Get Involved -+ [Port it](./PORTING.md) to a new technology. -+ Report bugs by submitting [Github issues]. ++ [Port it](./PORTING.md) to a new technology ++ Report bugs by submitting [Github issues] + Develop new features (see [how to contribute](./CONTRIBUTING.md)) + Submit code/fixes using a [Github pull request] -+ Follow our [project][Github project]. ++ Follow our [project][Github project] + Read and cite our [ICCAD paper][OpenRAMpaper] + + # Further Help + [Documentation][documentation] @@ -37,10 +45,14 @@ updating. + [OpenRAM Users Group][user-group] ([subscribe here][user-group-subscribe]) + [OpenRAM Developers Group][dev-group] ([subscribe here][dev-group-subscribe]) + + # License OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE). + + # Publications + [M. R. Guthaus, J. E. Stine, S. Ataei, B. Chen, B. Wu, M. Sarwar, "OpenRAM: An Open-Source Memory Compiler," Proceedings of the 35th International Conference on Computer-Aided Design (ICCAD), 2016.](https://escholarship.org/content/qt8x19c778/qt8x19c778_noSplash_b2b3fbbb57f1269f86d0de77865b0691.pdf) @@ -52,6 +64,7 @@ OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE). + [H. Nichols, "Statistical Modeling of SRAMs", M.S. Thesis, UCSC, 2022.](https://escholarship.org/content/qt7vx9n089/qt7vx9n089_noSplash_cfc4ba479d8eb1b6ec25d7c92357bc18.pdf?t=ra9wzr) + [M. Guthaus, H. Nichols, J. Cirimelli-Low, J. Kunzler, B. Wu, "Enabling Design Technology Co-Optimization of SRAMs though Open-Source Software", IEEE International Electron Devices Meeting (IEDM), 2020.](https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9372047) + # Contributors & Acknowledgment @@ -61,7 +74,7 @@ OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE). If I forgot to add you, please let me know! -* * * + [Matthew Guthaus]: https://users.soe.ucsc.edu/~mrg [James Stine]: https://ece.okstate.edu/content/stine-james-e-jr-phd From 4994e3ddde7d6e24a465d1c240926a4a1607c7ce Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Wed, 15 Mar 2023 12:40:04 -0700 Subject: [PATCH 21/98] Move library documentation to its own page --- docs/source/basic_setup.md | 26 +------- docs/source/basic_usage.md | 109 ++++++---------------------------- docs/source/index.md | 10 ++-- docs/source/python_library.md | 84 ++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 120 deletions(-) create mode 100644 docs/source/python_library.md diff --git a/docs/source/basic_setup.md b/docs/source/basic_setup.md index a1f70e0c..d142f99a 100644 --- a/docs/source/basic_setup.md +++ b/docs/source/basic_setup.md @@ -7,7 +7,6 @@ This page shows the basic setup for using OpenRAM. ## Table of Contents 1. [Dependencies](#dependencies) -1. [OpenRAM Library](#openram-library) 1. [Anaconda](#anaconda) 1. [Docker](#docker-deprecated-use-anaconda-instead) 1. [Environment](#environment) @@ -16,8 +15,6 @@ This page shows the basic setup for using OpenRAM. ## Dependencies -Please see the Dockerfile for the required versions of tools. - In general, the OpenRAM compiler has very few dependencies: + Git + Make @@ -27,28 +24,6 @@ In general, the OpenRAM compiler has very few dependencies: -## OpenRAM Library -OpenRAM is available as a Python library. There are a few ways to install it: - -+ Install the latest _stable_ version with pip: -``` -pip3 install openram -``` - -+ Install the latest _dev_ version: -``` -pip3 install git+https://git@github.com/VLSIDA/OpenRAM.git@dev -``` - -+ Install using Makefile (you need to clone the repo): -``` -git clone git@github.com:VLSIDA/OpenRAM.git -cd OpenRAM -make library -``` - - - ## Anaconda We use Anaconda package manager to install the tools used by OpenRAM. This way, you don't have to worry about updating/installing these tools. OpenRAM installs Anaconda silently in the background @@ -142,3 +117,4 @@ You can also run these from the package installation directory if you have the O [SCMOS]: https://www.mosis.com/files/scmos/scmos.pdf [FreePDK45]: https://www.eda.ncsu.edu/wiki/FreePDK45:Contents [Sky130]: https://github.com/google/skywater-pdk-libs-sky130_fd_bd_sram.git + diff --git a/docs/source/basic_usage.md b/docs/source/basic_usage.md index 25010d2f..bef7c85b 100644 --- a/docs/source/basic_usage.md +++ b/docs/source/basic_usage.md @@ -7,9 +7,8 @@ This page of the documentation explains the basic usage of OpenRAM. ## Table of Contents 1. [Environment Variable Setup](#environment-variable-setup-assuming-bash) -1. [Script Usage (with library)](#script-usage-with-library) -1. [Command Line Usage (with library)](#command-line-usage-with-library) -1. [Command Line Usage (without library)](#command-line-usage-without-library) +1. [Command Line Usage](#command-line-usage) +1. [Script Usage](#script-usage) 1. [Configuration Files](#configuration-files) 1. [Common Configuration File Options](#common-configuration-file-options) 1. [Output Files](#output-files) @@ -18,10 +17,11 @@ This page of the documentation explains the basic usage of OpenRAM. ## Environment Variable Setup (assuming bash) -> **Note**: This is optional if you have the OpenRAM library. See [basic setup](./basic_setup.md#go-back) for details. +> **Note**: This is optional if you have the OpenRAM library. +> See [Python library](./python_library.md#go-back) for details. * OPENRAM\_HOME defines where the compiler directory is - * ```export OPENRAM_HOME="$HOME/openram/compiler"``` -* OPENRAM_TECH defines list of paths where the technologies exist + * `export OPENRAM_HOME="$HOME/openram/compiler"` +* OPENRAM\_TECH defines list of paths where the technologies exist * `export OPENRAM_TECH="$HOME/openram/technology"` * Colon separated list so you can have private technology directories * Must also have any PDK related variables set up @@ -30,102 +30,25 @@ This page of the documentation explains the basic usage of OpenRAM. -## Script Usage (with library) -If you have the library installed, you can use OpenRAM in any Python script. You can import "openram" as follows: -```python -import openram -openram.init_openram("myconfig.py") # Config files are explained on this page -# Now you can use modules from openram -from openram import tech -... -``` - -Note that you need to initialize OpenRAM so that the modules are imported properly. You can also look -at [sram_compiler.py](../../sram_compiler.py) as an example on how to use "openram." - -If you want to pass custom configuration when generating an SRAM, you can use the `sram_config` class. -```python -import openram -openram.init_openram("myconfig.py") - -from openram import sram_config -c = sram_config(...) - -from openram import sram -s = sram(sram_config=c, - name="custom_name") - -s.save() - -openram.end_openram() -``` - - -## Command Line Usage (with library) -You can run OpenRAM from the command line using the [sram_compiler.py](../../sram_compiler.py) script that is -included in the library's installation. You can find the package directory on a path like: -``` -/home/mrg/.local/lib/python3.8/site-packages/openram -``` - -Alternatively, you can run the following command to find that path: -``` -echo -e "import os\nimport openram\nprint(os.path.dirname(openram.__file__))" | python3 - -``` - -You can continue with following section for more details. - - -## Command Line Usage (without library) +## Command Line Usage Once you have defined the environment, you can run OpenRAM from the command line -using a single configuration file written in Python. - -For example, create a file called *myconfig.py* specifying the following -parameters for your memory: -```python -# Data word size -word_size = 2 -# Number of words in the memory -num_words = 16 - -# Technology to use in $OPENRAM_TECH -tech_name = "scn4m_subm" - -# You can use the technology nominal corner only -nominal_corner_only = True -# Or you can specify particular corners -# Process corners to characterize -# process_corners = ["SS", "TT", "FF"] -# Voltage corners to characterize -# supply_voltages = [ 3.0, 3.3, 3.5 ] -# Temperature corners to characterize -# temperatures = [ 0, 25 100] - -# Output directory for the results -output_path = "temp" -# Output file base name -output_name = "sram_{0}_{1}_{2}".format(word_size,num_words,tech_name) - -# Disable analytical models for full characterization (WARNING: slow!) -# analytical_delay = False - -``` - -You can then run OpenRAM by executing: +using a single configuration file written in Python. You can then run OpenRAM by +executing: ``` python3 $OPENRAM_HOME/../sram_compiler.py myconfig ``` You can see all of the options for the configuration file in $OPENRAM\_HOME/options.py -To run designs in Docker, it is suggested to use, for example: +To run macros, it is suggested to use, for example: ``` cd OpenRAM/macros make example_config_scn4m_subm ``` * Common arguments: - * `-t` specify technology (scn4m_subm or scmos or freepdk45) + * `-h` print all arguments + * `-t` specify technology (scn4m\_subm or scmos or freepdk45) * `-v` increase verbosity of output * `-n` don't run DRC/LVS * `-c` perform simulation-based characterization @@ -133,6 +56,12 @@ make example_config_scn4m_subm +## Script Usage +OpenRAM is also available as a Python library. See +[Python library](./python_library.md#go-back) for details. + + + ## Configuration Files * Memories are created using a Python configuration file to replicate results * No YAML, JSON, etc. @@ -167,7 +96,7 @@ make example_config_scn4m_subm # Could be calibre for FreePDK45 drc_name = "magic" lvs_name = "netgen" - pex_name = "magic" + pex_name = "magic" ``` diff --git a/docs/source/index.md b/docs/source/index.md index a86f893e..c652318a 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -1,7 +1,8 @@ # OpenRAM Documentation ![OpenRAM Logo](../../images/OpenRAM_logo_yellow_transparent.svg) -These pages provide the documentation of OpenRAM. You can use the links below to navigate through the documentation. +These pages provide the documentation of OpenRAM. You can use the links below to +navigate through the documentation. @@ -10,6 +11,7 @@ These pages provide the documentation of OpenRAM. You can use the links below to 1. [Supported Technologies](#supported-technologies) 1. [Basic Setup](./basic_setup.md#go-back) 1. [Basic Usage](./basic_usage.md#go-back) +1. [Python Library](./python_library.md#go-back) 1. [Bitcells](./bitcells.md#go-back) 1. [Architecture](./architecture.md#go-back) 1. [Implementation](#implementation) @@ -29,10 +31,7 @@ These pages provide the documentation of OpenRAM. You can use the links below to - ## OpenRAM Dependencies -Please see the Dockerfile for the required versions of tools. - In general, the OpenRAM compiler has very few dependencies: + Git + Make @@ -90,6 +89,8 @@ Commercial tools (optional): * DRC and LVS can be performed at all levels of the design hierarchy to enhance bug tracking. * DRC and LVS can be disabled completely for improved run-time or if licenses are not available. + + ## Contributors/Collaborators @@ -108,4 +109,3 @@ Commercial tools (optional): * Marcelo Sero * Seokjoong Kim - diff --git a/docs/source/python_library.md b/docs/source/python_library.md new file mode 100644 index 00000000..5cba22e8 --- /dev/null +++ b/docs/source/python_library.md @@ -0,0 +1,84 @@ +### [Go Back](./index.md#table-of-contents) + +# Python Library +This page explains the Python library of OpenRAM. + + + +## Table of Contents +1. [Installation](#installation) +1. [Environment Variables](#environment-variables) +1. [Usage](#usage) + + + +## Installation +OpenRAM is available as a Python library. There are a few ways to install it: + ++ Install the latest _stable_ version with pip: +``` +pip3 install openram +``` + ++ Install the latest _dev_ version: +``` +pip3 install git+https://git@github.com/VLSIDA/OpenRAM.git@dev +``` + ++ Install using Makefile (you need to clone the repo): +``` +git clone git@github.com:VLSIDA/OpenRAM.git +cd OpenRAM +make library +``` + + + +## Environment Variables +OpenRAM library doesn't need any envinronment variable by default. However, if +you have set the environment variables explained on +[basic usage](.basic_usage.md#go-back), the library will use the OpenRAM source +code located at `OPENRAM_HOME`. + +If you want the convenience of being able to call OpenRAM from any Python script +and have a custom OpenRAM setup, you can set these environment variables to +point to that OpenRAM installation. + +If you don't want to use this feature, you can simply unset these environment +variables. + + + +## Usage +With the OpenRAM library, you can use OpenRAM in any Python script. You can +import "openram" as follows: +```python +import openram +openram.init_openram("myconfig.py") # Config files are explained on "Basic Usage" page +# Now you can use modules from openram +from openram import tech +... +``` + +Note that you need to initialize OpenRAM so that the modules are imported +properly. You can also look at [sram\_compiler.py](../../sram_compiler.py) as an +example on how to use "openram." + +If you want to pass custom configuration when generating an SRAM, you can use +the `sram_config` class. +```python +import openram +openram.init_openram("myconfig.py") + +from openram import sram_config +c = sram_config(...) + +from openram import sram +s = sram(sram_config=c, + name="custom_name") + +s.save() + +openram.end_openram() +``` + From 9873b4cdf9ddf5d3db34b34efd7bade8b9eff998 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Wed, 15 Mar 2023 12:41:50 -0700 Subject: [PATCH 22/98] Fix Python version in documentation --- docs/source/basic_setup.md | 2 +- docs/source/index.md | 2 +- setup.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/source/basic_setup.md b/docs/source/basic_setup.md index d142f99a..f76d6cd5 100644 --- a/docs/source/basic_setup.md +++ b/docs/source/basic_setup.md @@ -18,7 +18,7 @@ This page shows the basic setup for using OpenRAM. In general, the OpenRAM compiler has very few dependencies: + Git + Make -+ Python 3.6 or higher ++ Python 3.5 or higher + Various Python packages (pip install -r requirements.txt) + Anaconda diff --git a/docs/source/index.md b/docs/source/index.md index c652318a..bb2ede04 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -35,7 +35,7 @@ navigate through the documentation. In general, the OpenRAM compiler has very few dependencies: + Git + Make -+ Python 3.6 or higher ++ Python 3.5 or higher + Various Python packages (pip install -r requirements.txt) + Anaconda diff --git a/setup.py b/setup.py index b47d7096..80883771 100644 --- a/setup.py +++ b/setup.py @@ -74,7 +74,7 @@ setup( author_email="mrg+vlsida@ucsc.edu", keywords=[ "sram", "magic", "gds", "netgen", "ngspice", "netlist" ], license="BSD 3-Clause", - python_requires=">=3.6", + python_requires=">=3.5", classifiers=[ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", From 0fe8b3be17d5beba3cdd6ac817b53ead4ba2b28f Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Wed, 15 Mar 2023 21:08:20 +0000 Subject: [PATCH 23/98] Bump version: 1.2.5 -> 1.2.6 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c813fe11..3c43790f 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.5 +1.2.6 From c8b5b81bd87cdfca1bf44d5789a6a2d17ca6a689 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Thu, 16 Mar 2023 14:10:22 -0700 Subject: [PATCH 24/98] Cleanup documentation --- docs/source/basic_setup.md | 79 +++++++++++++++++++---------------- docs/source/basic_usage.md | 11 ++--- docs/source/index.md | 16 ++++--- docs/source/python_library.md | 8 ++-- 4 files changed, 63 insertions(+), 51 deletions(-) diff --git a/docs/source/basic_setup.md b/docs/source/basic_setup.md index f76d6cd5..9b0d0517 100644 --- a/docs/source/basic_setup.md +++ b/docs/source/basic_setup.md @@ -25,46 +25,49 @@ In general, the OpenRAM compiler has very few dependencies: ## Anaconda -We use Anaconda package manager to install the tools used by OpenRAM. This way, you don't have to -worry about updating/installing these tools. OpenRAM installs Anaconda silently in the background -(without affecting any existing anaconda setup you have). +We use Anaconda package manager to install the tools used by OpenRAM. This way, +you don't have to worry about updating/installing these tools. OpenRAM installs +Anaconda silently in the background (without affecting any existing Anaconda +setup you have). -OpenRAM uses Anaconda by default, but you can turn this feature off by setting `use_conda = False` -in your config file. Then, OpenRAM will use the tools you have installed on your system. +OpenRAM uses Anaconda by default, but you can turn this feature off by setting +`use_conda = False` in your config file. Then, OpenRAM will use the tools you +have installed on your system. -If you want to install Anaconda without running OpenRAM (for example to run unit tests, which do -not install Anaconda), you can run: -``` -cd OpenRAM -./install_conda.sh -``` +> **Note**: If you want to install Anaconda without running OpenRAM (for example +> to run unit tests, which do not install Anaconda), you can run: +> ``` +> ./install_conda.sh +> ``` ## Docker (deprecated, use Anaconda instead) -We have a [docker setup](../../docker) to run OpenRAM. To use this, you should run: +We have a [docker setup](../../docker) to run OpenRAM. To use this, you should +run: ``` cd OpenRAM/docker make build ``` -This must be run once and will take a while to build all the tools. If you have the -OpenRAM library installed, you can also run the docker setup from the package -installation directory. +This must be run once and will take a while to build all the tools. If you have +the OpenRAM library installed, you can also run the docker setup from the +package installation directory. ## Environment -If you haven't installed the OpenRAM library or you want to use a different OpenRAM installation, -you can set two environment variables: -+ OPENRAM\_HOME should point to the compiler source directory. -+ OPENRAM\_TECH should point to one or more root technology directories (colon separated). +If you haven't installed the OpenRAM library or you want to use a different +OpenRAM installation, you can set two environment variables: ++ `OPENRAM_HOME` should point to the compiler source directory. ++ `OPENRAM_TECH` should point to one or more root technology directories (colon + separated). -If you have the library installed and OPENRAM\_HOME set, the library will use the installation on -the OPENRAM\_HOME path. +If you have the library installed and `OPENRAM_HOME` set, the library will use +the installation on the `OPENRAM_HOME` path. -If you don't have the library, you should also add OPENRAM\_HOME to your PYTHONPATH. This is not -needed if you have the library. +If you don't have the library, you should also add `OPENRAM_HOME` to your +`PYTHONPATH`. This is not needed if you have the library. You can add these environment variables to your `.bashrc`: ``` @@ -73,44 +76,46 @@ export OPENRAM_TECH="$HOME/OpenRAM/technology" export PYTHONPATH=$OPENRAM_HOME ``` -Note that if you want symbols to resolve in your editor, you may also want to add the specific technology -directory that you use and any custom technology modules as well. For example: +Note that if you want symbols to resolve in your editor, you may also want to +add the specific technology directory that you use and any custom technology +modules as well. For example: ``` export PYTHONPATH="$OPENRAM_HOME:$OPENRAM_TECH/sky130:$OPENRAM_TECH/sky130/custom" ``` -We include the tech files necessary for [SCMOS] SCN4M\_SUBM, -[FreePDK45]. The [SCMOS] spice models, however, are -generic and should be replaced with foundry models. You may get the -entire [FreePDK45 PDK here][FreePDK45]. +We include the tech files necessary for [SCMOS] SCN4M\_SUBM, [FreePDK45]. The +[SCMOS] spice models, however, are generic and should be replaced with foundry +models. You may get the entire [FreePDK45 PDK here][FreePDK45]. ## Sky130 Setup -To install [Sky130], you must have open\_pdks installed in $PDK\_ROOT. We highly recommend that you -use the version tagged in the Makefile as others have not been verified. -To install this automatically, you can run: +To install [Sky130], you must have open\_pdks installed in $PDK\_ROOT. We highly +recommend that you use the version tagged in the Makefile as others have not +been verified. To install this automatically, you can run: ``` cd $HOME/OpenRAM make pdk ``` -> **Note**: If you don't have Magic installed, you need to install and activate the conda environment before running this command. -> You can install conda with: +> **Note**: If you don't have Magic installed, you need to install and activate +> the conda environment before running this command. You can run: > > ``` +> ./install_conda.sh > source miniconda/bin/activate > ``` -Then you must also install the [Sky130] SRAM build space with the appropriate cell views into the OpenRAM technology directory -by running: +Then you must also install the [Sky130] SRAM build space with the appropriate +cell views into the OpenRAM technology directory by running: ``` cd $HOME/OpenRAM make install ``` -You can also run these from the package installation directory if you have the OpenRAM library. +You can also run these from the package installation directory if you have the +OpenRAM library. diff --git a/docs/source/basic_usage.md b/docs/source/basic_usage.md index bef7c85b..7550137f 100644 --- a/docs/source/basic_usage.md +++ b/docs/source/basic_usage.md @@ -17,11 +17,11 @@ This page of the documentation explains the basic usage of OpenRAM. ## Environment Variable Setup (assuming bash) -> **Note**: This is optional if you have the OpenRAM library. -> See [Python library](./python_library.md#go-back) for details. -* OPENRAM\_HOME defines where the compiler directory is +> **Note**: This is optional if you have the OpenRAM library. See +> [Python library](./python_library.md#go-back) for details. +* `OPENRAM_HOME` defines where the compiler directory is * `export OPENRAM_HOME="$HOME/openram/compiler"` -* OPENRAM\_TECH defines list of paths where the technologies exist +* `OPENRAM_TECH` defines list of paths where the technologies exist * `export OPENRAM_TECH="$HOME/openram/technology"` * Colon separated list so you can have private technology directories * Must also have any PDK related variables set up @@ -131,7 +131,8 @@ OpenRAM is also available as a Python library. See ## Output Files -The output files are placed in the `output_dir` defined in the configuration file. +The output files are placed in the `output_dir` defined in the configuration +file. The base name is specified by `output_name` and suffixes are added. diff --git a/docs/source/index.md b/docs/source/index.md index bb2ede04..2bb59fbe 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -79,15 +79,21 @@ Commercial tools (optional): ## Technology and Tool Portability -* OpenRAM is technology independent by using a technology directory that includes: +* OpenRAM is technology independent by using a technology directory that + includes: * Technology's specific information * Technology's rules such as DRC rules and the GDS layer map - * Custom designed library cells (6T, sense amp, DFF) to improve the SRAM density. -* For technologies that have specific design requirements, such as specialized well contacts, the user can include helper functions in the technology directory. + * Custom designed library cells (6T, sense amp, DFF) to improve the SRAM + density. +* For technologies that have specific design requirements, such as specialized + well contacts, the user can include helper functions in the technology + directory. * Verification wrapper scripts * Uses a wrapper interface with DRC and LVS tools that allow flexibility - * DRC and LVS can be performed at all levels of the design hierarchy to enhance bug tracking. - * DRC and LVS can be disabled completely for improved run-time or if licenses are not available. + * DRC and LVS can be performed at all levels of the design hierarchy to + enhance bug tracking. + * DRC and LVS can be disabled completely for improved run-time or if + licenses are not available. diff --git a/docs/source/python_library.md b/docs/source/python_library.md index 5cba22e8..a4b92c5c 100644 --- a/docs/source/python_library.md +++ b/docs/source/python_library.md @@ -15,7 +15,7 @@ This page explains the Python library of OpenRAM. ## Installation OpenRAM is available as a Python library. There are a few ways to install it: -+ Install the latest _stable_ version with pip: ++ Install the latest _stable_ version: ``` pip3 install openram ``` @@ -35,14 +35,14 @@ make library ## Environment Variables -OpenRAM library doesn't need any envinronment variable by default. However, if +OpenRAM library doesn't need any environment variables by default. However, if you have set the environment variables explained on [basic usage](.basic_usage.md#go-back), the library will use the OpenRAM source code located at `OPENRAM_HOME`. -If you want the convenience of being able to call OpenRAM from any Python script +If you want the convenience of being able to run OpenRAM from any Python script and have a custom OpenRAM setup, you can set these environment variables to -point to that OpenRAM installation. +point to that OpenRAM installation directory. If you don't want to use this feature, you can simply unset these environment variables. From 6eebef8c72684219694d0772d7aeda39fc1f42b7 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Thu, 16 Mar 2023 14:40:24 -0700 Subject: [PATCH 25/98] Fix typo in Makefile --- compiler/tests/Makefile | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index bfa2ab8e..dd2d9738 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -132,10 +132,6 @@ else endif .DELETE_ON_ERROR: $(TEST_STAMPS) -.PHONY: docker-pull -docker-pull: - docker pull vlsida/openram-ubuntu:latest - clean: @rm -rf $(TOP_DIR)/compiler/tests/results -.PHONE: clean +.PHONY: clean From c166a50f2194e8563863976120c2852a3fd50f5b Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Thu, 16 Mar 2023 15:04:58 -0700 Subject: [PATCH 26/98] Update debugging documentation --- docs/source/debug.md | 129 ++++++++++++++++--------------------------- 1 file changed, 47 insertions(+), 82 deletions(-) diff --git a/docs/source/debug.md b/docs/source/debug.md index e8ae091c..a2ea6aaf 100644 --- a/docs/source/debug.md +++ b/docs/source/debug.md @@ -1,7 +1,8 @@ ### [Go Back](./index.md#table-of-contents) # Debugging and Unit Testing -This page of the documentation explains the debugging and unit testing of OpenRAM. +This page of the documentation explains the debugging and unit testing of +OpenRAM. @@ -16,11 +17,14 @@ This page of the documentation explains the debugging and unit testing of OpenRA ## Unit Tests -OpenRAM has the set of thorough regression tests implemented with the Python unit test framework: -* Unit tests allow users to add features without worrying about breaking functionality. +OpenRAM has the set of thorough regression tests implemented with the Python +unit test framework: +* Unit tests allow users to add features without worrying about breaking + functionality. * Unit tests guide users when porting to new technologies. * Every sub-module has its own regression test. -* There are regression tests for memory functionality, library cell verification, timing verification, and technology verification. +* There are regression tests for memory functionality, library cell + verification, timing verification, and technology verification. @@ -33,7 +37,8 @@ OpenRAM has the set of thorough regression tests implemented with the Python uni * `05-19_*_test.py` checks DRC and LVS of module cells (moving upward in hierarchy with numbers) * `20_*_test.py` check DRC and LVS of full SRAM layouts with various configurations. * `21_*_test.py` checks timing of full SRAMs and compares (with tolerance) to precomputed result. - > **Note**: These tests may fail using different simulators due to the tolerance level. + > **Note**: These tests may fail using different simulators due to the + > tolerance level. * `22_*_test.py` checks functional simulation of full SRAMs with various configurations. * `23-25_*_test.py` checks lib, lef, and verilog outputs using diff. * `30_openram_test.py` checks command-line interface and whether output files are created. @@ -41,16 +46,20 @@ OpenRAM has the set of thorough regression tests implemented with the Python uni ## Running Unit Tests - -Regression testing performs a number of tests for all modules in OpenRAM. -From the unit test directory ($OPENRAM\_HOME/tests), -use the following command to run all regression tests: +Regression testing performs a number of tests for all modules in OpenRAM. From +the unit test directory (`$OPENRAM_HOME/tests`), use the following command to run +all regression tests: ``` cd OpenRAM/compiler/tests make -j 3 ``` -The -j can run with 3 threads. By default, this will run in all technologies. Note that if you have not run openram, the conda environment will not be installed. You can install it by running OpenRAM/install_conda.sh (see [Basic Setup](basic_setup.md#anaconda) for more details). + +The `-j` can run with 3 threads. By default, this will run in all technologies. +> **Note**: If you have not run openram before running unit tests, the conda +> environment will not be installed. You can install it by running +> `OpenRAM/install_conda.sh` (see [Basic Setup](basic_setup.md#anaconda) for +> more details). To run a specific test in all technologies: ``` @@ -63,8 +72,8 @@ cd OpenRAM/compiler/tests TECHS=scn4m_subm make 05_bitcell_array_test ``` -To increase the verbosity of the test, add one (or more) -v options and -pass it as an argument to OpenRAM: +To increase the verbosity of the test, add one (or more) `-v` options and pass +it as an argument to OpenRAM: ``` ARGS="-v" make 05_bitcell_array_test ``` @@ -73,95 +82,52 @@ Unit test results are put in a directory: ``` OpenRAM/compiler/tests/results// ``` -If the test fails, there will be a tmp directory with intermediate results. -If the test passes, this directory will be deleted to save space. -You can view the .out file to see what the output of a test is in either case. -* Tests can be run in the `$OPENRAM_HOME/tests` directory -* Command line arguments - * `-v` for verbose - * `-t` freepdk45 for tech - * `-d` to preserve /tmp results (done automatically if test fails) -* Individual tests - * `01_library_drc_test.py` -* All tests - * `regress.py` +If the test fails, there will be a `tmp` directory with intermediate results. If +the test passes, this directory will be deleted to save space. You can view the +`.out` file to see what the output of a test is in either case. + +To preserve results on successful tests (done automatically if test fails): +``` +KEEP=1 make 05_bitcell_array_test +``` ## Successful Unit Tests ```console -user@host:/openram/compiler/tests$ ./regress.py - ______________________________________________________________________________ -|==============================================================================| -|========= Running Test for: =========| -|========= scn4m_subm =========| -|========= ./regress.py =========| -|========= /tmp/openram_mrg_13245_temp/ =========| -|==============================================================================| -runTest (00_code_format_check_test.code_format_test) ... ok -runTest (01_library_drc_test.library_drc_test) ... ok -runTest (02_library_lvs_test.library_lvs_test) ... ok -runTest (03_contact_test.contact_test) ... ok -runTest (03_path_test.path_test) ... ok +user@host:/openram/compiler/tests$ make +scn4m_subm/12_tri_gate_array_test ... PASS! +scn4m_subm/19_pmulti_bank_test ... PASS! +freepdk45/21_ngspice_delay_global_test ... PASS! +scn4m_subm/23_lib_sram_linear_regression_test ... PASS! . . . ``` ```console -user@host:/openram/compiler/tests$ ./03_ptx_1finger_nmos_test.py - ______________________________________________________________________________ -|==============================================================================| -|========= Running Test for: =========| -|========= scn4m_subm =========| -|========= ./03_ptx_1finger_nmos_test.py =========| -|========= /tmp/openram_mrg_13750_temp/ =========| -|==============================================================================| -. ----------------------------------------------------------------------- -Ran 1 test in 0.596s - -OK +user@host:/openram/compiler/tests$ make 01_library_test +scn4m_subm/01_library_test ... PASS! +freepdk45/01_library_test ... PASS! ``` ## Debugging Unsuccessful Unit Tests (or sram\_compiler.py) -* You will get an ERROR during unit test and see a stack trace -* Examine the temporary output files in the temp directory (/tmp/mydir) +* You will get a FAIL during unit test +* You can see the output and stack trace in + `$OPENRAM_HOME/tests/results//.out` +* Examine the temporary output files in the temp directory + (`$OPENRAM_HOME/tests/results///`) ```console - _____________________________________________________________________________ -|==============================================================================| -|========= Running Test for: =========| -|========= scn4m_subm =========| -|========= ./04_pinv_10x_test.py =========| -|========= /tmp/mydir =========| -|==============================================================================| -ERROR: file magic.py: line 174: DRC Errors pinv_0 2 -F -====================================================================== -FAIL: runTest (__main__.pinv_test) ----------------------------------------------------------------------- -Traceback (most recent call last): - File "./04_pinv_10x_test.py", line 22, in runTest - self.local_check(tx) - File "/Users/mrg/openram/compiler/tests/testutils.py", line 45, in local_check - self.fail("DRC failed: {}".format(a.name)) -AssertionError: DRC failed: pinv_0 - ----------------------------------------------------------------------- -Ran 1 test in 0.609s - -FAILED (failures=1) +user@host:/openram/compiler/tests$ make 01_library_test +scn4m_subm/01_library_test ... FAIL! ``` ### It didn't finish... where are my files? * OpenRAM puts all temporary files in a temporary directory named: - * `/tmp/openram___temp` - * This allows multiple processes/users to simultaneously run - * This allows /tmp to be mapped to a RAM disk for faster performance + * `$OPENRAM_HOME/tests/results///` + * This allows multiple unit tests to simultaneously run * After a successful run, the directory and contents are deleted - * To preserve the contents, you can run with the `-d` option for debugging -* `OPENRAM_TMP` will override the temporary directory location for debug - * `export OPENRAM_TMP="/home/myname/debugdir"` + * To preserve the contents, you can run with the `KEEP` option for debugging @@ -176,4 +142,3 @@ FAILED (failures=1) - From f62ca94ad41ca87de04d7f998a111e68613b298a Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Thu, 16 Mar 2023 15:20:26 -0700 Subject: [PATCH 27/98] Cleanup debug.md --- docs/source/debug.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/source/debug.md b/docs/source/debug.md index a2ea6aaf..32752704 100644 --- a/docs/source/debug.md +++ b/docs/source/debug.md @@ -37,8 +37,7 @@ unit test framework: * `05-19_*_test.py` checks DRC and LVS of module cells (moving upward in hierarchy with numbers) * `20_*_test.py` check DRC and LVS of full SRAM layouts with various configurations. * `21_*_test.py` checks timing of full SRAMs and compares (with tolerance) to precomputed result. - > **Note**: These tests may fail using different simulators due to the - > tolerance level. + > **Note**: These tests may fail using different simulators due to the tolerance level. * `22_*_test.py` checks functional simulation of full SRAMs with various configurations. * `23-25_*_test.py` checks lib, lef, and verilog outputs using diff. * `30_openram_test.py` checks command-line interface and whether output files are created. From 20ca8e3b22615a4bc3a7dd8e2881952eff0cdc44 Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Thu, 16 Mar 2023 23:46:12 +0000 Subject: [PATCH 28/98] Bump version: 1.2.6 -> 1.2.7 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 3c43790f..c04c650a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.6 +1.2.7 From 4db5c3be261de3d1e90108db2b94aa3fd0162676 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Fri, 22 Jul 2022 15:12:09 -0700 Subject: [PATCH 29/98] basic nmos array, for nand rom --- compiler/modules/rom_base_array.py | 131 ++++++++++++++++++++++++++++ compiler/tests/05_rom_array_test.py | 39 +++++++++ 2 files changed, 170 insertions(+) create mode 100644 compiler/modules/rom_base_array.py create mode 100644 compiler/tests/05_rom_array_test.py diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py new file mode 100644 index 00000000..ae2fe9b7 --- /dev/null +++ b/compiler/modules/rom_base_array.py @@ -0,0 +1,131 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 .bitcell_base_array import bitcell_base_array +from base import vector +from globals import OPTS +from sram_factory import factory + +class rom_base_array(bitcell_base_array): + + def __init__(self, rows, cols, bitmap, name="", column_offset=0): + super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset) + self.data = bitmap + + self.create_all_bitline_names() + self.create_all_wordline_names() + self.create_netlist() + + self.create_layout() + + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_instances() + + + def create_layout(self): + #self.add_layout_pins() + self.place_ptx() + self.route_supplies() + + #self.add_boundary() + + #self.DRC_LVS() + + #def add_pins(self): + def add_boundary(self): + self.width = self.nmos.width * self.column_size + self.height = self.nmos.height * self.row_size + super().add_boundary() + + def add_modules(self): + + self.nmos = factory.create(module_type="ptx", tx_type="nmos") + + + + def create_instances(self): + self.cell_inst = {} + self.current_row = 0 + for col in range(self.column_size): + for row in range(self.row_size): + name = "bit_r{0}_c{1}".format(row, col) + + if(self.data[col][row] == 1): + self.cell_inst[row, col]=self.add_inst(name=name, + mod=self.nmos) + + self.connect_inst(self.get_bitcell_pins(row, col)) + + # If it is a "core" cell, it could be trimmed for sim time + #if col>0 and col0 and row Date: Thu, 4 Aug 2022 12:47:17 -0700 Subject: [PATCH 30/98] array generation and bitline routing with array module --- compiler/modules/rom_base_array.py | 160 +++++++++++++++++++++------- compiler/tests/05_rom_array_test.py | 4 +- 2 files changed, 123 insertions(+), 41 deletions(-) diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index ae2fe9b7..94b6f7a5 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -17,8 +17,10 @@ class rom_base_array(bitcell_base_array): def __init__(self, rows, cols, bitmap, name="", column_offset=0): super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset) + + #TODO: data is input in col-major order for ease of parsing, create a function to convert a row-major input to col-major self.data = bitmap - + self.route_layer = 'm1' self.create_all_bitline_names() self.create_all_wordline_names() self.create_netlist() @@ -29,15 +31,21 @@ class rom_base_array(bitcell_base_array): def create_netlist(self): self.add_modules() self.add_pins() + self.create_instances() def create_layout(self): #self.add_layout_pins() self.place_ptx() + + #self.route_horizontal_pins(insts=self.cell_inst.values(), layer=self.route_layer, name="S") + self.route_bitlines() + #self.route_wordlines() + self.route_supplies() - #self.add_boundary() + self.add_boundary() #self.DRC_LVS() @@ -49,42 +57,30 @@ class rom_base_array(bitcell_base_array): def add_modules(self): - self.nmos = factory.create(module_type="ptx", tx_type="nmos") - - - + self.nmos = factory.create(module_type="ptx", tx_type="nmos", add_source_contact=self.route_layer, + add_drain_contact=self.route_layer) + temp = self.nmos.width + self.nmos.width = self.nmos.height + self.nmos.poly_extend_active + self.nmos.height = temp def create_instances(self): self.cell_inst = {} + self.cell_list = [] self.current_row = 0 - for col in range(self.column_size): - for row in range(self.row_size): + for row in range(self.row_size): + row_list = [] + + for col in range(self.column_size): + name = "bit_r{0}_c{1}".format(row, col) - if(self.data[col][row] == 1): + if(self.data[row][col] == 1): self.cell_inst[row, col]=self.add_inst(name=name, - mod=self.nmos) - + mod=self.nmos, rotate=90) + + row_list.append(self.cell_inst[row, col]) self.connect_inst(self.get_bitcell_pins(row, col)) - - # If it is a "core" cell, it could be trimmed for sim time - #if col>0 and col0 and row Date: Fri, 12 Aug 2022 19:51:08 -0700 Subject: [PATCH 31/98] base and dummy array alignment in sky130 --- compiler/modules/rom_base_array.py | 97 ++++++++++++++------- compiler/modules/rom_base_cell.py | 81 ++++++++++++++++++ compiler/modules/rom_dummy_cell.py | 125 ++++++++++++++++++++++++++++ compiler/tests/05_rom_array_test.py | 2 +- 4 files changed, 273 insertions(+), 32 deletions(-) create mode 100644 compiler/modules/rom_base_cell.py create mode 100644 compiler/modules/rom_dummy_cell.py diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 94b6f7a5..e86c9cd6 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -40,7 +40,7 @@ class rom_base_array(bitcell_base_array): self.place_ptx() #self.route_horizontal_pins(insts=self.cell_inst.values(), layer=self.route_layer, name="S") - self.route_bitlines() + #self.route_bitlines() #self.route_wordlines() self.route_supplies() @@ -51,17 +51,26 @@ class rom_base_array(bitcell_base_array): #def add_pins(self): def add_boundary(self): - self.width = self.nmos.width * self.column_size - self.height = self.nmos.height * self.row_size + self.width = self.cell.width * self.column_size + self.height = self.cell.height * self.row_size super().add_boundary() def add_modules(self): - self.nmos = factory.create(module_type="ptx", tx_type="nmos", add_source_contact=self.route_layer, - add_drain_contact=self.route_layer) - temp = self.nmos.width - self.nmos.width = self.nmos.height + self.nmos.poly_extend_active - self.nmos.height = temp + # base cell, nmos tx that represents a 1 + self.cell = factory.create(module_type="rom_base_cell") + + # "dummy" cells represent 0 + + #dummy cell with no contacts + self.dummy_nc = factory.create(module_type="rom_dummy_cell") + #dummy cell with drain contact + self.dummy_dc = factory.create(module_type="rom_dummy_cell", drain_contact=True) + #dummy cell with source contact + self.dummy_sc = factory.create(module_type="rom_dummy_cell", source_contact=True) + #dummy cell with all contacts + self.dummy_ac = factory.create(module_type="rom_dummy_cell", source_contact=True, drain_contact=True) + def create_instances(self): self.cell_inst = {} self.cell_list = [] @@ -75,11 +84,31 @@ class rom_base_array(bitcell_base_array): if(self.data[row][col] == 1): self.cell_inst[row, col]=self.add_inst(name=name, - mod=self.nmos, rotate=90) + mod=self.cell) - row_list.append(self.cell_inst[row, col]) - self.connect_inst(self.get_bitcell_pins(row, col)) - else: row_list.append(None) + + + self.connect_inst(["vdd", "gnd", "gnd"]) + else: + + if col < self.column_size - 1 and col > 0 and self.data[row][col + 1] == 1 and self.data[row][col - 1] == 1: + + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.dummy_ac) + + elif col > 0 and self.data[row][col - 1] == 1: + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.dummy_dc) + + elif col < self.column_size - 1 and self.data[row][col + 1] == 1: + + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.dummy_sc) + + else: + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.dummy_nc) + + + + self.connect_inst([]) + row_list.append(self.cell_inst[row, col]) self.cell_list.append(row_list) @@ -94,34 +123,40 @@ class rom_base_array(bitcell_base_array): def place_ptx(self): self.cell_pos = {} - for col in range(self.column_size): - for row in range(self.row_size): + + # rows are bitlines + for row in range(self.row_size): + # columns are word lines + for col in range(self.column_size): - #cell_x = (self.nmos.height + self.nmos.poly_extend_active) * col - #cell_y = (self.nmos.width + 2 * self.nmos.active_contact_to_gate + self.nmos.contact_width) * row - cell_x = self.nmos.width * col - cell_y = self.nmos.height * row - print(self.nmos.height + self.nmos.poly_extend_active) + cell_x = (self.cell.width) * col + cell_y = row * (self.cell.height) + + self.cell_pos[row, col] = vector(cell_x, cell_y) + self.cell_inst[row, col].place(self.cell_pos[row, col]) + #cell_x = self.cell.width * col + #cell_y = self.cell.height * row + #print(self.nmos.height + self.nmos.poly_extend_active) if(self.data[row][col] == 1): + pass - self.cell_pos[row, col] = self.nmos.active_offset.scale(1, 0) \ - + vector(cell_x, cell_y) - self.cell_inst[row, col].place(self.cell_pos[row, col], rotate=90) - self.add_label("S_{}_{}".format(row,col), self.route_layer, self.cell_inst[row, col].get_pin("S").center()) - self.add_label("D", self.route_layer, self.cell_inst[row, col].get_pin("D").center()) + + + #self.add_label("S_{}_{}".format(row,col), self.route_layer, self.cell_inst[row, col].center()) + #self.add_label("D", self.route_layer, self.cell_inst[row, col].center()) - else: + #else: #poly_offset = (self.nmos.contact_offset + vector(0.5 * self.nmos.active_contact.width + 0.5 * self.nmos.poly_width + self.nmos.active_contact_to_gate, 0)) + (0, cell_y) - poly_offset = (cell_x, cell_y) + #poly_offset = (cell_x, cell_y) #print(cell_x,cell_y) - self.add_rect(layer="poly", - offset=poly_offset, - width=self.nmos.height + self.nmos.poly_extend_active, - height=self.nmos.poly_width - ) + #self.add_rect(layer="poly", + # offset=poly_offset, + # width=self.nmos.height + self.nmos.poly_extend_active, + # height=self.nmos.poly_width + # ) diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py new file mode 100644 index 00000000..5c454619 --- /dev/null +++ b/compiler/modules/rom_base_cell.py @@ -0,0 +1,81 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 math +from .rom_dummy_cell import rom_dummy_cell +from base import design +from base import vector +from globals import OPTS +from sram_factory import factory + +from tech import drc + + +class rom_base_cell(rom_dummy_cell): + + def __init__(self, name="", cell_name=None): + super().__init__(name, cell_name) + #self.route_layer= route_layer + #self.create_netlist() + #self.create_layout() + + + def create_netlist(self): + print("using base cell netlist creation") + + self.add_pins() + self.add_nmos() + self.create_nmos() + + + def create_layout(self): + self.setup_drc_offsets() + self.place_nmos() + self.add_boundary() + + print(self.height) + print(self.width) + + def add_pins(self): + pin_list = ["bl_h", "bl_l", "wl"] + dir_list = ["INOUT", "GROUND", "INPUT"] + + self.add_pin_list(pin_list, dir_list) + + + def create_nmos(self): + self.cell_inst = self.add_inst( name=self.name, + mod=self.nmos, + rotate=90) + self.connect_inst(["bl_h", "wl", "bl_l", "gnd"]) + + + + def place_nmos(self): + + + poly_offset = vector(0.5 * self.nmos.active_contact.width + self.nmos.active_contact_to_gate, + self.nmos.poly_height) + + nmos_offset = vector(- 0.5 * self.nmos.contact_width - self.active_enclose_contact, self.nmos.poly_extend_active) + + # add rect of poly to account for offset from drc spacing + self.add_rect("poly", poly_offset, self.nmos.poly_width, self.poly_extend_active_spacing ) + + self.cell_inst.place(nmos_offset) + + self.add_label("S", self.route_layer, self.cell_inst.get_pin("S").center()) + self.add_label("D", self.route_layer, self.cell_inst.get_pin("D").center()) + + + + + + + diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py new file mode 100644 index 00000000..0ef5c97f --- /dev/null +++ b/compiler/modules/rom_dummy_cell.py @@ -0,0 +1,125 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 base import design +from base import vector +from globals import OPTS +from sram_factory import factory +from tech import drc + + +class rom_dummy_cell(design): + + def __init__(self, name="", cell_name=None, source_contact=False, drain_contact=False): + super().__init__(name, cell_name) + self.route_layer = "m1" + self.source_contact=source_contact + self.drain_contact=drain_contact + self.create_netlist() + self.create_layout() + + def create_netlist(self): + #creates nmos for layout dimensions + self.add_nmos() + + + #set height and width such that the cell will tile perfectly by only ofsetting in the array by its width and height + + + + def create_layout(self): + + + self.setup_drc_offsets() + + self.add_boundary() + self.add_poly() + self.add_metal() + #poly_offset = + # vector(0.5 * self.nmos.active_contact.width + 0.5 * self.nmos.poly_width + self.nmos.active_contact_to_gate, 0) + + #self.add_rect( layer="poly", + # offset=poly_offset, + # height=self.nmos.height + self.nmos.poly_extend_active, + # width=self.nmos.poly_width + # ) + self.add_label("0,0", self.route_layer) + #self.add_wire( layers=self.route_layer) + #self.add_rect( layer=self.route_layer) + + + + # Calculates offsets of cell width and height so that tiling of cells does not violate any drc rules + def setup_drc_offsets(self): + + #nmos contact to gate distance + self.contact_to_gate = 0.5 * (self.nmos.width - 2 * self.nmos.contact_width - self.nmos.poly_width - 2 * self.active_enclose_contact) + + #height offset to account for active-to-active spacing between adjacent bitlines + self.poly_extend_active_spacing = abs( 2 * self.nmos.poly_extend_active - drc("active_to_active") ) + + #contact to contact distance, minimum cell width before drc offsets + self.base_width = self.nmos.width - 2 * self.active_enclose_contact - self.nmos.contact_width + + #width offset to account for active-to-active spacing between cells on the same bitline + #this is calculated as a negative value + self.cell_diffusion_offset = ((self.base_width - 2 * self.active_enclose_contact - self.nmos.contact_width) - drc("active_to_active")) * 0.5 + + + # width offset to account for poly-active spacing between base and dummy cells on the same bitline + self.poly_active_offset = 0.5 * (self.base_width - 2 * self.cell_diffusion_offset - (self.poly_width + 2 * self.active_enclose_contact + self.nmos.contact_width)) - self.poly_to_active + + + def add_boundary(self): + + #cell height with offsets applied + self.height = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active + + # cell width with offsets applied, if the offsets are positive (greater than 0) they are not applied + self.width = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) + + super().add_boundary() + + + + def add_poly(self): + + poly_x = 0.5 * self.nmos.contact_width + self.contact_to_gate + + self.add_rect("poly", vector(poly_x, 0), self.poly_width, self.height) + + def add_metal(self): + + wire_x = min(self.cell_diffusion_offset, 0) + min(self.poly_active_offset, 0) + wire_y = 0.5 * (self.height - self.poly_extend_active_spacing) + + wire_start = vector( wire_x, wire_y ) + wire_end = vector(self.width, wire_y) + + if self.route_layer == 'm1': + + if self.drain_contact: + self.add_via_center(self.li_stack, [wire_x, wire_y]) + if self.source_contact: + self.add_via_center(self.li_stack, [self.width, wire_y]) + + self.add_path(self.route_layer, [wire_start, wire_end]) + + + + + + def add_nmos(self): + #used only for layout constants + self.nmos = factory.create(module_type="ptx", + tx_type="nmos" + ) + + diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/05_rom_array_test.py index 80ebc1c6..a1a3c906 100644 --- a/compiler/tests/05_rom_array_test.py +++ b/compiler/tests/05_rom_array_test.py @@ -24,7 +24,7 @@ class rom_array_test(openram_test): debug.info(2, "Testing 4x4 array for rom cell") - data = [[1, 1, 1, 1], [1, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 0]] + data = [[1, 0, 0, 0], [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 0, 1]] a = factory.create(module_type="rom_base_array", cols=4, rows=4, bitmap=data) self.local_check(a) From a3e271f6fbc05ef0635c06cd98a637772536df74 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 1 Sep 2022 20:06:48 -0700 Subject: [PATCH 32/98] reoriented cell and added tap cell --- compiler/modules/ptx.py | 7 ++- compiler/modules/rom_base_array.py | 91 ++++++++++++++++++------------ compiler/modules/rom_base_cell.py | 6 +- compiler/modules/rom_dummy_cell.py | 63 ++++++++++++--------- compiler/modules/rom_poly_tap.py | 54 ++++++++++++++++++ 5 files changed, 152 insertions(+), 69 deletions(-) create mode 100644 compiler/modules/rom_poly_tap.py diff --git a/compiler/modules/ptx.py b/compiler/modules/ptx.py index bc36f064..250cd3f6 100644 --- a/compiler/modules/ptx.py +++ b/compiler/modules/ptx.py @@ -39,7 +39,8 @@ class ptx(design): connect_drain_active=False, connect_source_active=False, connect_poly=False, - num_contacts=None): + num_contacts=None, + ): if "li" in layer: self.route_layer = "li" @@ -47,11 +48,11 @@ class ptx(design): self.route_layer = "m1" # Default contacts are the lowest layer - if not add_source_contact: + if add_source_contact == None: add_source_contact = self.route_layer # Default contacts are the lowest layer - if not add_drain_contact: + if add_drain_contact == None: add_drain_contact = self.route_layer # We need to keep unique names because outputting to GDSII diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index e86c9cd6..784e2595 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -31,15 +31,16 @@ class rom_base_array(bitcell_base_array): def create_netlist(self): self.add_modules() self.add_pins() - + self.create_instances() - + self.create_taps() def create_layout(self): #self.add_layout_pins() self.place_ptx() - - #self.route_horizontal_pins(insts=self.cell_inst.values(), layer=self.route_layer, name="S") + self.place_tap(self.column_size) + self.place_tap(0) + #self.route_horizo ntal_pins(insts=self.cell_inst.values(), layer=self.route_layer, name="S") #self.route_bitlines() #self.route_wordlines() @@ -51,63 +52,72 @@ class rom_base_array(bitcell_base_array): #def add_pins(self): def add_boundary(self): - self.width = self.cell.width * self.column_size - self.height = self.cell.height * self.row_size + self.width = self.dummy.width * self.column_size + self.height = self.dummy.height * self.row_size super().add_boundary() def add_modules(self): # base cell, nmos tx that represents a 1 - self.cell = factory.create(module_type="rom_base_cell") + self.dummy = factory.create(module_type="rom_dummy_cell", route_layer=self.route_layer) # "dummy" cells represent 0 #dummy cell with no contacts - self.dummy_nc = factory.create(module_type="rom_dummy_cell") + self.cell_nc = factory.create(module_type="rom_base_cell") #dummy cell with drain contact - self.dummy_dc = factory.create(module_type="rom_dummy_cell", drain_contact=True) + self.cell_dc = factory.create(module_type="rom_base_cell", add_drain_contact=self.route_layer) #dummy cell with source contact - self.dummy_sc = factory.create(module_type="rom_dummy_cell", source_contact=True) + self.cell_sc = factory.create(module_type="rom_base_cell", add_source_contact=self.route_layer) #dummy cell with all contacts - self.dummy_ac = factory.create(module_type="rom_dummy_cell", source_contact=True, drain_contact=True) + self.cell_ac = factory.create(module_type="rom_base_cell", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) + + self.poly_tap = factory.create(module_type="rom_poly_tap") + + + def create_taps(self): + self.tap_inst = {} + for() + + def create_instances(self): self.cell_inst = {} self.cell_list = [] self.current_row = 0 + + #When rotated correctly rows are bit lines for row in range(self.row_size): row_list = [] + + #when rotated correctly cols are word lines for col in range(self.column_size): name = "bit_r{0}_c{1}".format(row, col) if(self.data[row][col] == 1): - self.cell_inst[row, col]=self.add_inst(name=name, - mod=self.cell) - - - self.connect_inst(["vdd", "gnd", "gnd"]) - else: + if row < self.row_size - 1 and row > 0 and self.data[row + 1][col] == 0 and self.data[row - 1][col] == 0: + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_ac) - if col < self.column_size - 1 and col > 0 and self.data[row][col + 1] == 1 and self.data[row][col - 1] == 1: - - self.cell_inst[row, col]=self.add_inst(name=name, mod=self.dummy_ac) + elif row > 0 and self.data[row - 1][col] == 0: + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_sc) - elif col > 0 and self.data[row][col - 1] == 1: - self.cell_inst[row, col]=self.add_inst(name=name, mod=self.dummy_dc) - - elif col < self.column_size - 1 and self.data[row][col + 1] == 1: - - self.cell_inst[row, col]=self.add_inst(name=name, mod=self.dummy_sc) + elif row < self.row_size - 1 and self.data[row + 1][col] == 0: + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_dc) else: - self.cell_inst[row, col]=self.add_inst(name=name, mod=self.dummy_nc) - - + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_nc) + self.connect_inst(["vdd", "gnd", "gnd"]) + + else: + + self.cell_inst[row, col]=self.add_inst(name=name, + mod=self.dummy) self.connect_inst([]) + row_list.append(self.cell_inst[row, col]) self.cell_list.append(row_list) @@ -120,6 +130,19 @@ class rom_base_array(bitcell_base_array): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] + def place_tap(self, col): + + self.tap_pos = {} + for row in range(self.row_size): + + tap_x = self.dummy.width * (col_offset) + tap_y = self.dummy.height * row + + self.tap_pos[row, col] = vector(tap_x, tap_y) + self.tap_inst[row, col].place(self.tap_pos[row, col]) + + + def place_ptx(self): self.cell_pos = {} @@ -129,11 +152,11 @@ class rom_base_array(bitcell_base_array): # columns are word lines for col in range(self.column_size): - cell_x = (self.cell.width) * col - cell_y = row * (self.cell.height) + cell_x = (self.dummy.width) * col + cell_y = row * (self.dummy.height) self.cell_pos[row, col] = vector(cell_x, cell_y) - self.cell_inst[row, col].place(self.cell_pos[row, col]) + self.cell_inst[row, col].place(self.cell_pos[row, col], rotate=90) #cell_x = self.cell.width * col #cell_y = self.cell.height * row #print(self.nmos.height + self.nmos.poly_extend_active) @@ -242,7 +265,3 @@ class rom_base_array(bitcell_base_array): bitcell_pins.append("gnd") return bitcell_pins - - - - diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index 5c454619..cc9a8017 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -19,8 +19,8 @@ from tech import drc class rom_base_cell(rom_dummy_cell): - def __init__(self, name="", cell_name=None): - super().__init__(name, cell_name) + def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"): + super().__init__(name, cell_name, add_source_contact, add_drain_contact, route_layer) #self.route_layer= route_layer #self.create_netlist() #self.create_layout() @@ -52,7 +52,7 @@ class rom_base_cell(rom_dummy_cell): def create_nmos(self): self.cell_inst = self.add_inst( name=self.name, mod=self.nmos, - rotate=90) + ) self.connect_inst(["bl_h", "wl", "bl_l", "gnd"]) diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py index 0ef5c97f..6160cfb1 100644 --- a/compiler/modules/rom_dummy_cell.py +++ b/compiler/modules/rom_dummy_cell.py @@ -17,11 +17,11 @@ from tech import drc class rom_dummy_cell(design): - def __init__(self, name="", cell_name=None, source_contact=False, drain_contact=False): + def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"): super().__init__(name, cell_name) - self.route_layer = "m1" - self.source_contact=source_contact - self.drain_contact=drain_contact + self.route_layer = route_layer + self.add_source_contact=add_source_contact + self.add_drain_contact=add_drain_contact self.create_netlist() self.create_layout() @@ -42,17 +42,10 @@ class rom_dummy_cell(design): self.add_boundary() self.add_poly() self.add_metal() - #poly_offset = - # vector(0.5 * self.nmos.active_contact.width + 0.5 * self.nmos.poly_width + self.nmos.active_contact_to_gate, 0) - - #self.add_rect( layer="poly", - # offset=poly_offset, - # height=self.nmos.height + self.nmos.poly_extend_active, - # width=self.nmos.poly_width - # ) + print(self.height) + print(self.width) self.add_label("0,0", self.route_layer) - #self.add_wire( layers=self.route_layer) - #self.add_rect( layer=self.route_layer) + @@ -73,17 +66,21 @@ class rom_dummy_cell(design): self.cell_diffusion_offset = ((self.base_width - 2 * self.active_enclose_contact - self.nmos.contact_width) - drc("active_to_active")) * 0.5 + # width offset to account for poly-active spacing between base and dummy cells on the same bitline self.poly_active_offset = 0.5 * (self.base_width - 2 * self.cell_diffusion_offset - (self.poly_width + 2 * self.active_enclose_contact + self.nmos.contact_width)) - self.poly_to_active + #so that the poly taps are far enough apart + self.poly_tap_offset = (self.base_width - self.cell_diffusion_offset - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") + def add_boundary(self): - #cell height with offsets applied - self.height = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active + #cell width with offsets applied, height becomes width when the cells are rotated + self.width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active - # cell width with offsets applied, if the offsets are positive (greater than 0) they are not applied - self.width = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) + # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied + self.height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) super().add_boundary() @@ -93,22 +90,23 @@ class rom_dummy_cell(design): poly_x = 0.5 * self.nmos.contact_width + self.contact_to_gate - self.add_rect("poly", vector(poly_x, 0), self.poly_width, self.height) + self.poly = self.add_rect("poly", vector(poly_x, 0), self.poly_width, self.nmos.poly_height + self.poly_extend_active_spacing) + print(self.poly_width, self.height) def add_metal(self): wire_x = min(self.cell_diffusion_offset, 0) + min(self.poly_active_offset, 0) - wire_y = 0.5 * (self.height - self.poly_extend_active_spacing) + wire_y = 0.5 * (self.width - self.poly_extend_active_spacing) wire_start = vector( wire_x, wire_y ) - wire_end = vector(self.width, wire_y) + wire_end = vector(self.height, wire_y) - if self.route_layer == 'm1': + # if self.route_layer == 'm1': - if self.drain_contact: - self.add_via_center(self.li_stack, [wire_x, wire_y]) - if self.source_contact: - self.add_via_center(self.li_stack, [self.width, wire_y]) + # if self.drain_contact: + # self.add_via_center(self.li_stack, [wire_x, wire_y]) + # if self.source_contact: + # self.add_via_center(self.li_stack, [self.width, wire_y]) self.add_path(self.route_layer, [wire_start, wire_end]) @@ -118,8 +116,19 @@ class rom_dummy_cell(design): def add_nmos(self): #used only for layout constants + # if not self.source_contact: + # add_source = False + # else: + # add_source = self.route_layer + + # if not self.drain_contact: + # add_drain = False + # else: + # add_drain = self.route_layer self.nmos = factory.create(module_type="ptx", - tx_type="nmos" + tx_type="nmos", + add_source_contact=self.add_source_contact, + add_drain_contact=self.add_drain_contact ) diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py new file mode 100644 index 00000000..4f769eb7 --- /dev/null +++ b/compiler/modules/rom_poly_tap.py @@ -0,0 +1,54 @@ + + +from base import design +from base import vector +from sram_factory import factory + +class rom_poly_tap(design): + + def __init__(self, name, strap_length=0, cell_name=None, prop=None, strap_layer="m2"): + super().__init__(name, cell_name, prop) + self.strap_layer=strap_layer + self.length = strap_length + self.create_netlist() + self.create_layout() + + def create_netlist(self): + + + #for layout constants + self.dummy = factory.create(module_type="rom_dummy_cell") + pass + + def create_layout(self): + + self.place_via() + self.add_boundary() + if self.length < 0: + self.place_strap(self.length) + + def add_boundary(self): + self.height = self.dummy.height + self.width = self.poly_contact.width + super().add_boundary() + + def place_via(self): + + contact_width = self.poly_contact.width + + contact_x = contact_width * 0.5 + contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) + + contact_offset = vector(contact_x, contact_y) + self.via = self.add_via_stack_center(from_layer="poly", + to_layer=self.strap_layer, + offset=contact_offset) + + def place_strap(self, length): + + strap_start = vector(self.via.cx(), self.via.cy()) + + strap_end = vector( self.dummy.width * length, self.via.cy()) + + self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) + From aea3c0ad0120891dec933146c956a67f21503109 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Fri, 7 Oct 2022 14:40:28 -0700 Subject: [PATCH 33/98] passing drc/lvs on 4x4 rom array --- compiler/modules/rom_array_gnd_tap.py | 39 ++++++++ compiler/modules/rom_base_array.py | 136 ++++++++++++++++++-------- compiler/modules/rom_base_cell.py | 13 ++- compiler/modules/rom_dummy_cell.py | 9 +- compiler/modules/rom_poly_tap.py | 5 +- 5 files changed, 147 insertions(+), 55 deletions(-) create mode 100644 compiler/modules/rom_array_gnd_tap.py diff --git a/compiler/modules/rom_array_gnd_tap.py b/compiler/modules/rom_array_gnd_tap.py new file mode 100644 index 00000000..3bb3419a --- /dev/null +++ b/compiler/modules/rom_array_gnd_tap.py @@ -0,0 +1,39 @@ + + +from base import design +from base import vector +from sram_factory import factory + +class rom_array_gnd_tap(design): + + def __init__(self, name, length, cell_name=None, prop=None): + super().__init__(name, cell_name, prop) + self.length = length + self.create_layout() + + def create_layout(self): + + self.add_cell() + self.add_boundary() + self.place_gnd_rail() + + + def add_boundary(self): + self.height = self.dummy.height + self.width = self.dummy.width + super().add_boundary() + + def add_cell(self): + self.dummy = factory.create(module_type="rom_dummy_cell") + + def place_gnd_rail(self): + rail_start = vector(-self.dummy.width / 2 ,0) + rail_end = vector(self.dummy.width * self.length, 0) + + self.add_layout_pin_rect_ends( name="gnd", + layer="m1", + start=rail_start, + end=rail_end) + + + diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 784e2595..a347ac78 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -15,12 +15,13 @@ from sram_factory import factory class rom_base_array(bitcell_base_array): - def __init__(self, rows, cols, bitmap, name="", column_offset=0): + def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0): super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset) #TODO: data is input in col-major order for ease of parsing, create a function to convert a row-major input to col-major self.data = bitmap self.route_layer = 'm1' + self.strap_spacing = strap_spacing self.create_all_bitline_names() self.create_all_wordline_names() self.create_netlist() @@ -33,22 +34,20 @@ class rom_base_array(bitcell_base_array): self.add_pins() self.create_instances() - self.create_taps() + def create_layout(self): #self.add_layout_pins() self.place_ptx() - self.place_tap(self.column_size) - self.place_tap(0) + self.place_taps() + self.place_rails() #self.route_horizo ntal_pins(insts=self.cell_inst.values(), layer=self.route_layer, name="S") #self.route_bitlines() #self.route_wordlines() - self.route_supplies() - self.add_boundary() - #self.DRC_LVS() + #def add_pins(self): def add_boundary(self): @@ -58,67 +57,103 @@ class rom_base_array(bitcell_base_array): def add_modules(self): - # base cell, nmos tx that represents a 1 + # dummy cell, # "dummy" cells represent 0 self.dummy = factory.create(module_type="rom_dummy_cell", route_layer=self.route_layer) - # "dummy" cells represent 0 - - #dummy cell with no contacts - self.cell_nc = factory.create(module_type="rom_base_cell") - #dummy cell with drain contact - self.cell_dc = factory.create(module_type="rom_base_cell", add_drain_contact=self.route_layer) - #dummy cell with source contact - self.cell_sc = factory.create(module_type="rom_base_cell", add_source_contact=self.route_layer) - #dummy cell with all contacts - self.cell_ac = factory.create(module_type="rom_base_cell", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) - - self.poly_tap = factory.create(module_type="rom_poly_tap") - - - def create_taps(self): - self.tap_inst = {} - for() + + #base cell with no contacts + self.cell_nc = factory.create(module_name="base_mod_0_contact", module_type="rom_base_cell") + #base cell with drain contact + self.cell_dc = factory.create(module_name="base_mod_d_contact", module_type="rom_base_cell", add_drain_contact=self.route_layer) + #base cell with source contact + self.cell_sc = factory.create(module_name="base_mod_s_contact", module_type="rom_base_cell", add_source_contact=self.route_layer) + #base cell with all contacts + self.cell_ac = factory.create(module_name="base_mod_sd_contact", module_type="rom_base_cell", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) + + self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing) + self.gnd_rail = factory.create(module_type="rom_array_gnd_tap", length=self.row_size) def create_instances(self): + self.tap_inst = {} self.cell_inst = {} self.cell_list = [] self.current_row = 0 - - #When rotated correctly rows are bit lines + + #list of current bitline interconnect nets, starts as the same as the bitline list and is updated when new insts of cells are added + int_bl_list = self.bitline_names[0] + #When rotated correctly rows are word lines for row in range(self.row_size): row_list = [] - - #when rotated correctly cols are word lines + #when rotated correctly cols are bit lines for col in range(self.column_size): name = "bit_r{0}_c{1}".format(row, col) - if(self.data[row][col] == 1): - - if row < self.row_size - 1 and row > 0 and self.data[row + 1][col] == 0 and self.data[row - 1][col] == 0: + if self.data[row][col] == 1: + # if dummy/0 cell above and below a 1, add a tx with contacts on both drain and source + # if the first row and a 0 above, add both contacts + # if the last row and 0 below add both contacts + #(row == 0 and self.data[row + 1][col] == 0): + if (row < self.row_size - 1 and row > 0 and self.data[row + 1][col] == 0 and self.data[row - 1][col] == 0) or \ + (row == self.row_size - 1 and self.data[row - 1][col] == 0): + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_ac) - - elif row > 0 and self.data[row - 1][col] == 0: + + # if dummy/0 is below and not above, add a source contact + # if in the first row, add a source contact + elif (row > 0 and self.data[row - 1][col] == 0): self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_sc) - elif row < self.row_size - 1 and self.data[row + 1][col] == 0: + elif (row < self.row_size - 1 and self.data[row + 1][col] == 0) or \ + (row == self.row_size - 1): self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_dc) else: self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_nc) + + + if row == self.row_size - 1 or self.get_next_cell_in_bl(row, col) == -1: + print(self.cell_inst[row, col]) + bl_l = int_bl_list[col] + bl_h = "gnd" + else: + bl_l = int_bl_list[col] + int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) + bl_h = int_bl_list[col] + + + + self.connect_inst([bl_h, bl_l, self.wordline_names[0][row], "gnd"]) - self.connect_inst(["vdd", "gnd", "gnd"]) else: self.cell_inst[row, col]=self.add_inst(name=name, mod=self.dummy) self.connect_inst([]) + + # when col = 0 bl_h is connected to vdd, otherwise connect to previous bl connection + # when col = col_size - 1 connected to gnd otherwise create new bl connection + # + row_list.append(self.cell_inst[row, col]) + + if col % self.strap_spacing == 0: + + name = "tap_r{0}_c{1}".format(row, col) + + self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) + self.connect_inst([]) + + name = "tap_r{0}_c{1}".format(row, self.column_size) + #print(*row_list) + self.tap_inst[row, self.column_size]=self.add_inst(name=name, mod=self.poly_tap) + self.connect_inst([]) + self.cell_list.append(row_list) @@ -130,19 +165,38 @@ class rom_base_array(bitcell_base_array): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - def place_tap(self, col): + def place_taps(self): self.tap_pos = {} for row in range(self.row_size): + for s_col in range(0, self.column_size, self.strap_spacing): + col = s_col * self.strap_spacing - tap_x = self.dummy.width * (col_offset) + tap_x = self.dummy.width * col + tap_y = self.dummy.height * row + + self.tap_pos[row, col] = vector(tap_x, tap_y) + self.tap_inst[row, col].place(self.tap_pos[row, col]) + tap_x = self.dummy.width * self.column_size + self.poly_tap.width tap_y = self.dummy.height * row - self.tap_pos[row, col] = vector(tap_x, tap_y) - self.tap_inst[row, col].place(self.tap_pos[row, col]) - + self.tap_pos[row, self.column_size] = vector(tap_x, tap_y) + self.tap_inst[row, self.column_size].place(self.tap_pos[row, self.column_size]) + offset=vector(0, 0), + + def place_rails(self): + + #self.gnd_rail_inst = self.add_inst(name="gnd", mod=self.gnd_rail) + #self.connect_inst([]) + print (self.mcon_width) + rail_start = vector(-self.dummy.width / 2 , self.cell_inst[self.row_size - 1,0].uy() ) + rail_end = vector(self.dummy.height * (self.row_size ), self.cell_inst[self.row_size - 1,0].uy()) + self.add_layout_pin_rect_ends( name="gnd", + layer="m1", + start=rail_start, + end=rail_end) def place_ptx(self): self.cell_pos = {} diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index cc9a8017..1f7169ff 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -42,20 +42,19 @@ class rom_base_cell(rom_dummy_cell): print(self.height) print(self.width) - def add_pins(self): - pin_list = ["bl_h", "bl_l", "wl"] - dir_list = ["INOUT", "GROUND", "INPUT"] - - self.add_pin_list(pin_list, dir_list) - def create_nmos(self): - self.cell_inst = self.add_inst( name=self.name, + self.cell_inst = self.add_inst( name=self.name + "_nmos", mod=self.nmos, ) self.connect_inst(["bl_h", "wl", "bl_l", "gnd"]) + def add_pins(self): + pin_list = ["bl_h", "bl_l", "wl", "gnd"] + dir_list = ["INOUT", "INOUT", "INPUT", "GROUND"] + + self.add_pin_list(pin_list, dir_list) def place_nmos(self): diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py index 6160cfb1..67384a83 100644 --- a/compiler/modules/rom_dummy_cell.py +++ b/compiler/modules/rom_dummy_cell.py @@ -29,10 +29,9 @@ class rom_dummy_cell(design): #creates nmos for layout dimensions self.add_nmos() - #set height and width such that the cell will tile perfectly by only ofsetting in the array by its width and height - + def create_layout(self): @@ -47,6 +46,7 @@ class rom_dummy_cell(design): self.add_label("0,0", self.route_layer) + # Calculates offsets of cell width and height so that tiling of cells does not violate any drc rules @@ -95,11 +95,11 @@ class rom_dummy_cell(design): def add_metal(self): - wire_x = min(self.cell_diffusion_offset, 0) + min(self.poly_active_offset, 0) + wire_x = min(self.cell_diffusion_offset, 0) + min(self.poly_active_offset, 0) - self.mcon_width * 0.5 wire_y = 0.5 * (self.width - self.poly_extend_active_spacing) wire_start = vector( wire_x, wire_y ) - wire_end = vector(self.height, wire_y) + wire_end = vector(self.height + self.mcon_width * 0.5, wire_y) # if self.route_layer == 'm1': @@ -126,6 +126,7 @@ class rom_dummy_cell(design): # else: # add_drain = self.route_layer self.nmos = factory.create(module_type="ptx", + module_name="nmos_rom_mod", tx_type="nmos", add_source_contact=self.add_source_contact, add_drain_contact=self.add_drain_contact diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index 4f769eb7..662a2437 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -18,13 +18,12 @@ class rom_poly_tap(design): #for layout constants self.dummy = factory.create(module_type="rom_dummy_cell") - pass def create_layout(self): self.place_via() self.add_boundary() - if self.length < 0: + if self.length != 0: self.place_strap(self.length) def add_boundary(self): @@ -36,7 +35,7 @@ class rom_poly_tap(design): contact_width = self.poly_contact.width - contact_x = contact_width * 0.5 + contact_x = - contact_width * 0.5 - self.dummy.width contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) contact_offset = vector(contact_x, contact_y) From bc8d564dbf1505e375eb7c4c7d00b72595f6b5a2 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Sat, 15 Oct 2022 14:40:04 -0700 Subject: [PATCH 34/98] array with poly straps passing drc/lvs --- compiler/modules/rom_base_array.py | 139 +++++++++++++++------------- compiler/modules/rom_base_cell.py | 2 +- compiler/modules/rom_poly_tap.py | 8 +- compiler/tests/05_rom_array_test.py | 5 +- 4 files changed, 84 insertions(+), 70 deletions(-) diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index a347ac78..1a76e431 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -7,7 +7,7 @@ # - +import math from .bitcell_base_array import bitcell_base_array from base import vector from globals import OPTS @@ -16,12 +16,17 @@ from sram_factory import factory class rom_base_array(bitcell_base_array): def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0): + + super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset) #TODO: data is input in col-major order for ease of parsing, create a function to convert a row-major input to col-major self.data = bitmap self.route_layer = 'm1' self.strap_spacing = strap_spacing + self.data_col_size = self.column_size + self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing) + self.create_all_bitline_names() self.create_all_wordline_names() self.create_netlist() @@ -37,11 +42,8 @@ class rom_base_array(bitcell_base_array): def create_layout(self): - #self.add_layout_pins() - self.place_ptx() - self.place_taps() + self.place_array() self.place_rails() - #self.route_horizo ntal_pins(insts=self.cell_inst.values(), layer=self.route_layer, name="S") #self.route_bitlines() #self.route_wordlines() @@ -72,6 +74,8 @@ class rom_base_array(bitcell_base_array): self.cell_ac = factory.create(module_name="base_mod_sd_contact", module_type="rom_base_cell", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing) + + self.zero_tap = factory.create(module_type="rom_poly_tap", strap_length=0) self.gnd_rail = factory.create(module_type="rom_array_gnd_tap", length=self.row_size) @@ -87,27 +91,39 @@ class rom_base_array(bitcell_base_array): for row in range(self.row_size): row_list = [] + # for each new strap placed, offset the column index refrenced to get correct bit in the data array + strap_offset = 0 #when rotated correctly cols are bit lines - for col in range(self.column_size): + for col in range(self.array_col_size): name = "bit_r{0}_c{1}".format(row, col) + + data_col = col - strap_offset + if col % self.strap_spacing == 0: - if self.data[row][col] == 1: + name = "tap_r{0}_c{1}".format(row, col) + print("tap instance added at c{0}, r{1}".format(col, row)) + self.cell_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) + self.connect_inst([]) + strap_offset += 1 + continue + + if self.data[row][data_col] == 1: # if dummy/0 cell above and below a 1, add a tx with contacts on both drain and source # if the first row and a 0 above, add both contacts # if the last row and 0 below add both contacts #(row == 0 and self.data[row + 1][col] == 0): - if (row < self.row_size - 1 and row > 0 and self.data[row + 1][col] == 0 and self.data[row - 1][col] == 0) or \ - (row == self.row_size - 1 and self.data[row - 1][col] == 0): + if (row < self.row_size - 1 and row > 0 and self.data[row + 1][data_col] == 0 and self.data[row - 1][data_col] == 0) or \ + (row == self.row_size - 1 and self.data[row - 1][data_col] == 0): self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_ac) # if dummy/0 is below and not above, add a source contact # if in the first row, add a source contact - elif (row > 0 and self.data[row - 1][col] == 0): + elif (row > 0 and self.data[row - 1][data_col] == 0): self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_sc) - elif (row < self.row_size - 1 and self.data[row + 1][col] == 0) or \ + elif (row < self.row_size - 1 and self.data[row + 1][data_col] == 0) or \ (row == self.row_size - 1): self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_dc) @@ -115,14 +131,14 @@ class rom_base_array(bitcell_base_array): self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_nc) - if row == self.row_size - 1 or self.get_next_cell_in_bl(row, col) == -1: - print(self.cell_inst[row, col]) - bl_l = int_bl_list[col] + if row == self.row_size - 1 or self.get_next_cell_in_bl(row, data_col) == -1: + + bl_l = int_bl_list[data_col] bl_h = "gnd" else: - bl_l = int_bl_list[col] - int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) - bl_h = int_bl_list[col] + bl_l = int_bl_list[data_col] + int_bl_list[data_col] = "bl_int_{0}_{1}".format(row, data_col) + bl_h = int_bl_list[data_col] @@ -136,22 +152,17 @@ class rom_base_array(bitcell_base_array): self.connect_inst([]) # when col = 0 bl_h is connected to vdd, otherwise connect to previous bl connection - # when col = col_size - 1 connected to gnd otherwise create new bl connection + # when col = col_size - 1 connected column_sizeto gnd otherwise create new bl connection # row_list.append(self.cell_inst[row, col]) - if col % self.strap_spacing == 0: - - name = "tap_r{0}_c{1}".format(row, col) - - self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) - self.connect_inst([]) - name = "tap_r{0}_c{1}".format(row, self.column_size) + + name = "tap_r{0}_c{1}".format(row, self.array_col_size) #print(*row_list) - self.tap_inst[row, self.column_size]=self.add_inst(name=name, mod=self.poly_tap) + self.cell_inst[row, self.array_col_size]=self.add_inst(name=name, mod=self.zero_tap) self.connect_inst([]) self.cell_list.append(row_list) @@ -169,9 +180,9 @@ class rom_base_array(bitcell_base_array): self.tap_pos = {} for row in range(self.row_size): - for s_col in range(0, self.column_size, self.strap_spacing): - col = s_col * self.strap_spacing + for col in range(0, self.column_size, self.strap_spacing): + tap_x = self.dummy.width * col tap_y = self.dummy.height * row @@ -182,58 +193,58 @@ class rom_base_array(bitcell_base_array): self.tap_pos[row, self.column_size] = vector(tap_x, tap_y) self.tap_inst[row, self.column_size].place(self.tap_pos[row, self.column_size]) - offset=vector(0, 0), + def place_rails(self): - #self.gnd_rail_inst = self.add_inst(name="gnd", mod=self.gnd_rail) - #self.connect_inst([]) - print (self.mcon_width) - rail_start = vector(-self.dummy.width / 2 , self.cell_inst[self.row_size - 1,0].uy() ) - rail_end = vector(self.dummy.height * (self.row_size ), self.cell_inst[self.row_size - 1,0].uy()) + rail_y = self.dummy.height * (self.row_size) + self.mcon_width * 0.5 + start_x = self.cell_inst[self.row_size - 1, 0].rx() + end_x = self.cell_inst[self.row_size - 1, self.array_col_size - 1].cx() + #self.dummy.height * self.row_size + #self.cell_inst[self.row_size - 1,0].uy() + rail_start = vector(start_x , rail_y) + rail_end = vector(end_x, rail_y) self.add_layout_pin_rect_ends( name="gnd", layer="m1", start=rail_start, end=rail_end) - def place_ptx(self): + def place_array(self): self.cell_pos = {} - - # rows are bitlines + + # rows are wordlines for row in range(self.row_size): - # columns are word lines - for col in range(self.column_size): + + strap_cols = -1 + cell_y = row * (self.dummy.height) + + # columns are bit lines + for col in range(self.array_col_size): - cell_x = (self.dummy.width) * col - cell_y = row * (self.dummy.height) + if col % self.strap_spacing == 0: + strap_cols += 1 + rot = 0 + else: + rot = 90 + + bit_cols = col - strap_cols + + if col == 0: + cell_x = 0 + else: + cell_x = (self.dummy.width * bit_cols) + (self.poly_tap.width * strap_cols) self.cell_pos[row, col] = vector(cell_x, cell_y) - self.cell_inst[row, col].place(self.cell_pos[row, col], rotate=90) - #cell_x = self.cell.width * col - #cell_y = self.cell.height * row - #print(self.nmos.height + self.nmos.poly_extend_active) - if(self.data[row][col] == 1): + self.cell_inst[row, col].place(self.cell_pos[row, col], rotate=rot) - pass - - - - - #self.add_label("S_{}_{}".format(row,col), self.route_layer, self.cell_inst[row, col].center()) - #self.add_label("D", self.route_layer, self.cell_inst[row, col].center()) - - #else: - - #poly_offset = (self.nmos.contact_offset + vector(0.5 * self.nmos.active_contact.width + 0.5 * self.nmos.poly_width + self.nmos.active_contact_to_gate, 0)) + (0, cell_y) - #poly_offset = (cell_x, cell_y) - #print(cell_x,cell_y) - #self.add_rect(layer="poly", - # offset=poly_offset, - # width=self.nmos.height + self.nmos.poly_extend_active, - # height=self.nmos.poly_width - # ) + strap_cols += 1 + bit_cols = self.array_col_size - strap_cols + cell_x = (self.dummy.width * bit_cols) + (self.poly_tap.width * strap_cols) + self.cell_pos[row, self.array_col_size] = vector(cell_x, cell_y) + self.cell_inst[row, self.array_col_size].place(self.cell_pos[row, self.array_col_size]) + diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index 1f7169ff..8c0ce4e2 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -68,7 +68,7 @@ class rom_base_cell(rom_dummy_cell): self.add_rect("poly", poly_offset, self.nmos.poly_width, self.poly_extend_active_spacing ) self.cell_inst.place(nmos_offset) - + self.add_label("CELL ZERO", self.route_layer) self.add_label("S", self.route_layer, self.cell_inst.get_pin("S").center()) self.add_label("D", self.route_layer, self.cell_inst.get_pin("D").center()) diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index 662a2437..765a0e17 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -28,14 +28,14 @@ class rom_poly_tap(design): def add_boundary(self): self.height = self.dummy.height - self.width = self.poly_contact.width + self.width = self.poly_contact.width super().add_boundary() def place_via(self): contact_width = self.poly_contact.width - contact_x = - contact_width * 0.5 - self.dummy.width + contact_x = - contact_width * 0.5 contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) contact_offset = vector(contact_x, contact_y) @@ -43,11 +43,13 @@ class rom_poly_tap(design): to_layer=self.strap_layer, offset=contact_offset) + self.add_label("ZERO", "poly") + def place_strap(self, length): strap_start = vector(self.via.cx(), self.via.cy()) - strap_end = vector( self.dummy.width * length, self.via.cy()) + strap_end = vector( self.dummy.width * (length - 1) + self.m2_width, self.via.cy()) self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/05_rom_array_test.py index a1a3c906..fe75d054 100644 --- a/compiler/tests/05_rom_array_test.py +++ b/compiler/tests/05_rom_array_test.py @@ -24,9 +24,10 @@ class rom_array_test(openram_test): debug.info(2, "Testing 4x4 array for rom cell") - data = [[1, 0, 0, 0], [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 0, 1]] - a = factory.create(module_type="rom_base_array", cols=4, rows=4, bitmap=data) + data = [[1, 0, 0, 0, 0, 1, 0, 0, 1], [0, 1, 1, 1, 0, 1, 0, 0, 1], [1, 0, 1, 1, 0, 1, 0, 0, 1], [1, 1, 0, 1, 1, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 0, 0, 1], [0, 1, 1, 1, 1, 0, 0, 0, 1], [1, 0, 1, 1, 1, 0, 0, 0, 1], [1, 1, 0, 0, 1, 1, 0, 0, 1]] + + a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4) self.local_check(a) globals.end_openram() From 63925bd48efae2931dc4050d9a59e25f25790c5a Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Fri, 9 Dec 2022 14:25:11 -0800 Subject: [PATCH 35/98] Decoder array and start of rom bank --- compiler/modules/rom_base_array.py | 310 +++++++++++------- compiler/modules/rom_base_bank.py | 177 ++++++++++ compiler/modules/rom_base_cell.py | 39 ++- compiler/modules/rom_decoder.py | 249 ++++++++++++++ compiler/modules/rom_dummy_cell.py | 39 ++- compiler/modules/rom_inv_array.py | 130 ++++++++ compiler/modules/rom_poly_tap.py | 70 +++- compiler/modules/rom_precharge_array.py | 201 ++++++++++++ compiler/modules/rom_precharge_cell.py | 107 ++++++ compiler/tests/05_rom_array_test.py | 1 - compiler/tests/05_rom_base_bank_test.py | 37 +++ compiler/tests/05_rom_decoder_test.py | 37 +++ compiler/tests/05_rom_precharge_array_test.py | 37 +++ 13 files changed, 1261 insertions(+), 173 deletions(-) create mode 100644 compiler/modules/rom_base_bank.py create mode 100644 compiler/modules/rom_decoder.py create mode 100644 compiler/modules/rom_inv_array.py create mode 100644 compiler/modules/rom_precharge_array.py create mode 100644 compiler/modules/rom_precharge_cell.py create mode 100644 compiler/tests/05_rom_base_bank_test.py create mode 100644 compiler/tests/05_rom_decoder_test.py create mode 100644 compiler/tests/05_rom_precharge_array_test.py diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 1a76e431..1602a92b 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -12,25 +12,27 @@ from .bitcell_base_array import bitcell_base_array from base import vector from globals import OPTS from sram_factory import factory +import tech +from tech import drc class rom_base_array(bitcell_base_array): - def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0): - + def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0, route_layer="li", output_layer="m2"): super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset) - - #TODO: data is input in col-major order for ease of parsing, create a function to convert a row-major input to col-major - self.data = bitmap - self.route_layer = 'm1' - self.strap_spacing = strap_spacing - self.data_col_size = self.column_size - self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing) + self.data = bitmap + self.route_layer = route_layer + self.output_layer = output_layer + self.strap_spacing = strap_spacing + self.data_col_size = self.column_size + if strap_spacing != 0: + self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing) + else: + self.array_col_size = self.column_size self.create_all_bitline_names() self.create_all_wordline_names() self.create_netlist() - self.create_layout() @@ -38,31 +40,44 @@ class rom_base_array(bitcell_base_array): self.add_modules() self.add_pins() - self.create_instances() + self.create_cell_instances() + self.create_precharge_inst() def create_layout(self): self.place_array() + self.place_wordline_contacts() + self.place_bitline_contacts() + self.place_precharge() self.place_rails() - #self.route_bitlines() - #self.route_wordlines() + self.route_precharge() + self.add_boundary() + self.add_label("ARRAY ZERO", self.route_layer) + self.add_label("array height", self.route_layer, [0, self.height]) #def add_pins(self): def add_boundary(self): - self.width = self.dummy.width * self.column_size - self.height = self.dummy.height * self.row_size - super().add_boundary() - - def add_modules(self): - - # dummy cell, # "dummy" cells represent 0 - self.dummy = factory.create(module_type="rom_dummy_cell", route_layer=self.route_layer) + ll = self.find_lowest_coords() + bottom_offset = - self.dummy.nmos.end_to_contact + self.precharge_inst.offset.y + m1_offset = self.m1_width + self.translate_all(vector(0, ll.y + 0.5 * m1_offset)) + ur = self.find_highest_coords() + + ur = vector(ur.x, ur.y - self.m1_width) + #super().add_boundary(ll=vector(lowerx, lowery), ur=vector(upperx, uppery)) + super().add_boundary(vector(0, 0), ur) + self.width = ur.x + self.height = ur.y + def add_modules(self): + + # dummy cell, "dummy" cells represent 0 + self.dummy = factory.create(module_type="rom_dummy_cell", route_layer=self.route_layer) #base cell with no contacts self.cell_nc = factory.create(module_name="base_mod_0_contact", module_type="rom_base_cell") @@ -77,14 +92,24 @@ class rom_base_array(bitcell_base_array): self.zero_tap = factory.create(module_type="rom_poly_tap", strap_length=0) - self.gnd_rail = factory.create(module_type="rom_array_gnd_tap", length=self.row_size) - def create_instances(self): + self.precharge_array = factory.create(module_type="rom_precharge_array", cols=self.column_size, strap_spacing=self.strap_spacing, route_layer=self.route_layer) + + + def add_pins(self): + for bl_name in self.get_bitline_names(): + self.add_pin(bl_name, "INOUT") + for wl_name in self.get_wordline_names(): + self.add_pin(wl_name, "INPUT") + self.add_pin("precharge_gate", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def create_cell_instances(self): self.tap_inst = {} self.cell_inst = {} self.cell_list = [] self.current_row = 0 - #list of current bitline interconnect nets, starts as the same as the bitline list and is updated when new insts of cells are added int_bl_list = self.bitline_names[0] #When rotated correctly rows are word lines @@ -93,62 +118,61 @@ class rom_base_array(bitcell_base_array): # for each new strap placed, offset the column index refrenced to get correct bit in the data array strap_offset = 0 - #when rotated correctly cols are bit lines - for col in range(self.array_col_size): + # when rotated correctly cols are bit lines + for col in range(self.column_size): - name = "bit_r{0}_c{1}".format(row, col) - - data_col = col - strap_offset if col % self.strap_spacing == 0: name = "tap_r{0}_c{1}".format(row, col) - print("tap instance added at c{0}, r{1}".format(col, row)) - self.cell_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) + #print("tap instance added at c{0}, r{1}".format(col, row)) + self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) self.connect_inst([]) strap_offset += 1 - continue + + name = "bit_r{0}_c{1}".format(row, col) - if self.data[row][data_col] == 1: + if self.data[row][col] == 1: # if dummy/0 cell above and below a 1, add a tx with contacts on both drain and source # if the first row and a 0 above, add both contacts # if the last row and 0 below add both contacts - #(row == 0 and self.data[row + 1][col] == 0): - if (row < self.row_size - 1 and row > 0 and self.data[row + 1][data_col] == 0 and self.data[row - 1][data_col] == 0) or \ - (row == self.row_size - 1 and self.data[row - 1][data_col] == 0): + if (row < self.row_size - 1 and row > 0 and self.data[row + 1][col] == 0 and self.data[row - 1][col] == 0) or \ + (row == self.row_size - 1 and self.data[row - 1][col] == 0) or \ + (row == 0 and self.data[row + 1][col] == 0): + + new_inst = self.add_inst(name=name, mod=self.cell_ac) - self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_ac) # if dummy/0 is below and not above, add a source contact # if in the first row, add a source contact - elif (row > 0 and self.data[row - 1][data_col] == 0): - self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_sc) + elif (row > 0 and self.data[row - 1][col] == 0) or \ + (row == 0): - elif (row < self.row_size - 1 and self.data[row + 1][data_col] == 0) or \ + new_inst=self.add_inst(name=name, mod=self.cell_sc) + + elif (row < self.row_size - 1 and self.data[row + 1][col] == 0) or \ (row == self.row_size - 1): - self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_dc) + new_inst=self.add_inst(name=name, mod=self.cell_dc) else: - self.cell_inst[row, col]=self.add_inst(name=name, mod=self.cell_nc) + new_inst=self.add_inst(name=name, mod=self.cell_nc) - - if row == self.row_size - 1 or self.get_next_cell_in_bl(row, data_col) == -1: + if row == self.row_size - 1 or self.get_next_cell_in_bl(row, col) == -1: - bl_l = int_bl_list[data_col] + bl_l = int_bl_list[col] bl_h = "gnd" else: - bl_l = int_bl_list[data_col] - int_bl_list[data_col] = "bl_int_{0}_{1}".format(row, data_col) - bl_h = int_bl_list[data_col] + bl_l = int_bl_list[col] + int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) + bl_h = int_bl_list[col] - + self.cell_inst[row, col] = new_inst self.connect_inst([bl_h, bl_l, self.wordline_names[0][row], "gnd"]) else: - - self.cell_inst[row, col]=self.add_inst(name=name, - mod=self.dummy) + new_inst = self.add_inst(name=name, mod=self.dummy) + self.cell_inst[row, col] = new_inst self.connect_inst([]) # when col = 0 bl_h is connected to vdd, otherwise connect to previous bl connection @@ -156,18 +180,30 @@ class rom_base_array(bitcell_base_array): # - row_list.append(self.cell_inst[row, col]) + row_list.append(new_inst) name = "tap_r{0}_c{1}".format(row, self.array_col_size) #print(*row_list) - self.cell_inst[row, self.array_col_size]=self.add_inst(name=name, mod=self.zero_tap) + self.tap_inst[row, self.column_size]=self.add_inst(name=name, mod=self.zero_tap) self.connect_inst([]) self.cell_list.append(row_list) + def create_precharge_inst(self): + prechrg_pins = [] + + for bl in range(self.column_size): + prechrg_pins.append(self.bitline_names[0][bl]) + + prechrg_pins.append("precharge_gate") + prechrg_pins.append("vdd") + self.precharge_inst = self.add_inst(name="decode_array_precharge", mod=self.precharge_array) + self.connect_inst(prechrg_pins) + + def create_all_bitline_names(self): for col in range(self.column_size): @@ -176,110 +212,138 @@ class rom_base_array(bitcell_base_array): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - def place_taps(self): - - self.tap_pos = {} - for row in range(self.row_size): - for col in range(0, self.column_size, self.strap_spacing): - - - tap_x = self.dummy.width * col - tap_y = self.dummy.height * row - - self.tap_pos[row, col] = vector(tap_x, tap_y) - self.tap_inst[row, col].place(self.tap_pos[row, col]) - tap_x = self.dummy.width * self.column_size + self.poly_tap.width - tap_y = self.dummy.height * row - - self.tap_pos[row, self.column_size] = vector(tap_x, tap_y) - self.tap_inst[row, self.column_size].place(self.tap_pos[row, self.column_size]) - def place_rails(self): + + width = drc("minwidth_" + self.route_layer) + drc_rule = "{0}_to_{0}".format(self.route_layer) + spacing = drc(drc_rule) - rail_y = self.dummy.height * (self.row_size) + self.mcon_width * 0.5 - start_x = self.cell_inst[self.row_size - 1, 0].rx() - end_x = self.cell_inst[self.row_size - 1, self.array_col_size - 1].cx() + rail_y = self.cell_list[self.row_size - 1][0].offset.y + self.dummy.base_width + spacing + # self.dummy.height * (self.row_size) + start_x = self.get_pin(self.bitline_names[0][0]).cx() + # self.cell_list[self.row_size - 1][0].offset.x + end_x = self.get_pin(self.bitline_names[0][self.column_size - 1]).cx() + # self.cell_list[self.row_size - 1][self.column_size - 1].offset.x #self.dummy.height * self.row_size #self.cell_inst[self.row_size - 1,0].uy() rail_start = vector(start_x , rail_y) rail_end = vector(end_x, rail_y) - self.add_layout_pin_rect_ends( name="gnd", + self.gnd = self.add_layout_pin_rect_ends( name="gnd", layer="m1", start=rail_start, end=rail_end) + for bl in range(self.column_size): + drain_pin = self.cell_list[self.row_size - 1][bl].get_pin("D") + via_pos = vector(drain_pin.cx(), rail_y) + self.add_segment_center(self.route_layer, drain_pin.center(), via_pos) + + + self.add_via_stack_center(via_pos, self.route_layer, "m1", ["H", "V"]) + + prechrg_vdd = self.precharge_inst.get_pin("vdd") + + def place_array(self): self.cell_pos = {} - + self.strap_pos = {} # rows are wordlines for row in range(self.row_size): - strap_cols = -1 + # strap_cols = -1 + cell_y = row * (self.dummy.height) - # columns are bit lines - for col in range(self.array_col_size): - + cell_x = 0 + + for col in range(self.column_size): + if col % self.strap_spacing == 0: - strap_cols += 1 - rot = 0 - else: - rot = 90 - - bit_cols = col - strap_cols - - if col == 0: - cell_x = 0 - else: - cell_x = (self.dummy.width * bit_cols) + (self.poly_tap.width * strap_cols) - + self.strap_pos[row, col] = vector(cell_x, cell_y) + self.tap_inst[row, col].place(self.strap_pos[row, col]) + cell_x += self.poly_tap.width + self.cell_pos[row, col] = vector(cell_x, cell_y) - self.cell_inst[row, col].place(self.cell_pos[row, col], rotate=rot) + self.cell_inst[row, col].place(self.cell_pos[row, col]) + cell_x += self.dummy.width + self.add_label("debug", "li", self.cell_pos[row, col]) - strap_cols += 1 - bit_cols = self.array_col_size - strap_cols - cell_x = (self.dummy.width * bit_cols) + (self.poly_tap.width * strap_cols) - self.cell_pos[row, self.array_col_size] = vector(cell_x, cell_y) - self.cell_inst[row, self.array_col_size].place(self.cell_pos[row, self.array_col_size]) - + + self.strap_pos[row, self.column_size] = vector(cell_x, cell_y) + self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size]) + + + # tap_pin = self.cell_inst[row, self.array_col_size].get_pin("poly_tap").center() + # self.add_layout_pin_rect_center("wl{}".format(row), "m2", tap_pin) + + + def place_precharge(self): + + self.precharge_offset = vector(0, - self.precharge_inst.height - self.dummy.nmos.end_to_contact - 2 * drc["nwell_enclose_active"]) + + self.precharge_inst.place(offset=self.precharge_offset) + + self.copy_layout_pin(self.precharge_inst, "vdd") + + + def place_wordline_contacts(self): + + width = drc["minwidth_{}".format(self.route_layer)] + + height = drc["minwidth_{}".format(self.route_layer)] + + offset = vector(self.poly_contact.width * 0.5, self.dummy.poly.offset.y) + + for wl in range(self.row_size): + + poly_via = self.tap_inst[wl, 0].get_pin("via") + self.copy_layout_pin(self.tap_inst[wl, 0], "via", self.wordline_names[0][wl]) + self.add_via_stack_center(poly_via.center(), "m1", self.output_layer) + + corrected_offset = offset - vector(0.5 * width, 0.5 * height) + # self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.dummy.height, length=None) + + def place_bitline_contacts(self): + + src_pin = self.cell_nc.source_pos + + for bl in range(self.column_size): - def route_bitlines(self): + # self.copy_layout_pin(self.cell_list[0][bl], "S", self.bitline_names[0][bl]) - #get first nmos in col + src_pin = self.cell_list[0][bl].get_pin("S") + prechg_pin_name = "pre_bl{0}_out".format(bl) + pre_pin = self.precharge_inst.get_pin(prechg_pin_name) - #connect to main bitline wire + + # offset = src_pin_offset + vector(src_pin.x, 0) + - #get next nmos in col + middle_offset = (pre_pin.cy() - src_pin.cy()) * 0.5 - #route source to drain + corrected = vector(src_pin.cx(), src_pin.cy() - middle_offset) + self.add_via_stack_center(corrected, self.route_layer, self.output_layer) + self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, corrected ) - #loop + + # self.gnd[0].y() - for col in range(self.column_size): - for row in range(self.row_size ): - - #nmos at this position and another nmos further down - if self.data[row][col] == 1 : - - next_row = self.get_next_cell_in_bl(row, col) - if next_row != -1: - - drain_pin = self.cell_inst[row, col].get_pin("D") - source_pin = self.cell_inst[next_row, col].get_pin("S") - - source_pos = source_pin.bc() - drain_pos = drain_pin.bc() - self.add_path(self.route_layer, [drain_pos, source_pos]) - - + def route_precharge(self): + for bl in range(self.column_size): + bl_pin = self.cell_list[0][bl].get_pin("S") + prechg_pin = "pre_bl{0}_out".format(bl) + pre_out_pin = self.precharge_inst.get_pin(prechg_pin) + bl_start = bl_pin.center() + bl_end = vector(bl_start.x, pre_out_pin.cy()) + self.add_segment_center(self.route_layer, bl_start, bl_end) def get_next_cell_in_bl(self, row_start, col): for row in range(row_start + 1, self.row_size): diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py new file mode 100644 index 00000000..b9cb090e --- /dev/null +++ b/compiler/modules/rom_base_bank.py @@ -0,0 +1,177 @@ + +import math +from base import vector +from base import design +from globals import OPTS +from sram_factory import factory +import tech +from tech import drc + +class rom_base_bank(design): + + def __init__(self, strap_spacing=0, data_file=None, name="") -> None: + self.rows = 4 + self.cols = 4 + self.num_inputs = 2 + self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] + self.strap_spacing = strap_spacing + self.route_layer = "li" + self.bus_layer = "m1" + self.interconnect_layer = "m2" + + + + super().__init__(name=name) + self.setup_layout_constants() + self.create_netlist() + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.create_instances() + + def create_layout(self): + self.place_instances() + self.create_wl_bus() + self.route_decode_outputs() + self.route_array_inputs() + + self.route_supplies() + self.height = self.array_inst.height + self.width = self.array_inst.width + self.add_boundary() + + + def setup_layout_constants(self): + self.route_layer_width = drc["minwidth_{}".format(self.route_layer)] + self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_layer)] + self.bus_layer_width = drc["minwidth_{}".format(self.bus_layer)] + self.bus_layer_pitch = drc["{0}_to_{0}".format(self.bus_layer)] + + + def add_modules(self): + self.array = factory.create(module_type="rom_base_array", cols=self.cols, rows=self.rows, strap_spacing=self.strap_spacing, bitmap=self.data, route_layer=self.route_layer) + self.decode_array = factory.create(module_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer) + + + + def create_instances(self): + array_pins = [] + decode_pins = [] + + for bl in range(self.cols): + name = "bl_{}".format(bl) + array_pins.append(name) + for wl in range(self.rows): + name = "wl_{}".format(wl) + array_pins.append(wl) + + array_pins.append("array_precharge") + array_pins.append("vdd") + array_pins.append("gnd") + + + for addr in range(self.num_inputs): + name = "addr_{}".format(addr) + decode_pins.append(name) + for wl in range(self.rows): + name = "wl_{}".format(wl) + decode_pins.append(name) + + decode_pins.append("decode_precharge") + decode_pins.append("vdd") + decode_pins.append("gnd") + + + self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array) + self.connect_inst(array_pins) + + self.decode_inst = self.add_inst(name="rom_decoder", mod=self.decode_array) + self.connect_inst(decode_pins) + + + + def place_instances(self): + + array_x = self.decode_inst.width + (self.rows + 2) * ( self.route_layer_width + self.route_layer_pitch ) + array_y = self.array.height + + self.array_offset = vector(array_x ,array_y) + self.decode_offset = vector(0, 0) + + self.array_inst.place(offset=self.array_offset, mirror="MX") + + self.decode_inst.place(offset=self.decode_offset) + + def create_wl_bus(self): + bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) + bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width + self.wl_interconnects = [] + + for wl in range(self.rows): + self.wl_interconnects.append("wl_interconnect_{}".format(wl)) + + self.wl_bus = self.create_vertical_bus(self.bus_layer, vector(bus_x, bus_y), self.wl_interconnects, self.decode_inst.uy() - self.array_inst.by() ) + + def route_decode_outputs(self): + + for wl in range(self.rows): + decode_output = self.decode_array.output_names[wl] + decode_out_pin = self.decode_inst.get_pin(decode_output) + + wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] + + start = decode_out_pin.center() + end = vector(wl_bus_wire.cx(), start.y) + + self.add_segment_center(self.interconnect_layer, start, end) + self.add_via_stack_center(end, self.route_layer, self.interconnect_layer ) + + + def route_array_inputs(self): + + for wl in range(self.rows): + array_wl = self.array.wordline_names[0][wl] + array_wl_pin = self.array_inst.get_pin(array_wl) + + wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] + + end = array_wl_pin.center() + start = vector(wl_bus_wire.cx(), end.y) + + self.add_segment_center(self.interconnect_layer, start, end) + self.add_via_stack_center(start, self.route_layer, self.interconnect_layer ) + + + def route_supplies(self): + gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0) + print() + print(self.decode_inst.get_pin("gnd").center()) + decode_gnd = self.decode_inst.get_pin("gnd") + decode_vdd = self.decode_inst.get_pin("vdd") + array_vdd = self.array_inst.get_pin("vdd") + + self.add_segment_center("m1", gnd_start, decode_gnd.center()) + + + + self.add_power_pin("gnd", decode_vdd.center()) + self.add_power_pin("vdd", decode_gnd.center()) + + vdd_start = vector(array_vdd.lx() + 0.5 * self.via1_space, array_vdd.cy()) + end = vector(decode_vdd.lx(), vdd_start.y) + + self.add_segment_center(self.interconnect_layer, vdd_start, end) + self.add_via_stack_center(vdd_start, "m1", self.interconnect_layer) + + vdd_start = vector(decode_vdd.cx(), vdd_start.y) + + self.add_segment_center(self.interconnect_layer, vdd_start, decode_vdd.center()) + + + + + + + + diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index 8c0ce4e2..ced516ec 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -6,10 +6,7 @@ # All rights reserved. # - -import math from .rom_dummy_cell import rom_dummy_cell -from base import design from base import vector from globals import OPTS from sram_factory import factory @@ -26,9 +23,7 @@ class rom_base_cell(rom_dummy_cell): #self.create_layout() - def create_netlist(self): - print("using base cell netlist creation") - + def create_netlist(self): self.add_pins() self.add_nmos() self.create_nmos() @@ -39,9 +34,6 @@ class rom_base_cell(rom_dummy_cell): self.place_nmos() self.add_boundary() - print(self.height) - print(self.width) - def create_nmos(self): self.cell_inst = self.add_inst( name=self.name + "_nmos", @@ -58,19 +50,30 @@ class rom_base_cell(rom_dummy_cell): def place_nmos(self): - - poly_offset = vector(0.5 * self.nmos.active_contact.width + self.nmos.active_contact_to_gate, - self.nmos.poly_height) + # 0.5 * self.nmos.active_contact.width + self.nmos.active_contact_to_gate + poly_offset = vector(self.poly_extend_active_spacing * 0.5 + self.nmos.height + 2 * self.poly_extend_active, self.nmos.width * 0.5 - 0.5 * self.nmos.contact_width - self.active_enclose_contact) - nmos_offset = vector(- 0.5 * self.nmos.contact_width - self.active_enclose_contact, self.nmos.poly_extend_active) + # nmos_offset = vector(- 0.5 * self.nmos.contact_width - self.active_enclose_contact, self.nmos.poly_extend_active) + print("{} poly spacing".format(self.poly_extend_active_spacing)) + nmos_offset = vector(self.nmos.poly_extend_active + self.nmos.height ,- 0.5 * self.nmos.contact_width - self.active_enclose_contact) # add rect of poly to account for offset from drc spacing - self.add_rect("poly", poly_offset, self.nmos.poly_width, self.poly_extend_active_spacing ) + self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.nmos.poly_width) - self.cell_inst.place(nmos_offset) - self.add_label("CELL ZERO", self.route_layer) - self.add_label("S", self.route_layer, self.cell_inst.get_pin("S").center()) - self.add_label("D", self.route_layer, self.cell_inst.get_pin("D").center()) + self.cell_inst.place(nmos_offset, rotate=90) + # self.add_label("CELL ZERO", self.route_layer) + self.copy_layout_pin(self.cell_inst, "S", "S") + self.copy_layout_pin(self.cell_inst, "D", "D") + self.source_pos = self.cell_inst.get_pin("S").center() + # if self.add_source_contact != False: + # # drain_x = 0 + # # drain_y = 0.5 * (self.width - self.poly_extend_active_spacing) + + + # print("drained") + # print(drain_pos) + # self.add_layout_pin_rect_center("S", self.route_layer, drain_pos) + # self.add_label("S", self.route_layer, self.cell_inst.get_pin("S").center()) diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py new file mode 100644 index 00000000..024df34d --- /dev/null +++ b/compiler/modules/rom_decoder.py @@ -0,0 +1,249 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 math +from base import design +from sram_factory import factory +from base import vector +from globals import OPTS +import tech +from tech import drc + + +class rom_decoder(design): + def __init__(self, num_outputs, strap_spacing, name="", route_layer="li", output_layer="m2"): + + # word lines/ rows / inputs in the base array become the address lines / cols / inputs in the decoder + # bit lines / cols / outputs in the base array become the word lines / rows / outputs in the decoder + # array gets rotated 90deg so that rows/cols switch + self.strap_spacing=strap_spacing + self.num_outputs = num_outputs + self.num_inputs = math.ceil(math.log(num_outputs, 2)) + self.create_decode_map() + + for i in range(2 * self.num_inputs): print(self.decode_map[i]) + + super().__init__(name) + + b = factory.create(module_type=OPTS.bitcell) + self.cell_height = b.height + self.route_layer = route_layer + self.output_layer = output_layer + self.inv_route_layer = "m1" + self.create_netlist() + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_instances() + + + def create_layout(self): + self.place_array() + self.place_input_inverters() + self.create_outputs() + self.width = self.array_inst.height + self.height = self.array_inst.width + self.inv_inst.height + self.connect_inputs() + self.route_supplies() + self.add_boundary() + + def create_decode_map(self): + self.decode_map = [] + # create decoding map that will be the bitmap for the rom decoder + # row/col order in the map will be switched in the placed decoder/ + for col in range(self.num_inputs): + + # odd cols are address + # even cols are address bar + col_array = [] + inv_col_array = [] + for row in range(self.num_outputs): + + addr_idx = -col - 1 + + addr = format(row, 'b') + if col >= len(addr) : + bin_digit = 0 + else: + bin_digit = int(addr[addr_idx]) + + col_array.append(bin_digit) + # print("addr {0}, at indx {1}, digit {2}".format(addr, addr_idx, bin_digit)) + + if bin_digit == 0 : inv_col_array.append(1) + else : inv_col_array.append(0) + + + + self.decode_map.append(col_array) + self.decode_map.append(inv_col_array) + self.decode_map.reverse() + + + def add_pins(self): + for i in range(self.num_inputs): + self.add_pin("in_{0}".format(i), "INPUT") + + for j in range(self.num_outputs): + self.add_pin("out_{0}".format(j), "OUTPUT") + self.add_pin("precharge_gate", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + + def add_modules(self): + + self.inv_array = factory.create(module_type="rom_inv_array", cols=self.num_inputs) + + self.array_mod = factory.create(module_type="rom_base_array", \ + module_name="rom_decode_array", \ + cols=self.num_outputs, \ + rows=2 * self.num_inputs, \ + bitmap=self.decode_map, + strap_spacing = self.strap_spacing, + route_layer=self.route_layer, + output_layer=self.output_layer) + + + def create_instances(self): + + self.create_input_inverters() + self.create_array_inst() + + + def create_input_inverters(self): + name = "pre_inv_array" + self.inv_inst = self.add_inst(name=name, mod=self.inv_array) + + inv_pins = [] + + for i in range(self.num_inputs): + inv_pins.append("in_{0}".format(i)) + inv_pins.append("inbar_{0}".format(i)) + + inv_pins.append("vdd") + inv_pins.append("gnd") + self.connect_inst(inv_pins) + + + def create_array_inst(self): + self.array_inst = self.add_inst(name="decode_array_inst", mod=self.array_mod) + + array_pins = [] + + for j in range(self.num_outputs): + name = "out_{0}".format(j) + array_pins.append(name) + + + for i in reversed(range(self.num_inputs)): + array_pins.append("inbar_{0}".format(i)) + array_pins.append("in_{0}".format(i)) + array_pins.append("precharge_gate") + array_pins.append("vdd") + array_pins.append("gnd") + self.connect_inst(array_pins) + + + def place_input_inverters(self): + print(self.array_inst.ll().x) + self.inv_inst.place(vector(self.array_inst.ll().x, 0)) + + + def place_array(self): + offset = vector(self.array_mod.height, self.inv_array.height + self.m1_width + self.poly_contact.width) + self.array_inst.place(offset, rotate=90) + + def create_outputs(self): + + self.output_names = [] + self.outputs = [] + for j in range(self.num_outputs): + name = "out_{0}".format(j) + self.output_names.append(name) + + + for bl in range(self.num_outputs): + self.copy_layout_pin(self.array_inst, self.array_mod.bitline_names[0][bl], self.output_names[bl]) + # prechg_pin = self.array_mod.bitline_names[0][bl] + # src_pin = self.array_inst.get_pin(prechg_pin) + # offset = src_pin.center() + # self.add_via_stack_center(offset, self.route_layer, self.output_layer) + # self.outputs.append(self.add_layout_pin_rect_center(self.output_names[bl], self.output_layer, offset )) + + def connect_inputs(self): + + for i in range(self.num_inputs): + wl = self.num_inputs * 2 - i * 2 - 1 + wl_bar = wl - 1 + addr_pin = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl]) + addr_bar_pin = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl_bar]) + + inv_in_pin = self.inv_inst.get_pin("inv{}_in".format(i)) + inv_out_pin = self.inv_inst.get_pin("inv{}_out".format(i)) + + addr_start = inv_in_pin.center() + addr_end = vector(addr_start.x, addr_pin.cy()) + + addr_bar_start = inv_out_pin.center() + addr_bar_end = vector(addr_bar_start.x, addr_bar_pin.cy()) + self.add_segment_center(self.inv_route_layer, addr_start, addr_end) + self.add_segment_center(self.inv_route_layer, addr_bar_start, addr_bar_end) + + def route_supplies(self): + minwidth = drc["minwidth_{}".format(self.inv_route_layer)] + pitch = drc["{0}_to_{0}".format(self.inv_route_layer)] + + + # route decode array vdd and inv array vdd together + array_vdd = self.array_inst.get_pin("vdd") + inv_vdd = self.inv_inst.get_pins("vdd")[-1] + + end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth) + self.add_segment_center("m1", array_vdd.center(), end) + end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy()) + self.add_segment_center(self.route_layer, inv_vdd.center(), end) + + end = vector(array_vdd.cx(), inv_vdd.cy()) + self.add_via_stack_center(end, self.route_layer, "m1") + self.add_layout_pin_rect_center("vdd", "m1", end) + + # route pin on inv gnd + + inv_gnd = self.inv_inst.get_pins("gnd")[0] + array_gnd = self.array_inst.get_pins("gnd") + + # add x jog + + start = vector(array_gnd[0].cx(), inv_gnd.cy()) + self.add_via_stack_center(start, self.route_layer, "m1") + self.add_layout_pin_rect_center("gnd", "m1", start) + + end = array_gnd[0].center() + self.add_segment_center("m1", start, end) + # add y jog + + + width = minwidth + height = array_gnd[0].uy() - array_gnd[-1].uy() + minwidth + + offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy())) + + + + # self.add_rect_center(self.route_layer, offset, width, height) + + + start = end - vector(0, 0.5 * minwidth) + end = vector(start.x, array_gnd[1].uy()) + # self.add_segment_center("m1", start, end) + + + diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py index 67384a83..b6f8f27b 100644 --- a/compiler/modules/rom_dummy_cell.py +++ b/compiler/modules/rom_dummy_cell.py @@ -41,9 +41,7 @@ class rom_dummy_cell(design): self.add_boundary() self.add_poly() self.add_metal() - print(self.height) - print(self.width) - self.add_label("0,0", self.route_layer) + #self.add_label("0,0", self.route_layer) @@ -65,8 +63,6 @@ class rom_dummy_cell(design): #this is calculated as a negative value self.cell_diffusion_offset = ((self.base_width - 2 * self.active_enclose_contact - self.nmos.contact_width) - drc("active_to_active")) * 0.5 - - # width offset to account for poly-active spacing between base and dummy cells on the same bitline self.poly_active_offset = 0.5 * (self.base_width - 2 * self.cell_diffusion_offset - (self.poly_width + 2 * self.active_enclose_contact + self.nmos.contact_width)) - self.poly_to_active @@ -77,8 +73,8 @@ class rom_dummy_cell(design): def add_boundary(self): #cell width with offsets applied, height becomes width when the cells are rotated + # self.width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active self.width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active - # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied self.height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) @@ -88,18 +84,22 @@ class rom_dummy_cell(design): def add_poly(self): - poly_x = 0.5 * self.nmos.contact_width + self.contact_to_gate + poly_x = 0.5 * (self.nmos.poly_height + self.poly_extend_active_spacing) + # 0.5 * self.nmos.contact_width + self.contact_to_gate - self.poly = self.add_rect("poly", vector(poly_x, 0), self.poly_width, self.nmos.poly_height + self.poly_extend_active_spacing) - print(self.poly_width, self.height) + self.poly = self.add_rect_center("poly", vector(poly_x, self.base_width * 0.5), 2 * poly_x, self.poly_width) def add_metal(self): - wire_x = min(self.cell_diffusion_offset, 0) + min(self.poly_active_offset, 0) - self.mcon_width * 0.5 - wire_y = 0.5 * (self.width - self.poly_extend_active_spacing) + if self.route_layer == "li": + via = "mcon" + else: + via = "via{}".format(self.route_layer[len(self.route_layer) - 1]) + wire_y = self.height + drc["minwidth_{}".format(via)] * 0.5 + wire_x = 0.5 * (self.width - self.poly_extend_active_spacing) - wire_start = vector( wire_x, wire_y ) - wire_end = vector(self.height + self.mcon_width * 0.5, wire_y) + wire_start = vector( wire_x, 0) + wire_end = vector(wire_x, wire_y) # if self.route_layer == 'm1': @@ -109,11 +109,18 @@ class rom_dummy_cell(design): # self.add_via_center(self.li_stack, [self.width, wire_y]) self.add_path(self.route_layer, [wire_start, wire_end]) + + # drain_x = 0 + # drain_y = 0.5 * (self.width) + source_x = 0.5 * (self.width - self.poly_extend_active_spacing) + source_y = 0 + source_pos = vector(source_x, source_y) + self.add_layout_pin_rect_center("S", self.route_layer, source_pos) + + drain_pos = vector(source_x, self.height) + self.add_layout_pin_rect_center("D", self.route_layer, drain_pos) - - - def add_nmos(self): #used only for layout constants # if not self.source_contact: diff --git a/compiler/modules/rom_inv_array.py b/compiler/modules/rom_inv_array.py new file mode 100644 index 00000000..9e54044f --- /dev/null +++ b/compiler/modules/rom_inv_array.py @@ -0,0 +1,130 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 base import design +from sram_factory import factory +from base import vector +from tech import layer, drc + + + +class rom_inv_array(design): + """ + An array of inverters to create the inverted address lines for the rom decoder + """ + def __init__(self, cols, inv_size=None, name="", route_layer="m1"): + self.cols = cols + self.route_layer = route_layer + dff = factory.create(module_type="dff") + if name=="": + name = "rom_inv_array_{0}".format(cols) + if inv_size == None: + self.inv_size = dff.height * 0.5 + else: + self.inv_size = inv_size + + + if "li" in layer: + self.inv_layer = "li" + else: + self.inv_layer = "m1" + super().__init__(name) + self.create_netlist() + self.create_layout() + + def create_netlist(self): + self.create_modules() + self.add_pins() + self.create_instances() + + + def create_layout(self): + self.width = self.cols * self.poly_tap.height * 2 + self.height = self.inv_mod.height + self.setup_layout_constants() + self.place_instances() + self.place_vias() + self.route_sources() + self.add_boundary() + + + def create_modules(self): + + self.inv_mod = factory.create(module_type="pinv", module_name="inv_array_mod", height=self.inv_size, add_wells=False) + self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size) + # For layout constants + self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=0) + + def add_pins(self): + for col in range(self.cols): + self.add_pin("inv{0}_in".format(col), "INPUT") + self.add_pin("inv{0}_out".format(col), "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def create_instances(self): + self.inv_insts = [] + + for col in range(self.cols): + name = "Xinv_c{0}".format(col) + if col == self.cols - 1: + print("TAP ME DOWN") + self.inv_insts.append(self.add_inst(name=name, mod=self.end_inv)) + else: + self.inv_insts.append(self.add_inst(name=name, mod=self.inv_mod)) + inst_A = "inv{0}_in".format(col) + inst_Z = "inv{0}_out".format(col) + self.connect_inst([inst_A, inst_Z, "vdd", "gnd"]) + + def setup_layout_constants(self): + input_pin = self.inv_insts[0].get_pin("A") + output_pin = self.inv_insts[0].get_pin("Z") + + # NEED TO OFFSET OUTPUT VIA IN ORDER TO ALIGN WITH PITCH OF ADDRESS INPUTS TO ARRAY + + # print(self.poly_tap.get_pin("poly_tap").center()) + + # distance between input and output pins of inverter + in_out_distance = output_pin.cx() - input_pin.cx() + # distance from left edge of inverter to input plus right edge to output + edge_to_pins_distance = input_pin.cx() - self.inv_insts[0].lx() + self.inv_insts[0].rx() - output_pin.cx() + + self.alignment_offset = edge_to_pins_distance - in_out_distance + + def place_instances(self): + self.add_label("ZERO", self.route_layer) + for col in range(self.cols): + # base = vector(col*(self.inv_mod.width - self.alignment_offset), 0) + base = vector(col*(self.poly_tap.height * 2), 0) + self.inv_insts[col].place(offset=base) + #vdd_pin = self.inv_insts[0].get_pin("vdd").center() + #self.add_layout_pin_rect_center("vdd_align", self.inv_layer, vdd_pin, 0, 0) + + def place_vias(self): + for i in range(self.cols): + input_pin = self.inv_insts[i].get_pin("A") + output_pin = self.inv_insts[i].get_pin("Z") + + self.add_via_stack_center(input_pin.center(), self.inv_mod.route_layer, self.route_layer) + self.add_via_stack_center(output_pin.center(), self.inv_mod.route_layer, self.route_layer) + self.add_layout_pin_rect_center("inv{}_in".format(i), offset=input_pin.center(), layer=self.route_layer) + self.add_layout_pin_rect_center("inv{}_out".format(i), offset=output_pin.center(), layer=self.route_layer) + + def route_sources(self): + + vdd_start = self.inv_insts[0].get_pin("vdd") + vdd_end = self.inv_insts[-1].get_pin("vdd") + + gnd_start = self.inv_insts[0].get_pin("gnd") + gnd_end = self.inv_insts[-1].get_pin("gnd") + + self.copy_layout_pin(self.inv_insts[0], "vdd") + self.copy_layout_pin(self.inv_insts[0], "gnd") + # self.vdd = self.add_layout_pin_rect_ends("vdd", self.inv_layer, vdd_start.center(), vdd_end.center())[-1] + # self.gnd = self.add_layout_pin_rect_ends("gnd", self.inv_layer, gnd_start.center(), gnd_end.center())[-1] + diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index 765a0e17..57f97ca5 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -2,54 +2,94 @@ from base import design from base import vector +from globals import OPTS from sram_factory import factory class rom_poly_tap(design): - def __init__(self, name, strap_length=0, cell_name=None, prop=None, strap_layer="m2"): + def __init__(self, name, strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m1"): super().__init__(name, cell_name, prop) self.strap_layer=strap_layer self.length = strap_length + self.tx_type = tx_type self.create_netlist() self.create_layout() def create_netlist(self): - - #for layout constants self.dummy = factory.create(module_type="rom_dummy_cell") + self.pmos = factory.create(module_type="ptx", tx_type="pmos") def create_layout(self): self.place_via() + # if self.tx_type == "pmos": + self.extend_poly() self.add_boundary() if self.length != 0: - self.place_strap(self.length) + self.place_strap() + def add_boundary(self): self.height = self.dummy.height - self.width = self.poly_contact.width + self.width = self.poly_contact.width + 2 * self.contact_x_offset super().add_boundary() def place_via(self): - - contact_width = self.poly_contact.width - contact_x = - contact_width * 0.5 - contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) + contact_width = self.poly_contact.width + # DRC rule here is hard coded since licon.9 isnt included in skywater130 tech file - contact_offset = vector(contact_x, contact_y) + # poly contact spacing to P-diffusion < 0.235um (licon.9 + psdm.5a) + if OPTS.tech_name == "sky130": + self.contact_x_offset = 0.235 - (contact_width - self.pmos.contact_width) * 0.5 - self.poly_extend_active + else: + assert(False) + + if self.tx_type == "nmos": + + contact_y = self.dummy.poly.cy() + # contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) + # self.contact_x_offset = 0 + else: + contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x + print(self.tx_type) + print(contact_y) + + # contact_x = - contact_width * 0.5 - self.contact_x_offset + contact_x = contact_width * 0.5 + self.contact_x_offset + self.contact_offset = vector(contact_x, contact_y) + print("polycule") + print(self.contact_offset) self.via = self.add_via_stack_center(from_layer="poly", to_layer=self.strap_layer, - offset=contact_offset) + offset=self.contact_offset) + self.add_layout_pin_rect_center("via", self.strap_layer, self.contact_offset) + # if self.length == 0: + # self.add_layout_pin_rect_center(text="poly_tap", + # layer=self.strap_layer, + # offset=print()contact_offset, + # ) - self.add_label("ZERO", "poly") - def place_strap(self, length): - strap_start = vector(self.via.cx(), self.via.cy()) + def place_strap(self): - strap_end = vector( self.dummy.width * (length - 1) + self.m2_width, self.via.cy()) + strap_start = vector(self.via.lx() , self.via.cy()) + + strap_end = vector( self.dummy.width * (self.length + 1), self.via.cy()) self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) + def extend_poly(self): + poly_x = self.poly_contact.width + self.contact_x_offset + poly_y = self.contact_offset.y - self.poly_width * 0.5 + extend_offset = vector(poly_x, poly_y) + self.add_rect("poly", extend_offset, self.contact_x_offset, self.poly_width) + + poly_x = 0 + extend_offset = vector(poly_x, poly_y) + + self.add_rect("poly", extend_offset, self.contact_x_offset, self.poly_width) + + diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py new file mode 100644 index 00000000..172f4670 --- /dev/null +++ b/compiler/modules/rom_precharge_array.py @@ -0,0 +1,201 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 math +from base import geometry +from base import design +from sram_factory import factory +from base import vector +from tech import layer, drc + + + +class rom_precharge_array(design): + """ + An array of inverters to create the inverted address lines for the rom decoder + """ + def __init__(self, cols, pmos_size=None, name="", route_layer="li", strap_spacing=None): + self.cols = cols + self.route_layer = route_layer + if name=="": + name = "rom_inv_array_{0}".format(cols) + # if pmos_size == None: + # self.pmos_size = dff.height * 0.5 + # else: + # self.pmos_size = inv_size + if strap_spacing != None: + self.strap_spacing = strap_spacing + else: + self.strap_spacing = 0 + + if "li" in layer: + self.inv_layer = "li" + else: + self.inv_layer = "m1" + + + if strap_spacing != 0: + self.num_straps = math.ceil(self.cols / self.strap_spacing) + self.array_col_size = self.cols + self.num_straps + else: + self.num_straps = 0 + self.array_col_size = self.cols + + super().__init__(name) + self.create_netlist() + self.create_layout() + + def create_netlist(self): + self.create_modules() + self.add_pins() + self.create_instances() + + + + def create_layout(self): + self.width = self.cols * self.pmos.width + self.num_straps * self.poly_tap.width + self.height = self.pmos.width + self.place_instances() + self.create_layout_pins() + self.add_well_tap() + self.route_supply() + self.extend_implant() + + self.add_boundary() + + + + def add_boundary(self): + self.translate_all(self.well_ll) + ur = self.find_highest_coords() + ur = vector(ur.x, ur.y - self.well_ll.y) + super().add_boundary(vector(0, 0), ur) + self.width = self.cols * self.pmos.width + self.num_straps * self.poly_tap.width + self.height = ur.y + + def create_modules(self): + + self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", route_layer=self.route_layer) + + # For layout constants + self.dummy = factory.create(module_type="rom_base_cell") + self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing, tx_type="pmos") + + def add_pins(self): + for col in range(self.cols): + self.add_pin("pre_bl{0}_out".format(col), "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gate", "INPUT") + + def create_instances(self): + self.array_insts = [] + self.pmos_insts = [] + self.tap_insts = [] + for col in range(self.cols): + + + if col % self.strap_spacing == 0: + name = "tap_c{}".format(col) + tap = self.add_inst(name=name, mod=self.poly_tap) + self.array_insts.append(tap) + self.tap_insts.append(tap) + self.connect_inst([]) + name = "Xpmos_c{0}".format(col) + pmos = self.add_inst(name=name, mod=self.pmos) + self.array_insts.append(pmos) + self.pmos_insts.append(pmos) + bl = "pre_bl{0}_out".format(col) + self.connect_inst(["vdd", "gate", bl, "vdd"]) + print(self.array_insts) + + + + def place_instances(self): + self.add_label("ZERO", self.route_layer) + + self.array_pos = [] + strap_num = 0 + cell_y = 0 + # columns are bit lines4 + cell_x = 0 + print("starting array place") + + for col in range(self.cols): + + if col % self.strap_spacing == 0 : + self.tap_insts[strap_num].place(vector(cell_x, cell_y)) + self.add_label("debug", "li", vector(cell_x, cell_y)) + cell_x += self.poly_tap.width + strap_num += 1 + + self.pmos_insts[col].place(vector(cell_x, cell_y)) + self.add_label("debug", "li", vector(cell_x, cell_y)) + cell_x += self.pmos.width + + + def create_layout_pins(self): + for col in range(self.cols): + source_pin = self.pmos_insts[col].get_pin("D") + bl = "pre_bl{0}_out".format(col) + self.add_layout_pin_rect_center(bl, self.route_layer, source_pin.center()) + + + def extend_implant(self): + layer = "nwell" + # center of source contact minus radius of the well generated by the contact gives the lowermost well position + contact_well_by = self.pmos.pmos.source_contacts[0].cx() - self.pmos.pmos.source_contacts[0].mod.well_width * 0.5 + + ptx_well_by = 0.5 * self.pmos.pmos.active_width - 0.5 * self.pmos.pmos.well_width + + well_extend = ptx_well_by - contact_well_by + + + self.well_ll = vector(0, min(contact_well_by, ptx_well_by)) + + height = self.pmos.pmos.active_width + 2 * self.well_enclose_active + self.add_rect(layer, self.well_ll, self.width + well_extend, height + 2 * well_extend) + + def add_well_tap(self): + + layer_stack = self.active_stack + contact_x = self.pmos_insts[self.cols - 1].rx() + self.active_space + contact_offset = vector(contact_x, self.pmos.height * 0.5) + + self.nwell_contact = self.add_via_center(layers=layer_stack, + offset=contact_offset, + implant_type="n", + well_type="n", + directions=("V", "V")) + + def route_supply(self): + start_pin = self.pmos_insts[0].get_pin("S").lx() + end_pin = self.pmos_insts[-1].get_pin("S").rx() + spacing = drc["{0}_to_{0}".format(self.route_layer)] + start = vector(start_pin, -1.5*spacing) + end = vector(end_pin, -1.5*spacing) + + self.vdd = self.add_layout_pin_segment_center("vdd", "m1", start, end) + + for i in range(self.cols): + start = self.pmos_insts[i].get_pin("S").center() + end = vector(start.x, self.vdd.cy()) + + self.add_segment_center(self.route_layer, start, end) + self.add_via_stack_center(end, self.route_layer, "m1") + + + # connect nwell tap to vdd + + start = end + end = vector(self.nwell_contact.cx(), start.y) + self.add_segment_center(self.route_layer, start, end) + + start = end - vector(0, 0.5 * self.mcon_width) + end = self.nwell_contact.center() + self.add_segment_center(self.route_layer, start, end) + diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py new file mode 100644 index 00000000..ca890b80 --- /dev/null +++ b/compiler/modules/rom_precharge_cell.py @@ -0,0 +1,107 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 base import design +from base import vector +from globals import OPTS +from sram_factory import factory + +from tech import drc + + +class rom_precharge_cell(design): + + def __init__(self, name="", cell_name=None, route_layer="m1"): + + super().__init__(name, cell_name) + self.route_layer = route_layer + self.create_netlist() + self.create_layout() + + #self.route_layer= route_layer + #self.create_netlist() + #self.create_layout() + + + def create_netlist(self): + self.add_pins() + self.add_pmos() + self.create_pmos() + + + def create_layout(self): + self.setup_layout_constants() + self.place_pmos() + self.add_boundary() + + + def add_pmos(self): + + self.pmos = factory.create(module_type="ptx", + module_name="pre_pmos_mod", + tx_type="pmos" + ) + + def create_pmos(self): + self.cell_inst = self.add_inst( name="precharge_pmos", + mod=self.pmos, + ) + self.connect_inst(["bitline", "gate", "vdd", "vdd"]) + + + def add_pins(self): + pin_list = ["vdd", "gate", "bitline", "vdd"] + dir_list = ["OUTPUT", "INPUT", "OUTPUT", "POWER"] + + self.add_pin_list(pin_list, dir_list) + + def setup_layout_constants(self): + + #pmos contact to gate distance + self.contact_to_gate = 0.5 * (self.pmos.width - 2 * self.pmos.contact_width - self.pmos.poly_width - 2 * self.active_enclose_contact) + + #height offset to account for active-to-active spacing between adjacent bitlines + self.poly_extend_active_spacing = abs( 2 * self.pmos.poly_extend_active - drc("active_to_active") ) + + #contact to contact distance, minimum cell width before drc offsets + self.base_width = self.pmos.width - 2 * self.active_enclose_contact - self.pmos.contact_width + + # width offset to account for poly-active spacing between base and dummy cells on the same bitline + self.poly_active_offset = 0.5 * (self.base_width - (self.poly_width + 2 * self.active_enclose_contact + self.pmos.contact_width)) - self.poly_to_active + + #so that the poly taps are far enough apart + self.poly_tap_offset = (self.base_width - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") + + + def place_pmos(self): + + poly_offset = vector(self.poly_extend_active_spacing * 0.5 + self.pmos.height + 2 * self.poly_extend_active, 0.5 * self.pmos.width) + + # pmos_offset = vector(self.pmos.poly_extend_active, - 0.5 * self.pmos.contact_width - self.active_enclose_contact) + + # pmos_offset = vector(-self.pmos.poly_extend_active - self.poly_extend_active_spacing, 0) + pmos_offset = vector(self.pmos.poly_extend_active + self.pmos.height, 0) + # add rect of poly to account for offset from drc spacing + self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.pmos.poly_width ) + + self.cell_inst.place(pmos_offset, rotate=90) + # self.add_label("CELL ZERO", self.route_layer) + self.add_label("inst_zero", self.route_layer) + self.add_layout_pin_rect_center("S", self.route_layer, self.cell_inst.get_pin("S").center()) + self.add_layout_pin_rect_center("D", self.route_layer, self.cell_inst.get_pin("D").center()) + + def add_boundary(self): + + #cell width with offsets applied, height becomes width when the cells are rotated + self.width = self.pmos.height + self.poly_extend_active_spacing + 2 * self.pmos.poly_extend_active + + # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied + self.height = self.base_width - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) + + super().add_boundary() + diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/05_rom_array_test.py index fe75d054..1228dd9f 100644 --- a/compiler/tests/05_rom_array_test.py +++ b/compiler/tests/05_rom_array_test.py @@ -29,7 +29,6 @@ class rom_array_test(openram_test): a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4) self.local_check(a) - globals.end_openram() # run the test from the command line diff --git a/compiler/tests/05_rom_base_bank_test.py b/compiler/tests/05_rom_base_bank_test.py new file mode 100644 index 00000000..d2caacad --- /dev/null +++ b/compiler/tests/05_rom_base_bank_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 + +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class rom_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(2, "Testing 4x4 array for rom cell") + + a = factory.create(module_type="rom_base_bank", strap_spacing = 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()) \ No newline at end of file diff --git a/compiler/tests/05_rom_decoder_test.py b/compiler/tests/05_rom_decoder_test.py new file mode 100644 index 00000000..d1a3875a --- /dev/null +++ b/compiler/tests/05_rom_decoder_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 + +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class rom_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(2, "Testing 2x4 decoder for rom cell") + + + a = factory.create(module_type="rom_decoder", num_outputs=8, strap_spacing=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/05_rom_precharge_array_test.py b/compiler/tests/05_rom_precharge_array_test.py new file mode 100644 index 00000000..847ffaf2 --- /dev/null +++ b/compiler/tests/05_rom_precharge_array_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 + +import globals +from globals import OPTS +from sram_factory import factory +import debug + + +class rom_precharge_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + globals.init_openram(config_file) + + debug.info(2, "Testing precharge array for rom cell") + + + a = factory.create(module_type="rom_precharge_array", cols=4, strap_spacing=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()) From b2631b60ff4a32f1b516cbde5112df0c9b43d776 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 12 Dec 2022 16:35:23 -0800 Subject: [PATCH 36/98] updated imports to match upstream dev openram --- compiler/modules/rom_array_gnd_tap.py | 6 +++--- compiler/modules/rom_base_array.py | 9 ++++----- compiler/modules/rom_base_bank.py | 10 +++++----- compiler/modules/rom_base_cell.py | 9 ++++----- compiler/modules/rom_decoder.py | 15 +++++++-------- compiler/modules/rom_dummy_cell.py | 10 +++++----- compiler/modules/rom_inv_array.py | 8 ++++---- compiler/modules/rom_poly_tap.py | 16 +++++++++++----- compiler/modules/rom_precharge_array.py | 14 +++++++------- compiler/modules/rom_precharge_cell.py | 10 +++++----- compiler/tests/05_rom_array_test.py | 16 ++++++++-------- compiler/tests/05_rom_base_bank_test.py | 10 +++++----- compiler/tests/05_rom_decoder_test.py | 14 +++++++------- compiler/tests/05_rom_precharge_array_test.py | 10 +++++----- 14 files changed, 80 insertions(+), 77 deletions(-) diff --git a/compiler/modules/rom_array_gnd_tap.py b/compiler/modules/rom_array_gnd_tap.py index 3bb3419a..bbd7a06d 100644 --- a/compiler/modules/rom_array_gnd_tap.py +++ b/compiler/modules/rom_array_gnd_tap.py @@ -1,8 +1,8 @@ -from base import design -from base import vector -from sram_factory import factory +from openram.base import design +from openram.base import vector +from openram.sram_factory import factory class rom_array_gnd_tap(design): diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 1602a92b..0fb5584e 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -9,11 +9,10 @@ import math from .bitcell_base_array import bitcell_base_array -from base import vector -from globals import OPTS -from sram_factory import factory -import tech -from tech import drc +from openram.base import vector +from openram import OPTS +from openram.sram_factory import factory +from openram.tech import drc class rom_base_array(bitcell_base_array): diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index b9cb090e..2ce14ab7 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -1,11 +1,11 @@ import math -from base import vector -from base import design -from globals import OPTS -from sram_factory import factory +from openram.base import vector +from openram.base import design +from openram import OPTS +from openram.sram_factory import factory import tech -from tech import drc +from openram.tech import drc class rom_base_bank(design): diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index ced516ec..b6b5a8dd 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -7,11 +7,10 @@ # from .rom_dummy_cell import rom_dummy_cell -from base import vector -from globals import OPTS -from sram_factory import factory - -from tech import drc +from openram.base import vector +from openram import OPTS +from openram.sram_factory import factory +from openram.tech import drc class rom_base_cell(rom_dummy_cell): diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index 024df34d..0cd1ba16 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -6,13 +6,12 @@ # All rights reserved. # -import math -from base import design -from sram_factory import factory -from base import vector -from globals import OPTS -import tech -from tech import drc +from math import ceil, log +from openram.base import design +from openram.sram_factory import factory +from openram.base import vector +from openram import OPTS +from openram.tech import drc class rom_decoder(design): @@ -23,7 +22,7 @@ class rom_decoder(design): # array gets rotated 90deg so that rows/cols switch self.strap_spacing=strap_spacing self.num_outputs = num_outputs - self.num_inputs = math.ceil(math.log(num_outputs, 2)) + self.num_inputs = ceil(log(num_outputs, 2)) self.create_decode_map() for i in range(2 * self.num_inputs): print(self.decode_map[i]) diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py index b6f8f27b..89ce801b 100644 --- a/compiler/modules/rom_dummy_cell.py +++ b/compiler/modules/rom_dummy_cell.py @@ -8,11 +8,11 @@ -from base import design -from base import vector -from globals import OPTS -from sram_factory import factory -from tech import drc +from openram.base import design +from openram.base import vector +from openram import OPTS +from openram.sram_factory import factory +from openram.tech import drc class rom_dummy_cell(design): diff --git a/compiler/modules/rom_inv_array.py b/compiler/modules/rom_inv_array.py index 9e54044f..cc87dc24 100644 --- a/compiler/modules/rom_inv_array.py +++ b/compiler/modules/rom_inv_array.py @@ -6,10 +6,10 @@ # All rights reserved. # -from base import design -from sram_factory import factory -from base import vector -from tech import layer, drc +from openram.base import design +from openram.sram_factory import factory +from openram.base import vector +from openram.tech import layer, drc diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index 57f97ca5..c01ac380 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -1,9 +1,15 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 base import design -from base import vector -from globals import OPTS -from sram_factory import factory +from openram.base import design +from openram.base import vector +from openram import OPTS +from openram.sram_factory import factory class rom_poly_tap(design): diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index 172f4670..dc7fbb77 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -6,12 +6,12 @@ # All rights reserved. # -import math -from base import geometry -from base import design -from sram_factory import factory -from base import vector -from tech import layer, drc +from math import ceil +from openram.base import geometry +from openram.base import design +from openram.sram_factory import factory +from openram.base import vector +from openram.tech import layer, drc @@ -40,7 +40,7 @@ class rom_precharge_array(design): if strap_spacing != 0: - self.num_straps = math.ceil(self.cols / self.strap_spacing) + self.num_straps = ceil(self.cols / self.strap_spacing) self.array_col_size = self.cols + self.num_straps else: self.num_straps = 0 diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index ca890b80..16c2fac5 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -6,12 +6,12 @@ # All rights reserved. # -from base import design -from base import vector -from globals import OPTS -from sram_factory import factory +from openram.base import design +from openram.base import vector +from openram import OPTS +from openram.sram_factory import factory -from tech import drc +from openram.tech import drc class rom_precharge_cell(design): diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/05_rom_array_test.py index 1228dd9f..13708a6c 100644 --- a/compiler/tests/05_rom_array_test.py +++ b/compiler/tests/05_rom_array_test.py @@ -6,21 +6,21 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # +import sys, os import unittest from testutils import * -import sys, os -import globals -from globals import OPTS -from sram_factory import factory -import debug +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS class rom_array_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) + openram.init_openram(config_file, is_unit_test=True) debug.info(2, "Testing 4x4 array for rom cell") @@ -29,11 +29,11 @@ class rom_array_test(openram_test): a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4) self.local_check(a) - globals.end_openram() + openram.end_openram() # run the test from the command line if __name__ == "__main__": - (OPTS, args) = globals.parse_args() + (OPTS, args) = openram.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/05_rom_base_bank_test.py b/compiler/tests/05_rom_base_bank_test.py index d2caacad..2b5841e9 100644 --- a/compiler/tests/05_rom_base_bank_test.py +++ b/compiler/tests/05_rom_base_bank_test.py @@ -10,9 +10,9 @@ import unittest from testutils import * import sys, os -import globals -from globals import OPTS -from sram_factory import factory +import openram +from openram import OPTS +from openram.sram_factory import factory import debug @@ -20,7 +20,7 @@ class rom_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) + openram.init_openram(config_file, is_unit_test=True) debug.info(2, "Testing 4x4 array for rom cell") @@ -31,7 +31,7 @@ class rom_bank_test(openram_test): # run the test from the command line if __name__ == "__main__": - (OPTS, args) = globals.parse_args() + (OPTS, args) = openram.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) unittest.main(testRunner=debugTestRunner()) \ No newline at end of file diff --git a/compiler/tests/05_rom_decoder_test.py b/compiler/tests/05_rom_decoder_test.py index d1a3875a..9146ca42 100644 --- a/compiler/tests/05_rom_decoder_test.py +++ b/compiler/tests/05_rom_decoder_test.py @@ -10,28 +10,28 @@ import unittest from testutils import * import sys, os -import globals -from globals import OPTS -from sram_factory import factory -import debug +import openram +from openram import OPTS +from openram.sram_factory import factory +from openram import debug class rom_decoder_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) + openram.init_openram(config_file, is_unit_test=True) debug.info(2, "Testing 2x4 decoder for rom cell") a = factory.create(module_type="rom_decoder", num_outputs=8, strap_spacing=2) self.local_check(a) - globals.end_openram() + openram.end_openram() # run the test from the command line if __name__ == "__main__": - (OPTS, args) = globals.parse_args() + (OPTS, args) = openram.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/05_rom_precharge_array_test.py b/compiler/tests/05_rom_precharge_array_test.py index 847ffaf2..b8e9e5ff 100644 --- a/compiler/tests/05_rom_precharge_array_test.py +++ b/compiler/tests/05_rom_precharge_array_test.py @@ -10,9 +10,9 @@ import unittest from testutils import * import sys, os -import globals -from globals import OPTS -from sram_factory import factory +import openram +from openram import OPTS +from openram.sram_factory import factory import debug @@ -20,7 +20,7 @@ class rom_precharge_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - globals.init_openram(config_file) + openram.init_openram(config_file, is_unit_test=True) debug.info(2, "Testing precharge array for rom cell") @@ -31,7 +31,7 @@ class rom_precharge_test(openram_test): # run the test from the command line if __name__ == "__main__": - (OPTS, args) = globals.parse_args() + (OPTS, args) = openram.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) unittest.main(testRunner=debugTestRunner()) From e697efa5f67d747b135bc528d028fbb82e4f749f Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 12 Dec 2022 17:09:56 -0800 Subject: [PATCH 37/98] fixed base array lvs --- compiler/modules/rom_base_array.py | 56 ++++++------------- compiler/modules/rom_dummy_cell.py | 2 - compiler/modules/rom_precharge_cell.py | 1 - compiler/tests/05_rom_base_bank_test.py | 2 +- compiler/tests/05_rom_precharge_array_test.py | 2 +- 5 files changed, 18 insertions(+), 45 deletions(-) diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 0fb5584e..6cec6480 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -110,14 +110,15 @@ class rom_base_array(bitcell_base_array): self.cell_list = [] self.current_row = 0 #list of current bitline interconnect nets, starts as the same as the bitline list and is updated when new insts of cells are added - int_bl_list = self.bitline_names[0] + self.int_bl_list = self.bitline_names[0].copy() #When rotated correctly rows are word lines for row in range(self.row_size): row_list = [] # for each new strap placed, offset the column index refrenced to get correct bit in the data array strap_offset = 0 - # when rotated correctly cols are bit lines + first_in_col = True + # cols are bit lines for col in range(self.column_size): if col % self.strap_spacing == 0: @@ -140,7 +141,6 @@ class rom_base_array(bitcell_base_array): new_inst = self.add_inst(name=name, mod=self.cell_ac) - # if dummy/0 is below and not above, add a source contact # if in the first row, add a source contact elif (row > 0 and self.data[row - 1][col] == 0) or \ @@ -157,12 +157,17 @@ class rom_base_array(bitcell_base_array): if row == self.row_size - 1 or self.get_next_cell_in_bl(row, col) == -1: - bl_l = int_bl_list[col] + bl_l = self.int_bl_list[col] bl_h = "gnd" + # elif first_in_col: + # bl_l = self.bitline_names[0][col] + # int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) + # bl_h = int_bl_list[col] + # first_in_col = False else: - bl_l = int_bl_list[col] - int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) - bl_h = int_bl_list[col] + bl_l = self.int_bl_list[col] + self.int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) + bl_h = self.int_bl_list[col] self.cell_inst[row, col] = new_inst @@ -192,10 +197,12 @@ class rom_base_array(bitcell_base_array): def create_precharge_inst(self): - prechrg_pins = [] + prechrg_pins = self.bitline_names[0].copy() for bl in range(self.column_size): - prechrg_pins.append(self.bitline_names[0][bl]) + # if the internal bl was never updated there are no active cells in the bitline, so it should route straight to ground" + if self.int_bl_list[bl] == prechrg_pins[bl]: + prechrg_pins[bl] = "gnd" prechrg_pins.append("precharge_gate") prechrg_pins.append("vdd") @@ -362,34 +369,3 @@ class rom_base_array(bitcell_base_array): return "bli_{0}_{1}".format(row, col) - def get_bitcell_pins(self, row, col): - """ - return the correct nets to attack nmos/cell drain, gate, source, body pins to - """ - - bitcell_pins = [] - - #drain pin - if self.current_row == 0: - bitcell_pins.append(self.bitline_names[0][col]) - else: - bitcell_pins.append(self.get_current_bl_interconnect(col)) - - - #gate pin - bitcell_pins.append(self.get_wordline_names()[row]) - - #source pin - - """If there is another bitcell to be placed below the current cell, """ - - if self.get_next_cell_in_bl(row, col) == -1: - bitcell_pins.append("gnd") - else: - """create another interconnect net""" - bitcell_pins.append(self.create_next_bl_interconnect(row, col)) - - #body pin - bitcell_pins.append("gnd") - - return bitcell_pins diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py index 89ce801b..4ddbc1c7 100644 --- a/compiler/modules/rom_dummy_cell.py +++ b/compiler/modules/rom_dummy_cell.py @@ -6,8 +6,6 @@ # All rights reserved. # - - from openram.base import design from openram.base import vector from openram import OPTS diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 16c2fac5..2eb5c447 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -10,7 +10,6 @@ from openram.base import design from openram.base import vector from openram import OPTS from openram.sram_factory import factory - from openram.tech import drc diff --git a/compiler/tests/05_rom_base_bank_test.py b/compiler/tests/05_rom_base_bank_test.py index 2b5841e9..2685b57b 100644 --- a/compiler/tests/05_rom_base_bank_test.py +++ b/compiler/tests/05_rom_base_bank_test.py @@ -27,7 +27,7 @@ class rom_bank_test(openram_test): a = factory.create(module_type="rom_base_bank", strap_spacing = 2) self.local_check(a) - globals.end_openram() + openram.end_openram() # run the test from the command line if __name__ == "__main__": diff --git a/compiler/tests/05_rom_precharge_array_test.py b/compiler/tests/05_rom_precharge_array_test.py index b8e9e5ff..79bca2b3 100644 --- a/compiler/tests/05_rom_precharge_array_test.py +++ b/compiler/tests/05_rom_precharge_array_test.py @@ -27,7 +27,7 @@ class rom_precharge_test(openram_test): a = factory.create(module_type="rom_precharge_array", cols=4, strap_spacing=2) self.local_check(a) - globals.end_openram() + openram.end_openram() # run the test from the command line if __name__ == "__main__": From ce8197d206a0741ac1c620e2c21c99b0cd4fd148 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Fri, 30 Dec 2022 00:35:15 -0800 Subject: [PATCH 38/98] pitch match decoder and array --- compiler/modules/rom_base_array.py | 92 +++++++---- compiler/modules/rom_base_bank.py | 165 ++++++++++++++++---- compiler/modules/rom_base_cell.py | 13 +- compiler/modules/rom_control_logic.py | 81 ++++++++++ compiler/modules/rom_decoder.py | 17 +- compiler/modules/rom_dummy_cell.py | 24 ++- compiler/modules/rom_inv_array.py | 3 +- compiler/modules/rom_poly_tap.py | 33 ++-- compiler/modules/rom_precharge_array.py | 1 + compiler/modules/rom_precharge_cell.py | 6 +- compiler/tests/05_rom_array_test.py | 2 +- compiler/tests/05_rom_base_bank_test.py | 2 +- compiler/tests/05_rom_control_logic_test.py | 37 +++++ 13 files changed, 361 insertions(+), 115 deletions(-) create mode 100644 compiler/modules/rom_control_logic.py create mode 100644 compiler/tests/05_rom_control_logic_test.py diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 6cec6480..a46cce33 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -16,11 +16,12 @@ from openram.tech import drc class rom_base_array(bitcell_base_array): - def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0, route_layer="li", output_layer="m2"): + def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0, route_layer="li", output_layer="m2", pitch_match=False): super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset) self.data = bitmap + self.pitch_match = pitch_match self.route_layer = route_layer self.output_layer = output_layer self.strap_spacing = strap_spacing @@ -44,14 +45,18 @@ class rom_base_array(bitcell_base_array): def create_layout(self): + self.create_layout_constants() self.place_array() + if self.pitch_match: + self.route_pitch_offsets() + self.place_precharge() self.place_wordline_contacts() self.place_bitline_contacts() - self.place_precharge() + + self.place_rails() self.route_precharge() - self.add_boundary() self.add_label("ARRAY ZERO", self.route_layer) self.add_label("array height", self.route_layer, [0, self.height]) @@ -95,6 +100,12 @@ class rom_base_array(bitcell_base_array): self.precharge_array = factory.create(module_type="rom_precharge_array", cols=self.column_size, strap_spacing=self.strap_spacing, route_layer=self.route_layer) + def create_layout_constants(self): + self.route_width = drc("minwidth_" + self.route_layer) + + self.route_pitch = drc("{0}_to_{0}".format(self.route_layer)) + + def add_pins(self): for bl_name in self.get_bitline_names(): self.add_pin(bl_name, "INOUT") @@ -116,9 +127,13 @@ class rom_base_array(bitcell_base_array): row_list = [] # for each new strap placed, offset the column index refrenced to get correct bit in the data array - strap_offset = 0 - first_in_col = True # cols are bit lines + strap_row = False + pre_strap_row = False + if row % self.strap_spacing == 0 and self.pitch_match: + strap_row = True + if (row + 1) % self.strap_spacing == 0 and self.pitch_match: + pre_strap_row = True for col in range(self.column_size): if col % self.strap_spacing == 0: @@ -127,7 +142,6 @@ class rom_base_array(bitcell_base_array): #print("tap instance added at c{0}, r{1}".format(col, row)) self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) self.connect_inst([]) - strap_offset += 1 name = "bit_r{0}_c{1}".format(row, col) @@ -137,19 +151,23 @@ class rom_base_array(bitcell_base_array): # if the last row and 0 below add both contacts if (row < self.row_size - 1 and row > 0 and self.data[row + 1][col] == 0 and self.data[row - 1][col] == 0) or \ (row == self.row_size - 1 and self.data[row - 1][col] == 0) or \ - (row == 0 and self.data[row + 1][col] == 0): + (row == 0 and self.data[row + 1][col] == 0) or \ + (row < self.row_size - 1 and self.data[row + 1][col] == 0 and strap_row) or \ + (row > 0 and self.data[row - 1][col] == 0 and pre_strap_row): new_inst = self.add_inst(name=name, mod=self.cell_ac) # if dummy/0 is below and not above, add a source contact # if in the first row, add a source contact elif (row > 0 and self.data[row - 1][col] == 0) or \ - (row == 0): + (row == 0) or \ + (strap_row): new_inst=self.add_inst(name=name, mod=self.cell_sc) elif (row < self.row_size - 1 and self.data[row + 1][col] == 0) or \ - (row == self.row_size - 1): + (row == self.row_size - 1) or \ + (pre_strap_row): new_inst=self.add_inst(name=name, mod=self.cell_dc) else: @@ -187,7 +205,6 @@ class rom_base_array(bitcell_base_array): row_list.append(new_inst) - name = "tap_r{0}_c{1}".format(row, self.array_col_size) #print(*row_list) self.tap_inst[row, self.column_size]=self.add_inst(name=name, mod=self.zero_tap) @@ -222,9 +239,7 @@ class rom_base_array(bitcell_base_array): def place_rails(self): - width = drc("minwidth_" + self.route_layer) - drc_rule = "{0}_to_{0}".format(self.route_layer) - spacing = drc(drc_rule) + spacing = self.route_pitch rail_y = self.cell_list[self.row_size - 1][0].offset.y + self.dummy.base_width + spacing # self.dummy.height * (self.row_size) @@ -237,7 +252,7 @@ class rom_base_array(bitcell_base_array): rail_start = vector(start_x , rail_y) rail_end = vector(end_x, rail_y) - self.gnd = self.add_layout_pin_rect_ends( name="gnd", + self.gnd = self.add_layout_pin_rect_ends(name="gnd", layer="m1", start=rail_start, end=rail_end) @@ -249,22 +264,22 @@ class rom_base_array(bitcell_base_array): self.add_via_stack_center(via_pos, self.route_layer, "m1", ["H", "V"]) - - prechrg_vdd = self.precharge_inst.get_pin("vdd") def place_array(self): self.cell_pos = {} self.strap_pos = {} # rows are wordlines + + pitch_offset = 0 for row in range(self.row_size): - # strap_cols = -1 + if row % self.strap_spacing == 0 and row != 0 and self.pitch_match: + pitch_offset += self.poly_tap.width - cell_y = row * (self.dummy.height) + cell_y = row * (self.dummy.height) + pitch_offset cell_x = 0 - for col in range(self.column_size): if col % self.strap_spacing == 0: @@ -286,6 +301,19 @@ class rom_base_array(bitcell_base_array): # self.add_layout_pin_rect_center("wl{}".format(row), "m2", tap_pin) + def route_pitch_offsets(self): + + for row in range(0 , self.row_size, self.strap_spacing): + if row != 0: + for col in range(self.column_size): + source = self.cell_inst[row, col].get_pin("S") + drain = self.cell_inst[row - 1, col].get_pin("D") + + start = vector(drain.cx(), source.cy()) + end = drain.center() + self.add_segment_center(self.route_layer, start, end) + + def place_precharge(self): self.precharge_offset = vector(0, - self.precharge_inst.height - self.dummy.nmos.end_to_contact - 2 * drc["nwell_enclose_active"]) @@ -293,14 +321,15 @@ class rom_base_array(bitcell_base_array): self.precharge_inst.place(offset=self.precharge_offset) self.copy_layout_pin(self.precharge_inst, "vdd") + self.copy_layout_pin(self.precharge_inst, "gate", "precharge") def place_wordline_contacts(self): - width = drc["minwidth_{}".format(self.route_layer)] + width = self.route_width - height = drc["minwidth_{}".format(self.route_layer)] + height = self.route_width offset = vector(self.poly_contact.width * 0.5, self.dummy.poly.offset.y) @@ -308,36 +337,31 @@ class rom_base_array(bitcell_base_array): poly_via = self.tap_inst[wl, 0].get_pin("via") self.copy_layout_pin(self.tap_inst[wl, 0], "via", self.wordline_names[0][wl]) - self.add_via_stack_center(poly_via.center(), "m1", self.output_layer) + # self.add_via_stack_center(poly_via.center(), "m1", self.output_layer) - corrected_offset = offset - vector(0.5 * width, 0.5 * height) # self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.dummy.height, length=None) def place_bitline_contacts(self): - src_pin = self.cell_nc.source_pos + rail_y = self.precharge_inst.get_pin("vdd").cy() for bl in range(self.column_size): - - # self.copy_layout_pin(self.cell_list[0][bl], "S", self.bitline_names[0][bl]) - src_pin = self.cell_list[0][bl].get_pin("S") prechg_pin_name = "pre_bl{0}_out".format(bl) pre_pin = self.precharge_inst.get_pin(prechg_pin_name) - - # offset = src_pin_offset + vector(src_pin.x, 0) - - - middle_offset = (pre_pin.cy() - src_pin.cy()) * 0.5 + middle_offset = (src_pin.cy() - pre_pin.cy() ) * 0.5 corrected = vector(src_pin.cx(), src_pin.cy() - middle_offset) self.add_via_stack_center(corrected, self.route_layer, self.output_layer) - self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, corrected ) + output_pos = vector(corrected.x, rail_y) + + self.add_segment_center(self.output_layer, corrected, output_pos) - # self.gnd[0].y() + self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, output_pos ) + def route_precharge(self): diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index 2ce14ab7..d288fdc2 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -1,40 +1,82 @@ -import math +from math import ceil, log, sqrt from openram.base import vector from openram.base import design from openram import OPTS from openram.sram_factory import factory -import tech from openram.tech import drc class rom_base_bank(design): - def __init__(self, strap_spacing=0, data_file=None, name="") -> None: - self.rows = 4 - self.cols = 4 - self.num_inputs = 2 - self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] + def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2) -> None: + + # self.cols = word_size * 8 + self.read_binary(word_size=word_size, data_file=data_file) + + self.num_outputs = self.rows + self.num_inputs = ceil(log(self.rows, 2)) + + # self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] self.strap_spacing = strap_spacing self.route_layer = "li" - self.bus_layer = "m1" - self.interconnect_layer = "m2" + self.bus_layer = "m2" + self.interconnect_layer = "m1" - - super().__init__(name=name) self.setup_layout_constants() self.create_netlist() self.create_layout() + """ + Reads a hexadecimal file from a given directory to be used as the data written to the ROM + endian is either "big" or "little" + word_size is the number of bytes per word + sets the row and column size based on the size of binary input, tries to keep array as square as possible, + """ + def read_binary(self, data_file, word_size=2, endian="big"): + + hex_file = open(data_file, 'r') + hex_data = hex_file.read() + bin_data = list("{0:08b}".format(int(hex_data, 16))) + bin_data = [int(x) for x in bin_data] + + # data size in bytes + data_size = len(bin_data) / 8 + num_words = int(data_size / word_size) + + bytes_per_col = sqrt(num_words) + + self.words_per_row = int(ceil(bytes_per_col /(2*word_size))) + + bits_per_row = self.words_per_row * word_size * 8 + + chunked_data = [] + + for i in range(0, len(bin_data), bits_per_row): + word = bin_data[i:i + bits_per_row] + if len(word) < bits_per_row: + word = [0] * (bits_per_row - len(word)) + word + chunked_data.append(word) + + if endian == "big": + chunked_data.reverse() + + self.data = chunked_data + self.cols = bits_per_row + self.rows = int(num_words / (self.words_per_row)) + # print("hex: {0}, binary: {1}, chunked: {2}".format(hex_data, bin_data, chunked_data)) + + def create_netlist(self): self.add_modules() + # self.add_pins() self.create_instances() def create_layout(self): self.place_instances() - self.create_wl_bus() + # self.channel_route() self.route_decode_outputs() - self.route_array_inputs() + self.route_control() self.route_supplies() self.height = self.array_inst.height @@ -47,12 +89,31 @@ class rom_base_bank(design): self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_layer)] self.bus_layer_width = drc["minwidth_{}".format(self.bus_layer)] self.bus_layer_pitch = drc["{0}_to_{0}".format(self.bus_layer)] + self.interconnect_layer_width = drc["minwidth_{}".format(self.interconnect_layer)] + self.interconnect_layer_pitch = drc["{0}_to_{0}".format(self.interconnect_layer)] + + def add_pins(self): + self.add_pin("READ", "INPUT") + self.add_pin("CS", "INPUT") + + for i in range(self.num_inputs): + self.add_pin("addr_{}".format(i), "INPUT") + + + out_pins = [] + for j in range(self.num_outputs): + out_pins.append("rom_out_{}".format(j)) + self.add_pin_list(out_pins, "OUTPUT") + + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + def add_modules(self): - self.array = factory.create(module_type="rom_base_array", cols=self.cols, rows=self.rows, strap_spacing=self.strap_spacing, bitmap=self.data, route_layer=self.route_layer) + self.array = factory.create(module_type="rom_base_array", cols=self.cols, rows=self.rows, strap_spacing=self.strap_spacing, bitmap=self.data, route_layer=self.route_layer, pitch_match=True) self.decode_array = factory.create(module_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer) - + self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.rows + self.cols) / 2, height=self.decode_array.inv_inst.height) def create_instances(self): @@ -66,7 +127,7 @@ class rom_base_bank(design): name = "wl_{}".format(wl) array_pins.append(wl) - array_pins.append("array_precharge") + array_pins.append("precharge") array_pins.append("vdd") array_pins.append("gnd") @@ -78,7 +139,7 @@ class rom_base_bank(design): name = "wl_{}".format(wl) decode_pins.append(name) - decode_pins.append("decode_precharge") + decode_pins.append("precharge") decode_pins.append("vdd") decode_pins.append("gnd") @@ -89,20 +150,26 @@ class rom_base_bank(design): self.decode_inst = self.add_inst(name="rom_decoder", mod=self.decode_array) self.connect_inst(decode_pins) + self.control_inst = self.add_inst(name="rom_control", mod=self.control_logic) + self.connect_inst(["READ", "CS", "precharge", "vdd", "gnd"]) + def place_instances(self): - - array_x = self.decode_inst.width + (self.rows + 2) * ( self.route_layer_width + self.route_layer_pitch ) - array_y = self.array.height - + + array_x = self.decode_inst.width + (2) * ( self.route_layer_width + self.route_layer_pitch ) + array_y = self.decode_array.inv_inst.height - self.array.precharge_inst.cy() - self.array.dummy.height * 0.5 self.array_offset = vector(array_x ,array_y) self.decode_offset = vector(0, 0) - self.array_inst.place(offset=self.array_offset, mirror="MX") + self.control_offset = vector(0,0) + + self.array_inst.place(offset=self.array_offset) self.decode_inst.place(offset=self.decode_offset) + self.control_inst.place(offset=self.control_offset, mirror="MX") + def create_wl_bus(self): bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width @@ -119,13 +186,17 @@ class rom_base_bank(design): decode_output = self.decode_array.output_names[wl] decode_out_pin = self.decode_inst.get_pin(decode_output) - wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] + array_wl = self.array.wordline_names[0][wl] + array_wl_pin = self.array_inst.get_pin(array_wl) + + + # wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] start = decode_out_pin.center() - end = vector(wl_bus_wire.cx(), start.y) + end = vector(array_wl_pin.cx(), start.y) - self.add_segment_center(self.interconnect_layer, start, end) - self.add_via_stack_center(end, self.route_layer, self.interconnect_layer ) + self.add_segment_center(self.bus_layer, start, end) + self.add_via_stack_center(array_wl_pin.center(), self.bus_layer, self.interconnect_layer ) def route_array_inputs(self): @@ -142,18 +213,52 @@ class rom_base_bank(design): self.add_segment_center(self.interconnect_layer, start, end) self.add_via_stack_center(start, self.route_layer, self.interconnect_layer ) + def channel_route(self): + route_nets = [] + for wl in range(self.rows): + array_wl = self.array.wordline_names[0][wl] + + array_wl_pin = self.array_inst.get_pin(array_wl) + + decode_output = self.decode_array.output_names[wl] + decode_out_pin = self.decode_inst.get_pin(decode_output) + + route_nets.append([array_wl_pin, decode_out_pin]) + + array_prechrg = self.array_inst.get_pin("precharge") + decode_prechrg = self.decode_inst.get_pin("precharge") + route_nets.append([array_prechrg, decode_prechrg]) + + channel_start = vector(decode_out_pin.cx(), self.decode_array.array_inst.by()) + + channel = self.create_vertical_channel_route(netlist=route_nets, offset=channel_start, layer_stack=self.m1_stack, directions="nonpref") + + + def route_control(self): + + prechrg_control = self.control_inst.get_pin("prechrg") + decode_prechrg = self.decode_inst.get_pin("precharge") + array_prechrg = self.array_inst.get_pin("precharge") + + end = vector(decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy()) + + self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end) + + start = end + vector(0.5 * self.interconnect_layer_width, 0) + self.add_segment_center(self.interconnect_layer, start, decode_prechrg.center()) + + + def route_supplies(self): gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0) - print() - print(self.decode_inst.get_pin("gnd").center()) + decode_gnd = self.decode_inst.get_pin("gnd") decode_vdd = self.decode_inst.get_pin("vdd") array_vdd = self.array_inst.get_pin("vdd") - self.add_segment_center("m1", gnd_start, decode_gnd.center()) + # self.add_segment_center("m1", gnd_start, decode_gnd.center()) - self.add_power_pin("gnd", decode_vdd.center()) self.add_power_pin("vdd", decode_gnd.center()) diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index b6b5a8dd..668bc82d 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -17,9 +17,7 @@ class rom_base_cell(rom_dummy_cell): def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"): super().__init__(name, cell_name, add_source_contact, add_drain_contact, route_layer) - #self.route_layer= route_layer - #self.create_netlist() - #self.create_layout() + def create_netlist(self): @@ -27,7 +25,6 @@ class rom_base_cell(rom_dummy_cell): self.add_nmos() self.create_nmos() - def create_layout(self): self.setup_drc_offsets() self.place_nmos() @@ -64,15 +61,7 @@ class rom_base_cell(rom_dummy_cell): self.copy_layout_pin(self.cell_inst, "S", "S") self.copy_layout_pin(self.cell_inst, "D", "D") self.source_pos = self.cell_inst.get_pin("S").center() - # if self.add_source_contact != False: - # # drain_x = 0 - # # drain_y = 0.5 * (self.width - self.poly_extend_active_spacing) - - # print("drained") - # print(drain_pos) - # self.add_layout_pin_rect_center("S", self.route_layer, drain_pos) - # self.add_label("S", self.route_layer, self.cell_inst.get_pin("S").center()) diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py new file mode 100644 index 00000000..4d3da899 --- /dev/null +++ b/compiler/modules/rom_control_logic.py @@ -0,0 +1,81 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2022 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 openram.sram_factory import factory +from openram.base import vector, design + + +class rom_control_logic(design): + def __init__(self, num_outputs, name="", height=None): + self.output_size = num_outputs + self.mod_height = height + + # dff = factory.create(module_type="dff") + + # if height == None: + # self.mod_height = dff.height * 0.5 + # else: + # self.mod_height = height + + super().__init__(name) + self.create_netlist() + self.create_layout() + self.add_boundary() + + + def create_netlist(self): + self.add_modules() + self.add_pins() + + def create_layout(self): + self.create_instances() + self.height=self.nand_inst.height + self.width=self.nand_inst.width + self.inv_inst.width + self.driver_inst.width + self.place_instances() + self.route_insts() + + def add_modules(self): + + self.inv_mod = factory.create(module_type="pinv", module_name="rom_control_logic_pinv", height=self.mod_height) + self.nand_mod = factory.create(module_type="pnand2", module_name="rom_control_nand", height=self.mod_height) + self.driver_mod = factory.create(module_type="pdriver", inverting=True, fanout=self.output_size, height=self.mod_height, add_wells=False) + + + def add_pins(self): + self.add_pin("READ", "INPUT") + self.add_pin("CS", "INPUT") + self.add_pin("prechrg", "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def create_instances(self): + + self.inv_inst = self.add_inst(name="read_signal_inv", mod=self.inv_mod) + self.connect_inst(["READ", "READ_BAR", "vdd", "gnd"]) + + self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod) + self.connect_inst(["CS", "READ_BAR", "pre_drive", "vdd", "gnd"]) + + self.driver_inst = self.add_inst(name="driver_inst", mod=self.driver_mod) + self.connect_inst(["pre_drive", "prechrg", "vdd", "gnd"]) + + + def place_instances(self): + self.nand_inst.place(offset=[self.inv_inst.width, 0]) + self.driver_inst.place(offset=[self.nand_inst.width + self.inv_inst.width, 0]) + + def route_insts(self): + + self.copy_layout_pin(self.inv_inst, "A", "READ") + self.copy_layout_pin(self.driver_inst, "Z", "prechrg") + self.copy_layout_pin(self.nand_inst, "B", "CS") + + self.add_path("li", [self.inv_inst.get_pin("Z").center(), self.nand_inst.get_pin("A").center()]) + + self.add_path("li", [self.nand_inst.get_pin("Z").center(), self.driver_inst.get_pin("A").center()]) + \ No newline at end of file diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index 0cd1ba16..34fb5453 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -5,15 +5,14 @@ # (acting for and on behalf of Oklahoma State University) # All rights reserved. # - from math import ceil, log -from openram.base import design from openram.sram_factory import factory -from openram.base import vector +from openram.base import vector, design from openram import OPTS from openram.tech import drc + class rom_decoder(design): def __init__(self, num_outputs, strap_spacing, name="", route_layer="li", output_layer="m2"): @@ -25,7 +24,7 @@ class rom_decoder(design): self.num_inputs = ceil(log(num_outputs, 2)) self.create_decode_map() - for i in range(2 * self.num_inputs): print(self.decode_map[i]) + # for i in range(2 * self.num_inputs): print(self.decode_map[i]) super().__init__(name) @@ -152,7 +151,6 @@ class rom_decoder(design): def place_input_inverters(self): - print(self.array_inst.ll().x) self.inv_inst.place(vector(self.array_inst.ll().x, 0)) @@ -163,7 +161,6 @@ class rom_decoder(design): def create_outputs(self): self.output_names = [] - self.outputs = [] for j in range(self.num_outputs): name = "out_{0}".format(j) self.output_names.append(name) @@ -179,6 +176,8 @@ class rom_decoder(design): def connect_inputs(self): + self.copy_layout_pin(self.array_inst, "precharge") + for i in range(self.num_inputs): wl = self.num_inputs * 2 - i * 2 - 1 wl_bar = wl - 1 @@ -235,14 +234,8 @@ class rom_decoder(design): offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy())) - - - # self.add_rect_center(self.route_layer, offset, width, height) - - start = end - vector(0, 0.5 * minwidth) end = vector(start.x, array_gnd[1].uy()) - # self.add_segment_center("m1", start, end) diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py index 4ddbc1c7..bf5932b6 100644 --- a/compiler/modules/rom_dummy_cell.py +++ b/compiler/modules/rom_dummy_cell.py @@ -18,8 +18,8 @@ class rom_dummy_cell(design): def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"): super().__init__(name, cell_name) self.route_layer = route_layer - self.add_source_contact=add_source_contact - self.add_drain_contact=add_drain_contact + self.add_source_contact="li" + self.add_drain_contact="li" self.create_netlist() self.create_layout() @@ -70,12 +70,22 @@ class rom_dummy_cell(design): def add_boundary(self): - #cell width with offsets applied, height becomes width when the cells are rotated - # self.width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active - self.width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active - # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied - self.height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) + width = self.nmos.width + self.active_space + #cell width with offsets applied, height becomes width when the cells are rotated + # width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active + # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied + height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) + + # make the cells square so the pitch of wordlines will match bitlines + print("height: {0} width: {1}".format(height, width)) + if width > height: + self.width = width + self.height = width + else: + self.width = height + self.height = height + super().add_boundary() diff --git a/compiler/modules/rom_inv_array.py b/compiler/modules/rom_inv_array.py index cc87dc24..5774e2fc 100644 --- a/compiler/modules/rom_inv_array.py +++ b/compiler/modules/rom_inv_array.py @@ -56,7 +56,7 @@ class rom_inv_array(design): def create_modules(self): self.inv_mod = factory.create(module_type="pinv", module_name="inv_array_mod", height=self.inv_size, add_wells=False) - self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size) + self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size, add_wells=True) # For layout constants self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=0) @@ -73,7 +73,6 @@ class rom_inv_array(design): for col in range(self.cols): name = "Xinv_c{0}".format(col) if col == self.cols - 1: - print("TAP ME DOWN") self.inv_insts.append(self.add_inst(name=name, mod=self.end_inv)) else: self.inv_insts.append(self.add_inst(name=name, mod=self.inv_mod)) diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index c01ac380..ec6a1a4e 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -13,7 +13,7 @@ from openram.sram_factory import factory class rom_poly_tap(design): - def __init__(self, name, strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m1"): + def __init__(self, name="", strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m1"): super().__init__(name, cell_name, prop) self.strap_layer=strap_layer self.length = strap_length @@ -37,13 +37,20 @@ class rom_poly_tap(design): def add_boundary(self): + contact_width = self.poly_contact.width + 2 * self.contact_x_offset + + offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact) + print("THINGY {}".format(offset)) self.height = self.dummy.height - self.width = self.poly_contact.width + 2 * self.contact_x_offset + self.width = contact_width + self.pitch_offset + + print("poly height: {0}, width: {1}".format(self.height, self.width)) super().add_boundary() def place_via(self): contact_width = self.poly_contact.width + # DRC rule here is hard coded since licon.9 isnt included in skywater130 tech file # poly contact spacing to P-diffusion < 0.235um (licon.9 + psdm.5a) @@ -59,23 +66,16 @@ class rom_poly_tap(design): # self.contact_x_offset = 0 else: contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x - print(self.tx_type) - print(contact_y) # contact_x = - contact_width * 0.5 - self.contact_x_offset contact_x = contact_width * 0.5 + self.contact_x_offset self.contact_offset = vector(contact_x, contact_y) - print("polycule") - print(self.contact_offset) + self.via = self.add_via_stack_center(from_layer="poly", to_layer=self.strap_layer, offset=self.contact_offset) self.add_layout_pin_rect_center("via", self.strap_layer, self.contact_offset) - # if self.length == 0: - # self.add_layout_pin_rect_center(text="poly_tap", - # layer=self.strap_layer, - # offset=print()contact_offset, - # ) + @@ -88,14 +88,21 @@ class rom_poly_tap(design): self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) def extend_poly(self): + + base_contact_width = self.poly_contact.width + 2 * self.contact_x_offset + + self.pitch_offset = (base_contact_width - self.active_enclose_contact - self.active_extend_contact) - self.active_space + + poly_x = self.poly_contact.width + self.contact_x_offset poly_y = self.contact_offset.y - self.poly_width * 0.5 extend_offset = vector(poly_x, poly_y) - self.add_rect("poly", extend_offset, self.contact_x_offset, self.poly_width) + + self.add_rect("poly", extend_offset, self.contact_x_offset + self.pitch_offset, self.poly_width) poly_x = 0 extend_offset = vector(poly_x, poly_y) - self.add_rect("poly", extend_offset, self.contact_x_offset, self.poly_width) + self.add_rect("poly", extend_offset, self.contact_x_offset , self.poly_width) diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index dc7fbb77..8acfb8c8 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -139,6 +139,7 @@ class rom_precharge_array(design): def create_layout_pins(self): + self.copy_layout_pin(self.tap_insts[0], "via", "gate") for col in range(self.cols): source_pin = self.pmos_insts[col].get_pin("D") bl = "pre_bl{0}_out".format(col) diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 2eb5c447..d41f07c2 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -50,12 +50,12 @@ class rom_precharge_cell(design): self.cell_inst = self.add_inst( name="precharge_pmos", mod=self.pmos, ) - self.connect_inst(["bitline", "gate", "vdd", "vdd"]) + self.connect_inst(["bitline", "gate", "vdd", "body"]) def add_pins(self): - pin_list = ["vdd", "gate", "bitline", "vdd"] - dir_list = ["OUTPUT", "INPUT", "OUTPUT", "POWER"] + pin_list = ["vdd", "gate", "bitline", "body"] + dir_list = ["POWER", "INPUT", "OUTPUT", "INPUT"] self.add_pin_list(pin_list, dir_list) diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/05_rom_array_test.py index 13708a6c..790d8839 100644 --- a/compiler/tests/05_rom_array_test.py +++ b/compiler/tests/05_rom_array_test.py @@ -27,7 +27,7 @@ class rom_array_test(openram_test): data = [[1, 0, 0, 0, 0, 1, 0, 0, 1], [0, 1, 1, 1, 0, 1, 0, 0, 1], [1, 0, 1, 1, 0, 1, 0, 0, 1], [1, 1, 0, 1, 1, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 0, 0, 1], [0, 1, 1, 1, 1, 0, 0, 0, 1], [1, 0, 1, 1, 1, 0, 0, 0, 1], [1, 1, 0, 0, 1, 1, 0, 0, 1]] - a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4) + a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4, pitch_match=True) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/05_rom_base_bank_test.py b/compiler/tests/05_rom_base_bank_test.py index 2685b57b..277205b1 100644 --- a/compiler/tests/05_rom_base_bank_test.py +++ b/compiler/tests/05_rom_base_bank_test.py @@ -24,7 +24,7 @@ class rom_bank_test(openram_test): debug.info(2, "Testing 4x4 array for rom cell") - a = factory.create(module_type="rom_base_bank", strap_spacing = 2) + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data", word_size=1) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/05_rom_control_logic_test.py b/compiler/tests/05_rom_control_logic_test.py new file mode 100644 index 00000000..4e13b9bf --- /dev/null +++ b/compiler/tests/05_rom_control_logic_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 + +import openram +from openram import OPTS +from openram.sram_factory import factory +from openram import debug + + +class rom_decoder_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + debug.info(2, "Testing control logic for rom cell") + + + a = factory.create(module_type="rom_control_logic", num_outputs=4) + self.local_check(a) + openram.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From f7aed247fd89f4e2208c8ea45b3acb6d4d75f6cb Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 16 Jan 2023 16:15:03 -0800 Subject: [PATCH 39/98] column control and address precharge --- compiler/base/hierarchy_layout.py | 4 +- compiler/modules/pbuf_dec.py | 10 +- compiler/modules/rom_address_control_array.py | 120 +++++++++ compiler/modules/rom_address_control_buf.py | 214 ++++++++++++++++ compiler/modules/rom_base_array.py | 201 ++++++--------- compiler/modules/rom_base_bank.py | 113 +++++++-- compiler/modules/rom_base_cell.py | 131 ++++++++-- compiler/modules/rom_column_mux.py | 239 ++++++++++++++++++ compiler/modules/rom_column_mux_array.py | 215 ++++++++++++++++ compiler/modules/rom_control_logic.py | 17 +- compiler/modules/rom_decoder.py | 129 ++++++---- compiler/modules/rom_dummy_cell.py | 63 ----- compiler/modules/rom_inv_array.py | 129 ---------- compiler/modules/rom_poly_tap.py | 27 +- compiler/modules/rom_precharge_array.py | 61 ++--- compiler/modules/rom_precharge_cell.py | 92 +++---- compiler/modules/rom_wordline_driver_array.py | 119 +++++++++ compiler/tests/05_rom_array_test.py | 2 +- .../tests/05_rom_column_mux_array_test.py | 36 +++ .../tests/05_rom_decoder_buffer_array_test.py | 37 +++ compiler/tests/05_rom_decoder_test.py | 2 +- .../05_rom_wordline_driver_array_test.py | 38 +++ 22 files changed, 1479 insertions(+), 520 deletions(-) create mode 100644 compiler/modules/rom_address_control_array.py create mode 100644 compiler/modules/rom_address_control_buf.py create mode 100644 compiler/modules/rom_column_mux.py create mode 100644 compiler/modules/rom_column_mux_array.py delete mode 100644 compiler/modules/rom_inv_array.py create mode 100644 compiler/modules/rom_wordline_driver_array.py create mode 100644 compiler/tests/05_rom_column_mux_array_test.py create mode 100644 compiler/tests/05_rom_decoder_buffer_array_test.py create mode 100644 compiler/tests/05_rom_wordline_driver_array_test.py diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 9a11b68a..eb586a18 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -696,13 +696,15 @@ class layout(): start=left_pos, end=right_pos) - def connect_row_pins(self, layer, pins, name=None, full=False): + def connect_row_pins(self, layer, pins, name=None, full=False, round=False): """ Connects left/right rows that are aligned. """ bins = {} for pin in pins: y = pin.cy() + if round: + y = round_to_grid(y) try: bins[y].append(pin) except KeyError: diff --git a/compiler/modules/pbuf_dec.py b/compiler/modules/pbuf_dec.py index e42c159e..5e2877f3 100644 --- a/compiler/modules/pbuf_dec.py +++ b/compiler/modules/pbuf_dec.py @@ -15,7 +15,7 @@ class pbuf_dec(pgate): """ This is a simple buffer used for driving wordlines. """ - def __init__(self, name, size=4, height=None): + def __init__(self, name, size=4, height=None, add_wells=True): debug.info(1, "creating {0} with size of {1}".format(name, size)) self.add_comment("size: {}".format(size)) @@ -25,7 +25,7 @@ class pbuf_dec(pgate): self.height = height # Creates the netlist and layout - pgate.__init__(self, name, height) + pgate.__init__(self, name, height, add_wells) def create_netlist(self): self.add_pins() @@ -51,11 +51,13 @@ class pbuf_dec(pgate): input_size = max(1, int(self.size / self.stage_effort)) self.inv1 = factory.create(module_type="pinv_dec", size=input_size, - height=self.height) + height=self.height, + add_wells=self.add_wells) self.inv2 = factory.create(module_type="pinv_dec", size=self.size, - height=self.height) + height=self.height, + add_wells=self.add_wells) def create_insts(self): self.inv1_inst = self.add_inst(name="buf_inv1", diff --git a/compiler/modules/rom_address_control_array.py b/compiler/modules/rom_address_control_array.py new file mode 100644 index 00000000..2b195bd8 --- /dev/null +++ b/compiler/modules/rom_address_control_array.py @@ -0,0 +1,120 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 openram.base import design +from openram.sram_factory import factory +from openram.base import vector +from openram.tech import layer, drc + + + +class rom_address_control_array(design): + """ + Takes the input address lines and creates the address and address bar lines for the decoder. + Adds control logic for the precharge cycle so that all address lines are high before the read cycle + """ + def __init__(self, cols, inv_height=None, inv_size=1, name="", route_layer="m1"): + self.size=inv_size + self.cols = cols + self.route_layer = route_layer + dff = factory.create(module_type="dff") + if name=="": + name = "rom_inv_array_{0}".format(cols) + if inv_height == None: + self.inv_height = dff.height * 0.5 + else: + self.inv_height = inv_height + + + if "li" in layer: + self.inv_layer = "li" + else: + self.inv_layer = "m1" + super().__init__(name) + self.create_netlist() + self.create_layout() + + def create_netlist(self): + self.create_modules() + self.add_pins() + self.create_instances() + + + def create_layout(self): + self.width = self.cols * self.addr_control.width + self.height = self.addr_control.height + self.setup_layout_constants() + self.place_instances() + self.route_clk() + self.route_sources() + self.copy_pins() + self.add_boundary() + + + def create_modules(self): + + self.addr_control = factory.create(module_type="rom_address_control_buf", size=self.inv_height) + # For layout constants + # self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=0) + + def add_pins(self): + for col in range(self.cols): + self.add_pin("A{0}_in".format(col), "INPUT") + self.add_pin("A{0}_out".format(col), "OUTPUT") + self.add_pin("Abar{0}_out".format(col), "OUTPUT") + self.add_pin("clk", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def create_instances(self): + + self.buf_insts = [] + + for col in range(self.cols): + + name = "Xaddr_buf_{0}".format(col) + + addr_buf = self.add_inst(name=name, mod=self.addr_control) + + A_in = "A{0}_in".format(col) + Aout = "A{0}_out".format(col) + Abar_out = "Abar{0}_out".format(col) + self.connect_inst([A_in, Aout, Abar_out, "clk", "vdd", "gnd"]) + + self.buf_insts.append(addr_buf) + + def setup_layout_constants(self): + self.route_width = drc["minwidth_{}".format(self.route_layer)] + + def place_instances(self): + for col in range(self.cols): + base = vector((col+1)*(self.addr_control.width), 0) + + self.buf_insts[col].place(offset=base, mirror="MY") + + + def copy_pins(self): + for i in range(self.cols): + self.copy_layout_pin(self.buf_insts[i], "A_out", "A{0}_out".format(i)) + self.copy_layout_pin(self.buf_insts[i], "Abar_out", "Abar{0}_out".format(i)) + self.copy_layout_pin(self.buf_insts[i], "A_in", "A{0}_in".format(i)) + + + + def route_clk(self): + self.route_horizontal_pins("clk", insts=self.buf_insts, layer=self.route_layer) + + + + def route_sources(self): + + self.route_horizontal_pins("vdd", insts=self.buf_insts, layer=self.route_layer) + self.route_horizontal_pins("gnd", insts=self.buf_insts, layer=self.route_layer) + + + diff --git a/compiler/modules/rom_address_control_buf.py b/compiler/modules/rom_address_control_buf.py new file mode 100644 index 00000000..f486e855 --- /dev/null +++ b/compiler/modules/rom_address_control_buf.py @@ -0,0 +1,214 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 openram.base import design +from openram.sram_factory import factory +from openram.base import vector +from openram.tech import layer, drc + + + +class rom_address_control_buf(design): + """ + Takes the input address lines and creates the address and address bar lines for the decoder. + Adds control logic for the precharge cycle so that all address lines are high before the read cycle + """ + def __init__(self, size, name="", route_layer="m1", add_wells=False): + + self.route_layer = route_layer + self.add_wells = add_wells + + self.size = size + + + if "li" in layer: + self.inv_layer = "li" + else: + self.inv_layer = "m1" + super().__init__(name) + self.create_netlist() + self.create_layout() + + def create_netlist(self): + self.create_modules() + self.add_pins() + self.create_instances() + + + def create_layout(self): + self.width = self.cell.height * 2 + self.height = self.inv.width + 2 * self.nand.width + self.setup_layout_constants() + self.place_instances() + # self.place_vias() + self.route_gates() + self.route_sources() + self.add_boundary() + + + def create_modules(self): + + + # self.inv1_mod = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size, add_wells=False) + self.inv = factory.create(module_type="pinv_dec", module_name="inv_array_mod", add_wells=False, size=self.size) + # self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", size=self.size, add_wells=True) + self.nand = factory.create(module_type="nand2_dec", height=self.inv.height) + # For layout constants + self.cell = factory.create(module_type="rom_base_cell") + + def add_pins(self): + + self.add_pin("A_in", "INPUT") + self.add_pin("A_out", "INOUT") + self.add_pin("Abar_out", "OUTPUT") + self.add_pin("clk", "INPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def create_instances(self): + + name = "XinvAbar" + + self.inv_inst = self.add_inst(name=name, mod=self.inv) + inst_A = "A_in" + inst_Z = "Abar_internal" + self.connect_inst([inst_A, inst_Z, "vdd", "gnd"]) + + name = "Xnand_addr" + + self.addr_nand = self.add_inst(name=name, mod=self.nand) + inst_A = "clk" + inst_B = "Abar_internal" + inst_Z = "A_out" + self.connect_inst([inst_A, inst_B, inst_Z, "vdd", "gnd"]) + + name = "Xnand_addr_bar" + + self.addr_bar_nand = self.add_inst(name=name, mod=self.nand) + inst_A = "clk" + inst_B = "A_out" + inst_Z = "Abar_out" + self.connect_inst([inst_A, inst_B, inst_Z, "vdd", "gnd"]) + + + + + def setup_layout_constants(self): + self.route_width = drc["minwidth_{}".format(self.route_layer)] + self.interconnect_width = drc["minwidth_{}".format(self.inv_layer)] + + def place_instances(self): + + + self.inv_inst.place(offset=vector(self.inv_inst.height,0), rotate=90) + self.addr_nand.place(offset=vector(self.addr_nand.height , self.inv_inst.width + self.route_width ), rotate=90) + + self.addr_bar_nand.place(offset=vector( self.addr_bar_nand.height, self.addr_nand.width + self.inv_inst.width + self.route_width), rotate=90) + + + + + def route_gates(self): + clk1_pin = self.addr_nand.get_pin("A") + clk2_pin = self.addr_bar_nand.get_pin("A") + # self.add_label("HERE I AM", "poly", clk_pins.cl()) + + Abar_out = self.addr_bar_nand.get_pin("Z") + A_out = self.addr_nand.get_pin("Z") + + Abar_in = self.addr_nand.get_pin("B") + Abar_int_out = self.inv_inst.get_pin("Z") + + Aint_in = self.addr_bar_nand.get_pin("B") + A_in = self.inv_inst.get_pin("A") + + + # Find the center of the pmos poly/gate + poly_right = clk1_pin.cx() + self.poly_enclose_contact + 0.5 * self.contact_width + + ppoly_center = poly_right - 0.7 * self.poly_width + + contact_offset = vector(ppoly_center, clk2_pin.cy()) + + # Route the two shared clk inputs together by connecting poly + self.add_segment_center("poly", contact_offset, vector(ppoly_center, A_out.cy())) + + + clk_offset = vector(clk2_pin.cx(), self.addr_nand.uy()) + self.add_layout_pin_rect_center("clk", offset=clk_offset, layer=self.route_layer) + + self.add_via_stack_center(from_layer=self.inv_layer, to_layer=self.route_layer, offset=self.addr_bar_nand.get_pin("A").center()) + self.add_segment_center(self.route_layer, clk_offset, vector(clk_offset.x, clk2_pin.cy())) + + + + # Route first NAND output to second NAND input + start = A_out.center() + end = Aint_in.center() + self.add_path("m2", [start, end]) + self.add_via_stack_center(Aint_in.center(), self.inv_layer, "m2") + self.add_via_stack_center(A_out.center(), self.inv_layer, "m2") + + + # Route first NAND to output pin + self.add_segment_center("m2", end, vector(end.x, self.addr_bar_nand.uy())) + self.add_layout_pin_rect_center("A_out", offset=vector(end.x, self.addr_bar_nand.uy() - 0.5 * self.m2_width), layer="m2") + + + # Route second NAND to output pin + self.add_via_stack_center(Abar_out.center(), self.inv_layer, "m2") + self.add_segment_center("m2", Abar_out.center(), vector(Abar_out.cx(), self.addr_bar_nand.uy())) + self.add_layout_pin_rect_center("Abar_out", offset=vector(Abar_out.cx(), self.addr_bar_nand.uy() - 0.5 * self.m2_width), layer="m2") + + + # Route inverter output to NAND + end = vector(Abar_int_out.cx(), Abar_in.cy() + 0.5 * self.interconnect_width) + self.add_segment_center(self.inv_layer, Abar_int_out.center(), end) + self.copy_layout_pin(self.inv_inst, "A", "A_in") + + + + + def route_sources(self): + + self.copy_layout_pin(self.addr_nand, "vdd") + self.copy_layout_pin(self.addr_bar_nand, "vdd") + self.copy_layout_pin(self.inv_inst, "vdd") + + self.copy_layout_pin(self.addr_bar_nand, "gnd") + self.copy_layout_pin(self.addr_nand, "gnd") + self.copy_layout_pin(self.inv_inst, "gnd") + + + """ Add n/p well taps to the layout and connect to supplies """ + + source_pin = self.inv_inst.get_pin("vdd") + gnd_pin = self.inv_inst.get_pin("gnd") + + left_edge = self.inv_inst.get_pin("Z").cx() - 2 * self.contact_width - 2 * self.active_contact_to_gate - 4 * self.active_enclose_contact - self.poly_width - self.active_space + + contact_pos = vector(left_edge, source_pin.cy()) + + self.add_via_center(layers=self.active_stack, + offset=contact_pos, + implant_type="n", + well_type="n") + self.add_via_stack_center(offset=contact_pos, + from_layer=self.active_stack[2], + to_layer=self.route_layer) + + contact_pos = vector(left_edge, gnd_pin.cy()) + self.add_via_center(layers=self.active_stack, + offset=contact_pos, + implant_type="p", + well_type="p") + self.add_via_stack_center(offset=contact_pos, + from_layer=self.active_stack[2], + to_layer=self.route_layer) + + diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index a46cce33..030cedd7 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -54,25 +54,24 @@ class rom_base_array(bitcell_base_array): self.place_bitline_contacts() - self.place_rails() + self.route_precharge() self.add_boundary() + self.place_rails() self.add_label("ARRAY ZERO", self.route_layer) self.add_label("array height", self.route_layer, [0, self.height]) - #def add_pins(self): def add_boundary(self): ll = self.find_lowest_coords() - bottom_offset = - self.dummy.nmos.end_to_contact + self.precharge_inst.offset.y + bottom_offset = - self.zero_cell.nmos.end_to_contact + self.precharge_inst.offset.y m1_offset = self.m1_width self.translate_all(vector(0, ll.y + 0.5 * m1_offset)) ur = self.find_highest_coords() ur = vector(ur.x, ur.y - self.m1_width) - #super().add_boundary(ll=vector(lowerx, lowery), ur=vector(upperx, uppery)) super().add_boundary(vector(0, 0), ur) self.width = ur.x self.height = ur.y @@ -80,17 +79,9 @@ class rom_base_array(bitcell_base_array): def add_modules(self): - # dummy cell, "dummy" cells represent 0 - self.dummy = factory.create(module_type="rom_dummy_cell", route_layer=self.route_layer) + self.zero_cell = factory.create(module_name="rom_base_zero_cell", module_type="rom_base_cell", bitline_layer=self.route_layer, bit_value=0) + self.one_cell = factory.create(module_name="rom_base_one_cell", module_type="rom_base_cell", bitline_layer=self.route_layer, bit_value=1) - #base cell with no contacts - self.cell_nc = factory.create(module_name="base_mod_0_contact", module_type="rom_base_cell") - #base cell with drain contact - self.cell_dc = factory.create(module_name="base_mod_d_contact", module_type="rom_base_cell", add_drain_contact=self.route_layer) - #base cell with source contact - self.cell_sc = factory.create(module_name="base_mod_s_contact", module_type="rom_base_cell", add_source_contact=self.route_layer) - #base cell with all contacts - self.cell_ac = factory.create(module_name="base_mod_sd_contact", module_type="rom_base_cell", add_source_contact=self.route_layer, add_drain_contact=self.route_layer) self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing) @@ -128,98 +119,74 @@ class rom_base_array(bitcell_base_array): # for each new strap placed, offset the column index refrenced to get correct bit in the data array # cols are bit lines - strap_row = False - pre_strap_row = False + if row % self.strap_spacing == 0 and self.pitch_match: strap_row = True if (row + 1) % self.strap_spacing == 0 and self.pitch_match: pre_strap_row = True + for col in range(self.column_size): if col % self.strap_spacing == 0: + self.create_tap(row, col) - name = "tap_r{0}_c{1}".format(row, col) - #print("tap instance added at c{0}, r{1}".format(col, row)) - self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) - self.connect_inst([]) - - name = "bit_r{0}_c{1}".format(row, col) - - if self.data[row][col] == 1: - # if dummy/0 cell above and below a 1, add a tx with contacts on both drain and source - # if the first row and a 0 above, add both contacts - # if the last row and 0 below add both contacts - if (row < self.row_size - 1 and row > 0 and self.data[row + 1][col] == 0 and self.data[row - 1][col] == 0) or \ - (row == self.row_size - 1 and self.data[row - 1][col] == 0) or \ - (row == 0 and self.data[row + 1][col] == 0) or \ - (row < self.row_size - 1 and self.data[row + 1][col] == 0 and strap_row) or \ - (row > 0 and self.data[row - 1][col] == 0 and pre_strap_row): - - new_inst = self.add_inst(name=name, mod=self.cell_ac) - - # if dummy/0 is below and not above, add a source contact - # if in the first row, add a source contact - elif (row > 0 and self.data[row - 1][col] == 0) or \ - (row == 0) or \ - (strap_row): - - new_inst=self.add_inst(name=name, mod=self.cell_sc) - - elif (row < self.row_size - 1 and self.data[row + 1][col] == 0) or \ - (row == self.row_size - 1) or \ - (pre_strap_row): - new_inst=self.add_inst(name=name, mod=self.cell_dc) - - else: - new_inst=self.add_inst(name=name, mod=self.cell_nc) - - if row == self.row_size - 1 or self.get_next_cell_in_bl(row, col) == -1: - - bl_l = self.int_bl_list[col] - bl_h = "gnd" - # elif first_in_col: - # bl_l = self.bitline_names[0][col] - # int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) - # bl_h = int_bl_list[col] - # first_in_col = False - else: - bl_l = self.int_bl_list[col] - self.int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) - bl_h = self.int_bl_list[col] - - - self.cell_inst[row, col] = new_inst - self.connect_inst([bl_h, bl_l, self.wordline_names[0][row], "gnd"]) - - - else: - new_inst = self.add_inst(name=name, mod=self.dummy) - self.cell_inst[row, col] = new_inst - self.connect_inst([]) - - # when col = 0 bl_h is connected to vdd, otherwise connect to previous bl connection - # when col = col_size - 1 connected column_sizeto gnd otherwise create new bl connection - # + new_inst = self.create_cell(row, col) + + self.cell_inst[row, col] = new_inst row_list.append(new_inst) - + name = "tap_r{0}_c{1}".format(row, self.array_col_size) - #print(*row_list) - self.tap_inst[row, self.column_size]=self.add_inst(name=name, mod=self.zero_tap) + self.tap_inst[row, 0]=self.add_inst(name=name, mod=self.zero_tap) self.connect_inst([]) self.cell_list.append(row_list) + def create_poly_tap(self, row, col): + name = "tap_r{0}_c{1}".format(row, col) + self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) + self.connect_inst([]) + + + def create_cell(self, row, col): + name = "bit_r{0}_c{1}".format(row, col) + + + # when col = 0, bl_h is connected to vdd, otherwise connect to previous bl connection + # when col = col_size - 1 connected column_sizeto gnd otherwise create new bl connection + if row == self.row_size - 1 or self.get_next_cell_in_bl(row, col) == -1: + + bl_l = self.int_bl_list[col] + bl_h = "gnd" + else: + bl_l = self.int_bl_list[col] + + if self.data[row][col] == 1: + self.int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) + + bl_h = self.int_bl_list[col] + + if self.data[row][col] == 1: + new_inst = self.add_inst(name=name, mod=self.one_cell) + self.connect_inst([bl_h, bl_l, self.wordline_names[0][row], "gnd"]) + else: + new_inst = self.add_inst(name=name, mod=self.zero_cell) + self.connect_inst([bl_h, self.wordline_names[0][row], "gnd"]) + + return new_inst + + + def create_precharge_inst(self): prechrg_pins = self.bitline_names[0].copy() - for bl in range(self.column_size): - # if the internal bl was never updated there are no active cells in the bitline, so it should route straight to ground" - if self.int_bl_list[bl] == prechrg_pins[bl]: - prechrg_pins[bl] = "gnd" + # for bl in range(self.column_size): + # # if the internal bl was never updated there are no active cells in the bitline, so it should route straight to ground" + # if self.int_bl_list[bl] == prechrg_pins[bl]: + # prechrg_pins[bl] = "gnd" prechrg_pins.append("precharge_gate") prechrg_pins.append("vdd") @@ -239,32 +206,21 @@ class rom_base_array(bitcell_base_array): def place_rails(self): - spacing = self.route_pitch + self.route_horizontal_pins("D", insts=self.cell_list[self.row_size - 1]) + self.copy_layout_pin(self, "D", "gnd") + - rail_y = self.cell_list[self.row_size - 1][0].offset.y + self.dummy.base_width + spacing - # self.dummy.height * (self.row_size) - start_x = self.get_pin(self.bitline_names[0][0]).cx() - # self.cell_list[self.row_size - 1][0].offset.x - end_x = self.get_pin(self.bitline_names[0][self.column_size - 1]).cx() - # self.cell_list[self.row_size - 1][self.column_size - 1].offset.x - #self.dummy.height * self.row_size - #self.cell_inst[self.row_size - 1,0].uy() - rail_start = vector(start_x , rail_y) - rail_end = vector(end_x, rail_y) + def place_well_tap(self): + tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 - self.gnd = self.add_layout_pin_rect_ends(name="gnd", - layer="m1", - start=rail_start, - end=rail_end) - - for bl in range(self.column_size): - drain_pin = self.cell_list[self.row_size - 1][bl].get_pin("D") - via_pos = vector(drain_pin.cx(), rail_y) - self.add_segment_center(self.route_layer, drain_pin.center(), via_pos) - - - self.add_via_stack_center(via_pos, self.route_layer, "m1", ["H", "V"]) - + contact_pos = vector(self.via.cx(), tap_y) + self.add_via_center(layers=self.active_stack, + offset=contact_pos, + implant_type="p", + well_type="p") + self.add_power_pin(name="gnd", + loc=contact_pos, + start_layer=self.active_stack[2]) def place_array(self): self.cell_pos = {} @@ -274,10 +230,10 @@ class rom_base_array(bitcell_base_array): pitch_offset = 0 for row in range(self.row_size): - if row % self.strap_spacing == 0 and row != 0 and self.pitch_match: - pitch_offset += self.poly_tap.width + # if row % self.strap_spacing == 0 and row != 0 and self.pitch_match: + # pitch_offset += self.poly_tap.width - cell_y = row * (self.dummy.height) + pitch_offset + cell_y = row * (self.zero_cell.height) + pitch_offset cell_x = 0 for col in range(self.column_size): @@ -285,19 +241,19 @@ class rom_base_array(bitcell_base_array): if col % self.strap_spacing == 0: self.strap_pos[row, col] = vector(cell_x, cell_y) self.tap_inst[row, col].place(self.strap_pos[row, col]) - cell_x += self.poly_tap.width + # cell_x += self.poly_tap.width self.cell_pos[row, col] = vector(cell_x, cell_y) self.cell_inst[row, col].place(self.cell_pos[row, col]) - cell_x += self.dummy.width + cell_x += self.zero_cell.width self.add_label("debug", "li", self.cell_pos[row, col]) - self.strap_pos[row, self.column_size] = vector(cell_x, cell_y) - self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size]) + self.strap_pos[row, 0] = vector(0, cell_y) + self.tap_inst[row, 0].place(self.strap_pos[row, 0]) - # tap_pin = self.cell_inst[row, self.array_col_size].get_pin("poly_tap").center() + # tap_pin = self.tap_inst[row, 0].get_pin("poly_tap").center() # self.add_layout_pin_rect_center("wl{}".format(row), "m2", tap_pin) @@ -316,7 +272,7 @@ class rom_base_array(bitcell_base_array): def place_precharge(self): - self.precharge_offset = vector(0, - self.precharge_inst.height - self.dummy.nmos.end_to_contact - 2 * drc["nwell_enclose_active"]) + self.precharge_offset = vector(0, - self.precharge_inst.height - self.zero_cell.nmos.end_to_contact - 2 * drc["nwell_enclose_active"]) self.precharge_inst.place(offset=self.precharge_offset) @@ -327,19 +283,12 @@ class rom_base_array(bitcell_base_array): def place_wordline_contacts(self): - width = self.route_width - - height = self.route_width - - offset = vector(self.poly_contact.width * 0.5, self.dummy.poly.offset.y) - for wl in range(self.row_size): - poly_via = self.tap_inst[wl, 0].get_pin("via") self.copy_layout_pin(self.tap_inst[wl, 0], "via", self.wordline_names[0][wl]) # self.add_via_stack_center(poly_via.center(), "m1", self.output_layer) - # self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.dummy.height, length=None) + # self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.zero_cell.height, length=None) def place_bitline_contacts(self): diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index d288fdc2..67bf2796 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -4,21 +4,32 @@ from openram.base import vector from openram.base import design from openram import OPTS from openram.sram_factory import factory -from openram.tech import drc +from openram.tech import drc, layer class rom_base_bank(design): + """ + Rom data bank with row and column decoder + control logic + + word size is in bytes + """ + def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2) -> None: - # self.cols = word_size * 8 + self.word_size = word_size * 8 self.read_binary(word_size=word_size, data_file=data_file) self.num_outputs = self.rows self.num_inputs = ceil(log(self.rows, 2)) + self.col_bits = ceil(log(self.words_per_row, 2)) + self.row_bits = self.num_inputs # self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] self.strap_spacing = strap_spacing - self.route_layer = "li" + if "li" in layer: + self.route_layer = "li" + else: + self.route_layer = "m1" self.bus_layer = "m2" self.interconnect_layer = "m1" @@ -78,7 +89,7 @@ class rom_base_bank(design): self.route_decode_outputs() self.route_control() - self.route_supplies() + # self.route_supplies() self.height = self.array_inst.height self.width = self.array_inst.width self.add_boundary() @@ -102,7 +113,7 @@ class rom_base_bank(design): out_pins = [] - for j in range(self.num_outputs): + for j in range(self.rows): out_pins.append("rom_out_{}".format(j)) self.add_pin_list(out_pins, "OUTPUT") @@ -112,11 +123,16 @@ class rom_base_bank(design): def add_modules(self): self.array = factory.create(module_type="rom_base_array", cols=self.cols, rows=self.rows, strap_spacing=self.strap_spacing, bitmap=self.data, route_layer=self.route_layer, pitch_match=True) - self.decode_array = factory.create(module_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer) - self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.rows + self.cols) / 2, height=self.decode_array.inv_inst.height) + self.decode_array = factory.create(module_name="rom_row_decode", module_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer, cols=self.cols) + self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.rows + self.cols) / 2, height=self.decode_array.buf_inst.height) + self.column_mux = factory.create(module_type="rom_column_mux_array", columns=self.cols, word_size=self.word_size, bitline_layer=self.route_layer) + self.column_decode = factory.create(module_name="rom_column_decode", module_type="rom_decoder", num_outputs=self.words_per_row, strap_spacing=self.strap_spacing, route_layer=self.route_layer, cols=1) def create_instances(self): + gnd = ["gnd"] + vdd = ["vdd"] + prechrg = ["precharge"] array_pins = [] decode_pins = [] @@ -132,8 +148,8 @@ class rom_base_bank(design): array_pins.append("gnd") - for addr in range(self.num_inputs): - name = "addr_{}".format(addr) + for addr in range(self.row_bits): + name = "row_addr_{}".format(addr) decode_pins.append(name) for wl in range(self.rows): name = "wl_{}".format(wl) @@ -144,31 +160,67 @@ class rom_base_bank(design): decode_pins.append("gnd") + bitlines = ["bl_{}".format(bl) for bl in range(self.cols)] + select_lines = ["word_sel_{}".format(word) for word in range(self.words_per_row)] + bitline_out = ["rom_out_{}".format(bl) for bl in range(self.word_size)] + addr_lsb = ["col_addr_{}".format(addr) for addr in range(self.col_bits)] + col_mux_pins = bitlines + select_lines + bitline_out + gnd + + col_decode_pins = addr_lsb + select_lines + prechrg + vdd + gnd self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array) self.connect_inst(array_pins) - self.decode_inst = self.add_inst(name="rom_decoder", mod=self.decode_array) + self.decode_inst = self.add_inst(name="rom_row_decoder", mod=self.decode_array) self.connect_inst(decode_pins) self.control_inst = self.add_inst(name="rom_control", mod=self.control_logic) self.connect_inst(["READ", "CS", "precharge", "vdd", "gnd"]) + self.mux_inst = self.add_inst(name="rom_column_mux", mod=self.column_mux) + self.connect_inst(col_mux_pins) + + self.col_decode_inst = self.add_inst(name="rom_column_decoder", mod=self.column_decode) + self.connect_inst(col_decode_pins) + def place_instances(self): - + self.place_row_decoder() + self.place_data_array() + self.place_control_logic() + self.place_col_decoder() + self.place_col_mux() + + + def place_row_decoder(self): + self.decode_offset = vector(0, self.control_inst.height) + self.decode_inst.place(offset=self.decode_offset) + + def place_data_array(self): + # We approximate the correct position for the array array_x = self.decode_inst.width + (2) * ( self.route_layer_width + self.route_layer_pitch ) - array_y = self.decode_array.inv_inst.height - self.array.precharge_inst.cy() - self.array.dummy.height * 0.5 + array_y = self.decode_array.buf_inst.height - self.array.precharge_inst.cy() - self.array.zero_cell.height * 0.5 self.array_offset = vector(array_x ,array_y) - self.decode_offset = vector(0, 0) - - self.control_offset = vector(0,0) - self.array_inst.place(offset=self.array_offset) - self.decode_inst.place(offset=self.decode_offset) + # now move array to correct alignment with decoder + array_align = self.decode_inst.get_pin("wl_0").cy() - self.array_inst.get_pin("wl_0_0").cy() + self.array_inst.place(offset=(self.array_offset + vector(0, array_align))) + + def place_control_logic(self): + self.control_offset = vector(0,0) + self.control_inst.place(offset=self.control_offset) - self.control_inst.place(offset=self.control_offset, mirror="MX") + def place_col_decoder(self): + self.col_decode_offset = vector(self.control_logic.width * 1.3, 0) + self.col_decode_inst.place(offset=self.col_decode_offset) + + def place_col_mux(self): + + self.mux_offset = vector(self.decode_inst.width, 0) + self.mux_inst.place(offset=self.mux_offset) + + def create_wl_bus(self): bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) @@ -182,21 +234,26 @@ class rom_base_bank(design): def route_decode_outputs(self): - for wl in range(self.rows): - decode_output = self.decode_array.output_names[wl] - decode_out_pin = self.decode_inst.get_pin(decode_output) + route_pins = [self.array_inst.get_pin("wl_0_{}".format(wl)) for wl in range(self.rows)] + decode_pins = [self.decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.rows)] + route_pins.extend(decode_pins) + self.connect_row_pins(self.interconnect_layer, route_pins, round=True) - array_wl = self.array.wordline_names[0][wl] - array_wl_pin = self.array_inst.get_pin(array_wl) + # for wl in range(self.rows): + # decode_output = self.decode_array.output_names[wl] + # decode_out_pin = self.decode_inst.get_pin(decode_output) + + # array_wl = self.array.wordline_names[0][wl] + # array_wl_pin = self.array_inst.get_pin(array_wl) - # wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] + # # wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] - start = decode_out_pin.center() - end = vector(array_wl_pin.cx(), start.y) + # start = decode_out_pin.center() + # end = vector(array_wl_pin.cx(), start.y) - self.add_segment_center(self.bus_layer, start, end) - self.add_via_stack_center(array_wl_pin.center(), self.bus_layer, self.interconnect_layer ) + # self.add_segment_center(self.bus_layer, start, end) + # self.add_via_stack_center(array_wl_pin.center(), self.bus_layer, self.interconnect_layer ) def route_array_inputs(self): diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index 668bc82d..83370d4d 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -6,62 +6,149 @@ # All rights reserved. # -from .rom_dummy_cell import rom_dummy_cell +from openram.base import design from openram.base import vector from openram import OPTS from openram.sram_factory import factory from openram.tech import drc -class rom_base_cell(rom_dummy_cell): - - def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"): - super().__init__(name, cell_name, add_source_contact, add_drain_contact, route_layer) +class rom_base_cell(design): + def __init__(self, name="", bitline_layer="li", bit_value=1): + super().__init__(name) + self.bit_value = bit_value + self.bitline_layer = bitline_layer + self.create_netlist() + self.create_layout() + def create_netlist(self): self.add_pins() - self.add_nmos() - self.create_nmos() + self.add_modules() + def create_layout(self): + + self.create_tx() self.setup_drc_offsets() - self.place_nmos() self.add_boundary() + self.place_tx() + self.place_bitline() + self.place_poly() + if self.bit_value == 0: + self.short_gate() + - def create_nmos(self): + # Calculates offsets of cell width and height so that tiling of cells does not violate any drc rules + def setup_drc_offsets(self): + + + + self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active) + #nmos contact to gate distance + self.contact_to_gate = 0.5 * (self.nmos.width - 2 * self.nmos.contact_width - self.nmos.poly_width - 2 * self.active_enclose_contact) + + #height offset to account for active-to-active spacing between adjacent bitlines + self.poly_extend_active_spacing = abs( 2 * self.nmos.poly_extend_active - drc("active_to_active") ) + + #contact to contact distance, minimum cell width before drc offsets + self.base_width = self.nmos.width - 2 * self.active_enclose_contact - self.nmos.contact_width + + #width offset to account for active-to-active spacing between cells on the same bitline + #this is calculated as a negative value + self.cell_diffusion_offset = ((self.base_width - 2 * self.active_enclose_contact - self.nmos.contact_width) - drc("active_to_active")) * 0.5 + + # width offset to account for poly-active spacing between base and dummy cells on the same bitline + self.poly_active_offset = 0.5 * (self.base_width - 2 * self.cell_diffusion_offset - (self.poly_width + 2 * self.active_enclose_contact + self.nmos.contact_width)) - self.poly_to_active + + #so that the poly taps are far enough apart + self.poly_tap_offset = (self.base_width - self.cell_diffusion_offset - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") + + + def add_boundary(self): + + height = self.cell_inst.width + self.active_space + + #cell width with offsets applied, height becomes width when the cells are rotated + width = self.cell_inst.height + 2 * self.poly_extend_active + # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied + # height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) + + # make the cells square so the pitch of wordlines will match bitlines + print("height: {0} width: {1}".format(height, width)) + if width > height: + self.width = width + self.height = width + else: + self.width = height + self.height = height + + super().add_boundary() + + + def add_modules(self): + + self.nmos = factory.create(module_type="ptx", + module_name="nmos_rom_mod", + tx_type="nmos", + add_source_contact=self.bitline_layer, + add_drain_contact=self.bitline_layer + ) + + + def create_tx(self): self.cell_inst = self.add_inst( name=self.name + "_nmos", mod=self.nmos, ) - self.connect_inst(["bl_h", "wl", "bl_l", "gnd"]) + if self.bit_value == 0: + self.connect_inst(["bl", "wl", "bl", "gnd"]) + else: + self.connect_inst(["bl_h", "wl", "bl_l", "gnd"]) - def add_pins(self): - pin_list = ["bl_h", "bl_l", "wl", "gnd"] - dir_list = ["INOUT", "INOUT", "INPUT", "GROUND"] + def add_pins(self): + if self.bit_value == 0 : + pin_list = ["bl", "wl", "gnd"] + dir_list = ["INOUT", "INPUT", "GROUND"] + else: + pin_list = ["bl_h", "bl_l", "wl", "gnd"] + dir_list = ["INOUT", "INOUT", "INPUT", "GROUND"] self.add_pin_list(pin_list, dir_list) - def place_nmos(self): + def place_tx(self): - # 0.5 * self.nmos.active_contact.width + self.nmos.active_contact_to_gate - poly_offset = vector(self.poly_extend_active_spacing * 0.5 + self.nmos.height + 2 * self.poly_extend_active, self.nmos.width * 0.5 - 0.5 * self.nmos.contact_width - self.active_enclose_contact) - # nmos_offset = vector(- 0.5 * self.nmos.contact_width - self.active_enclose_contact, self.nmos.poly_extend_active) - print("{} poly spacing".format(self.poly_extend_active_spacing)) - - nmos_offset = vector(self.nmos.poly_extend_active + self.nmos.height ,- 0.5 * self.nmos.contact_width - self.active_enclose_contact) + tx_offset = vector(self.poly_extend_active + self.cell_inst.height + (self.poly_size) ,- 0.5 * self.contact_width - self.active_enclose_contact) # add rect of poly to account for offset from drc spacing - self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.nmos.poly_width) + # self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.poly_width) - self.cell_inst.place(nmos_offset, rotate=90) + self.cell_inst.place(tx_offset, rotate=90) # self.add_label("CELL ZERO", self.route_layer) self.copy_layout_pin(self.cell_inst, "S", "S") self.copy_layout_pin(self.cell_inst, "D", "D") self.source_pos = self.cell_inst.get_pin("S").center() + def place_poly(self): + poly_offset = vector(0, self.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact) + + start = poly_offset + end = poly_offset + vector(self.poly_size, 0) + self.add_segment_center("poly", start, end) + + + def place_bitline(self): + + start = self.get_pin("D").center() + end = start + vector(0, 2 * self.active_enclose_contact + 0.5 * self.contact_width + self.active_space) + self.add_segment_center(self.bitline_layer, start, end) + + def short_gate(self): + + self.add_segment_center(self.bitline_layer, self.get_pin("D").center(), self.get_pin("S").center()) diff --git a/compiler/modules/rom_column_mux.py b/compiler/modules/rom_column_mux.py new file mode 100644 index 00000000..ae7ece30 --- /dev/null +++ b/compiler/modules/rom_column_mux.py @@ -0,0 +1,239 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2022 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 openram import debug +from openram.base import vector +from openram.sram_factory import factory +from openram.tech import drc, layer +from openram.tech import cell_properties as cell_props +from openram import OPTS +from .pgate import * + + +class rom_column_mux(pgate): + """ + This module implements the columnmux bitline cell used in the design. + Creates a single column mux cell with the given integer size relative + to minimum size. Default is 8x. Per Samira and Hodges-Jackson book: + Column-mux transistors driven by the decoder must be sized + for optimal speed + """ + def __init__(self, name, tx_size=8, bitline_layer="li"): + + debug.info(2, "creating single ROM column mux cell: {0}".format(name)) + self.tx_size = int(tx_size) + self.bitline_layer = bitline_layer + + super().__init__(name) + + + + def get_bl_names(self): + return "bl" + + + def create_netlist(self): + self.add_pins() + self.add_ptx() + + def create_layout(self): + + # If li exists, use li and m1 for the mux, otherwise use m1 and m2 + if self.bitline_layer == "li" : + self.col_mux_stack = self.li_stack + else: + self.col_mux_stack = self.m1_stack + self.pin_layer = self.bitcell.bitline_layer + self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer)) + self.pin_width = getattr(self, "{}_width".format(self.pin_layer)) + self.pin_height = 2 * self.pin_width + + self.place_ptx() + + # cell = factory.create(module_type=OPTS.bitcell) + # if(cell_props.use_strap == True and OPTS.num_ports == 1): + # strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version) + # precharge_width = cell.width + strap.width + # else: + # precharge_width = cell.width + self.width = self.bitcell.width + self.height = self.nmos_lower.uy() + self.pin_height + + self.connect_poly() + self.add_bitline_pins() + self.connect_bitlines() + # self.add_pn_wells() + + def add_ptx(self): + self.bitcell = factory.create(module_type="rom_base_cell", bitline_layer=self.bitline_layer) + + # 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) + + # Space it in the center + self.nmos_lower = self.add_inst(name="mux_tx1", + mod=self.nmos) + self.connect_inst(["bl", "sel", "bl_out", "gnd"]) + + + def add_pins(self): + self.add_pin_list(["bl", "bl_out", "sel", "gnd"]) + + def add_bitline_pins(self): + """ Add the top and bottom pins to this cell """ + + bl_pos = vector(self.pin_pitch, 0) + + # bl and br + self.add_layout_pin(text="bl", + layer=self.pin_layer, + offset=bl_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=self.col_mux_stack[2], + offset=bl_pos, + height=self.pin_height) + + + def place_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) + self.nmos_lower.place(nmos_lower_position) + + # # This aligns it directly above the other tx with gates abutting + # nmos_upper_position = nmos_lower_position \ + # + vector(0, self.nmos.active_height + max(self.active_space, self.poly_space)) + # self.nmos_upper.place(nmos_upper_position) + + # if cell_props.pgate.add_implants: + # self.extend_implants() + + 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.poly_extend_active - offset.y + 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 """ + + bl_pin = self.get_pin("bl") + # br_pin = self.get_pin("br") + bl_out_pin = self.get_pin("bl_out") + + nmos_lower_s_pin = self.nmos_lower.get_pin("S") + nmos_lower_d_pin = self.nmos_lower.get_pin("D") + + + # Add vias to bl, br_out, nmos_upper/S, nmos_lower/D + # self.add_via_stack_center(from_layer=bl_pin.layer, + # to_layer=self.col_mux_stack[0], + # offset=bl_pin.bc()) + # self.add_via_stack_center(from_layer=br_out_pin.layer, + # to_layer=self.col_mux_stack[0], + # offset=br_out_pin.uc()) + # self.add_via_stack_center(from_layer=nmos_upper_s_pin.layer, + # to_layer=self.col_mux_stack[2], + # offset=nmos_upper_s_pin.center()) + self.add_via_stack_center(from_layer=nmos_lower_d_pin.layer, + to_layer=self.col_mux_stack[2], + offset=nmos_lower_d_pin.center()) + + # bl -> nmos_upper/D on metal1 + # bl_out -> nmos_upper/S on metal2 + mid1 = bl_pin.bc().scale(1, 0.4) \ + + nmos_lower_s_pin.uc().scale(0, 0.5) + mid2 = bl_pin.bc().scale(0, 0.4) \ + + nmos_lower_s_pin.uc().scale(1, 0.5) + self.add_path(self.col_mux_stack[0], + [bl_pin.bc(), mid1, mid2, nmos_lower_s_pin.center()]) + # halfway up, move over + mid1 = bl_out_pin.uc().scale(1, 0.4) \ + + nmos_lower_d_pin.bc().scale(0, 0.4) + mid2 = bl_out_pin.uc().scale(0, 0.4) \ + + nmos_lower_d_pin.bc().scale(1, 0.4) + self.add_path(self.col_mux_stack[2], + [bl_out_pin.uc(), mid1, mid2, nmos_lower_d_pin.center()]) + + # # br -> nmos_lower/D on metal2 + # # br_out -> nmos_lower/S on metal1 + # 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()]) + # # halfway up, move over + # mid1 = br_pin.bc().scale(1, 0.5) \ + # + 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(self.col_mux_stack[2], + # [br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()]) + + def extend_implants(self): + """ + Add top-to-bottom implants for adjacency issues in s8. + """ + # Route to the bottom + ll = (self.nmos_lower.ll() - vector(2 * [self.implant_enclose_active])).scale(1, 0) + # Don't route to the top + ur = self.nmos_upper.ur() + vector(self.implant_enclose_active, 0) + self.add_rect("nimplant", + ll, + ur.x - ll.x, + ur.y - ll.y) + + def add_pn_wells(self): + """ + Add a well and implant over the whole cell. Also, add the + pwell contact (if it exists) + """ + # if(cell_props.use_strap == True and OPTS.num_ports == 1): + # strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version) + # rbc_width = self.bitcell.width + strap.width + # else: + # rbc_width = self.bitcell.width + # Add it to the right, aligned in between the two tx + active_pos = vector(self.bitcell.width, + self.nmos_upper.by() - 0.5 * self.poly_space) + + self.add_via_center(layers=self.active_stack, + offset=active_pos, + 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) + + self.add_layout_pin_rect_center(text="gnd", + layer="m1", + offset=active_pos) + + # Add well enclosure over all the tx and contact + if "pwell" in layer: + self.add_rect(layer="pwell", + offset=vector(0, 0), + width=rbc_width, + height=self.height) diff --git a/compiler/modules/rom_column_mux_array.py b/compiler/modules/rom_column_mux_array.py new file mode 100644 index 00000000..a1a1fc29 --- /dev/null +++ b/compiler/modules/rom_column_mux_array.py @@ -0,0 +1,215 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2022 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 openram import debug +from openram.base import design +from openram.base import vector +from openram.sram_factory import factory +from openram.tech import layer, preferred_directions +from openram.tech import layer_properties as layer_props +from openram import OPTS + + +class rom_column_mux_array(design): + """ + Dynamically generated column mux array. + Array of column mux to read the bitlines from ROM, based on the RAM column mux + """ + + def __init__(self, name, columns, word_size, offsets=None, column_offset=0, bitline_layer="m1"): + super().__init__(name) + debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("cols: {0} word_size: {1} ".format(columns, word_size)) + + self.columns = columns + self.word_size = word_size + self.offsets = offsets + self.words_per_row = int(self.columns / self.word_size) + self.column_offset = column_offset + + self.sel_layer = layer_props.column_mux_array.select_layer + self.sel_pitch = getattr(self, self.sel_layer + "_pitch") + self.bitline_layer = bitline_layer + + if preferred_directions[self.sel_layer] == "V": + self.via_directions = ("H", "H") + else: + self.via_directions = "pref" + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def get_bl_name(self): + bl_name = self.mux.get_bl_names() + return bl_name + + def get_br_name(self, port=0): + br_name = self.mux.get_br_names() + return br_name + + def create_netlist(self): + 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.add_layout_pins() + 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)) + for i in range(self.words_per_row): + self.add_pin("sel_{}".format(i)) + for i in range(self.word_size): + self.add_pin("bl_out_{}".format(i)) + self.add_pin("gnd") + + def add_modules(self): + self.mux = factory.create(module_type="rom_column_mux") + + self.cell = factory.create(module_type="rom_base_cell") + + def setup_layout_constants(self): + 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.sel_pitch + + def create_array(self): + self.mux_inst = [] + # For every column, add a pass gate + for col_num in range(self.columns): + 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), + "bl_out_{}".format(int(col_num / self.words_per_row)), + "sel_{}".format(col_num % self.words_per_row), + "gnd"]) + + def place_array(self): + # Default to single spaced columns + if not self.offsets: + self.offsets = [n * self.mux.width for n in range(self.columns)] + + # For every column, add a pass gate + for col_num, xoffset in enumerate(self.offsets[0:self.columns]): + # if self.cell.mirror.y and (col_num + self.column_offset) % 2: + # mirror = "MY" + # xoffset = xoffset + self.mux.width + # else: + # mirror = "" + + offset = vector(xoffset, self.route_height) + self.mux_inst[col_num].place(offset=offset) + + 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] + bl_pin = mux_inst.get_pin("bl") + offset = bl_pin.ll() + self.add_layout_pin(text="bl_{}".format(col_num), + layer=bl_pin.layer, + offset=offset, + height=self.height - offset.y) + + + def route_supplies(self): + self.route_horizontal_pins("gnd", self.insts) + + def add_routing(self): + self.add_horizontal_input_rail() + self.add_vertical_poly_rail() + self.route_bitlines() + self.route_supplies() + + def add_horizontal_input_rail(self): + """ Create address input rails below the mux transistors """ + for j in range(self.words_per_row): + offset = vector(0, self.route_height + (j - self.words_per_row) * self.sel_pitch) + self.add_layout_pin(text="sel_{}".format(j), + layer=self.sel_layer, + offset=offset, + width=self.mux_inst[-1].rx()) + + 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 + sel_index = col % self.words_per_row + # Add the column x offset to find the right select bit + gate_offset = self.mux_inst[col].get_pin("sel").bc() + # 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()) + + bl_offset = offset.scale(0, 1) + vector((self.mux_inst[col].get_pin("bl_out").cx()), 0) + self.add_via_stack_center(from_layer="poly", + to_layer=self.sel_layer, + offset=bl_offset, + directions=self.via_directions) + self.add_path("poly", [offset, gate_offset, bl_offset]) + + def route_bitlines(self): + """ Connect the output bit-lines to form the appropriate width mux """ + for j in range(self.columns): + + bl_offset_begin = self.mux_inst[j].get_pin("bl_out").bc() + + bl_out_offset_begin = bl_offset_begin - vector(0, (self.words_per_row + 1) * self.sel_pitch) + + # Add the horizontal wires for the first bit + if j % self.words_per_row == 0: + bl_offset_end = self.mux_inst[j + self.words_per_row - 1].get_pin("bl_out").bc() + bl_out_offset_end = bl_offset_end - vector(0, (self.words_per_row + 1) * self.sel_pitch) + + self.add_path(self.sel_layer, [bl_out_offset_begin, bl_out_offset_end]) + + # 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=self.bitline_layer, + start=bl_offset_begin, + end=bl_out_offset_begin) + + + else: + self.add_path(self.bitline_layer, [bl_out_offset_begin, bl_offset_begin]) + + # This via is on the right of the wire + self.add_via_stack_center(from_layer=self.bitline_layer, + to_layer=self.sel_layer, + offset=bl_out_offset_begin, + directions=self.via_directions) + + + + def graph_exclude_columns(self, column_include_num): + """ + Excludes all columns muxes unrelated to the target bit being simulated. + Each mux in mux_inst corresponds to respective column in bitcell array. + """ + for i in range(len(self.mux_inst)): + if i != column_include_num: + self.graph_inst_exclude.add(self.mux_inst[i]) diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index 4d3da899..7801fad5 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -15,6 +15,11 @@ class rom_control_logic(design): self.output_size = num_outputs self.mod_height = height + if "li" in layer: + self.route_layer = "li" + else: + self.route_layer = "m1" + # dff = factory.create(module_type="dff") # if height == None: @@ -43,11 +48,11 @@ class rom_control_logic(design): self.inv_mod = factory.create(module_type="pinv", module_name="rom_control_logic_pinv", height=self.mod_height) self.nand_mod = factory.create(module_type="pnand2", module_name="rom_control_nand", height=self.mod_height) - self.driver_mod = factory.create(module_type="pdriver", inverting=True, fanout=self.output_size, height=self.mod_height, add_wells=False) + self.driver_mod = factory.create(module_type="pdriver", inverting=True, fanout=self.output_size, height=self.mod_height, add_wells=True) def add_pins(self): - self.add_pin("READ", "INPUT") + self.add_pin("clk", "INPUT") self.add_pin("CS", "INPUT") self.add_pin("prechrg", "OUTPUT") self.add_pin("vdd", "POWER") @@ -56,10 +61,10 @@ class rom_control_logic(design): def create_instances(self): self.inv_inst = self.add_inst(name="read_signal_inv", mod=self.inv_mod) - self.connect_inst(["READ", "READ_BAR", "vdd", "gnd"]) + self.connect_inst(["clk", "clk_bar", "vdd", "gnd"]) self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod) - self.connect_inst(["CS", "READ_BAR", "pre_drive", "vdd", "gnd"]) + self.connect_inst(["CS", "clk_bar", "pre_drive", "vdd", "gnd"]) self.driver_inst = self.add_inst(name="driver_inst", mod=self.driver_mod) self.connect_inst(["pre_drive", "prechrg", "vdd", "gnd"]) @@ -75,7 +80,7 @@ class rom_control_logic(design): self.copy_layout_pin(self.driver_inst, "Z", "prechrg") self.copy_layout_pin(self.nand_inst, "B", "CS") - self.add_path("li", [self.inv_inst.get_pin("Z").center(), self.nand_inst.get_pin("A").center()]) + self.add_path(self.route_layer, [self.inv_inst.get_pin("Z").center(), self.nand_inst.get_pin("A").center()]) - self.add_path("li", [self.nand_inst.get_pin("Z").center(), self.driver_inst.get_pin("A").center()]) + self.add_path(self.route_layer, [self.nand_inst.get_pin("Z").center(), self.driver_inst.get_pin("A").center()]) \ No newline at end of file diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index 34fb5453..46687611 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -14,7 +14,7 @@ from openram.tech import drc class rom_decoder(design): - def __init__(self, num_outputs, strap_spacing, name="", route_layer="li", output_layer="m2"): + def __init__(self, num_outputs, cols, strap_spacing, name="", route_layer="m1", output_layer="m2"): # word lines/ rows / inputs in the base array become the address lines / cols / inputs in the decoder # bit lines / cols / outputs in the base array become the word lines / rows / outputs in the decoder @@ -32,7 +32,8 @@ class rom_decoder(design): self.cell_height = b.height self.route_layer = route_layer self.output_layer = output_layer - self.inv_route_layer = "m1" + self.inv_route_layer = "m2" + self.cols=cols self.create_netlist() self.create_layout() @@ -43,15 +44,20 @@ class rom_decoder(design): def create_layout(self): + self.setup_layout_constants() self.place_array() - self.place_input_inverters() - self.create_outputs() - self.width = self.array_inst.height - self.height = self.array_inst.width + self.inv_inst.height + self.place_input_buffer() + self.place_driver() + self.route_outputs() + self.width = self.array_inst.height + self.wordline_buf_inst.width + self.height = self.array_inst.width + self.buf_inst.height self.connect_inputs() - self.route_supplies() + # self.route_supplies() self.add_boundary() + def setup_layout_constants(self): + self.inv_route_width = drc["minwidth_{}".format(self.inv_route_layer)] + def create_decode_map(self): self.decode_map = [] # create decoding map that will be the bitmap for the rom decoder @@ -64,7 +70,7 @@ class rom_decoder(design): inv_col_array = [] for row in range(self.num_outputs): - addr_idx = -col - 1 + addr_idx = -col - 1 addr = format(row, 'b') if col >= len(addr) : @@ -87,10 +93,10 @@ class rom_decoder(design): def add_pins(self): for i in range(self.num_inputs): - self.add_pin("in_{0}".format(i), "INPUT") + self.add_pin("A{0}".format(i), "INPUT") for j in range(self.num_outputs): - self.add_pin("out_{0}".format(j), "OUTPUT") + self.add_pin("wl_{0}".format(j), "OUTPUT") self.add_pin("precharge_gate", "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -98,10 +104,14 @@ class rom_decoder(design): def add_modules(self): - self.inv_array = factory.create(module_type="rom_inv_array", cols=self.num_inputs) + self.control_array = factory.create(module_type="rom_address_control_array", cols=self.num_inputs) + + self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), \ + rows=self.num_outputs, \ + cols=self.cols) self.array_mod = factory.create(module_type="rom_base_array", \ - module_name="rom_decode_array", \ + module_name="{}_array".format(self.name), \ cols=self.num_outputs, \ rows=2 * self.num_inputs, \ bitmap=self.decode_map, @@ -112,23 +122,25 @@ class rom_decoder(design): def create_instances(self): - self.create_input_inverters() self.create_array_inst() + self.create_input_buffer() + self.create_wordline_buffer() - def create_input_inverters(self): - name = "pre_inv_array" - self.inv_inst = self.add_inst(name=name, mod=self.inv_array) + def create_input_buffer(self): + name = "pre_control_array" + self.buf_inst = self.add_inst(name=name, mod=self.control_array) - inv_pins = [] + control_pins = [] for i in range(self.num_inputs): - inv_pins.append("in_{0}".format(i)) - inv_pins.append("inbar_{0}".format(i)) - - inv_pins.append("vdd") - inv_pins.append("gnd") - self.connect_inst(inv_pins) + control_pins.append("A{0}".format(i)) + control_pins.append("A{0}_int".format(i)) + control_pins.append("Abar{0}_int".format(i)) + control_pins.append("clk") + control_pins.append("vdd") + control_pins.append("gnd") + self.connect_inst(control_pins) def create_array_inst(self): @@ -137,7 +149,7 @@ class rom_decoder(design): array_pins = [] for j in range(self.num_outputs): - name = "out_{0}".format(j) + name = "wl_int{0}".format(j) array_pins.append(name) @@ -149,51 +161,70 @@ class rom_decoder(design): array_pins.append("gnd") self.connect_inst(array_pins) + def create_wordline_buffer(self): + self.wordline_buf_inst = self.add_inst("rom_wordline_driver", mod=self.wordline_buf) + in_pins = ["wl_int{}".format(wl) for wl in range(self.num_outputs)] + out_pins = ["wl_{}".format(wl) for wl in range(self.num_outputs)] + pwr_pins = ["vdd", "gnd"] + self.connect_inst(in_pins + out_pins + pwr_pins) + + + + def place_input_buffer(self): + wl = self.array_mod.row_size - 1 + align = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl]).cx() - self.buf_inst.get_pin("A0_out").cx() + print("align: {}".format(align)) + + self.buf_inst.place(vector(align, 0)) - def place_input_inverters(self): - self.inv_inst.place(vector(self.array_inst.ll().x, 0)) def place_array(self): - offset = vector(self.array_mod.height, self.inv_array.height + self.m1_width + self.poly_contact.width) + offset = vector(self.array_mod.height, self.control_array.height + self.m1_width + self.poly_contact.width) self.array_inst.place(offset, rotate=90) + + def place_driver(self): + + offset = vector(self.array_inst.height + self.m1_width, self.array_inst.by()) + self.wordline_buf_inst.place(offset) - def create_outputs(self): + # calculate the offset between the decode array and the buffer inputs now that their zeros are aligned + pin_offset = self.array_inst.get_pin("bl_0_0").cy() - self.wordline_buf_inst.get_pin("in_0").cy() + self.wordline_buf_inst.place(offset + vector(0, pin_offset)) - self.output_names = [] + def route_outputs(self): for j in range(self.num_outputs): - name = "out_{0}".format(j) - self.output_names.append(name) + self.copy_layout_pin(self.wordline_buf_inst, "out_{}".format(j), "wl_{}".format(j)) + + array_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.num_outputs)] + driver_pins = [self.wordline_buf_inst.get_pin("in_{}".format(bl)) for bl in range(self.num_outputs)] + + route_pins = array_pins + driver_pins + self.connect_row_pins(self.output_layer, route_pins, round=True) - for bl in range(self.num_outputs): - self.copy_layout_pin(self.array_inst, self.array_mod.bitline_names[0][bl], self.output_names[bl]) - # prechg_pin = self.array_mod.bitline_names[0][bl] - # src_pin = self.array_inst.get_pin(prechg_pin) - # offset = src_pin.center() - # self.add_via_stack_center(offset, self.route_layer, self.output_layer) - # self.outputs.append(self.add_layout_pin_rect_center(self.output_names[bl], self.output_layer, offset )) def connect_inputs(self): self.copy_layout_pin(self.array_inst, "precharge") for i in range(self.num_inputs): - wl = self.num_inputs * 2 - i * 2 - 1 + wl = (self.num_inputs - i) * 2 - 1 wl_bar = wl - 1 addr_pin = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl]) addr_bar_pin = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl_bar]) - inv_in_pin = self.inv_inst.get_pin("inv{}_in".format(i)) - inv_out_pin = self.inv_inst.get_pin("inv{}_out".format(i)) + addr_out_pin = self.buf_inst.get_pin("A{}_out".format(i)) + addr_bar_out_pin = self.buf_inst.get_pin("Abar{}_out".format(i)) - addr_start = inv_in_pin.center() - addr_end = vector(addr_start.x, addr_pin.cy()) + addr_middle = vector(addr_pin.cx(), addr_out_pin.cy()) + + addr_bar_middle = vector(addr_bar_pin.cx(), addr_bar_out_pin.cy()) - addr_bar_start = inv_out_pin.center() - addr_bar_end = vector(addr_bar_start.x, addr_bar_pin.cy()) - self.add_segment_center(self.inv_route_layer, addr_start, addr_end) - self.add_segment_center(self.inv_route_layer, addr_bar_start, addr_bar_end) + self.add_path(self.inv_route_layer, [addr_out_pin.center(), addr_middle, addr_pin.center()]) + self.add_path(self.inv_route_layer, [addr_bar_out_pin.center(), addr_bar_middle, addr_bar_pin.center()]) + + # self.add_segment_center(self.inv_route_layer, addr_bar_middle + vector(0, self.inv_route_width * 0.5), addr_bar_out_pin.center() + vector(0, self.inv_route_width * 0.5), self.inv_route_width) def route_supplies(self): minwidth = drc["minwidth_{}".format(self.inv_route_layer)] @@ -202,7 +233,7 @@ class rom_decoder(design): # route decode array vdd and inv array vdd together array_vdd = self.array_inst.get_pin("vdd") - inv_vdd = self.inv_inst.get_pins("vdd")[-1] + inv_vdd = self.buf_inst.get_pins("vdd")[-1] end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth) self.add_segment_center("m1", array_vdd.center(), end) @@ -215,7 +246,7 @@ class rom_decoder(design): # route pin on inv gnd - inv_gnd = self.inv_inst.get_pins("gnd")[0] + inv_gnd = self.buf_inst.get_pins("gnd")[0] array_gnd = self.array_inst.get_pins("gnd") # add x jog diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py index bf5932b6..8ebd138f 100644 --- a/compiler/modules/rom_dummy_cell.py +++ b/compiler/modules/rom_dummy_cell.py @@ -41,55 +41,8 @@ class rom_dummy_cell(design): self.add_metal() #self.add_label("0,0", self.route_layer) - - - # Calculates offsets of cell width and height so that tiling of cells does not violate any drc rules - def setup_drc_offsets(self): - - #nmos contact to gate distance - self.contact_to_gate = 0.5 * (self.nmos.width - 2 * self.nmos.contact_width - self.nmos.poly_width - 2 * self.active_enclose_contact) - - #height offset to account for active-to-active spacing between adjacent bitlines - self.poly_extend_active_spacing = abs( 2 * self.nmos.poly_extend_active - drc("active_to_active") ) - - #contact to contact distance, minimum cell width before drc offsets - self.base_width = self.nmos.width - 2 * self.active_enclose_contact - self.nmos.contact_width - - #width offset to account for active-to-active spacing between cells on the same bitline - #this is calculated as a negative value - self.cell_diffusion_offset = ((self.base_width - 2 * self.active_enclose_contact - self.nmos.contact_width) - drc("active_to_active")) * 0.5 - - # width offset to account for poly-active spacing between base and dummy cells on the same bitline - self.poly_active_offset = 0.5 * (self.base_width - 2 * self.cell_diffusion_offset - (self.poly_width + 2 * self.active_enclose_contact + self.nmos.contact_width)) - self.poly_to_active - - #so that the poly taps are far enough apart - self.poly_tap_offset = (self.base_width - self.cell_diffusion_offset - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") - - - def add_boundary(self): - - width = self.nmos.width + self.active_space - - #cell width with offsets applied, height becomes width when the cells are rotated - # width = self.nmos.height + self.poly_extend_active_spacing + 2 * self.nmos.poly_extend_active - # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied - height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) - - # make the cells square so the pitch of wordlines will match bitlines - print("height: {0} width: {1}".format(height, width)) - if width > height: - self.width = width - self.height = width - else: - self.width = height - self.height = height - - super().add_boundary() - - - def add_poly(self): poly_x = 0.5 * (self.nmos.poly_height + self.poly_extend_active_spacing) @@ -129,22 +82,6 @@ class rom_dummy_cell(design): self.add_layout_pin_rect_center("D", self.route_layer, drain_pos) - def add_nmos(self): - #used only for layout constants - # if not self.source_contact: - # add_source = False - # else: - # add_source = self.route_layer - # if not self.drain_contact: - # add_drain = False - # else: - # add_drain = self.route_layer - self.nmos = factory.create(module_type="ptx", - module_name="nmos_rom_mod", - tx_type="nmos", - add_source_contact=self.add_source_contact, - add_drain_contact=self.add_drain_contact - ) diff --git a/compiler/modules/rom_inv_array.py b/compiler/modules/rom_inv_array.py deleted file mode 100644 index 5774e2fc..00000000 --- a/compiler/modules/rom_inv_array.py +++ /dev/null @@ -1,129 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2021 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 openram.base import design -from openram.sram_factory import factory -from openram.base import vector -from openram.tech import layer, drc - - - -class rom_inv_array(design): - """ - An array of inverters to create the inverted address lines for the rom decoder - """ - def __init__(self, cols, inv_size=None, name="", route_layer="m1"): - self.cols = cols - self.route_layer = route_layer - dff = factory.create(module_type="dff") - if name=="": - name = "rom_inv_array_{0}".format(cols) - if inv_size == None: - self.inv_size = dff.height * 0.5 - else: - self.inv_size = inv_size - - - if "li" in layer: - self.inv_layer = "li" - else: - self.inv_layer = "m1" - super().__init__(name) - self.create_netlist() - self.create_layout() - - def create_netlist(self): - self.create_modules() - self.add_pins() - self.create_instances() - - - def create_layout(self): - self.width = self.cols * self.poly_tap.height * 2 - self.height = self.inv_mod.height - self.setup_layout_constants() - self.place_instances() - self.place_vias() - self.route_sources() - self.add_boundary() - - - def create_modules(self): - - self.inv_mod = factory.create(module_type="pinv", module_name="inv_array_mod", height=self.inv_size, add_wells=False) - self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size, add_wells=True) - # For layout constants - self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=0) - - def add_pins(self): - for col in range(self.cols): - self.add_pin("inv{0}_in".format(col), "INPUT") - self.add_pin("inv{0}_out".format(col), "OUTPUT") - self.add_pin("vdd", "POWER") - self.add_pin("gnd", "GROUND") - - def create_instances(self): - self.inv_insts = [] - - for col in range(self.cols): - name = "Xinv_c{0}".format(col) - if col == self.cols - 1: - self.inv_insts.append(self.add_inst(name=name, mod=self.end_inv)) - else: - self.inv_insts.append(self.add_inst(name=name, mod=self.inv_mod)) - inst_A = "inv{0}_in".format(col) - inst_Z = "inv{0}_out".format(col) - self.connect_inst([inst_A, inst_Z, "vdd", "gnd"]) - - def setup_layout_constants(self): - input_pin = self.inv_insts[0].get_pin("A") - output_pin = self.inv_insts[0].get_pin("Z") - - # NEED TO OFFSET OUTPUT VIA IN ORDER TO ALIGN WITH PITCH OF ADDRESS INPUTS TO ARRAY - - # print(self.poly_tap.get_pin("poly_tap").center()) - - # distance between input and output pins of inverter - in_out_distance = output_pin.cx() - input_pin.cx() - # distance from left edge of inverter to input plus right edge to output - edge_to_pins_distance = input_pin.cx() - self.inv_insts[0].lx() + self.inv_insts[0].rx() - output_pin.cx() - - self.alignment_offset = edge_to_pins_distance - in_out_distance - - def place_instances(self): - self.add_label("ZERO", self.route_layer) - for col in range(self.cols): - # base = vector(col*(self.inv_mod.width - self.alignment_offset), 0) - base = vector(col*(self.poly_tap.height * 2), 0) - self.inv_insts[col].place(offset=base) - #vdd_pin = self.inv_insts[0].get_pin("vdd").center() - #self.add_layout_pin_rect_center("vdd_align", self.inv_layer, vdd_pin, 0, 0) - - def place_vias(self): - for i in range(self.cols): - input_pin = self.inv_insts[i].get_pin("A") - output_pin = self.inv_insts[i].get_pin("Z") - - self.add_via_stack_center(input_pin.center(), self.inv_mod.route_layer, self.route_layer) - self.add_via_stack_center(output_pin.center(), self.inv_mod.route_layer, self.route_layer) - self.add_layout_pin_rect_center("inv{}_in".format(i), offset=input_pin.center(), layer=self.route_layer) - self.add_layout_pin_rect_center("inv{}_out".format(i), offset=output_pin.center(), layer=self.route_layer) - - def route_sources(self): - - vdd_start = self.inv_insts[0].get_pin("vdd") - vdd_end = self.inv_insts[-1].get_pin("vdd") - - gnd_start = self.inv_insts[0].get_pin("gnd") - gnd_end = self.inv_insts[-1].get_pin("gnd") - - self.copy_layout_pin(self.inv_insts[0], "vdd") - self.copy_layout_pin(self.inv_insts[0], "gnd") - # self.vdd = self.add_layout_pin_rect_ends("vdd", self.inv_layer, vdd_start.center(), vdd_end.center())[-1] - # self.gnd = self.add_layout_pin_rect_ends("gnd", self.inv_layer, gnd_start.center(), gnd_end.center())[-1] - diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index ec6a1a4e..c09ef984 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -10,10 +10,11 @@ from openram.base import design from openram.base import vector from openram import OPTS from openram.sram_factory import factory +from openram.tech import drc class rom_poly_tap(design): - def __init__(self, name="", strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m1"): + def __init__(self, name="", strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m2"): super().__init__(name, cell_name, prop) self.strap_layer=strap_layer self.length = strap_length @@ -23,7 +24,7 @@ class rom_poly_tap(design): def create_netlist(self): #for layout constants - self.dummy = factory.create(module_type="rom_dummy_cell") + self.dummy = factory.create(module_type="rom_base_cell") self.pmos = factory.create(module_type="ptx", tx_type="pmos") def create_layout(self): @@ -31,20 +32,19 @@ class rom_poly_tap(design): self.place_via() # if self.tx_type == "pmos": self.extend_poly() + self.place_ptap() self.add_boundary() - if self.length != 0: - self.place_strap() + # if self.length != 0: + # self.place_strap() def add_boundary(self): contact_width = self.poly_contact.width + 2 * self.contact_x_offset offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact) - print("THINGY {}".format(offset)) self.height = self.dummy.height self.width = contact_width + self.pitch_offset - print("poly height: {0}, width: {1}".format(self.height, self.width)) super().add_boundary() def place_via(self): @@ -61,7 +61,7 @@ class rom_poly_tap(design): if self.tx_type == "nmos": - contact_y = self.dummy.poly.cy() + contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact # contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) # self.contact_x_offset = 0 else: @@ -77,8 +77,6 @@ class rom_poly_tap(design): self.add_layout_pin_rect_center("via", self.strap_layer, self.contact_offset) - - def place_strap(self): strap_start = vector(self.via.lx() , self.via.cy()) @@ -105,4 +103,15 @@ class rom_poly_tap(design): self.add_rect("poly", extend_offset, self.contact_x_offset , self.poly_width) + def place_ptap(self): + tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 + + contact_pos = vector(self.via.cx(), tap_y) + self.add_via_center(layers=self.active_stack, + offset=contact_pos, + implant_type="p", + well_type="p") + self.add_power_pin(name="gnd", + loc=contact_pos, + start_layer=self.active_stack[2]) diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index 8acfb8c8..247d2d4e 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -58,24 +58,23 @@ class rom_precharge_array(design): def create_layout(self): - self.width = self.cols * self.pmos.width + self.num_straps * self.poly_tap.width + self.width = self.cols * self.pmos.width self.height = self.pmos.width self.place_instances() self.create_layout_pins() self.add_well_tap() self.route_supply() - self.extend_implant() self.add_boundary() def add_boundary(self): - self.translate_all(self.well_ll) + # self.translate_all(self.well_ll) ur = self.find_highest_coords() - ur = vector(ur.x, ur.y - self.well_ll.y) + # ur = vector(ur.x, ur.y - self.well_ll.y) super().add_boundary(vector(0, 0), ur) - self.width = self.cols * self.pmos.width + self.num_straps * self.poly_tap.width + self.width = self.cols * self.pmos.width self.height = ur.y def create_modules(self): @@ -84,7 +83,7 @@ class rom_precharge_array(design): # For layout constants self.dummy = factory.create(module_type="rom_base_cell") - self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing, tx_type="pmos") + self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing) def add_pins(self): for col in range(self.cols): @@ -96,21 +95,25 @@ class rom_precharge_array(design): self.array_insts = [] self.pmos_insts = [] self.tap_insts = [] + + self.tap_insts.append(self.add_inst(name="tap_0", mod=self.poly_tap)) + self.connect_inst([]) for col in range(self.cols): - if col % self.strap_spacing == 0: - name = "tap_c{}".format(col) - tap = self.add_inst(name=name, mod=self.poly_tap) - self.array_insts.append(tap) - self.tap_insts.append(tap) - self.connect_inst([]) + # if col % self.strap_spacing == 0: + # name = "tap_c{}".format(col) + # tap = self.add_inst(name=name, mod=self.poly_tap) + # self.array_insts.append(tap) + # self.tap_insts.append(tap) + # self.connect_inst([]) name = "Xpmos_c{0}".format(col) pmos = self.add_inst(name=name, mod=self.pmos) self.array_insts.append(pmos) self.pmos_insts.append(pmos) bl = "pre_bl{0}_out".format(col) self.connect_inst(["vdd", "gate", bl, "vdd"]) + print(self.array_insts) @@ -123,15 +126,16 @@ class rom_precharge_array(design): cell_y = 0 # columns are bit lines4 cell_x = 0 - print("starting array place") + + self.tap_insts[0].place(vector(cell_x, cell_y)) for col in range(self.cols): - if col % self.strap_spacing == 0 : - self.tap_insts[strap_num].place(vector(cell_x, cell_y)) - self.add_label("debug", "li", vector(cell_x, cell_y)) - cell_x += self.poly_tap.width - strap_num += 1 + # if col % self.strap_spacing == 0 : + # self.tap_insts[strap_num].place(vector(cell_x, cell_y)) + # self.add_label("debug", "li", vector(cell_x, cell_y)) + # cell_x += self.poly_tap.width + # strap_num += 1 self.pmos_insts[col].place(vector(cell_x, cell_y)) self.add_label("debug", "li", vector(cell_x, cell_y)) @@ -146,21 +150,6 @@ class rom_precharge_array(design): self.add_layout_pin_rect_center(bl, self.route_layer, source_pin.center()) - def extend_implant(self): - layer = "nwell" - # center of source contact minus radius of the well generated by the contact gives the lowermost well position - contact_well_by = self.pmos.pmos.source_contacts[0].cx() - self.pmos.pmos.source_contacts[0].mod.well_width * 0.5 - - ptx_well_by = 0.5 * self.pmos.pmos.active_width - 0.5 * self.pmos.pmos.well_width - - well_extend = ptx_well_by - contact_well_by - - - self.well_ll = vector(0, min(contact_well_by, ptx_well_by)) - - height = self.pmos.pmos.active_width + 2 * self.well_enclose_active - self.add_rect(layer, self.well_ll, self.width + well_extend, height + 2 * well_extend) - def add_well_tap(self): layer_stack = self.active_stack @@ -174,11 +163,13 @@ class rom_precharge_array(design): directions=("V", "V")) def route_supply(self): + + start_pin = self.pmos_insts[0].get_pin("S").lx() end_pin = self.pmos_insts[-1].get_pin("S").rx() spacing = drc["{0}_to_{0}".format(self.route_layer)] - start = vector(start_pin, -1.5*spacing) - end = vector(end_pin, -1.5*spacing) + start = vector(start_pin, -2*spacing) + end = vector(end_pin, -2*spacing) self.vdd = self.add_layout_pin_segment_center("vdd", "m1", start, end) diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index d41f07c2..57477626 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -6,47 +6,41 @@ # All rights reserved. # -from openram.base import design +from .rom_base_cell import rom_base_cell from openram.base import vector from openram import OPTS from openram.sram_factory import factory from openram.tech import drc -class rom_precharge_cell(design): +class rom_precharge_cell(rom_base_cell): - def __init__(self, name="", cell_name=None, route_layer="m1"): + def __init__(self, name="", route_layer="m1"): - super().__init__(name, cell_name) - self.route_layer = route_layer - self.create_netlist() - self.create_layout() - - #self.route_layer= route_layer - #self.create_netlist() - #self.create_layout() + super().__init__(name=name, bitline_layer=route_layer) - def create_netlist(self): - self.add_pins() - self.add_pmos() - self.create_pmos() + + # def create_netlist(self): + # self.add_pins() + # self.add_modules() + # self.create_tx() def create_layout(self): - self.setup_layout_constants() - self.place_pmos() - self.add_boundary() + super().create_layout() + self.extend_well() - def add_pmos(self): + + def add_modules(self): self.pmos = factory.create(module_type="ptx", module_name="pre_pmos_mod", tx_type="pmos" ) - def create_pmos(self): + def create_tx(self): self.cell_inst = self.add_inst( name="precharge_pmos", mod=self.pmos, ) @@ -55,17 +49,15 @@ class rom_precharge_cell(design): def add_pins(self): pin_list = ["vdd", "gate", "bitline", "body"] - dir_list = ["POWER", "INPUT", "OUTPUT", "INPUT"] + dir_list = ["POWER", "INPUT", "OUTPUT", "POWER"] self.add_pin_list(pin_list, dir_list) - def setup_layout_constants(self): - - #pmos contact to gate distance - self.contact_to_gate = 0.5 * (self.pmos.width - 2 * self.pmos.contact_width - self.pmos.poly_width - 2 * self.active_enclose_contact) + def setup_drc_offsets(self): - #height offset to account for active-to-active spacing between adjacent bitlines - self.poly_extend_active_spacing = abs( 2 * self.pmos.poly_extend_active - drc("active_to_active") ) + self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active) + + #contact to contact distance, minimum cell width before drc offsets self.base_width = self.pmos.width - 2 * self.active_enclose_contact - self.pmos.contact_width @@ -77,30 +69,38 @@ class rom_precharge_cell(design): self.poly_tap_offset = (self.base_width - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") - def place_pmos(self): + def extend_well(self): + self.pmos - poly_offset = vector(self.poly_extend_active_spacing * 0.5 + self.pmos.height + 2 * self.poly_extend_active, 0.5 * self.pmos.width) + well_y = - (0.5 * self.nwell_width) + well_ll = vector(0, well_y) + # height = self.active_width + 2 * self.well_enclose_active + height = self.height + 0.5 * self.nwell_width + self.add_rect("nwell", well_ll, self.width , height) + # def place_tx(self): - # pmos_offset = vector(self.pmos.poly_extend_active, - 0.5 * self.pmos.contact_width - self.active_enclose_contact) - - # pmos_offset = vector(-self.pmos.poly_extend_active - self.poly_extend_active_spacing, 0) - pmos_offset = vector(self.pmos.poly_extend_active + self.pmos.height, 0) - # add rect of poly to account for offset from drc spacing - self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.pmos.poly_width ) + # pmos_offset = vector(self.pmos.poly_extend_active + self.pmos.height, 0) - self.cell_inst.place(pmos_offset, rotate=90) - # self.add_label("CELL ZERO", self.route_layer) - self.add_label("inst_zero", self.route_layer) - self.add_layout_pin_rect_center("S", self.route_layer, self.cell_inst.get_pin("S").center()) - self.add_layout_pin_rect_center("D", self.route_layer, self.cell_inst.get_pin("D").center()) + # self.cell_inst.place(pmos_offset, rotate=90) + # self.add_label("inst_zero", self.bitline_layer) + # self.add_layout_pin_rect_center("S", self.bitline_layer, self.cell_inst.get_pin("S").center()) + # self.add_layout_pin_rect_center("D", self.bitline_layer, self.cell_inst.get_pin("D").center()) - def add_boundary(self): - #cell width with offsets applied, height becomes width when the cells are rotated - self.width = self.pmos.height + self.poly_extend_active_spacing + 2 * self.pmos.poly_extend_active + # def place_poly(self): + # poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.rx() + self.poly_extend_active) + # poly_offset = vector(self.cell_inst.rx() + self.poly_extend_active, self.cell_inst.width * 0.5 ) - # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied - self.height = self.base_width - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) + # start = poly_offset + # end = poly_offset + vector(poly_size, 0) + # self.add_segment_center("poly", start, end) + # def add_boundary(self): - super().add_boundary() + # #cell width with offsets applied, height becomes width when the cells are rotated + # self.width = self.pmos.height + self.poly_extend_active_spacing + 2 * self.pmos.poly_extend_active + + # # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied + # # self.height = self.base_width - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) + + # super().add_boundary() diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py new file mode 100644 index 00000000..9a19919c --- /dev/null +++ b/compiler/modules/rom_wordline_driver_array.py @@ -0,0 +1,119 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2022 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 openram import debug +from openram.base import design, drc +from openram.base import vector +from openram.sram_factory import factory +from openram.tech import layer +from openram.tech import layer_properties as layer_props +from openram import OPTS + + +class rom_wordline_driver_array(design): + """ + Creates a Wordline Buffer/Inverter array + """ + + def __init__(self, name, rows, cols): + design.__init__(self, name) + debug.info(1, "Creating {0}".format(self.name)) + self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + + self.rows = rows + self.cols = cols + + self.create_netlist() + if not OPTS.netlist_only: + self.create_layout() + + def create_netlist(self): + self.add_modules() + self.add_pins() + self.create_drivers() + + def create_layout(self): + if "li" in layer: + self.route_layer = "li" + else: + self.route_layer = "m1" + self.place_drivers() + self.route_layout() + self.route_supplies() + self.add_boundary() + self.DRC_LVS() + + def add_pins(self): + # inputs to wordline_driver. + for i in range(self.rows): + self.add_pin("in_{0}".format(i), "INPUT") + # Outputs from wordline_driver. + for i in range(self.rows): + self.add_pin("out_{0}".format(i), "OUTPUT") + self.add_pin("vdd", "POWER") + self.add_pin("gnd", "GROUND") + + def add_modules(self): + b = factory.create(module_type="rom_base_cell") + + self.wl_driver = factory.create(module_type="pbuf_dec", + size=self.cols, + height=b.height, + add_wells=False) + + def route_supplies(self): + """ + Add a pin for each row of vdd/gnd which + are must-connects next level up. + """ + if layer_props.wordline_driver.vertical_supply: + self.route_vertical_pins("vdd", self.wld_inst) + self.route_vertical_pins("gnd", self.wld_inst) + else: + self.route_vertical_pins("vdd", self.wld_inst, xside="rx",) + self.route_vertical_pins("gnd", self.wld_inst, xside="lx",) + + def create_drivers(self): + self.wld_inst = [] + for row in range(self.rows): + self.wld_inst.append(self.add_inst(name="wld{0}".format(row), + mod=self.wl_driver)) + self.connect_inst(["in_{0}".format(row), + "out_{0}".format(row), + "vdd", "gnd"]) + + def place_drivers(self): + + for row in range(self.rows): + # These are flipped since we always start with an RBL on the bottom + y_offset = self.wl_driver.height * row + + offset = [0, y_offset] + + self.wld_inst[row].place(offset=offset) + + self.width = self.wl_driver.width + self.height = self.wl_driver.height * self.rows + + def route_layout(self): + """ Route all of the signals """ + route_width = drc["minwidth_{}".format(self.route_layer)] + for row in range(self.rows): + inst = self.wld_inst[row] + + self.copy_layout_pin(inst, "A", "in_{0}".format(row)) + + # output each WL on the right + wl_offset = inst.get_pin("Z").rc() - vector( 0.5 * route_width, 0) + + end = vector(wl_offset.x, \ + self.get_pin("in_{}".format(row)).cy() + 0.5 * route_width) + self.add_segment_center(layer=self.route_layer, + start=wl_offset, + end=end) + + self.add_layout_pin_rect_center(text="out_{}".format(row), layer=self.route_layer, offset=end - vector(0, 0.5 * route_width)) diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/05_rom_array_test.py index 790d8839..a7d70abe 100644 --- a/compiler/tests/05_rom_array_test.py +++ b/compiler/tests/05_rom_array_test.py @@ -25,7 +25,7 @@ class rom_array_test(openram_test): debug.info(2, "Testing 4x4 array for rom cell") - data = [[1, 0, 0, 0, 0, 1, 0, 0, 1], [0, 1, 1, 1, 0, 1, 0, 0, 1], [1, 0, 1, 1, 0, 1, 0, 0, 1], [1, 1, 0, 1, 1, 0, 0, 0, 1], [1, 0, 0, 0, 1, 0, 0, 0, 1], [0, 1, 1, 1, 1, 0, 0, 0, 1], [1, 0, 1, 1, 1, 0, 0, 0, 1], [1, 1, 0, 0, 1, 1, 0, 0, 1]] + data = [[1, 0, 0, 1, 0, 0, 1, 1, 0], [0, 1, 0, 0, 1, 0, 1, 0, 0], [0, 0, 1, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0, 1], [0, 1, 0, 0, 1, 1, 0, 0, 1], [0, 0, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 0, 0, 0, 1, 0]] a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4, pitch_match=True) self.local_check(a) diff --git a/compiler/tests/05_rom_column_mux_array_test.py b/compiler/tests/05_rom_column_mux_array_test.py new file mode 100644 index 00000000..17915852 --- /dev/null +++ b/compiler/tests/05_rom_column_mux_array_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2022 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 sys, os +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class rom_column_mux_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + debug.info(1, "Testing sample for 2-way rom column_mux_array") + a = factory.create(module_type="rom_column_mux_array", columns=16, word_size=8) + self.local_check(a) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/05_rom_decoder_buffer_array_test.py b/compiler/tests/05_rom_decoder_buffer_array_test.py new file mode 100644 index 00000000..915dfe34 --- /dev/null +++ b/compiler/tests/05_rom_decoder_buffer_array_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 + +import openram +from openram import OPTS +from openram.sram_factory import factory +from openram import debug + + +class rom_decoder_buffer_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + debug.info(2, "Testing 4 col decoder buffer for rom decoder") + + + a = factory.create(module_type="rom_address_control_array", cols=4) + self.local_check(a) + openram.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/05_rom_decoder_test.py b/compiler/tests/05_rom_decoder_test.py index 9146ca42..48f977c8 100644 --- a/compiler/tests/05_rom_decoder_test.py +++ b/compiler/tests/05_rom_decoder_test.py @@ -25,7 +25,7 @@ class rom_decoder_test(openram_test): debug.info(2, "Testing 2x4 decoder for rom cell") - a = factory.create(module_type="rom_decoder", num_outputs=8, strap_spacing=2) + a = factory.create(module_type="rom_decoder", num_outputs=20, strap_spacing=2, cols=16) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/05_rom_wordline_driver_array_test.py b/compiler/tests/05_rom_wordline_driver_array_test.py new file mode 100644 index 00000000..36144661 --- /dev/null +++ b/compiler/tests/05_rom_wordline_driver_array_test.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2022 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 sys, os +import unittest +from testutils import * + +import openram +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + +class wordline_driver_array_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + + # check wordline driver for single port + debug.info(2, "Checking driver") + tx = factory.create(module_type="rom_wordline_driver_array", rows=8, cols=32) + self.local_check(tx) + + openram.end_openram() + + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) From 559300e5cceeac8d6327d9a84e22d8e9acf61548 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Sun, 22 Jan 2023 18:34:11 -0800 Subject: [PATCH 40/98] taps in main array and decoder --- compiler/modules/pinvbuf.py | 37 ++- compiler/modules/rom_base_array.py | 189 +++++++++----- compiler/modules/rom_base_bank.py | 238 ++++++++++++------ compiler/modules/rom_base_cell.py | 18 +- compiler/modules/rom_column_mux.py | 55 ++-- compiler/modules/rom_column_mux_array.py | 28 ++- compiler/modules/rom_control_logic.py | 110 ++++++-- compiler/modules/rom_decoder.py | 95 ++++--- compiler/modules/rom_poly_tap.py | 104 ++++---- compiler/modules/rom_precharge_array.py | 124 +++++---- compiler/modules/rom_precharge_cell.py | 75 +++--- compiler/modules/rom_wordline_driver_array.py | 40 ++- compiler/tests/05_rom_base_bank_test.py | 2 +- compiler/tests/05_rom_control_logic_test.py | 2 +- 14 files changed, 692 insertions(+), 425 deletions(-) diff --git a/compiler/modules/pinvbuf.py b/compiler/modules/pinvbuf.py index 2ac793c6..c277dd2a 100644 --- a/compiler/modules/pinvbuf.py +++ b/compiler/modules/pinvbuf.py @@ -17,13 +17,14 @@ class pinvbuf(pgate): This is a simple inverter/buffer used for driving loads. It is used in the column decoder for 1:2 decoding and as the clock buffer. """ - def __init__(self, name, size=4, height=None): + def __init__(self, name, size=4, height=None, route_in_cell=False): debug.info(1, "creating pinvbuf {}".format(name)) self.add_comment("size: {}".format(size)) self.stage_effort = 4 self.row_height = height + self.route_in_cell = route_in_cell # FIXME: Change the number of stages to support high drives. # stage effort of 4 or less @@ -132,15 +133,35 @@ class pinvbuf(pgate): to_layer=a3_pin.layer, offset=a3_pin.center()) - # inv1 Z to inv4 A (up and over) z1_pin = self.inv1_inst.get_pin("Z") a4_pin = self.inv4_inst.get_pin("A") - mid_point = vector(z1_pin.cx(), a4_pin.cy()) - self.add_wire(route_stack, - [z1_pin.center(), mid_point, a4_pin.center()]) - self.add_via_stack_center(from_layer=z1_pin.layer, - to_layer=route_stack[2], - offset=z1_pin.center()) + if self.route_in_cell: + # inv1 Z to inv4 A (under and up) + mid_point = vector(a4_pin.cx(), z1_pin.cy()) + end_point = a4_pin.center() + # end_point = vector(a4_pin.cx(), a4_pin.by() - self.m1_space - self.contact_space) + self.add_path(route_stack[2], + [z1_pin.center(), mid_point, end_point]) + + self.add_via_stack_center(from_layer=z1_pin.layer, + to_layer=route_stack[2], + offset=z1_pin.center()) + + self.add_via_stack_center(from_layer=a4_pin.layer, + to_layer=route_stack[2], + offset=end_point) + + + self.add_segment_center(a4_pin.layer, end_point, a4_pin.center()) + else: + # inv1 Z to inv4 A (up and over) + + mid_point = vector(z1_pin.cx(), a4_pin.cy()) + self.add_wire(route_stack, + [z1_pin.center(), mid_point, a4_pin.center()]) + self.add_via_stack_center(from_layer=z1_pin.layer, + to_layer=route_stack[2], + offset=z1_pin.center()) def add_layout_pins(self): diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 030cedd7..2d2be82a 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -12,20 +12,25 @@ from .bitcell_base_array import bitcell_base_array from openram.base import vector from openram import OPTS from openram.sram_factory import factory -from openram.tech import drc +from openram.tech import drc, layer class rom_base_array(bitcell_base_array): - def __init__(self, rows, cols, strap_spacing, bitmap, name="", column_offset=0, route_layer="li", output_layer="m2", pitch_match=False): + def __init__(self, rows, cols, strap_spacing, bitmap, tap_spacing = 4, name="", bitline_layer="m1", wordline_layer="m2", tap_direction="row", pitch_match=False): - super().__init__(name=name, rows=rows, cols=cols, column_offset=column_offset) + super().__init__(name=name, rows=rows, cols=cols, column_offset=0) self.data = bitmap + self.tap_direction = tap_direction self.pitch_match = pitch_match - self.route_layer = route_layer - self.output_layer = output_layer + self.bitline_layer = bitline_layer self.strap_spacing = strap_spacing + self.wordline_layer = wordline_layer self.data_col_size = self.column_size + self.tap_spacing = tap_spacing + + + if strap_spacing != 0: self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing) else: @@ -47,20 +52,23 @@ class rom_base_array(bitcell_base_array): def create_layout(self): self.create_layout_constants() self.place_array() - if self.pitch_match: + if self.tap_direction == "row": self.route_pitch_offsets() + self.place_precharge() self.place_wordline_contacts() self.place_bitline_contacts() - - - - self.route_precharge() - self.add_boundary() + self.route_precharge() self.place_rails() - self.add_label("ARRAY ZERO", self.route_layer) - self.add_label("array height", self.route_layer, [0, self.height]) + self.connect_taps() + + + + + + + @@ -79,22 +87,32 @@ class rom_base_array(bitcell_base_array): def add_modules(self): - self.zero_cell = factory.create(module_name="rom_base_zero_cell", module_type="rom_base_cell", bitline_layer=self.route_layer, bit_value=0) - self.one_cell = factory.create(module_name="rom_base_one_cell", module_type="rom_base_cell", bitline_layer=self.route_layer, bit_value=1) + self.zero_cell = factory.create(module_name="rom_base_zero_cell", + module_type="rom_base_cell", + bitline_layer=self.bitline_layer, + bit_value=0) + self.one_cell = factory.create(module_name="rom_base_one_cell", + module_type="rom_base_cell", + bitline_layer=self.bitline_layer, + bit_value=1) - self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing) - - self.zero_tap = factory.create(module_type="rom_poly_tap", strap_length=0) - - - self.precharge_array = factory.create(module_type="rom_precharge_array", cols=self.column_size, strap_spacing=self.strap_spacing, route_layer=self.route_layer) + if self.tap_direction == "row": + self.poly_tap = factory.create(module_type="rom_poly_tap") + else: + self.poly_tap = factory.create(module_type="rom_poly_tap", add_tap=True) + self.precharge_array = factory.create(module_type="rom_precharge_array", + cols=self.column_size, + strap_spacing=self.strap_spacing, + route_layer=self.bitline_layer, + strap_layer=self.wordline_layer, + tap_direction=self.tap_direction) def create_layout_constants(self): - self.route_width = drc("minwidth_" + self.route_layer) + self.route_width = drc("minwidth_" + self.bitline_layer) - self.route_pitch = drc("{0}_to_{0}".format(self.route_layer)) + self.route_pitch = drc("{0}_to_{0}".format(self.bitline_layer)) def add_pins(self): @@ -108,8 +126,10 @@ class rom_base_array(bitcell_base_array): def create_cell_instances(self): self.tap_inst = {} + self.tap_list = [] self.cell_inst = {} self.cell_list = [] + self.current_row = 0 #list of current bitline interconnect nets, starts as the same as the bitline list and is updated when new insts of cells are added self.int_bl_list = self.bitline_names[0].copy() @@ -120,15 +140,10 @@ class rom_base_array(bitcell_base_array): # for each new strap placed, offset the column index refrenced to get correct bit in the data array # cols are bit lines - if row % self.strap_spacing == 0 and self.pitch_match: - strap_row = True - if (row + 1) % self.strap_spacing == 0 and self.pitch_match: - pre_strap_row = True - for col in range(self.column_size): if col % self.strap_spacing == 0: - self.create_tap(row, col) + self.create_poly_tap(row, col) new_inst = self.create_cell(row, col) @@ -139,7 +154,9 @@ class rom_base_array(bitcell_base_array): name = "tap_r{0}_c{1}".format(row, self.array_col_size) - self.tap_inst[row, 0]=self.add_inst(name=name, mod=self.zero_tap) + new_tap = self.add_inst(name=name, mod=self.poly_tap) + self.tap_inst[row, self.column_size] = new_tap + self.tap_list.append(new_tap) self.connect_inst([]) self.cell_list.append(row_list) @@ -147,7 +164,9 @@ class rom_base_array(bitcell_base_array): def create_poly_tap(self, row, col): name = "tap_r{0}_c{1}".format(row, col) - self.tap_inst[row, col]=self.add_inst(name=name, mod=self.poly_tap) + new_tap = self.add_inst(name=name, mod=self.poly_tap) + self.tap_inst[row, col]=new_tap + self.tap_list.append(new_tap) self.connect_inst([]) @@ -205,33 +224,32 @@ class rom_base_array(bitcell_base_array): def place_rails(self): + via_width = drc("m2_enclose_via1") * 0.5 + drc("minwidth_via1") + pitch = drc["{0}_to_{0}".format(self.wordline_layer)] - self.route_horizontal_pins("D", insts=self.cell_list[self.row_size - 1]) - self.copy_layout_pin(self, "D", "gnd") + for i in range(self.column_size): + drain = self.cell_list[self.row_size - 1][i].get_pin("D") + + gnd_pos = drain.center() + vector(0, pitch + via_width + self.route_pitch) + self.add_layout_pin_rect_center(text="gnd", layer=self.bitline_layer, offset=gnd_pos) + self.route_horizontal_pins("gnd", insts=[self], yside="cy") + + + self.copy_layout_pin(self.precharge_inst, "vdd") - def place_well_tap(self): - tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 - contact_pos = vector(self.via.cx(), tap_y) - self.add_via_center(layers=self.active_stack, - offset=contact_pos, - implant_type="p", - well_type="p") - self.add_power_pin(name="gnd", - loc=contact_pos, - start_layer=self.active_stack[2]) def place_array(self): self.cell_pos = {} self.strap_pos = {} # rows are wordlines - + col_offset = 0 pitch_offset = 0 for row in range(self.row_size): - # if row % self.strap_spacing == 0 and row != 0 and self.pitch_match: - # pitch_offset += self.poly_tap.width + if row % self.tap_spacing == 0 and self.pitch_match: + pitch_offset += self.active_contact.width + self.active_space cell_y = row * (self.zero_cell.height) + pitch_offset @@ -241,7 +259,9 @@ class rom_base_array(bitcell_base_array): if col % self.strap_spacing == 0: self.strap_pos[row, col] = vector(cell_x, cell_y) self.tap_inst[row, col].place(self.strap_pos[row, col]) - # cell_x += self.poly_tap.width + + if self.tap_direction == "col": + cell_x += self.poly_tap.pitch_offset self.cell_pos[row, col] = vector(cell_x, cell_y) self.cell_inst[row, col].place(self.cell_pos[row, col]) @@ -249,25 +269,59 @@ class rom_base_array(bitcell_base_array): self.add_label("debug", "li", self.cell_pos[row, col]) - self.strap_pos[row, 0] = vector(0, cell_y) - self.tap_inst[row, 0].place(self.strap_pos[row, 0]) + self.strap_pos[row, self.column_size] = vector(cell_x, cell_y) + self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size]) - # tap_pin = self.tap_inst[row, 0].get_pin("poly_tap").center() - # self.add_layout_pin_rect_center("wl{}".format(row), "m2", tap_pin) def route_pitch_offsets(self): - for row in range(0 , self.row_size, self.strap_spacing): - if row != 0: - for col in range(self.column_size): - source = self.cell_inst[row, col].get_pin("S") - drain = self.cell_inst[row - 1, col].get_pin("D") + for row in range(0 , self.row_size, self.tap_spacing): + for col in range(self.column_size): + cell = self.cell_inst[row, col] + + source = cell.get_pin("S") + + if row != 0: + drain = self.cell_inst[row - 1, col].get_pin("D") start = vector(drain.cx(), source.cy()) end = drain.center() - self.add_segment_center(self.route_layer, start, end) + self.add_segment_center(self.bitline_layer, start, end) + + self.place_well_tap(row, col) + + + + def place_well_tap(self, row, col): + cell = self.cell_inst[row, col] + source = cell.get_pin("S") + + if col != self.column_size - 1: + tap_x = (self.cell_inst[row , col + 1].get_pin("S").cx() + source.cx()) * 0.5 + else: + tap_x = cell.rx() + self.active_space + + if row != 0: + drain = self.cell_inst[row - 1, col].get_pin("D") + tap_y = (source.cy() + drain.cy()) * 0.5 + else: + tap_y = source.cy() - self.contact_width - 2 * self.active_enclose_contact - self.active_space + + + tap_pos = vector(tap_x, tap_y) + + self.add_via_center(layers=self.active_stack, + offset=tap_pos, + implant_type="p", + well_type="p", + directions="nonpref") + self.add_via_stack_center(offset=tap_pos, + from_layer=self.active_stack[2], + to_layer=self.wordline_layer) + self.add_layout_pin_rect_center("gnd", self.wordline_layer, tap_pos) + def place_precharge(self): @@ -285,14 +339,14 @@ class rom_base_array(bitcell_base_array): for wl in range(self.row_size): - self.copy_layout_pin(self.tap_inst[wl, 0], "via", self.wordline_names[0][wl]) + self.copy_layout_pin(self.tap_inst[wl, 0], "poly_tap", self.wordline_names[0][wl]) # self.add_via_stack_center(poly_via.center(), "m1", self.output_layer) # self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.zero_cell.height, length=None) def place_bitline_contacts(self): - rail_y = self.precharge_inst.get_pin("vdd").cy() + rail_y = self.precharge_inst.get_pins("vdd")[0].cy() for bl in range(self.column_size): @@ -303,13 +357,12 @@ class rom_base_array(bitcell_base_array): middle_offset = (src_pin.cy() - pre_pin.cy() ) * 0.5 corrected = vector(src_pin.cx(), src_pin.cy() - middle_offset) - self.add_via_stack_center(corrected, self.route_layer, self.output_layer) output_pos = vector(corrected.x, rail_y) - self.add_segment_center(self.output_layer, corrected, output_pos) + self.add_segment_center(self.bitline_layer, corrected, output_pos) - self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.output_layer, output_pos ) + self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.bitline_layer, output_pos ) @@ -322,7 +375,17 @@ class rom_base_array(bitcell_base_array): bl_start = bl_pin.center() bl_end = vector(bl_start.x, pre_out_pin.cy()) - self.add_segment_center(self.route_layer, bl_start, bl_end) + self.add_segment_center(self.bitline_layer, bl_start, bl_end) + def connect_taps(self): + array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))] + + self.connect_row_pins(layer=self.wordline_layer, pins=array_pins, name=None, round=False) + # self.connect_row_pins(layer="poly", pins=array_pins, name=None, round=False) + + if self.tap_direction == "col": + self.route_vertical_pins("active_tap", insts=self.tap_list, layer=self.supply_stack[0], full_width=False) + + def get_next_cell_in_bl(self, row_start, col): for row in range(row_start + 1, self.row_size): diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index 67bf2796..297af7f1 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -26,14 +26,17 @@ class rom_base_bank(design): # self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] self.strap_spacing = strap_spacing - if "li" in layer: - self.route_layer = "li" - else: - self.route_layer = "m1" - self.bus_layer = "m2" + self.tap_spacing = 8 self.interconnect_layer = "m1" + self.bitline_layer = "m1" + self.wordline_layer = "m2" super().__init__(name=name) + if "li" in layer: + self.route_stack = self.m1_stack + else: + self.route_stack = self.m2_stack + self.route_layer = self.route_stack[0] self.setup_layout_constants() self.create_netlist() self.create_layout() @@ -81,37 +84,46 @@ class rom_base_bank(design): def create_netlist(self): self.add_modules() # self.add_pins() + + print("Creating ROM bank instances") self.create_instances() def create_layout(self): + print("Placing ROM bank instances") self.place_instances() - # self.channel_route() - self.route_decode_outputs() - self.route_control() + print("Routing decoders to array") + self.route_decode_outputs() + + print("Routing precharge signal") + self.route_precharge() + + print("Routing clock signal") + self.route_clock() + self.route_array_outputs() # self.route_supplies() self.height = self.array_inst.height self.width = self.array_inst.width self.add_boundary() + print("Rom bank placement complete") + def setup_layout_constants(self): - self.route_layer_width = drc["minwidth_{}".format(self.route_layer)] - self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_layer)] - self.bus_layer_width = drc["minwidth_{}".format(self.bus_layer)] - self.bus_layer_pitch = drc["{0}_to_{0}".format(self.bus_layer)] + self.route_layer_width = drc["minwidth_{}".format(self.route_stack[0])] + self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_stack[0])] + self.interconnect_layer_width = drc["minwidth_{}".format(self.interconnect_layer)] self.interconnect_layer_pitch = drc["{0}_to_{0}".format(self.interconnect_layer)] def add_pins(self): - self.add_pin("READ", "INPUT") + self.add_pin("clk", "INPUT") self.add_pin("CS", "INPUT") for i in range(self.num_inputs): self.add_pin("addr_{}".format(i), "INPUT") - out_pins = [] for j in range(self.rows): out_pins.append("rom_out_{}".format(j)) @@ -122,17 +134,54 @@ class rom_base_bank(design): def add_modules(self): - self.array = factory.create(module_type="rom_base_array", cols=self.cols, rows=self.rows, strap_spacing=self.strap_spacing, bitmap=self.data, route_layer=self.route_layer, pitch_match=True) - self.decode_array = factory.create(module_name="rom_row_decode", module_type="rom_decoder", num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer, cols=self.cols) - self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.rows + self.cols) / 2, height=self.decode_array.buf_inst.height) - self.column_mux = factory.create(module_type="rom_column_mux_array", columns=self.cols, word_size=self.word_size, bitline_layer=self.route_layer) + + print("Creating bank modules") + self.array = factory.create(module_type="rom_base_array", + cols=self.cols, + rows=self.rows, + strap_spacing=self.strap_spacing, + bitmap=self.data, + bitline_layer=self.bitline_layer, + wordline_layer=self.wordline_layer, + pitch_match=True, + tap_spacing=self.tap_spacing) - self.column_decode = factory.create(module_name="rom_column_decode", module_type="rom_decoder", num_outputs=self.words_per_row, strap_spacing=self.strap_spacing, route_layer=self.route_layer, cols=1) + + self.decode_array = factory.create(module_name="rom_row_decode", + module_type="rom_decoder", + num_outputs=self.rows, + strap_spacing=self.strap_spacing, + route_layer=self.route_layer, + cols=self.cols) + + + + + self.column_mux = factory.create(module_type="rom_column_mux_array", + columns=self.cols, + word_size=self.word_size, + bitline_layer=self.interconnect_layer) + + self.column_decode = factory.create(module_name="rom_column_decode", + module_type="rom_decoder", + num_outputs=self.words_per_row, + strap_spacing=self.strap_spacing, + route_layer=self.route_layer, + cols=1, + invert_outputs=True ) + + self.control_logic = factory.create(module_type="rom_control_logic", + num_outputs=(self.rows + self.cols + self.words_per_row) * 0.5, + clk_fanout=(self.col_bits + self.row_bits) * 2, + height=self.column_decode.height) + + print("Col decode height of {}".format(self.column_decode.height)) def create_instances(self): gnd = ["gnd"] vdd = ["vdd"] prechrg = ["precharge"] + clk = ["clk_int"] array_pins = [] decode_pins = [] @@ -156,6 +205,7 @@ class rom_base_bank(design): decode_pins.append(name) decode_pins.append("precharge") + decode_pins.append("clk_int") decode_pins.append("vdd") decode_pins.append("gnd") @@ -166,7 +216,7 @@ class rom_base_bank(design): addr_lsb = ["col_addr_{}".format(addr) for addr in range(self.col_bits)] col_mux_pins = bitlines + select_lines + bitline_out + gnd - col_decode_pins = addr_lsb + select_lines + prechrg + vdd + gnd + col_decode_pins = addr_lsb + select_lines + prechrg + clk + vdd + gnd self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array) self.connect_inst(array_pins) @@ -174,7 +224,7 @@ class rom_base_bank(design): self.connect_inst(decode_pins) self.control_inst = self.add_inst(name="rom_control", mod=self.control_logic) - self.connect_inst(["READ", "CS", "precharge", "vdd", "gnd"]) + self.connect_inst(["clk", "CS", "precharge", "clk_int", "vdd", "gnd"]) self.mux_inst = self.add_inst(name="rom_column_mux", mod=self.column_mux) self.connect_inst(col_mux_pins) @@ -187,13 +237,13 @@ class rom_base_bank(design): def place_instances(self): self.place_row_decoder() self.place_data_array() - self.place_control_logic() - self.place_col_decoder() self.place_col_mux() + self.place_col_decoder() + self.place_control_logic() def place_row_decoder(self): - self.decode_offset = vector(0, self.control_inst.height) + self.decode_offset = vector(0, self.control_inst.height - self.decode_array.control_array.height) self.decode_inst.place(offset=self.decode_offset) def place_data_array(self): @@ -208,53 +258,49 @@ class rom_base_bank(design): self.array_inst.place(offset=(self.array_offset + vector(0, array_align))) def place_control_logic(self): - self.control_offset = vector(0,0) - self.control_inst.place(offset=self.control_offset) + + + self.control_offset = vector(self.control_inst.width + self.decode_array.control_array.width + 2 * (self.route_layer_pitch + self.route_layer_width), self.col_decode_inst.by() + self.control_logic.height) + self.control_inst.place(offset=self.control_offset, mirror="XY") def place_col_decoder(self): - self.col_decode_offset = vector(self.control_logic.width * 1.3, 0) + col_decode_y = self.mux_inst.get_pin("sel_0").cy() - self.col_decode_inst.get_pin("wl_0").cy() + self.col_decode_offset = vector(self.decode_inst.width - self.col_decode_inst.width, col_decode_y) self.col_decode_inst.place(offset=self.col_decode_offset) def place_col_mux(self): + mux_y_offset = self.array_inst.by() - self.mux_inst.height - self.route_layer_pitch - self.mux_offset = vector(self.decode_inst.width, 0) + mux_x_offset = self.array_inst.get_pin("bl_0_0").cx() - self.mux_inst.get_pin("bl_0").cx() + self.mux_offset = vector(mux_x_offset, mux_y_offset) self.mux_inst.place(offset=self.mux_offset) + # def create_wl_bus(self): + # bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) + # bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width + # self.wl_interconnects = [] - def create_wl_bus(self): - bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) - bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width - self.wl_interconnects = [] - - for wl in range(self.rows): - self.wl_interconnects.append("wl_interconnect_{}".format(wl)) + # for wl in range(self.rows): + # self.wl_interconnects.append("wl_interconnect_{}".format(wl)) - self.wl_bus = self.create_vertical_bus(self.bus_layer, vector(bus_x, bus_y), self.wl_interconnects, self.decode_inst.uy() - self.array_inst.by() ) + # self.wl_bus = self.create_vertical_bus(self.bus_layer, vector(bus_x, bus_y), self.wl_interconnects, self.decode_inst.uy() - self.array_inst.by() ) def route_decode_outputs(self): - + # for the row decoder route_pins = [self.array_inst.get_pin("wl_0_{}".format(wl)) for wl in range(self.rows)] decode_pins = [self.decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.rows)] route_pins.extend(decode_pins) self.connect_row_pins(self.interconnect_layer, route_pins, round=True) - # for wl in range(self.rows): - # decode_output = self.decode_array.output_names[wl] - # decode_out_pin = self.decode_inst.get_pin(decode_output) - # array_wl = self.array.wordline_names[0][wl] - # array_wl_pin = self.array_inst.get_pin(array_wl) + # then for the column decoder + col_decode_pins = [self.col_decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.words_per_row)] + sel_pins = [self.mux_inst.get_pin("sel_{}".format(wl)) for wl in range(self.words_per_row)] + sel_pins.extend(col_decode_pins) + self.connect_row_pins(self.array.bitline_layer, sel_pins, round=True) - # # wl_bus_wire = self.wl_bus[self.wl_interconnects[wl]] - - # start = decode_out_pin.center() - # end = vector(array_wl_pin.cx(), start.y) - - # self.add_segment_center(self.bus_layer, start, end) - # self.add_via_stack_center(array_wl_pin.center(), self.bus_layer, self.interconnect_layer ) - def route_array_inputs(self): @@ -270,44 +316,88 @@ class rom_base_bank(design): self.add_segment_center(self.interconnect_layer, start, end) self.add_via_stack_center(start, self.route_layer, self.interconnect_layer ) - def channel_route(self): - route_nets = [] - for wl in range(self.rows): - array_wl = self.array.wordline_names[0][wl] - - array_wl_pin = self.array_inst.get_pin(array_wl) - - decode_output = self.decode_array.output_names[wl] - decode_out_pin = self.decode_inst.get_pin(decode_output) - - route_nets.append([array_wl_pin, decode_out_pin]) - - array_prechrg = self.array_inst.get_pin("precharge") - decode_prechrg = self.decode_inst.get_pin("precharge") - route_nets.append([array_prechrg, decode_prechrg]) - - channel_start = vector(decode_out_pin.cx(), self.decode_array.array_inst.by()) - - channel = self.create_vertical_channel_route(netlist=route_nets, offset=channel_start, layer_stack=self.m1_stack, directions="nonpref") - - def route_control(self): + def route_precharge(self): prechrg_control = self.control_inst.get_pin("prechrg") - decode_prechrg = self.decode_inst.get_pin("precharge") + row_decode_prechrg = self.decode_inst.get_pin("precharge") + col_decode_prechrg = self.col_decode_inst.get_pin("precharge") array_prechrg = self.array_inst.get_pin("precharge") - end = vector(decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy()) + + # Route precharge signal to the row decoder + end = vector(row_decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy()) self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end) start = end + vector(0.5 * self.interconnect_layer_width, 0) - self.add_segment_center(self.interconnect_layer, start, decode_prechrg.center()) + self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center()) + self.add_via_stack_center(from_layer=self.route_stack[0], + to_layer=prechrg_control.layer, + offset=prechrg_control.center()) + + # Route precharge to col decoder + start = row_decode_prechrg.center() - vector(0, self.route_layer_pitch + 2 * self.route_layer_width) + mid = vector(col_decode_prechrg.cx(), start.y) + end = vector(col_decode_prechrg.cx(), 0.5 * (self.col_decode_inst.uy() + mid.y) ) + self.add_path(self.route_stack[0], [start, mid, end]) + + self.add_via_stack_center(from_layer=self.route_stack[0], + to_layer=col_decode_prechrg.layer, + offset=end) + self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center()) + + # Route precharge to main array + end = vector(col_decode_prechrg.cx(), array_prechrg.cy()) + self.add_segment_center(self.route_stack[0], array_prechrg.center(), end) + + + def route_clock(self): + clk_out = self.control_inst.get_pin("clk_out") + row_decode_clk = self.decode_inst.get_pin("clk") + col_decode_clk = self.col_decode_inst.get_pin("clk") + self.add_via_stack_center(from_layer=self.route_stack[2], + to_layer=clk_out.layer, + offset=clk_out.center()) + # Route clock to row decoder + end = row_decode_clk.rc() + vector( 2 * self.route_layer_pitch + self.route_layer_width, 0) + self.add_path(self.route_stack[2], [clk_out.center(), end]) + + self.add_via_stack_center(from_layer=self.route_stack[2], + to_layer=row_decode_clk.layer, + offset=end) + + self.add_segment_center(row_decode_clk.layer, end, row_decode_clk.rc()) + + # Route clock to column decoder + end = col_decode_clk.lc() - vector( 2 * self.route_layer_pitch + self.route_layer_width, 0) + self.add_path(self.route_stack[2], [clk_out.center(), end]) + + self.add_via_stack_center(from_layer=self.route_stack[2], + to_layer=row_decode_clk.layer, + offset=end) + + self.add_segment_center(col_decode_clk.layer, end, col_decode_clk.lc()) + + + + + def route_array_outputs(self): + for i in range(self.cols): + bl_out = self.array_inst.get_pin("bl_0_{}".format(i)).center() + bl_mux = self.mux_inst.get_pin("bl_{}".format(i)).center() + + self.add_path(self.array.bitline_layer, [bl_out, bl_mux]) + def route_supplies(self): + + for inst in self.insts: + self.copy_layout_pin(inst, "vdd") + self.copy_layout_pin(inst, "gnd") gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0) decode_gnd = self.decode_inst.get_pin("gnd") diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index 83370d4d..c7297ec5 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -15,10 +15,11 @@ from openram.tech import drc class rom_base_cell(design): - def __init__(self, name="", bitline_layer="li", bit_value=1): + def __init__(self, name="", bitline_layer="li", bit_value=1, add_well=False): super().__init__(name) self.bit_value = bit_value self.bitline_layer = bitline_layer + self.add_well=add_well self.create_netlist() self.create_layout() @@ -39,6 +40,7 @@ class rom_base_cell(design): self.place_poly() if self.bit_value == 0: self.short_gate() + @@ -150,7 +152,19 @@ class rom_base_cell(design): self.add_segment_center(self.bitline_layer, self.get_pin("D").center(), self.get_pin("S").center()) - + # def place_tap(self): + + # tap_x = self.poly_contact.width * 0.5 + # tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 + + # contact_pos = vector(tap_x, tap_y) + # self.add_via_center(layers=self.active_stack, + # offset=contact_pos, + # implant_type="p", + # well_type="p") + # self.add_power_pin(name="gnd", + # loc=contact_pos, + # start_layer=self.active_stack[2]) diff --git a/compiler/modules/rom_column_mux.py b/compiler/modules/rom_column_mux.py index ae7ece30..4364d3e2 100644 --- a/compiler/modules/rom_column_mux.py +++ b/compiler/modules/rom_column_mux.py @@ -22,12 +22,12 @@ class rom_column_mux(pgate): Column-mux transistors driven by the decoder must be sized for optimal speed """ - def __init__(self, name, tx_size=8, bitline_layer="li"): + def __init__(self, name, tx_size=8, input_layer="m2", output_layer="m1"): debug.info(2, "creating single ROM column mux cell: {0}".format(name)) self.tx_size = int(tx_size) - self.bitline_layer = bitline_layer - + self.input_layer = input_layer + self.output_layer= output_layer super().__init__(name) @@ -42,16 +42,19 @@ class rom_column_mux(pgate): def create_layout(self): - # If li exists, use li and m1 for the mux, otherwise use m1 and m2 - if self.bitline_layer == "li" : - self.col_mux_stack = self.li_stack - else: - self.col_mux_stack = self.m1_stack - self.pin_layer = self.bitcell.bitline_layer + + self.pin_layer = self.input_layer self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer)) self.pin_width = getattr(self, "{}_width".format(self.pin_layer)) self.pin_height = 2 * self.pin_width + # If li exists, use li and m1 for the mux, otherwise use m1 and m2 + if self.output_layer == "li" : + self.col_mux_stack = self.li_stack + else: + self.col_mux_stack = self.m1_stack + + self.place_ptx() # cell = factory.create(module_type=OPTS.bitcell) @@ -69,7 +72,7 @@ class rom_column_mux(pgate): # self.add_pn_wells() def add_ptx(self): - self.bitcell = factory.create(module_type="rom_base_cell", bitline_layer=self.bitline_layer) + self.bitcell = factory.create(module_type="rom_base_cell") # Adds nmos_lower,nmos_upper to the module self.ptx_width = self.tx_size * drc("minwidth_tx") @@ -98,7 +101,7 @@ class rom_column_mux(pgate): # bl_out and br_out self.add_layout_pin(text="bl_out", - layer=self.col_mux_stack[2], + layer=self.col_mux_stack[0], offset=bl_pos, height=self.pin_height) @@ -147,18 +150,8 @@ class rom_column_mux(pgate): nmos_lower_d_pin = self.nmos_lower.get_pin("D") - # Add vias to bl, br_out, nmos_upper/S, nmos_lower/D - # self.add_via_stack_center(from_layer=bl_pin.layer, - # to_layer=self.col_mux_stack[0], - # offset=bl_pin.bc()) - # self.add_via_stack_center(from_layer=br_out_pin.layer, - # to_layer=self.col_mux_stack[0], - # offset=br_out_pin.uc()) - # self.add_via_stack_center(from_layer=nmos_upper_s_pin.layer, - # to_layer=self.col_mux_stack[2], - # offset=nmos_upper_s_pin.center()) self.add_via_stack_center(from_layer=nmos_lower_d_pin.layer, - to_layer=self.col_mux_stack[2], + to_layer=self.output_layer, offset=nmos_lower_d_pin.center()) # bl -> nmos_upper/D on metal1 @@ -167,29 +160,17 @@ class rom_column_mux(pgate): + nmos_lower_s_pin.uc().scale(0, 0.5) mid2 = bl_pin.bc().scale(0, 0.4) \ + nmos_lower_s_pin.uc().scale(1, 0.5) - self.add_path(self.col_mux_stack[0], + self.add_path(self.col_mux_stack[2], [bl_pin.bc(), mid1, mid2, nmos_lower_s_pin.center()]) # halfway up, move over mid1 = bl_out_pin.uc().scale(1, 0.4) \ + nmos_lower_d_pin.bc().scale(0, 0.4) mid2 = bl_out_pin.uc().scale(0, 0.4) \ + nmos_lower_d_pin.bc().scale(1, 0.4) - self.add_path(self.col_mux_stack[2], + self.add_path(self.col_mux_stack[0], [bl_out_pin.uc(), mid1, mid2, nmos_lower_d_pin.center()]) - # # br -> nmos_lower/D on metal2 - # # br_out -> nmos_lower/S on metal1 - # 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()]) - # # halfway up, move over - # mid1 = br_pin.bc().scale(1, 0.5) \ - # + 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(self.col_mux_stack[2], - # [br_pin.bc(), mid1, mid2, nmos_lower_d_pin.center()]) + def extend_implants(self): """ diff --git a/compiler/modules/rom_column_mux_array.py b/compiler/modules/rom_column_mux_array.py index a1a1fc29..1a119044 100644 --- a/compiler/modules/rom_column_mux_array.py +++ b/compiler/modules/rom_column_mux_array.py @@ -9,7 +9,7 @@ from openram import debug from openram.base import design from openram.base import vector from openram.sram_factory import factory -from openram.tech import layer, preferred_directions +from openram.tech import layer, preferred_directions, drc from openram.tech import layer_properties as layer_props from openram import OPTS @@ -20,18 +20,18 @@ class rom_column_mux_array(design): Array of column mux to read the bitlines from ROM, based on the RAM column mux """ - def __init__(self, name, columns, word_size, offsets=None, column_offset=0, bitline_layer="m1"): + def __init__(self, name, columns, word_size, input_layer="m2", bitline_layer="m1", sel_layer="m2"): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} word_size: {1} ".format(columns, word_size)) self.columns = columns self.word_size = word_size - self.offsets = offsets self.words_per_row = int(self.columns / self.word_size) - self.column_offset = column_offset + self.input_layer = input_layer + # self.sel_layer = layer_props.column_mux_array.select_layer + self.sel_layer = sel_layer - self.sel_layer = layer_props.column_mux_array.select_layer self.sel_pitch = getattr(self, self.sel_layer + "_pitch") self.bitline_layer = bitline_layer @@ -89,7 +89,9 @@ class rom_column_mux_array(design): 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.sel_pitch + self.route_height = (self.words_per_row + 3) * self.cell.width + self.route_layer_width = drc["minwidth_{}".format(self.bitline_layer)] + self.route_layer_pitch = drc["{0}_to_{0}".format(self.bitline_layer)] def create_array(self): self.mux_inst = [] @@ -106,8 +108,7 @@ class rom_column_mux_array(design): def place_array(self): # Default to single spaced columns - if not self.offsets: - self.offsets = [n * self.mux.width for n in range(self.columns)] + self.offsets = [n * self.mux.width for n in range(self.columns)] # For every column, add a pass gate for col_num, xoffset in enumerate(self.offsets[0:self.columns]): @@ -145,7 +146,7 @@ class rom_column_mux_array(design): def add_horizontal_input_rail(self): """ Create address input rails below the mux transistors """ for j in range(self.words_per_row): - offset = vector(0, self.route_height + (j - self.words_per_row) * self.sel_pitch) + offset = vector(0, self.route_height + (j - self.words_per_row) * self.cell.width) self.add_layout_pin(text="sel_{}".format(j), layer=self.sel_layer, offset=offset, @@ -154,6 +155,7 @@ class rom_column_mux_array(design): 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 @@ -165,7 +167,9 @@ class rom_column_mux_array(design): offset = vector(gate_offset.x, self.get_pin("sel_{}".format(sel_index)).cy()) - bl_offset = offset.scale(0, 1) + vector((self.mux_inst[col].get_pin("bl_out").cx()), 0) + bl_x_offset = self.mux_inst[col].get_pin("bl_out").cx() + 2 * self.route_layer_width + self.route_layer_pitch + 0.5 * self.poly_contact.width + + bl_offset = offset.scale(0, 1) + vector(bl_x_offset, 0) self.add_via_stack_center(from_layer="poly", to_layer=self.sel_layer, offset=bl_offset, @@ -178,12 +182,12 @@ class rom_column_mux_array(design): bl_offset_begin = self.mux_inst[j].get_pin("bl_out").bc() - bl_out_offset_begin = bl_offset_begin - vector(0, (self.words_per_row + 1) * self.sel_pitch) + bl_out_offset_begin = bl_offset_begin - vector(0, (self.words_per_row + 1) * self.cell.width) # Add the horizontal wires for the first bit if j % self.words_per_row == 0: bl_offset_end = self.mux_inst[j + self.words_per_row - 1].get_pin("bl_out").bc() - bl_out_offset_end = bl_offset_end - vector(0, (self.words_per_row + 1) * self.sel_pitch) + bl_out_offset_end = bl_offset_end - vector(0, (self.words_per_row + 1) * self.cell.width) self.add_path(self.sel_layer, [bl_out_offset_begin, bl_out_offset_end]) diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index 7801fad5..60410ab9 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -8,26 +8,34 @@ from openram.sram_factory import factory from openram.base import vector, design +from openram.tech import layer, drc class rom_control_logic(design): - def __init__(self, num_outputs, name="", height=None): + + def __init__(self, num_outputs, clk_fanout, name="", height=None): self.output_size = num_outputs - self.mod_height = height + super().__init__(name, prop=False) + self.height = height + if self.height is not None: + + print("got height of {}".format(self.height)) + self.driver_height = 0.6 * self.height + self.gate_height = 0.2 * self.height + else: + print("got none height") + self.gate_height = 20 * self.m1_pitch + self.driver_height = self.gate_height + + + self.clk_fanout = clk_fanout + if "li" in layer: - self.route_layer = "li" + self.route_stack = self.li_stack else: - self.route_layer = "m1" + self.route_stack = self.m1_stack - # dff = factory.create(module_type="dff") - - # if height == None: - # self.mod_height = dff.height * 0.5 - # else: - # self.mod_height = height - - super().__init__(name) self.create_netlist() self.create_layout() self.add_boundary() @@ -39,29 +47,40 @@ class rom_control_logic(design): def create_layout(self): self.create_instances() - self.height=self.nand_inst.height - self.width=self.nand_inst.width + self.inv_inst.width + self.driver_inst.width + self.height=self.driver_inst.height + self.buf_inst.height + self.width= max(self.nand_inst.width + self.buf_inst.width, self.driver_inst.width) self.place_instances() self.route_insts() def add_modules(self): - self.inv_mod = factory.create(module_type="pinv", module_name="rom_control_logic_pinv", height=self.mod_height) - self.nand_mod = factory.create(module_type="pnand2", module_name="rom_control_nand", height=self.mod_height) - self.driver_mod = factory.create(module_type="pdriver", inverting=True, fanout=self.output_size, height=self.mod_height, add_wells=True) + self.buf_mod = factory.create(module_type="pinvbuf", + module_name="rom_control_logic_pinv", + height=self.gate_height, + route_in_cell=True ) + self.nand_mod = factory.create(module_type="pnand2", + module_name="rom_control_nand", + height=self.gate_height, + add_wells=False) + self.driver_mod = factory.create(module_type="pdriver", + inverting=True, + fanout=self.output_size, + height=self.driver_height, + add_wells=True) def add_pins(self): - self.add_pin("clk", "INPUT") + self.add_pin("clk_in", "INPUT") self.add_pin("CS", "INPUT") self.add_pin("prechrg", "OUTPUT") + self.add_pin("clk_out", "OUTPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") def create_instances(self): - self.inv_inst = self.add_inst(name="read_signal_inv", mod=self.inv_mod) - self.connect_inst(["clk", "clk_bar", "vdd", "gnd"]) + self.buf_inst = self.add_inst(name="clk_invbuf", mod=self.buf_mod) + self.connect_inst(["clk_in", "clk_bar", "clk_out", "vdd", "gnd"]) self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod) self.connect_inst(["CS", "clk_bar", "pre_drive", "vdd", "gnd"]) @@ -71,16 +90,55 @@ class rom_control_logic(design): def place_instances(self): - self.nand_inst.place(offset=[self.inv_inst.width, 0]) - self.driver_inst.place(offset=[self.nand_inst.width + self.inv_inst.width, 0]) + buf_correction = drc["minwidth_{}".format(self.route_stack[0])] * 0.5 + # nand_y = self.buf_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy() + self.nand_inst.place(offset=[0, self.nand_inst.height + self.buf_mod.inv2.height + buf_correction], mirror="MX") + self.driver_inst.place(offset=[0, self.buf_inst.height + buf_correction]) def route_insts(self): + + route_width = drc["minwidth_{}".format(self.route_stack[2])] - self.copy_layout_pin(self.inv_inst, "A", "READ") + self.copy_layout_pin(self.buf_inst, "A", "clk_in") + self.copy_layout_pin(self.buf_inst, "Zb", "clkb_out") + self.copy_layout_pin(self.buf_inst, "Z", "clk_out") self.copy_layout_pin(self.driver_inst, "Z", "prechrg") self.copy_layout_pin(self.nand_inst, "B", "CS") + self.copy_layout_pin(self.buf_inst, "gnd") + self.copy_layout_pin(self.driver_inst, "vdd") + self.copy_layout_pin(self.buf_inst, "vdd") + # self.copy_layout_pin(self.buf_inst, "vdd") - self.add_path(self.route_layer, [self.inv_inst.get_pin("Z").center(), self.nand_inst.get_pin("A").center()]) + clk_bar = self.buf_inst.get_pin("Zb") - self.add_path(self.route_layer, [self.nand_inst.get_pin("Z").center(), self.driver_inst.get_pin("A").center()]) - \ No newline at end of file + nand_B = self.nand_inst.get_pin("B") + + + # Connect buffered clock bar to nand input + + mid = vector(clk_bar.lx() - route_width - 2 * self.m1_space) + self.add_path(self.route_stack[2], [clk_bar.center(), mid, nand_B.center()]) + + self.add_via_stack_center(from_layer=clk_bar.layer, + to_layer=self.route_stack[2], + offset=clk_bar.center()) + self.add_via_stack_center(from_layer=nand_B.layer, + to_layer=self.route_stack[2], + offset=nand_B.center()) + + + # Connect nand output to precharge driver + nand_Z = self.nand_inst.get_pin("Z") + nand_output = vector(nand_Z.cx(), nand_B.cy() + 3 * route_width) + + driver_A = self.driver_inst.get_pin("A") + self.add_path(self.route_stack[2], [nand_output, driver_A.center()]) + + + self.add_via_stack_center(from_layer=nand_Z.layer, + to_layer=self.route_stack[2], + offset=nand_output) + + self.add_via_stack_center(from_layer=driver_A.layer, + to_layer=self.route_stack[2], + offset=driver_A.center()) \ No newline at end of file diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index 46687611..4a40444b 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -14,7 +14,7 @@ from openram.tech import drc class rom_decoder(design): - def __init__(self, num_outputs, cols, strap_spacing, name="", route_layer="m1", output_layer="m2"): + def __init__(self, num_outputs, cols, strap_spacing, name="", route_layer="m1", output_layer="m1", invert_outputs=False): # word lines/ rows / inputs in the base array become the address lines / cols / inputs in the decoder # bit lines / cols / outputs in the base array become the word lines / rows / outputs in the decoder @@ -34,7 +34,11 @@ class rom_decoder(design): self.output_layer = output_layer self.inv_route_layer = "m2" self.cols=cols + self.invert_outputs=invert_outputs self.create_netlist() + + self.width = self.array_mod.height + self.wordline_buf.width + self.height = self.array_mod.width + self.control_array.height self.create_layout() def create_netlist(self): @@ -49,10 +53,9 @@ class rom_decoder(design): self.place_input_buffer() self.place_driver() self.route_outputs() - self.width = self.array_inst.height + self.wordline_buf_inst.width - self.height = self.array_inst.width + self.buf_inst.height + self.connect_inputs() - # self.route_supplies() + self.route_supplies() self.add_boundary() def setup_layout_constants(self): @@ -97,18 +100,24 @@ class rom_decoder(design): for j in range(self.num_outputs): self.add_pin("wl_{0}".format(j), "OUTPUT") - self.add_pin("precharge_gate", "INPUT") + self.add_pin("precharge", "INPUT") + self.add_pin("clk", "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") def add_modules(self): - self.control_array = factory.create(module_type="rom_address_control_array", cols=self.num_inputs) + self.control_array = factory.create(module_type="rom_address_control_array", + cols=self.num_inputs) + self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), \ - rows=self.num_outputs, \ - cols=self.cols) + rows=self.num_outputs, \ + cols=self.cols, + invert_outputs=self.invert_outputs, + tap_spacing=self.strap_spacing) + self.array_mod = factory.create(module_type="rom_base_array", \ module_name="{}_array".format(self.name), \ @@ -116,8 +125,8 @@ class rom_decoder(design): rows=2 * self.num_inputs, \ bitmap=self.decode_map, strap_spacing = self.strap_spacing, - route_layer=self.route_layer, - output_layer=self.output_layer) + bitline_layer=self.output_layer, + tap_direction="col") def create_instances(self): @@ -135,8 +144,8 @@ class rom_decoder(design): for i in range(self.num_inputs): control_pins.append("A{0}".format(i)) - control_pins.append("A{0}_int".format(i)) - control_pins.append("Abar{0}_int".format(i)) + control_pins.append("in_{0}".format(i)) + control_pins.append("inbar_{0}".format(i)) control_pins.append("clk") control_pins.append("vdd") control_pins.append("gnd") @@ -156,7 +165,7 @@ class rom_decoder(design): for i in reversed(range(self.num_inputs)): array_pins.append("inbar_{0}".format(i)) array_pins.append("in_{0}".format(i)) - array_pins.append("precharge_gate") + array_pins.append("precharge") array_pins.append("vdd") array_pins.append("gnd") self.connect_inst(array_pins) @@ -173,10 +182,11 @@ class rom_decoder(design): def place_input_buffer(self): wl = self.array_mod.row_size - 1 align = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl]).cx() - self.buf_inst.get_pin("A0_out").cx() - print("align: {}".format(align)) self.buf_inst.place(vector(align, 0)) + self.copy_layout_pin(self.buf_inst, "clk") + def place_array(self): @@ -196,6 +206,9 @@ class rom_decoder(design): for j in range(self.num_outputs): self.copy_layout_pin(self.wordline_buf_inst, "out_{}".format(j), "wl_{}".format(j)) + offset = self.wordline_buf_inst.get_pin("out_{}".format(j)).center() + + # self.add_via_stack_center(offset, self.output_layer, self.wordline_buf.route_layer) array_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.num_outputs)] driver_pins = [self.wordline_buf_inst.get_pin("in_{}".format(bl)) for bl in range(self.num_outputs)] @@ -229,44 +242,50 @@ class rom_decoder(design): def route_supplies(self): minwidth = drc["minwidth_{}".format(self.inv_route_layer)] pitch = drc["{0}_to_{0}".format(self.inv_route_layer)] + self.copy_layout_pin(self.array_inst, "vdd") + self.copy_layout_pin(self.wordline_buf_inst, "vdd") + self.copy_layout_pin(self.buf_inst, "vdd") + self.copy_layout_pin(self.array_inst, "gnd") + self.copy_layout_pin(self.wordline_buf_inst, "gnd") + self.copy_layout_pin(self.buf_inst, "gnd") # route decode array vdd and inv array vdd together - array_vdd = self.array_inst.get_pin("vdd") - inv_vdd = self.buf_inst.get_pins("vdd")[-1] + # array_vdd = self.array_inst.get_pin("vdd") + # inv_vdd = self.buf_inst.get_pins("vdd")[-1] - end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth) - self.add_segment_center("m1", array_vdd.center(), end) - end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy()) - self.add_segment_center(self.route_layer, inv_vdd.center(), end) + # end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth) + # self.add_segment_center("m1", array_vdd.center(), end) + # end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy()) + # self.add_segment_center(self.route_layer, inv_vdd.center(), end) - end = vector(array_vdd.cx(), inv_vdd.cy()) - self.add_via_stack_center(end, self.route_layer, "m1") - self.add_layout_pin_rect_center("vdd", "m1", end) + # end = vector(array_vdd.cx(), inv_vdd.cy()) + # self.add_via_stack_center(end, self.route_layer, "m1") + # self.add_layout_pin_rect_center("vdd", "m1", end) - # route pin on inv gnd + # # route pin on inv gnd - inv_gnd = self.buf_inst.get_pins("gnd")[0] - array_gnd = self.array_inst.get_pins("gnd") + # inv_gnd = self.buf_inst.get_pins("gnd")[0] + # array_gnd = self.array_inst.get_pins("gnd") - # add x jog + # # add x jog - start = vector(array_gnd[0].cx(), inv_gnd.cy()) - self.add_via_stack_center(start, self.route_layer, "m1") - self.add_layout_pin_rect_center("gnd", "m1", start) + # start = vector(array_gnd[0].cx(), inv_gnd.cy()) + # self.add_via_stack_center(start, self.route_layer, "m1") + # self.add_layout_pin_rect_center("gnd", "m1", start) - end = array_gnd[0].center() - self.add_segment_center("m1", start, end) - # add y jog + # end = array_gnd[0].center() + # self.add_segment_center("m1", start, end) + # # add y jog - width = minwidth - height = array_gnd[0].uy() - array_gnd[-1].uy() + minwidth + # width = minwidth + # height = array_gnd[0].uy() - array_gnd[-1].uy() + minwidth - offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy())) + # offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy())) - start = end - vector(0, 0.5 * minwidth) - end = vector(start.x, array_gnd[1].uy()) + # start = end - vector(0, 0.5 * minwidth) + # end = vector(start.x, array_gnd[1].uy()) diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index c09ef984..31acee5a 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -14,36 +14,43 @@ from openram.tech import drc class rom_poly_tap(design): - def __init__(self, name="", strap_length=0, cell_name=None, prop=None, tx_type="nmos", strap_layer="m2"): - super().__init__(name, cell_name, prop) + def __init__(self, name="", cell_name=None, tx_type="nmos", strap_layer="m2", add_tap=False): + super().__init__(name, cell_name) self.strap_layer=strap_layer - self.length = strap_length self.tx_type = tx_type + self.add_tap = add_tap + self.pitch_offset = 0 self.create_netlist() self.create_layout() def create_netlist(self): #for layout constants - self.dummy = factory.create(module_type="rom_base_cell") + if self.tx_type == "nmos": + self.dummy = factory.create(module_type="rom_base_cell") + else: + self.dummy = factory.create(module_type="rom_precharge_cell") + self.pmos = factory.create(module_type="ptx", tx_type="pmos") def create_layout(self): self.place_via() - # if self.tx_type == "pmos": - self.extend_poly() - self.place_ptap() + + if self.add_tap: + self.place_active_tap() + self.extend_poly() self.add_boundary() + # if self.length != 0: # self.place_strap() def add_boundary(self): - contact_width = self.poly_contact.width + 2 * self.contact_x_offset + contact_width = self.poly_contact.width - offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact) + # offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact) self.height = self.dummy.height - self.width = contact_width + self.pitch_offset + self.width = contact_width + self.pitch_offset super().add_boundary() @@ -59,59 +66,66 @@ class rom_poly_tap(design): else: assert(False) + contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact + if self.tx_type == "nmos": - contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact + # contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact # contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) - # self.contact_x_offset = 0 - else: - contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x + self.contact_x_offset = 0 + # else: + # contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x - # contact_x = - contact_width * 0.5 - self.contact_x_offset - contact_x = contact_width * 0.5 + self.contact_x_offset + contact_x = contact_width * 0.5 + self.contact_x_offset self.contact_offset = vector(contact_x, contact_y) self.via = self.add_via_stack_center(from_layer="poly", to_layer=self.strap_layer, offset=self.contact_offset) - self.add_layout_pin_rect_center("via", self.strap_layer, self.contact_offset) + self.add_layout_pin_rect_center("poly_tap", self.strap_layer, self.contact_offset) - def place_strap(self): + # def place_strap(self): - strap_start = vector(self.via.lx() , self.via.cy()) + # strap_start = vector(self.via.lx() , self.via.cy()) - strap_end = vector( self.dummy.width * (self.length + 1), self.via.cy()) + # strap_end = vector( self.dummy.width * (self.length + 1), self.via.cy()) - self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) + # self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) def extend_poly(self): - - base_contact_width = self.poly_contact.width + 2 * self.contact_x_offset - - self.pitch_offset = (base_contact_width - self.active_enclose_contact - self.active_extend_contact) - self.active_space + + self.add_segment_center("poly", self.via.center(), vector(self.via.cx() + self.pitch_offset, self.via.cy())) + self.add_segment_center("poly", self.via.center(), vector(0, self.via.cy())) - poly_x = self.poly_contact.width + self.contact_x_offset - poly_y = self.contact_offset.y - self.poly_width * 0.5 - extend_offset = vector(poly_x, poly_y) - - self.add_rect("poly", extend_offset, self.contact_x_offset + self.pitch_offset, self.poly_width) - - poly_x = 0 - extend_offset = vector(poly_x, poly_y) - - self.add_rect("poly", extend_offset, self.contact_x_offset , self.poly_width) - def place_ptap(self): - tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 + def place_active_tap(self): + gap = self.poly_extend_active - 0.5 * ( self.active_contact.height - self.poly_contact.width ) + offset = self.active_space - gap + # tap_x = self.via.cx() + self.contact_width + self.active_enclose_contact + self.poly_enclose_contact + tap_x = self.via.cx() + offset + tap_y = self.via.cy() + self.dummy.width * 0.5 + contact_pos = vector(tap_x, tap_y) + + + # edge of the next nmos + active_edge = self.dummy.width - self.dummy.cell_inst.height - self.poly_extend_active + + # edge of the active contact + tap_edge = tap_x + 0.5 * self.active_contact.height + self.pitch_offset += (self.active_space * 2) - (tap_edge - active_edge) + self.contact_x_offset + + if self.tx_type == "nmos": + + self.add_via_center(layers=self.active_stack, + offset=contact_pos, + implant_type="p", + well_type="p", + directions="nonpref") + self.add_power_pin(name="gnd", + loc=contact_pos, + start_layer=self.active_stack[2]) + self.add_layout_pin_rect_center("active_tap", self.supply_stack[0], contact_pos) - contact_pos = vector(self.via.cx(), tap_y) - self.add_via_center(layers=self.active_stack, - offset=contact_pos, - implant_type="p", - well_type="p") - self.add_power_pin(name="gnd", - loc=contact_pos, - start_layer=self.active_stack[2]) diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index 247d2d4e..5fd585d1 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -19,25 +19,25 @@ class rom_precharge_array(design): """ An array of inverters to create the inverted address lines for the rom decoder """ - def __init__(self, cols, pmos_size=None, name="", route_layer="li", strap_spacing=None): + def __init__(self, cols, name="", route_layer="li", strap_spacing=None, strap_layer="m2", tap_direction="row"): self.cols = cols self.route_layer = route_layer + self.strap_layer = strap_layer + self.tap_direction = tap_direction + + if self.route_layer == "m1" : + self.supply_layer = "li" + else: + self.supply_layer = "m1" + if name=="": name = "rom_inv_array_{0}".format(cols) - # if pmos_size == None: - # self.pmos_size = dff.height * 0.5 - # else: - # self.pmos_size = inv_size + if strap_spacing != None: self.strap_spacing = strap_spacing else: self.strap_spacing = 0 - if "li" in layer: - self.inv_layer = "li" - else: - self.inv_layer = "m1" - if strap_spacing != 0: self.num_straps = ceil(self.cols / self.strap_spacing) @@ -62,28 +62,30 @@ class rom_precharge_array(design): self.height = self.pmos.width self.place_instances() self.create_layout_pins() - self.add_well_tap() self.route_supply() + self.connect_taps() self.add_boundary() - + self.extend_well() def add_boundary(self): # self.translate_all(self.well_ll) ur = self.find_highest_coords() + self.add_label(layer="nwell", text="upper right",offset=ur) # ur = vector(ur.x, ur.y - self.well_ll.y) super().add_boundary(vector(0, 0), ur) - self.width = self.cols * self.pmos.width self.height = ur.y + self.width = ur.x def create_modules(self): - self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", route_layer=self.route_layer) + self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", route_layer=self.route_layer, supply_layer=self.supply_layer) # For layout constants self.dummy = factory.create(module_type="rom_base_cell") - self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=self.strap_spacing) + + self.poly_tap = factory.create(module_type="rom_poly_tap", tx_type="pmos", add_tap=(self.tap_direction == "col")) def add_pins(self): for col in range(self.cols): @@ -96,33 +98,34 @@ class rom_precharge_array(design): self.pmos_insts = [] self.tap_insts = [] - self.tap_insts.append(self.add_inst(name="tap_0", mod=self.poly_tap)) - self.connect_inst([]) + self.create_poly_tap(-1) for col in range(self.cols): + if col % self.strap_spacing == 0: + self.create_poly_tap(col) + self.create_precharge_tx(col) - # if col % self.strap_spacing == 0: - # name = "tap_c{}".format(col) - # tap = self.add_inst(name=name, mod=self.poly_tap) - # self.array_insts.append(tap) - # self.tap_insts.append(tap) - # self.connect_inst([]) - name = "Xpmos_c{0}".format(col) - pmos = self.add_inst(name=name, mod=self.pmos) - self.array_insts.append(pmos) - self.pmos_insts.append(pmos) - bl = "pre_bl{0}_out".format(col) - self.connect_inst(["vdd", "gate", bl, "vdd"]) - print(self.array_insts) + def create_precharge_tx(self, col): + name = "Xpmos_c{0}".format(col) + pmos = self.add_inst(name=name, mod=self.pmos) + self.array_insts.append(pmos) + self.pmos_insts.append(pmos) + bl = "pre_bl{0}_out".format(col) + self.connect_inst(["vdd", "gate", bl]) + def create_poly_tap(self, col): + name = "tap_c{}".format( col) + new_tap = self.add_inst(name=name, mod=self.poly_tap) + self.tap_insts.append(new_tap) + self.connect_inst([]) def place_instances(self): self.add_label("ZERO", self.route_layer) self.array_pos = [] - strap_num = 0 + strap_num = 1 cell_y = 0 # columns are bit lines4 cell_x = 0 @@ -130,12 +133,19 @@ class rom_precharge_array(design): self.tap_insts[0].place(vector(cell_x, cell_y)) for col in range(self.cols): + + if col % self.strap_spacing == 0: + self.tap_insts[strap_num].place(vector(cell_x, cell_y)) + strap_num += 1 + + if self.tap_direction == "col": + cell_x += self.poly_tap.pitch_offset + # if col % self.strap_spacing == 0 : # self.tap_insts[strap_num].place(vector(cell_x, cell_y)) # self.add_label("debug", "li", vector(cell_x, cell_y)) # cell_x += self.poly_tap.width - # strap_num += 1 self.pmos_insts[col].place(vector(cell_x, cell_y)) self.add_label("debug", "li", vector(cell_x, cell_y)) @@ -143,51 +153,31 @@ class rom_precharge_array(design): def create_layout_pins(self): - self.copy_layout_pin(self.tap_insts[0], "via", "gate") + self.copy_layout_pin(self.tap_insts[0], "poly_tap", "gate") for col in range(self.cols): source_pin = self.pmos_insts[col].get_pin("D") bl = "pre_bl{0}_out".format(col) self.add_layout_pin_rect_center(bl, self.route_layer, source_pin.center()) - def add_well_tap(self): - - layer_stack = self.active_stack - contact_x = self.pmos_insts[self.cols - 1].rx() + self.active_space - contact_offset = vector(contact_x, self.pmos.height * 0.5) - - self.nwell_contact = self.add_via_center(layers=layer_stack, - offset=contact_offset, - implant_type="n", - well_type="n", - directions=("V", "V")) - def route_supply(self): - - start_pin = self.pmos_insts[0].get_pin("S").lx() - end_pin = self.pmos_insts[-1].get_pin("S").rx() - spacing = drc["{0}_to_{0}".format(self.route_layer)] - start = vector(start_pin, -2*spacing) - end = vector(end_pin, -2*spacing) - - self.vdd = self.add_layout_pin_segment_center("vdd", "m1", start, end) - - for i in range(self.cols): - start = self.pmos_insts[i].get_pin("S").center() - end = vector(start.x, self.vdd.cy()) - - self.add_segment_center(self.route_layer, start, end) - self.add_via_stack_center(end, self.route_layer, "m1") + # self.vdd = self.add_layout_pin_segment_center("vdd", self.supply_layer, start, end) + # vdd = [self.pmos_insts[i].get_pin("vdd") for i in range(self.cols)]routeroute_horizon_horizon + self.route_horizontal_pins("vdd", insts=self.pmos_insts) - # connect nwell tap to vdd - start = end - end = vector(self.nwell_contact.cx(), start.y) - self.add_segment_center(self.route_layer, start, end) - start = end - vector(0, 0.5 * self.mcon_width) - end = self.nwell_contact.center() - self.add_segment_center(self.route_layer, start, end) + def connect_taps(self): + array_pins = [self.tap_insts[i].get_pin("poly_tap") for i in range(len(self.tap_insts))] + self.connect_row_pins(layer=self.strap_layer, pins=array_pins, name=None, round=False) + + def extend_well(self): + well_y = self.pmos_insts[0].get_pin("vdd").cy() - 0.5 * self.nwell_width + + well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width + well_ll = vector(0, well_y) + + self.add_rect("nwell", well_ll, self.width , self.height - well_y) diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 57477626..4108f7cb 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -15,20 +15,16 @@ from openram.tech import drc class rom_precharge_cell(rom_base_cell): - def __init__(self, name="", route_layer="m1"): - + def __init__(self, name="", route_layer="m1", supply_layer="li"): + self.supply_layer = supply_layer super().__init__(name=name, bitline_layer=route_layer) - - - # def create_netlist(self): - # self.add_pins() - # self.add_modules() - # self.create_tx() def create_layout(self): super().create_layout() + + self.place_tap() self.extend_well() @@ -37,19 +33,21 @@ class rom_precharge_cell(rom_base_cell): self.pmos = factory.create(module_type="ptx", module_name="pre_pmos_mod", - tx_type="pmos" + tx_type="pmos", + add_source_contact=self.supply_layer, + add_drain_contact=self.bitline_layer ) def create_tx(self): self.cell_inst = self.add_inst( name="precharge_pmos", mod=self.pmos, ) - self.connect_inst(["bitline", "gate", "vdd", "body"]) + self.connect_inst(["bitline", "gate", "vdd", "vdd"]) def add_pins(self): - pin_list = ["vdd", "gate", "bitline", "body"] - dir_list = ["POWER", "INPUT", "OUTPUT", "POWER"] + pin_list = ["vdd", "gate", "bitline"] + dir_list = ["POWER", "INPUT", "OUTPUT"] self.add_pin_list(pin_list, dir_list) @@ -57,8 +55,6 @@ class rom_precharge_cell(rom_base_cell): self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active) - - #contact to contact distance, minimum cell width before drc offsets self.base_width = self.pmos.width - 2 * self.active_enclose_contact - self.pmos.contact_width @@ -70,37 +66,34 @@ class rom_precharge_cell(rom_base_cell): def extend_well(self): - self.pmos - well_y = - (0.5 * self.nwell_width) + well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width well_ll = vector(0, well_y) # height = self.active_width + 2 * self.well_enclose_active - height = self.height + 0.5 * self.nwell_width + height = self.get_pin("D").cy() + 0.5 * self.nwell_width - well_y self.add_rect("nwell", well_ll, self.width , height) - # def place_tx(self): - # pmos_offset = vector(self.pmos.poly_extend_active + self.pmos.height, 0) + + def place_tap(self): + source = self.cell_inst.get_pin("S") + + tap_y = source.cy() - self.contact_width - 2 * self.active_enclose_contact - self.active_space + + pos = vector(source.cx(), tap_y ) + + self.add_via_center(layers=self.active_stack, + offset=pos, + implant_type="n", + well_type="n", + directions="nonpref") + self.add_via_stack_center(offset=pos, + from_layer=self.active_stack[2], + to_layer=self.supply_layer) - # self.cell_inst.place(pmos_offset, rotate=90) - # self.add_label("inst_zero", self.bitline_layer) - # self.add_layout_pin_rect_center("S", self.bitline_layer, self.cell_inst.get_pin("S").center()) - # self.add_layout_pin_rect_center("D", self.bitline_layer, self.cell_inst.get_pin("D").center()) - - - # def place_poly(self): - # poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.rx() + self.poly_extend_active) - # poly_offset = vector(self.cell_inst.rx() + self.poly_extend_active, self.cell_inst.width * 0.5 ) - - # start = poly_offset - # end = poly_offset + vector(poly_size, 0) - # self.add_segment_center("poly", start, end) - # def add_boundary(self): - - # #cell width with offsets applied, height becomes width when the cells are rotated - # self.width = self.pmos.height + self.poly_extend_active_spacing + 2 * self.pmos.poly_extend_active - - # # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied - # # self.height = self.base_width - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) - - # super().add_boundary() + bitline_offset = vector( 2 * (drc("minwidth_{}".format(self.bitline_layer)) + drc("{0}_to_{0}".format(self.bitline_layer))) ,0) + self.add_layout_pin_rect_center("vdd", self.supply_layer, pos - bitline_offset) + + self.add_path(self.supply_layer, [self.get_pin("vdd").center(), pos, self.get_pin("S").center()]) + + self.remove_layout_pin("S") diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index 9a19919c..b50b7fc8 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -19,14 +19,15 @@ class rom_wordline_driver_array(design): Creates a Wordline Buffer/Inverter array """ - def __init__(self, name, rows, cols): + def __init__(self, name, rows, cols, invert_outputs=False, tap_spacing=4): design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("rows: {0} cols: {1}".format(rows, cols)) self.rows = rows self.cols = cols - + self.invert_outputs=invert_outputs + self.tap_spacing = tap_spacing self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -60,10 +61,25 @@ class rom_wordline_driver_array(design): def add_modules(self): b = factory.create(module_type="rom_base_cell") - self.wl_driver = factory.create(module_type="pbuf_dec", - size=self.cols, - height=b.height, - add_wells=False) + if self.invert_outputs: + self.wl_driver = factory.create(module_type="pinv_dec", + size=self.cols, + height=b.height, + add_wells=False) + + self.wl_driver_tap = factory.create(module_type="pinv_dec", + size=self.cols, + add_wells=True) + else: + self.wl_driver = factory.create(module_type="pbuf_dec", + size=self.cols, + height=b.height, + add_wells=False) + self.wl_driver_tap = factory.create(module_type="pbuf_dec", + size=self.cols, + add_wells=True) + print(self.wl_driver.height) + print(self.wl_driver_tap.height) def route_supplies(self): """ @@ -80,21 +96,25 @@ class rom_wordline_driver_array(design): def create_drivers(self): self.wld_inst = [] for row in range(self.rows): - self.wld_inst.append(self.add_inst(name="wld{0}".format(row), - mod=self.wl_driver)) + if row % self.tap_spacing == 0: + self.wld_inst.append(self.add_inst(name="wld{0}".format(row), + mod=self.wl_driver_tap)) + else: + self.wld_inst.append(self.add_inst(name="wld{0}".format(row), + mod=self.wl_driver)) self.connect_inst(["in_{0}".format(row), "out_{0}".format(row), "vdd", "gnd"]) def place_drivers(self): - + y_offset = 0 for row in range(self.rows): # These are flipped since we always start with an RBL on the bottom - y_offset = self.wl_driver.height * row offset = [0, y_offset] self.wld_inst[row].place(offset=offset) + y_offset += self.wld_inst[row].height self.width = self.wl_driver.width self.height = self.wl_driver.height * self.rows diff --git a/compiler/tests/05_rom_base_bank_test.py b/compiler/tests/05_rom_base_bank_test.py index 277205b1..f8c578dc 100644 --- a/compiler/tests/05_rom_base_bank_test.py +++ b/compiler/tests/05_rom_base_bank_test.py @@ -24,7 +24,7 @@ class rom_bank_test(openram_test): debug.info(2, "Testing 4x4 array for rom cell") - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data", word_size=1) + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_1kB", word_size=1) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/05_rom_control_logic_test.py b/compiler/tests/05_rom_control_logic_test.py index 4e13b9bf..e6c5d173 100644 --- a/compiler/tests/05_rom_control_logic_test.py +++ b/compiler/tests/05_rom_control_logic_test.py @@ -25,7 +25,7 @@ class rom_decoder_test(openram_test): debug.info(2, "Testing control logic for rom cell") - a = factory.create(module_type="rom_control_logic", num_outputs=4) + a = factory.create(module_type="rom_control_logic", num_outputs=4, clk_fanout=4, height=40) self.local_check(a) openram.end_openram() From 16df8e0e43cc5c6af36e0c76bd0fb4a3fc9e5a02 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 26 Jan 2023 15:48:38 -0800 Subject: [PATCH 41/98] fixing decoder lvs --- compiler/modules/rom_address_control_array.py | 2 + compiler/modules/rom_base_array.py | 2 +- compiler/modules/rom_decoder.py | 57 ++++++-------- compiler/modules/rom_precharge_array.py | 1 + compiler/modules/rom_precharge_cell.py | 2 +- compiler/modules/rom_wordline_driver_array.py | 76 ++++++++++++++----- compiler/tests/05_rom_decoder_test.py | 2 +- 7 files changed, 89 insertions(+), 53 deletions(-) diff --git a/compiler/modules/rom_address_control_array.py b/compiler/modules/rom_address_control_array.py index 2b195bd8..cfb8a278 100644 --- a/compiler/modules/rom_address_control_array.py +++ b/compiler/modules/rom_address_control_array.py @@ -65,7 +65,9 @@ class rom_address_control_array(design): def add_pins(self): for col in range(self.cols): self.add_pin("A{0}_in".format(col), "INPUT") + for col in range(self.cols): self.add_pin("A{0}_out".format(col), "OUTPUT") + for col in range(self.cols): self.add_pin("Abar{0}_out".format(col), "OUTPUT") self.add_pin("clk", "INPUT") self.add_pin("vdd", "POWER") diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 2d2be82a..7c329c67 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -117,7 +117,7 @@ class rom_base_array(bitcell_base_array): def add_pins(self): for bl_name in self.get_bitline_names(): - self.add_pin(bl_name, "INOUT") + self.add_pin(bl_name, "OUTPUT") for wl_name in self.get_wordline_names(): self.add_pin(wl_name, "INPUT") self.add_pin("precharge_gate", "INPUT") diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index 4a40444b..e1a642fd 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -144,8 +144,12 @@ class rom_decoder(design): for i in range(self.num_inputs): control_pins.append("A{0}".format(i)) - control_pins.append("in_{0}".format(i)) - control_pins.append("inbar_{0}".format(i)) + for i in range(self.num_inputs): + control_pins.append("A_int_{0}".format(i)) + for i in range(self.num_inputs): + control_pins.append("Ab_int_{0}".format(i)) + + control_pins.append("clk") control_pins.append("vdd") control_pins.append("gnd") @@ -163,8 +167,8 @@ class rom_decoder(design): for i in reversed(range(self.num_inputs)): - array_pins.append("inbar_{0}".format(i)) - array_pins.append("in_{0}".format(i)) + array_pins.append("Ab_int_{0}".format(i)) + array_pins.append("A_int_{0}".format(i)) array_pins.append("precharge") array_pins.append("vdd") array_pins.append("gnd") @@ -236,6 +240,7 @@ class rom_decoder(design): self.add_path(self.inv_route_layer, [addr_out_pin.center(), addr_middle, addr_pin.center()]) self.add_path(self.inv_route_layer, [addr_bar_out_pin.center(), addr_bar_middle, addr_bar_pin.center()]) + self.copy_layout_pin(self.buf_inst, "A{}_in".format(i), "A{}".format(i)) # self.add_segment_center(self.inv_route_layer, addr_bar_middle + vector(0, self.inv_route_width * 0.5), addr_bar_out_pin.center() + vector(0, self.inv_route_width * 0.5), self.inv_route_width) @@ -250,42 +255,28 @@ class rom_decoder(design): self.copy_layout_pin(self.wordline_buf_inst, "gnd") self.copy_layout_pin(self.buf_inst, "gnd") - # route decode array vdd and inv array vdd together - # array_vdd = self.array_inst.get_pin("vdd") - # inv_vdd = self.buf_inst.get_pins("vdd")[-1] - # end = vector(array_vdd.cx(), inv_vdd.cy() - 0.5 * minwidth) - # self.add_segment_center("m1", array_vdd.center(), end) - # end = vector(array_vdd.cx() + 0.5 * minwidth, inv_vdd.cy()) - # self.add_segment_center(self.route_layer, inv_vdd.center(), end) - - # end = vector(array_vdd.cx(), inv_vdd.cy()) - # self.add_via_stack_center(end, self.route_layer, "m1") - # self.add_layout_pin_rect_center("vdd", "m1", end) + # Extend nwells to connect with eachother + self.extend_wells() - # # route pin on inv gnd - # inv_gnd = self.buf_inst.get_pins("gnd")[0] - # array_gnd = self.array_inst.get_pins("gnd") - - # # add x jog - - # start = vector(array_gnd[0].cx(), inv_gnd.cy()) - # self.add_via_stack_center(start, self.route_layer, "m1") - # self.add_layout_pin_rect_center("gnd", "m1", start) - - # end = array_gnd[0].center() - # self.add_segment_center("m1", start, end) - # # add y jog + def extend_wells(self): + precharge_well_rx = self.array_inst.get_pins("vdd")[0].cx() + 0.5 * self.nwell_width + precharge_well_lx = precharge_well_rx - self.array_mod.precharge_array.height - 0.5 * self.nwell_width - self.array_mod.precharge_array.well_offset - # width = minwidth - # height = array_gnd[0].uy() - array_gnd[-1].uy() + minwidth + offset = vector(precharge_well_rx ,self.array_inst.by()) - # offset = vector(-0.5 *width ,0.5 * (array_gnd[0].cy() + array_gnd[-1].cy())) + self.add_label(text="well_right", layer="nwell", offset=offset) + offset = vector(precharge_well_lx ,self.array_inst.by()) + self.add_label(text="well_left", layer="nwell", offset=offset) + vdd_pins=self.buf_inst.get_pins("vdd").copy() + print(vdd_pins) + well_by = vdd_pins[1].cy() + well_ll = vector(precharge_well_lx, well_by) + + self.add_rect(layer="nwell", offset=well_ll, height = self.array_inst.by() - well_by, width=precharge_well_rx - precharge_well_lx) - # start = end - vector(0, 0.5 * minwidth) - # end = vector(start.x, array_gnd[1].uy()) diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index 5fd585d1..d473357e 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -175,6 +175,7 @@ class rom_precharge_array(design): self.connect_row_pins(layer=self.strap_layer, pins=array_pins, name=None, round=False) def extend_well(self): + self.well_offset = self.pmos.tap_offset well_y = self.pmos_insts[0].get_pin("vdd").cy() - 0.5 * self.nwell_width well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 4108f7cb..25201ffd 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -78,7 +78,7 @@ class rom_precharge_cell(rom_base_cell): source = self.cell_inst.get_pin("S") tap_y = source.cy() - self.contact_width - 2 * self.active_enclose_contact - self.active_space - + self.tap_offset = abs(tap_y) pos = vector(source.cx(), tap_y ) self.add_via_center(layers=self.active_stack, diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index b50b7fc8..cb4a6768 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -28,6 +28,12 @@ class rom_wordline_driver_array(design): self.cols = cols self.invert_outputs=invert_outputs self.tap_spacing = tap_spacing + + if OPTS.tech_name == "sky130": + self.supply_layer = "m1" + else: + self.supply_layer = "m2" + self.create_netlist() if not OPTS.netlist_only: self.create_layout() @@ -45,8 +51,8 @@ class rom_wordline_driver_array(design): self.place_drivers() self.route_layout() self.route_supplies() + self.place_taps() self.add_boundary() - self.DRC_LVS() def add_pins(self): # inputs to wordline_driver. @@ -60,6 +66,7 @@ class rom_wordline_driver_array(design): def add_modules(self): b = factory.create(module_type="rom_base_cell") + self.tap = factory.create(module_type="rom_poly_tap", add_tap = True) if self.invert_outputs: self.wl_driver = factory.create(module_type="pinv_dec", @@ -67,19 +74,12 @@ class rom_wordline_driver_array(design): height=b.height, add_wells=False) - self.wl_driver_tap = factory.create(module_type="pinv_dec", - size=self.cols, - add_wells=True) else: self.wl_driver = factory.create(module_type="pbuf_dec", size=self.cols, height=b.height, add_wells=False) - self.wl_driver_tap = factory.create(module_type="pbuf_dec", - size=self.cols, - add_wells=True) - print(self.wl_driver.height) - print(self.wl_driver_tap.height) + def route_supplies(self): """ @@ -89,6 +89,8 @@ class rom_wordline_driver_array(design): if layer_props.wordline_driver.vertical_supply: self.route_vertical_pins("vdd", self.wld_inst) self.route_vertical_pins("gnd", self.wld_inst) + self.route_vertical_pins("vdd", self.wld_inst, layer=self.supply_layer) + self.route_vertical_pins("gnd", self.wld_inst, layer=self.supply_layer) else: self.route_vertical_pins("vdd", self.wld_inst, xside="rx",) self.route_vertical_pins("gnd", self.wld_inst, xside="lx",) @@ -96,12 +98,8 @@ class rom_wordline_driver_array(design): def create_drivers(self): self.wld_inst = [] for row in range(self.rows): - if row % self.tap_spacing == 0: - self.wld_inst.append(self.add_inst(name="wld{0}".format(row), - mod=self.wl_driver_tap)) - else: - self.wld_inst.append(self.add_inst(name="wld{0}".format(row), - mod=self.wl_driver)) + self.wld_inst.append(self.add_inst(name="wld{0}".format(row), + mod=self.wl_driver)) self.connect_inst(["in_{0}".format(row), "out_{0}".format(row), "vdd", "gnd"]) @@ -109,13 +107,14 @@ class rom_wordline_driver_array(design): def place_drivers(self): y_offset = 0 for row in range(self.rows): - # These are flipped since we always start with an RBL on the bottom - + if row % self.tap_spacing == 0: + y_offset += self.tap.pitch_offset offset = [0, y_offset] self.wld_inst[row].place(offset=offset) y_offset += self.wld_inst[row].height + self.width = self.wl_driver.width self.height = self.wl_driver.height * self.rows @@ -137,3 +136,46 @@ class rom_wordline_driver_array(design): end=end) self.add_layout_pin_rect_center(text="out_{}".format(row), layer=self.route_layer, offset=end - vector(0, 0.5 * route_width)) + + + def place_taps(self): + + for wl in range(0 , self.rows, self.tap_spacing): + driver = self.wld_inst[wl] + + source_pin1 = driver.get_pins("vdd")[0] + gnd_pin1 = driver.get_pins("gnd")[0] + + left_edge = driver.get_pin("Z").cy() - 0.5 * self.contact_width - self.active_enclose_contact - self.active_space - 0.5 * self.active_contact.width + + contact_pos = vector(source_pin1.cx(), left_edge) + self.place_tap(contact_pos, "n") + + contact_pos = vector( gnd_pin1.cx(), left_edge) + self.place_tap(contact_pos, "p") + + if not self.invert_outputs: + source_pin2 = driver.get_pins("vdd")[1] + gnd_pin2 = driver.get_pins("gnd")[1] + contact_pos = vector(source_pin2.cx(), left_edge) + self.place_tap(contact_pos, "n") + + contact_pos = vector( gnd_pin2.cx(), left_edge) + self.place_tap(contact_pos, "p") + + + def place_tap(self, offset, well_type): + self.add_via_center(layers=self.active_stack, + offset=offset, + implant_type=well_type, + well_type=well_type, + directions="nonpref") + self.add_via_stack_center(offset=offset, + from_layer=self.active_stack[2], + to_layer=self.supply_layer) + if well_type == "p": + pin = "gnd" + else: + pin = "vdd" + self.add_layout_pin_rect_center(text=pin, layer=self.supply_layer, offset=offset) + diff --git a/compiler/tests/05_rom_decoder_test.py b/compiler/tests/05_rom_decoder_test.py index 48f977c8..b2447fb4 100644 --- a/compiler/tests/05_rom_decoder_test.py +++ b/compiler/tests/05_rom_decoder_test.py @@ -25,7 +25,7 @@ class rom_decoder_test(openram_test): debug.info(2, "Testing 2x4 decoder for rom cell") - a = factory.create(module_type="rom_decoder", num_outputs=20, strap_spacing=2, cols=16) + a = factory.create(module_type="rom_decoder", num_outputs=16, strap_spacing=4, cols=16) self.local_check(a) openram.end_openram() From 81bf2d7ae7cf7efcc95eed262fb27ea0e830de5d Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 26 Jan 2023 17:33:47 -0800 Subject: [PATCH 42/98] fixed decode lvs --- compiler/modules/rom_base_array.py | 4 ++-- compiler/modules/rom_decoder.py | 15 ++++++--------- compiler/modules/rom_precharge_array.py | 5 +++-- compiler/modules/rom_wordline_driver_array.py | 12 ++++++++---- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 7c329c67..8341e620 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -120,7 +120,7 @@ class rom_base_array(bitcell_base_array): self.add_pin(bl_name, "OUTPUT") for wl_name in self.get_wordline_names(): self.add_pin(wl_name, "INPUT") - self.add_pin("precharge_gate", "INPUT") + self.add_pin("precharge", "INPUT") self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") @@ -207,7 +207,7 @@ class rom_base_array(bitcell_base_array): # if self.int_bl_list[bl] == prechrg_pins[bl]: # prechrg_pins[bl] = "gnd" - prechrg_pins.append("precharge_gate") + prechrg_pins.append("precharge") prechrg_pins.append("vdd") self.precharge_inst = self.add_inst(name="decode_array_precharge", mod=self.precharge_array) self.connect_inst(prechrg_pins) diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index e1a642fd..c20b05e6 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -245,8 +245,7 @@ class rom_decoder(design): # self.add_segment_center(self.inv_route_layer, addr_bar_middle + vector(0, self.inv_route_width * 0.5), addr_bar_out_pin.center() + vector(0, self.inv_route_width * 0.5), self.inv_route_width) def route_supplies(self): - minwidth = drc["minwidth_{}".format(self.inv_route_layer)] - pitch = drc["{0}_to_{0}".format(self.inv_route_layer)] + self.copy_layout_pin(self.array_inst, "vdd") self.copy_layout_pin(self.wordline_buf_inst, "vdd") self.copy_layout_pin(self.buf_inst, "vdd") @@ -255,9 +254,8 @@ class rom_decoder(design): self.copy_layout_pin(self.wordline_buf_inst, "gnd") self.copy_layout_pin(self.buf_inst, "gnd") - # Extend nwells to connect with eachother - self.extend_wells() + # self.extend_wells() def extend_wells(self): @@ -272,11 +270,10 @@ class rom_decoder(design): self.add_label(text="well_left", layer="nwell", offset=offset) vdd_pins=self.buf_inst.get_pins("vdd").copy() print(vdd_pins) - well_by = vdd_pins[1].cy() - well_ll = vector(precharge_well_lx, well_by) - - self.add_rect(layer="nwell", offset=well_ll, height = self.array_inst.by() - well_by, width=precharge_well_rx - precharge_well_lx) - + well_by = vdd_pins[0].cy() + # well_ll = vector(precharge_well_lx, well_by) + well_ll = vector(self.buf_inst.rx(), well_by) + # self.add_rect(layer="nwell", offset=well_ll, height = self.array_inst.by() - well_by, width=precharge_well_rx - self.buf_inst.rx()) diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index d473357e..7e5a0e2f 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -90,8 +90,9 @@ class rom_precharge_array(design): def add_pins(self): for col in range(self.cols): self.add_pin("pre_bl{0}_out".format(col), "OUTPUT") - self.add_pin("vdd", "POWER") self.add_pin("gate", "INPUT") + self.add_pin("vdd", "POWER") + def create_instances(self): self.array_insts = [] @@ -164,7 +165,7 @@ class rom_precharge_array(design): # self.vdd = self.add_layout_pin_segment_center("vdd", self.supply_layer, start, end) # vdd = [self.pmos_insts[i].get_pin("vdd") for i in range(self.cols)]routeroute_horizon_horizon - self.route_horizontal_pins("vdd", insts=self.pmos_insts) + self.route_horizontal_pins("vdd", insts=self.pmos_insts, layer=self.strap_layer) diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index cb4a6768..f4b6482d 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -86,11 +86,13 @@ class rom_wordline_driver_array(design): Add a pin for each row of vdd/gnd which are must-connects next level up. """ + if layer_props.wordline_driver.vertical_supply: - self.route_vertical_pins("vdd", self.wld_inst) - self.route_vertical_pins("gnd", self.wld_inst) - self.route_vertical_pins("vdd", self.wld_inst, layer=self.supply_layer) - self.route_vertical_pins("gnd", self.wld_inst, layer=self.supply_layer) + print("copied") + # self.route_vertical_pins("vdd", self.wld_inst) + # self.route_vertical_pins("gnd", self.wld_inst) + self.route_vertical_pins("vdd", [self], layer=self.supply_layer) + self.route_vertical_pins("gnd", [self], layer=self.supply_layer) else: self.route_vertical_pins("vdd", self.wld_inst, xside="rx",) self.route_vertical_pins("gnd", self.wld_inst, xside="lx",) @@ -123,6 +125,8 @@ class rom_wordline_driver_array(design): route_width = drc["minwidth_{}".format(self.route_layer)] for row in range(self.rows): inst = self.wld_inst[row] + self.copy_layout_pin(inst, "vdd") + self.copy_layout_pin(inst, "gnd") self.copy_layout_pin(inst, "A", "in_{0}".format(row)) From 736bd51fe101c3901ea426577dac99c6fbfa776d Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Wed, 1 Feb 2023 14:49:59 -0800 Subject: [PATCH 43/98] add top level pins for sim --- compiler/modules/rom_base_array.py | 4 +- compiler/modules/rom_base_bank.py | 147 +++++++++--------- compiler/modules/rom_base_cell.py | 2 +- compiler/modules/rom_column_mux.py | 37 ++--- compiler/modules/rom_column_mux_array.py | 28 ++-- compiler/modules/rom_control_logic.py | 9 +- compiler/modules/rom_decoder.py | 14 +- compiler/modules/rom_precharge_array.py | 2 +- compiler/modules/rom_wordline_driver_array.py | 1 - ...k_test.py => 05_rom_base_bank_1kB_test.py} | 5 +- compiler/tests/05_rom_base_bank_small_test.py | 36 +++++ 11 files changed, 161 insertions(+), 124 deletions(-) rename compiler/tests/{05_rom_base_bank_test.py => 05_rom_base_bank_1kB_test.py} (89%) create mode 100644 compiler/tests/05_rom_base_bank_small_test.py diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 8341e620..b3c72ba9 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -266,7 +266,7 @@ class rom_base_array(bitcell_base_array): self.cell_pos[row, col] = vector(cell_x, cell_y) self.cell_inst[row, col].place(self.cell_pos[row, col]) cell_x += self.zero_cell.width - self.add_label("debug", "li", self.cell_pos[row, col]) + # self.add_label("debug", "li", self.cell_pos[row, col]) self.strap_pos[row, self.column_size] = vector(cell_x, cell_y) @@ -326,7 +326,7 @@ class rom_base_array(bitcell_base_array): def place_precharge(self): - self.precharge_offset = vector(0, - self.precharge_inst.height - self.zero_cell.nmos.end_to_contact - 2 * drc["nwell_enclose_active"]) + self.precharge_offset = vector(0, - self.precharge_inst.height - self.zero_cell.nmos.end_to_contact - 2 * drc["nwell_enclose_active"] - 3 * self.m1_pitch) self.precharge_inst.place(offset=self.precharge_offset) diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index 297af7f1..27299efa 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -2,7 +2,7 @@ from math import ceil, log, sqrt from openram.base import vector from openram.base import design -from openram import OPTS +from openram import OPTS, debug from openram.sram_factory import factory from openram.tech import drc, layer @@ -14,8 +14,8 @@ class rom_base_bank(design): word size is in bytes """ - def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2) -> None: - + def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2): + super().__init__(name=name) self.word_size = word_size * 8 self.read_binary(word_size=word_size, data_file=data_file) @@ -31,7 +31,7 @@ class rom_base_bank(design): self.bitline_layer = "m1" self.wordline_layer = "m2" - super().__init__(name=name) + if "li" in layer: self.route_stack = self.m1_stack else: @@ -39,7 +39,8 @@ class rom_base_bank(design): self.route_layer = self.route_stack[0] self.setup_layout_constants() self.create_netlist() - self.create_layout() + if not OPTS.netlist_only: + self.create_layout() """ Reads a hexadecimal file from a given directory to be used as the data written to the ROM endian is either "big" or "little" @@ -48,10 +49,17 @@ class rom_base_bank(design): """ def read_binary(self, data_file, word_size=2, endian="big"): - + # Read data as hexidecimal text file hex_file = open(data_file, 'r') hex_data = hex_file.read() - bin_data = list("{0:08b}".format(int(hex_data, 16))) + + # Convert from hex into an int + data_int = int(hex_data, 16) + # Then from int into a right aligned, zero padded string + bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4) + + # Then turn the string into a list of ints + bin_data = list(bin_string) bin_data = [int(x) for x in bin_data] # data size in bytes @@ -78,17 +86,20 @@ class rom_base_bank(design): self.data = chunked_data self.cols = bits_per_row self.rows = int(num_words / (self.words_per_row)) + debug.info(1, "Read rom binary: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, num_words, self.cols, self.rows, self.words_per_row)) + # print("hex: {0}, binary: {1}, chunked: {2}".format(hex_data, bin_data, chunked_data)) def create_netlist(self): self.add_modules() - # self.add_pins() + self.add_pins() + - print("Creating ROM bank instances") - self.create_instances() def create_layout(self): + print("Creating ROM bank instances") + self.create_instances() print("Placing ROM bank instances") self.place_instances() @@ -101,13 +112,12 @@ class rom_base_bank(design): print("Routing clock signal") self.route_clock() self.route_array_outputs() - # self.route_supplies() + self.place_top_level_pins() + self.route_supplies() self.height = self.array_inst.height self.width = self.array_inst.width self.add_boundary() - print("Rom bank placement complete") - def setup_layout_constants(self): self.route_layer_width = drc["minwidth_{}".format(self.route_stack[0])] @@ -121,11 +131,11 @@ class rom_base_bank(design): self.add_pin("clk", "INPUT") self.add_pin("CS", "INPUT") - for i in range(self.num_inputs): + for i in range(self.row_bits + self.col_bits): self.add_pin("addr_{}".format(i), "INPUT") out_pins = [] - for j in range(self.rows): + for j in range(self.word_size): out_pins.append("rom_out_{}".format(j)) self.add_pin_list(out_pins, "OUTPUT") @@ -153,14 +163,14 @@ class rom_base_bank(design): strap_spacing=self.strap_spacing, route_layer=self.route_layer, cols=self.cols) - - - + self.column_mux = factory.create(module_type="rom_column_mux_array", columns=self.cols, word_size=self.word_size, - bitline_layer=self.interconnect_layer) + tap_spacing=self.strap_spacing, + bitline_layer=self.interconnect_layer, + input_layer=self.bitline_layer) self.column_decode = factory.create(module_name="rom_column_decode", module_type="rom_decoder", @@ -173,55 +183,37 @@ class rom_base_bank(design): self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.rows + self.cols + self.words_per_row) * 0.5, clk_fanout=(self.col_bits + self.row_bits) * 2, - height=self.column_decode.height) + height=self.column_decode.height ) - print("Col decode height of {}".format(self.column_decode.height)) def create_instances(self): gnd = ["gnd"] vdd = ["vdd"] prechrg = ["precharge"] clk = ["clk_int"] - array_pins = [] - decode_pins = [] - - for bl in range(self.cols): - name = "bl_{}".format(bl) - array_pins.append(name) - for wl in range(self.rows): - name = "wl_{}".format(wl) - array_pins.append(wl) - - array_pins.append("precharge") - array_pins.append("vdd") - array_pins.append("gnd") - - - for addr in range(self.row_bits): - name = "row_addr_{}".format(addr) - decode_pins.append(name) - for wl in range(self.rows): - name = "wl_{}".format(wl) - decode_pins.append(name) - - decode_pins.append("precharge") - decode_pins.append("clk_int") - decode_pins.append("vdd") - decode_pins.append("gnd") - bitlines = ["bl_{}".format(bl) for bl in range(self.cols)] - select_lines = ["word_sel_{}".format(word) for word in range(self.words_per_row)] - bitline_out = ["rom_out_{}".format(bl) for bl in range(self.word_size)] - addr_lsb = ["col_addr_{}".format(addr) for addr in range(self.col_bits)] - col_mux_pins = bitlines + select_lines + bitline_out + gnd + wordlines = ["wl_{}".format(wl) for wl in range(self.rows)] + addr_msb = ["addr_{}".format(addr + self.col_bits) for addr in range(self.row_bits)] + addr_lsb = ["addr_{}".format(addr) for addr in range(self.col_bits)] + + select_lines = ["word_sel_{}".format(word) for word in range(self.words_per_row)] + outputs = ["rom_out_{}".format(bl) for bl in range(self.word_size)] + + + array_pins = bitlines + wordlines + prechrg + vdd + gnd + + row_decode_pins = addr_msb + wordlines + prechrg + clk + vdd + gnd col_decode_pins = addr_lsb + select_lines + prechrg + clk + vdd + gnd + + col_mux_pins = bitlines + select_lines + outputs + gnd + self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array) self.connect_inst(array_pins) self.decode_inst = self.add_inst(name="rom_row_decoder", mod=self.decode_array) - self.connect_inst(decode_pins) + self.connect_inst(row_decode_pins) self.control_inst = self.add_inst(name="rom_control", mod=self.control_logic) self.connect_inst(["clk", "CS", "precharge", "clk_int", "vdd", "gnd"]) @@ -269,7 +261,7 @@ class rom_base_bank(design): self.col_decode_inst.place(offset=self.col_decode_offset) def place_col_mux(self): - mux_y_offset = self.array_inst.by() - self.mux_inst.height - self.route_layer_pitch + mux_y_offset = self.array_inst.by() - self.mux_inst.height - 5 * self.route_layer_pitch mux_x_offset = self.array_inst.get_pin("bl_0_0").cx() - self.mux_inst.get_pin("bl_0").cx() self.mux_offset = vector(mux_x_offset, mux_y_offset) @@ -298,7 +290,7 @@ class rom_base_bank(design): col_decode_pins = [self.col_decode_inst.get_pin("wl_{}".format(wl)) for wl in range(self.words_per_row)] sel_pins = [self.mux_inst.get_pin("sel_{}".format(wl)) for wl in range(self.words_per_row)] sel_pins.extend(col_decode_pins) - self.connect_row_pins(self.array.bitline_layer, sel_pins, round=True) + self.connect_row_pins(self.wordline_layer, sel_pins, round=True) @@ -391,34 +383,49 @@ class rom_base_bank(design): self.add_path(self.array.bitline_layer, [bl_out, bl_mux]) + def place_top_level_pins(self): + self.copy_layout_pin(self.control_inst, "CS", "CS") + for i in range(self.word_size): + self.copy_layout_pin(self.mux_inst, "bl_out_{}".format(i), "rom_out_{}".format(i)) + for lsb in range(self.col_bits): + name = "addr_{}".format(lsb) + self.copy_layout_pin(self.col_decode_inst, "A{}".format(lsb), name) + + for msb in range(self.col_bits, self.row_bits + self.col_bits): + name = "addr_{}".format(msb) + pin_num = msb - self.col_bits + self.copy_layout_pin(self.decode_inst, "A{}".format(pin_num), name) + + def route_supplies(self): for inst in self.insts: - self.copy_layout_pin(inst, "vdd") - self.copy_layout_pin(inst, "gnd") - gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0) + if not inst.mod.name.__contains__("contact"): + self.copy_layout_pin(inst, "vdd") + self.copy_layout_pin(inst, "gnd") + # gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0) - decode_gnd = self.decode_inst.get_pin("gnd") - decode_vdd = self.decode_inst.get_pin("vdd") - array_vdd = self.array_inst.get_pin("vdd") + # decode_gnd = self.decode_inst.get_pin("gnd") + # decode_vdd = self.decode_inst.get_pin("vdd") + # array_vdd = self.array_inst.get_pin("vdd") - # self.add_segment_center("m1", gnd_start, decode_gnd.center()) + # # self.add_segment_center("m1", gnd_start, decode_gnd.center()) - self.add_power_pin("gnd", decode_vdd.center()) - self.add_power_pin("vdd", decode_gnd.center()) + # self.add_power_pin("gnd", decode_vdd.center()) + # self.add_power_pin("vdd", decode_gnd.center()) - vdd_start = vector(array_vdd.lx() + 0.5 * self.via1_space, array_vdd.cy()) - end = vector(decode_vdd.lx(), vdd_start.y) + # vdd_start = vector(array_vdd.lx() + 0.5 * self.via1_space, array_vdd.cy()) + # end = vector(decode_vdd.lx(), vdd_start.y) - self.add_segment_center(self.interconnect_layer, vdd_start, end) - self.add_via_stack_center(vdd_start, "m1", self.interconnect_layer) + # self.add_segment_center(self.interconnect_layer, vdd_start, end) + # self.add_via_stack_center(vdd_start, "m1", self.interconnect_layer) - vdd_start = vector(decode_vdd.cx(), vdd_start.y) + # vdd_start = vector(decode_vdd.cx(), vdd_start.y) - self.add_segment_center(self.interconnect_layer, vdd_start, decode_vdd.center()) + # self.add_segment_center(self.interconnect_layer, vdd_start, decode_vdd.center()) diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index c7297ec5..1816475c 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -80,7 +80,7 @@ class rom_base_cell(design): # height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) # make the cells square so the pitch of wordlines will match bitlines - print("height: {0} width: {1}".format(height, width)) + # print("height: {0} width: {1}".format(height, width)) if width > height: self.width = width self.height = width diff --git a/compiler/modules/rom_column_mux.py b/compiler/modules/rom_column_mux.py index 4364d3e2..ad776ddf 100644 --- a/compiler/modules/rom_column_mux.py +++ b/compiler/modules/rom_column_mux.py @@ -57,19 +57,13 @@ class rom_column_mux(pgate): self.place_ptx() - # cell = factory.create(module_type=OPTS.bitcell) - # if(cell_props.use_strap == True and OPTS.num_ports == 1): - # strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version) - # precharge_width = cell.width + strap.width - # else: - # precharge_width = cell.width self.width = self.bitcell.width self.height = self.nmos_lower.uy() + self.pin_height self.connect_poly() self.add_bitline_pins() self.connect_bitlines() - # self.add_pn_wells() + self.add_pn_wells() def add_ptx(self): self.bitcell = factory.create(module_type="rom_base_cell") @@ -107,7 +101,7 @@ class rom_column_mux(pgate): def place_ptx(self): - """ Create the two pass gate NMOS transistors to switch the bitlines""" + """ Create the pass gate NMOS transistor to switch the bitline """ # Space it in the center nmos_lower_position = self.nmos.active_offset.scale(0, 1) \ @@ -148,7 +142,9 @@ class rom_column_mux(pgate): nmos_lower_s_pin = self.nmos_lower.get_pin("S") nmos_lower_d_pin = self.nmos_lower.get_pin("D") - + self.add_via_stack_center(from_layer=nmos_lower_s_pin.layer, + to_layer=self.input_layer, + offset=nmos_lower_s_pin.center()) self.add_via_stack_center(from_layer=nmos_lower_d_pin.layer, to_layer=self.output_layer, @@ -160,14 +156,14 @@ class rom_column_mux(pgate): + nmos_lower_s_pin.uc().scale(0, 0.5) mid2 = bl_pin.bc().scale(0, 0.4) \ + nmos_lower_s_pin.uc().scale(1, 0.5) - self.add_path(self.col_mux_stack[2], + self.add_path(self.input_layer, [bl_pin.bc(), mid1, mid2, nmos_lower_s_pin.center()]) # halfway up, move over mid1 = bl_out_pin.uc().scale(1, 0.4) \ + nmos_lower_d_pin.bc().scale(0, 0.4) mid2 = bl_out_pin.uc().scale(0, 0.4) \ + nmos_lower_d_pin.bc().scale(1, 0.4) - self.add_path(self.col_mux_stack[0], + self.add_path(self.output_layer, [bl_out_pin.uc(), mid1, mid2, nmos_lower_d_pin.center()]) @@ -197,7 +193,7 @@ class rom_column_mux(pgate): # rbc_width = self.bitcell.width # Add it to the right, aligned in between the two tx active_pos = vector(self.bitcell.width, - self.nmos_upper.by() - 0.5 * self.poly_space) + self.nmos_lower.uy() + self.active_contact.height + self.active_space) self.add_via_center(layers=self.active_stack, offset=active_pos, @@ -205,16 +201,17 @@ class rom_column_mux(pgate): 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) + self.add_via_stack_center(from_layer=self.active_stack[2], + to_layer=self.supply_stack[0], + offset=active_pos) self.add_layout_pin_rect_center(text="gnd", - layer="m1", + layer=self.supply_stack[0], offset=active_pos) # Add well enclosure over all the tx and contact - if "pwell" in layer: - self.add_rect(layer="pwell", - offset=vector(0, 0), - width=rbc_width, - height=self.height) + # if "pwell" in layer: + # self.add_rect(layer="pwell", + # offset=vector(0, 0), + # width=rbc_width, + # height=self.height) diff --git a/compiler/modules/rom_column_mux_array.py b/compiler/modules/rom_column_mux_array.py index 1a119044..fea8f505 100644 --- a/compiler/modules/rom_column_mux_array.py +++ b/compiler/modules/rom_column_mux_array.py @@ -20,7 +20,7 @@ class rom_column_mux_array(design): Array of column mux to read the bitlines from ROM, based on the RAM column mux """ - def __init__(self, name, columns, word_size, input_layer="m2", bitline_layer="m1", sel_layer="m2"): + def __init__(self, name, columns, word_size, tap_spacing=4, input_layer="m2", bitline_layer="m1", sel_layer="m2"): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} word_size: {1} ".format(columns, word_size)) @@ -29,6 +29,7 @@ class rom_column_mux_array(design): self.word_size = word_size self.words_per_row = int(self.columns / self.word_size) self.input_layer = input_layer + self.tap_spacing = tap_spacing # self.sel_layer = layer_props.column_mux_array.select_layer self.sel_layer = sel_layer @@ -44,14 +45,6 @@ class rom_column_mux_array(design): if not OPTS.netlist_only: self.create_layout() - def get_bl_name(self): - bl_name = self.mux.get_bl_names() - return bl_name - - def get_br_name(self, port=0): - br_name = self.mux.get_br_names() - return br_name - def create_netlist(self): self.add_modules() self.add_pins() @@ -61,12 +54,14 @@ class rom_column_mux_array(design): 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.add_layout_pins() if "pwell" in layer: self.add_enclosure(self.mux_inst, "pwell") + self.add_boundary() self.DRC_LVS() @@ -80,8 +75,8 @@ class rom_column_mux_array(design): self.add_pin("gnd") def add_modules(self): - self.mux = factory.create(module_type="rom_column_mux") - + self.mux = factory.create(module_type="rom_column_mux", input_layer=self.input_layer, output_layer=self.bitline_layer) + self.tap = factory.create(module_type="rom_poly_tap", add_tap=True) self.cell = factory.create(module_type="rom_base_cell") def setup_layout_constants(self): @@ -145,8 +140,12 @@ class rom_column_mux_array(design): def add_horizontal_input_rail(self): """ Create address input rails below the mux transistors """ + tap_offset = 0 for j in range(self.words_per_row): - offset = vector(0, self.route_height + (j - self.words_per_row) * self.cell.width) + if j % self.tap_spacing == 0 and j != 0: + tap_offset += self.tap.pitch_offset + offset = vector(0, self.route_height + tap_offset + (j - self.words_per_row) * self.cell.width) + self.add_layout_pin(text="sel_{}".format(j), layer=self.sel_layer, offset=offset, @@ -208,7 +207,10 @@ class rom_column_mux_array(design): directions=self.via_directions) - + def add_taps(self): + pass + + def graph_exclude_columns(self, column_include_num): """ Excludes all columns muxes unrelated to the target bit being simulated. diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index 60410ab9..b5ca0426 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -19,11 +19,9 @@ class rom_control_logic(design): self.height = height if self.height is not None: - print("got height of {}".format(self.height)) - self.driver_height = 0.6 * self.height - self.gate_height = 0.2 * self.height + self.driver_height = 0.5 * self.height + self.gate_height = 0.25 * self.height else: - print("got none height") self.gate_height = 20 * self.m1_pitch self.driver_height = self.gate_height @@ -98,12 +96,11 @@ class rom_control_logic(design): def route_insts(self): route_width = drc["minwidth_{}".format(self.route_stack[2])] - self.copy_layout_pin(self.buf_inst, "A", "clk_in") self.copy_layout_pin(self.buf_inst, "Zb", "clkb_out") self.copy_layout_pin(self.buf_inst, "Z", "clk_out") self.copy_layout_pin(self.driver_inst, "Z", "prechrg") - self.copy_layout_pin(self.nand_inst, "B", "CS") + self.copy_layout_pin(self.nand_inst, "A", "CS") self.copy_layout_pin(self.buf_inst, "gnd") self.copy_layout_pin(self.driver_inst, "vdd") self.copy_layout_pin(self.buf_inst, "vdd") diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index c20b05e6..10d55f85 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -112,17 +112,17 @@ class rom_decoder(design): cols=self.num_inputs) - self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), \ - rows=self.num_outputs, \ - cols=self.cols, + self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), + rows=self.num_outputs, + cols=ceil(self.cols * 0.5), invert_outputs=self.invert_outputs, tap_spacing=self.strap_spacing) - self.array_mod = factory.create(module_type="rom_base_array", \ - module_name="{}_array".format(self.name), \ - cols=self.num_outputs, \ - rows=2 * self.num_inputs, \ + self.array_mod = factory.create(module_type="rom_base_array", + module_name="{}_array".format(self.name), + cols=self.num_outputs, + rows=2 * self.num_inputs, bitmap=self.decode_map, strap_spacing = self.strap_spacing, bitline_layer=self.output_layer, diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index 7e5a0e2f..9cb262e6 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -109,7 +109,7 @@ class rom_precharge_array(design): def create_precharge_tx(self, col): - name = "Xpmos_c{0}".format(col) + name = "pmos_c{0}".format(col) pmos = self.add_inst(name=name, mod=self.pmos) self.array_insts.append(pmos) self.pmos_insts.append(pmos) diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index f4b6482d..4d3fde06 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -88,7 +88,6 @@ class rom_wordline_driver_array(design): """ if layer_props.wordline_driver.vertical_supply: - print("copied") # self.route_vertical_pins("vdd", self.wld_inst) # self.route_vertical_pins("gnd", self.wld_inst) self.route_vertical_pins("vdd", [self], layer=self.supply_layer) diff --git a/compiler/tests/05_rom_base_bank_test.py b/compiler/tests/05_rom_base_bank_1kB_test.py similarity index 89% rename from compiler/tests/05_rom_base_bank_test.py rename to compiler/tests/05_rom_base_bank_1kB_test.py index f8c578dc..8f742f94 100644 --- a/compiler/tests/05_rom_base_bank_test.py +++ b/compiler/tests/05_rom_base_bank_1kB_test.py @@ -13,7 +13,7 @@ import sys, os import openram from openram import OPTS from openram.sram_factory import factory -import debug +from openram import debug class rom_bank_test(openram_test): @@ -21,8 +21,7 @@ class rom_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) openram.init_openram(config_file, is_unit_test=True) - - debug.info(2, "Testing 4x4 array for rom cell") + debug.info(1, "Testing 1kB rom cell") a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_1kB", word_size=1) diff --git a/compiler/tests/05_rom_base_bank_small_test.py b/compiler/tests/05_rom_base_bank_small_test.py new file mode 100644 index 00000000..85b1ce76 --- /dev/null +++ b/compiler/tests/05_rom_base_bank_small_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 + +import openram +from openram import OPTS +from openram.sram_factory import factory +from openram import debug + + +class rom_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + debug.info(1, "Testing 32 byte rom cell") + + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_64B", word_size=1) + + self.local_check(a) + openram.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) \ No newline at end of file From a64361b9d1b807b974145dd1d37b6a2e3b1252a7 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Wed, 1 Feb 2023 21:47:45 -0800 Subject: [PATCH 44/98] testing data for rom tests --- technology/rom_data_64B | 1 + 1 file changed, 1 insertion(+) create mode 100644 technology/rom_data_64B diff --git a/technology/rom_data_64B b/technology/rom_data_64B new file mode 100644 index 00000000..7e216561 --- /dev/null +++ b/technology/rom_data_64B @@ -0,0 +1 @@ +73630b5c3105aeda99f7892feeea277f1fe45fbc1909bce7840e37ee186edefe73630b5c3105aeda99f7892feeea277f1fe45fbc1909bce7840e37ee186edefe \ No newline at end of file From 6981cfa58bf972d209c8515675c51b30cdf37ac8 Mon Sep 17 00:00:00 2001 From: Jesse Cirimelli-Low Date: Wed, 1 Feb 2023 23:08:47 -0800 Subject: [PATCH 45/98] add example of writing out simulation netlist --- compiler/tests/05_rom_base_bank_small_test.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/tests/05_rom_base_bank_small_test.py b/compiler/tests/05_rom_base_bank_small_test.py index 85b1ce76..69128d83 100644 --- a/compiler/tests/05_rom_base_bank_small_test.py +++ b/compiler/tests/05_rom_base_bank_small_test.py @@ -26,6 +26,8 @@ class rom_bank_test(openram_test): a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_64B", word_size=1) self.local_check(a) + print('wriitng file') + a.sp_write(OPTS.openram_temp + 'simulation_file.sp') openram.end_openram() # run the test from the command line @@ -33,4 +35,4 @@ if __name__ == "__main__": (OPTS, args) = openram.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file + unittest.main(testRunner=debugTestRunner()) From 764601a721da2bc62d5f1342fd8b84afcff418a8 Mon Sep 17 00:00:00 2001 From: SWalker Date: Thu, 2 Feb 2023 12:46:07 -0800 Subject: [PATCH 46/98] added binning to precharge pmos --- compiler/modules/rom_precharge_cell.py | 4 +++- compiler/tests/05_rom_array_test.py | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 25201ffd..c7627bf7 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -7,6 +7,7 @@ # from .rom_base_cell import rom_base_cell +from .pgate import pgate from openram.base import vector from openram import OPTS from openram.sram_factory import factory @@ -30,10 +31,11 @@ class rom_precharge_cell(rom_base_cell): def add_modules(self): - + width = pgate.nearest_bin("pmos", drc["minwidth_tx"]) self.pmos = factory.create(module_type="ptx", module_name="pre_pmos_mod", tx_type="pmos", + width=width, add_source_contact=self.supply_layer, add_drain_contact=self.bitline_layer ) diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/05_rom_array_test.py index a7d70abe..8854f667 100644 --- a/compiler/tests/05_rom_array_test.py +++ b/compiler/tests/05_rom_array_test.py @@ -29,6 +29,8 @@ class rom_array_test(openram_test): a = factory.create(module_type="rom_base_array", cols=9, rows=8, bitmap=data, strap_spacing=4, pitch_match=True) self.local_check(a) + a.sp_write(OPTS.openram_temp + 'simulation_file.sp') + openram.end_openram() # run the test from the command line From 9cefe5da7c27501294263c8028d5788b283ffc8e Mon Sep 17 00:00:00 2001 From: SWalker Date: Thu, 2 Feb 2023 23:39:08 -0800 Subject: [PATCH 47/98] added unrouted output buffers --- compiler/modules/rom_base_bank.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index 27299efa..34119b50 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -184,6 +184,10 @@ class rom_base_bank(design): num_outputs=(self.rows + self.cols + self.words_per_row) * 0.5, clk_fanout=(self.col_bits + self.row_bits) * 2, height=self.column_decode.height ) + + self.output_buffer = factory.create(module_type="rom_wordline_driver_array", + rows=self.word_size, + cols=4) def create_instances(self): @@ -199,6 +203,8 @@ class rom_base_bank(design): addr_lsb = ["addr_{}".format(addr) for addr in range(self.col_bits)] select_lines = ["word_sel_{}".format(word) for word in range(self.words_per_row)] + + pre_buf_outputs = ["rom_out_prebuf_{}".format(bit) for bit in range(self.word_size)] outputs = ["rom_out_{}".format(bl) for bl in range(self.word_size)] @@ -207,7 +213,9 @@ class rom_base_bank(design): row_decode_pins = addr_msb + wordlines + prechrg + clk + vdd + gnd col_decode_pins = addr_lsb + select_lines + prechrg + clk + vdd + gnd - col_mux_pins = bitlines + select_lines + outputs + gnd + col_mux_pins = bitlines + select_lines + pre_buf_outputs + gnd + + output_buffer_pins = pre_buf_outputs + outputs + vdd + gnd self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array) self.connect_inst(array_pins) @@ -224,6 +232,9 @@ class rom_base_bank(design): self.col_decode_inst = self.add_inst(name="rom_column_decoder", mod=self.column_decode) self.connect_inst(col_decode_pins) + self.output_buf_inst = self.add_inst(name="rom_output_buffer", mod=self.output_buffer) + self.connect_inst(output_buffer_pins) + def place_instances(self): @@ -232,6 +243,7 @@ class rom_base_bank(design): self.place_col_mux() self.place_col_decoder() self.place_control_logic() + self.place_output_buffer() def place_row_decoder(self): @@ -267,6 +279,11 @@ class rom_base_bank(design): self.mux_offset = vector(mux_x_offset, mux_y_offset) self.mux_inst.place(offset=self.mux_offset) + def place_output_buffer(self): + output_x = self.col_decode_inst.rx() + output_y = 0 + self.output_buf_offset = vector(output_x, output_y) + self.output_buf_inst.place(offset=self.output_buf_offset, rotate=90) # def create_wl_bus(self): # bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) From f847721500005e18f13bb84d2a6e2b40144a145a Mon Sep 17 00:00:00 2001 From: SWalker Date: Fri, 3 Feb 2023 17:12:36 -0800 Subject: [PATCH 48/98] changes to control logic, invert polarity of precharge --- compiler/modules/rom_control_logic.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index b5ca0426..caad772a 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -106,19 +106,19 @@ class rom_control_logic(design): self.copy_layout_pin(self.buf_inst, "vdd") # self.copy_layout_pin(self.buf_inst, "vdd") - clk_bar = self.buf_inst.get_pin("Zb") + clk = self.buf_inst.get_pin("Z") nand_B = self.nand_inst.get_pin("B") # Connect buffered clock bar to nand input - mid = vector(clk_bar.lx() - route_width - 2 * self.m1_space) - self.add_path(self.route_stack[2], [clk_bar.center(), mid, nand_B.center()]) + mid = vector(clk.lx() - route_width - 2 * self.m1_space) + self.add_path(self.route_stack[2], [clk.center(), mid, nand_B.center()]) - self.add_via_stack_center(from_layer=clk_bar.layer, + self.add_via_stack_center(from_layer=clk.layer, to_layer=self.route_stack[2], - offset=clk_bar.center()) + offset=clk.center()) self.add_via_stack_center(from_layer=nand_B.layer, to_layer=self.route_stack[2], offset=nand_B.center()) From 89c7d50bd1569974836918237b026b0371f054cc Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Fri, 3 Feb 2023 17:21:35 -0800 Subject: [PATCH 49/98] added row of nmos to end of array for precharge --- compiler/modules/rom_base_array.py | 49 ++++++++++++++++--------- compiler/modules/rom_base_bank.py | 38 ++++++++++++++++--- compiler/modules/rom_base_cell.py | 4 +- compiler/modules/rom_control_logic.py | 2 +- compiler/modules/rom_poly_tap.py | 24 +++++++----- compiler/modules/rom_precharge_array.py | 26 ++++++++++--- compiler/modules/rom_precharge_cell.py | 2 + 7 files changed, 105 insertions(+), 40 deletions(-) diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index b3c72ba9..4e228660 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -65,13 +65,6 @@ class rom_base_array(bitcell_base_array): - - - - - - - def add_boundary(self): ll = self.find_lowest_coords() bottom_offset = - self.zero_cell.nmos.end_to_contact + self.precharge_inst.offset.y @@ -134,7 +127,7 @@ class rom_base_array(bitcell_base_array): #list of current bitline interconnect nets, starts as the same as the bitline list and is updated when new insts of cells are added self.int_bl_list = self.bitline_names[0].copy() #When rotated correctly rows are word lines - for row in range(self.row_size): + for row in range(self.row_size + 1): row_list = [] # for each new strap placed, offset the column index refrenced to get correct bit in the data array @@ -153,6 +146,7 @@ class rom_base_array(bitcell_base_array): row_list.append(new_inst) + name = "tap_r{0}_c{1}".format(row, self.array_col_size) new_tap = self.add_inst(name=name, mod=self.poly_tap) self.tap_inst[row, self.column_size] = new_tap @@ -160,6 +154,9 @@ class rom_base_array(bitcell_base_array): self.connect_inst([]) self.cell_list.append(row_list) + + + def create_poly_tap(self, row, col): @@ -173,13 +170,12 @@ class rom_base_array(bitcell_base_array): def create_cell(self, row, col): name = "bit_r{0}_c{1}".format(row, col) - - # when col = 0, bl_h is connected to vdd, otherwise connect to previous bl connection + # when col = 0, bl_h is connected to precharge, otherwise connect to previous bl connection # when col = col_size - 1 connected column_sizeto gnd otherwise create new bl connection - if row == self.row_size - 1 or self.get_next_cell_in_bl(row, col) == -1: + if row == self.row_size : bl_l = self.int_bl_list[col] - bl_h = "gnd" + bl_h = "gnd" else: bl_l = self.int_bl_list[col] @@ -187,8 +183,12 @@ class rom_base_array(bitcell_base_array): self.int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) bl_h = self.int_bl_list[col] + # Final row of dummy nmos that contains only 1s, acts to prevent shorting bl to ground when precharging - if self.data[row][col] == 1: + if row == self.row_size: + new_inst = self.add_inst(name=name, mod=self.one_cell) + self.connect_inst([bl_h, bl_l, "precharge", "gnd"]) + elif self.data[row][col] == 1: new_inst = self.add_inst(name=name, mod=self.one_cell) self.connect_inst([bl_h, bl_l, self.wordline_names[0][row], "gnd"]) else: @@ -228,7 +228,7 @@ class rom_base_array(bitcell_base_array): pitch = drc["{0}_to_{0}".format(self.wordline_layer)] for i in range(self.column_size): - drain = self.cell_list[self.row_size - 1][i].get_pin("D") + drain = self.cell_list[self.row_size][i].get_pin("D") gnd_pos = drain.center() + vector(0, pitch + via_width + self.route_pitch) self.add_layout_pin_rect_center(text="gnd", layer=self.bitline_layer, offset=gnd_pos) @@ -244,11 +244,10 @@ class rom_base_array(bitcell_base_array): self.cell_pos = {} self.strap_pos = {} # rows are wordlines - col_offset = 0 pitch_offset = 0 - for row in range(self.row_size): + for row in range(self.row_size + 1): - if row % self.tap_spacing == 0 and self.pitch_match: + if row % self.tap_spacing == 0 and self.pitch_match and row != self.row_size: pitch_offset += self.active_contact.width + self.active_space cell_y = row * (self.zero_cell.height) + pitch_offset @@ -376,6 +375,22 @@ class rom_base_array(bitcell_base_array): bl_end = vector(bl_start.x, pre_out_pin.cy()) self.add_segment_center(self.bitline_layer, bl_start, bl_end) + + upper_precharge = self.precharge_inst.get_pin("precharge_r") + lower_precharge = self.tap_inst[self.row_size, self.column_size ].get_pin("poly_tap") + + if self.pitch_match: + wire_offset = 2 * self.m1_pitch + else: + wire_offset = 3 * self.m1_pitch + start = upper_precharge.center() + end = lower_precharge.center() + mid1 = start + vector(wire_offset, 0) + mid2 = end + vector(wire_offset, 0) + + self.add_path(layer="m1", coordinates=[start, mid1, mid2, end]) + + def connect_taps(self): array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))] diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index 34119b50..27fa40f4 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -114,6 +114,7 @@ class rom_base_bank(design): self.route_array_outputs() self.place_top_level_pins() self.route_supplies() + self.route_output_buffers() self.height = self.array_inst.height self.width = self.array_inst.width self.add_boundary() @@ -185,7 +186,8 @@ class rom_base_bank(design): clk_fanout=(self.col_bits + self.row_bits) * 2, height=self.column_decode.height ) - self.output_buffer = factory.create(module_type="rom_wordline_driver_array", + self.output_buffer = factory.create(module_type="rom_wordline_driver_array", + module_name="rom_output_buffer", rows=self.word_size, cols=4) @@ -280,10 +282,10 @@ class rom_base_bank(design): self.mux_inst.place(offset=self.mux_offset) def place_output_buffer(self): - output_x = self.col_decode_inst.rx() - output_y = 0 + output_x = self.col_decode_inst.rx() + self.output_buf_inst.height + output_y = self.col_decode_inst.by() + self.output_buf_inst.width self.output_buf_offset = vector(output_x, output_y) - self.output_buf_inst.place(offset=self.output_buf_offset, rotate=90) + self.output_buf_inst.place(offset=self.output_buf_offset, rotate=270) # def create_wl_bus(self): # bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) @@ -396,14 +398,38 @@ class rom_base_bank(design): def route_array_outputs(self): for i in range(self.cols): bl_out = self.array_inst.get_pin("bl_0_{}".format(i)).center() + bl_mux = self.mux_inst.get_pin("bl_{}".format(i)).center() self.add_path(self.array.bitline_layer, [bl_out, bl_mux]) + + def route_output_buffers(self): + mux = self.mux_inst + buf = self.output_buf_inst + route_nets = [ [mux.get_pin("bl_out_{}".format(bit)), buf.get_pin("in_{}".format(bit))] for bit in range(self.word_size)] + + channel_ll = vector( route_nets[0][0].cx(), route_nets[0][1].cy() + self.m1_pitch * 3) + self.create_horizontal_channel_route(netlist=route_nets, offset=channel_ll, layer_stack=self.m1_stack) + # for bit in range(self.word_size): + # mux_pin = self.mux_inst.get_pin("bl_out_{}".format(bit)) + # buf_pin = self.output_buf_inst.get_pin("in_{}".format(bit)) + # mux_out = vector(mux_pin.cx(), mux_pin.by()) + # buf_in = buf_pin.center() + + # mid1 = vector(mux_out.x, buf_in.y + bit * self.m2_pitch) + # mid2 = vector(buf_in.x, mid1.y) + # print("start: {0}, mid: {1}, stop: {2}".format(mux_out, mid1, buf_in)) + # self.add_path(layer="m2", coordinates=[mux_out, mid1, mid2, buf_in]) + + + def place_top_level_pins(self): - self.copy_layout_pin(self.control_inst, "CS", "CS") + self.copy_layout_pin(self.control_inst, "CS") + self.copy_layout_pin(self.control_inst, "clk_in", "clk") + for i in range(self.word_size): - self.copy_layout_pin(self.mux_inst, "bl_out_{}".format(i), "rom_out_{}".format(i)) + self.copy_layout_pin(self.output_buf_inst, "out_{}".format(i), "rom_out_{}".format(i)) for lsb in range(self.col_bits): name = "addr_{}".format(lsb) self.copy_layout_pin(self.col_decode_inst, "A{}".format(lsb), name) diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index 1816475c..3b2aac7d 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -123,8 +123,8 @@ class rom_base_cell(design): def place_tx(self): - - tx_offset = vector(self.poly_extend_active + self.cell_inst.height + (self.poly_size) ,- 0.5 * self.contact_width - self.active_enclose_contact) + # sizing_offset = self.cell_inst.height - drc["minwidth_tx"] + tx_offset = vector(self.poly_extend_active + self.cell_inst.height + self.poly_size,- 0.5 * self.contact_width - self.active_enclose_contact) # add rect of poly to account for offset from drc spacing # self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.poly_width) diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index caad772a..0668bd19 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -81,7 +81,7 @@ class rom_control_logic(design): self.connect_inst(["clk_in", "clk_bar", "clk_out", "vdd", "gnd"]) self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod) - self.connect_inst(["CS", "clk_bar", "pre_drive", "vdd", "gnd"]) + self.connect_inst(["CS", "clk_out", "pre_drive", "vdd", "gnd"]) self.driver_inst = self.add_inst(name="driver_inst", mod=self.driver_mod) self.connect_inst(["pre_drive", "prechrg", "vdd", "gnd"]) diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index 31acee5a..d5731d93 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -25,21 +25,23 @@ class rom_poly_tap(design): def create_netlist(self): #for layout constants - if self.tx_type == "nmos": - self.dummy = factory.create(module_type="rom_base_cell") - else: - self.dummy = factory.create(module_type="rom_precharge_cell") + self.dummy = factory.create(module_type="rom_base_cell") + + # if self.tx_type == "nmos": + # self.dummy = factory.create(module_type="rom_base_cell") + # else: + # self.dummy = factory.create(module_type="rom_precharge_cell") self.pmos = factory.create(module_type="ptx", tx_type="pmos") def create_layout(self): self.place_via() - + self.add_boundary() if self.add_tap: self.place_active_tap() self.extend_poly() - self.add_boundary() + # if self.length != 0: # self.place_strap() @@ -94,9 +96,13 @@ class rom_poly_tap(design): # self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) def extend_poly(self): - - self.add_segment_center("poly", self.via.center(), vector(self.via.cx() + self.pitch_offset, self.via.cy())) - self.add_segment_center("poly", self.via.center(), vector(0, self.via.cy())) + y_offset = 0 + if self.tx_type == "pmos": + y_offset = -self.height + start = self.via.center() + vector(0, y_offset) + + self.add_segment_center("poly", start, vector(self.via.cx() + self.pitch_offset, self.via.cy() + y_offset)) + self.add_segment_center("poly", start, vector(0, self.via.cy() + y_offset)) diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index 9cb262e6..e3de7ed4 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -126,17 +126,16 @@ class rom_precharge_array(design): self.add_label("ZERO", self.route_layer) self.array_pos = [] - strap_num = 1 + strap_num = 0 cell_y = 0 - # columns are bit lines4 + # columns are bit lines cell_x = 0 - self.tap_insts[0].place(vector(cell_x, cell_y)) - + for col in range(self.cols): if col % self.strap_spacing == 0: - self.tap_insts[strap_num].place(vector(cell_x, cell_y)) + self.tap_insts[strap_num].place(vector(cell_x, cell_y + self.poly_tap.height)) strap_num += 1 if self.tap_direction == "col": @@ -151,10 +150,14 @@ class rom_precharge_array(design): self.pmos_insts[col].place(vector(cell_x, cell_y)) self.add_label("debug", "li", vector(cell_x, cell_y)) cell_x += self.pmos.width + print(self.tap_insts) + + self.tap_insts[strap_num].place(vector(cell_x, cell_y + self.poly_tap.height)) def create_layout_pins(self): self.copy_layout_pin(self.tap_insts[0], "poly_tap", "gate") + self.copy_layout_pin(self.tap_insts[-1], "poly_tap", "precharge_r") for col in range(self.cols): source_pin = self.pmos_insts[col].get_pin("D") bl = "pre_bl{0}_out".format(col) @@ -175,6 +178,19 @@ class rom_precharge_array(design): self.connect_row_pins(layer=self.strap_layer, pins=array_pins, name=None, round=False) + for tap in self.tap_insts: + tap_pin = tap.get_pin("poly_tap") + start = vector(tap_pin.cx(), tap_pin.by()) + end = vector(start.x, tap.mod.get_pin("poly_tap").cy()) + self.add_segment_center(layer="poly", start=start, end=end) + print(end) + offset_start = vector(end.x - self.poly_tap.width + self.poly_extend_active, end.y) + offset_end = end + vector(0.5*self.poly_width, 0) + print(self.poly_tap.width) + print(end) + print(offset_start) + self.add_segment_center(layer="poly", start=offset_start, end=offset_end) + def extend_well(self): self.well_offset = self.pmos.tap_offset well_y = self.pmos_insts[0].get_pin("vdd").cy() - 0.5 * self.nwell_width diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index c7627bf7..f83a5c51 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -99,3 +99,5 @@ class rom_precharge_cell(rom_base_cell): self.add_path(self.supply_layer, [self.get_pin("vdd").center(), pos, self.get_pin("S").center()]) self.remove_layout_pin("S") + def place_bitline(self): + pass From bbf2cd2913cecc9bc12d0c8c7cb5b92606050da7 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 27 Feb 2023 14:48:10 -0800 Subject: [PATCH 50/98] Changes for test generation and simulation --- compiler/base/hierarchy_layout.py | 7 +- compiler/modules/pinv_dec.py | 18 +- compiler/modules/rom_array_gnd_tap.py | 39 --- compiler/modules/rom_base_array.py | 10 +- compiler/modules/rom_base_bank.py | 248 +++++++++++------- compiler/modules/rom_control_logic.py | 40 +-- compiler/modules/rom_decoder.py | 19 +- compiler/modules/rom_wordline_driver_array.py | 38 ++- compiler/tests/05_rom_base_bank_1kB_test.py | 5 +- compiler/tests/05_rom_base_bank_2kB_test.py | 39 +++ compiler/tests/05_rom_base_bank_4kB_test.py | 39 +++ compiler/tests/05_rom_base_bank_8kB_test.py | 39 +++ 12 files changed, 363 insertions(+), 178 deletions(-) delete mode 100644 compiler/modules/rom_array_gnd_tap.py create mode 100644 compiler/tests/05_rom_base_bank_2kB_test.py create mode 100644 compiler/tests/05_rom_base_bank_4kB_test.py create mode 100644 compiler/tests/05_rom_base_bank_8kB_test.py diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index eb586a18..c1227cc2 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -787,13 +787,15 @@ class layout(): end=bot_pos) - def connect_col_pins(self, layer, pins, name=None, full=False): + def connect_col_pins(self, layer, pins, name=None, full=False, round=False, directions="pref"): """ Connects top/bot columns that are aligned. """ bins = {} for pin in pins: x = pin.cx() + if round: + x = round_to_grid(x) try: bins[x].append(pin) except KeyError: @@ -819,7 +821,8 @@ class layout(): self.add_via_stack_center(from_layer=pin.layer, to_layer=layer, offset=pin.center(), - min_area=True) + min_area=True, + directions=directions) if name: self.add_layout_pin_segment_center(text=name, diff --git a/compiler/modules/pinv_dec.py b/compiler/modules/pinv_dec.py index eda634f5..1ee75266 100644 --- a/compiler/modules/pinv_dec.py +++ b/compiler/modules/pinv_dec.py @@ -20,7 +20,7 @@ class pinv_dec(pinv): Other stuff is the same (netlist, sizes, etc.) """ - def __init__(self, name, size=1, beta=parameter["beta"], height=None, add_wells=True): + def __init__(self, name, size=1, beta=parameter["beta"], height=None, add_wells=True, flip_io=False): debug.info(2, "creating pinv_dec structure {0} with size of {1}".format(name, @@ -37,7 +37,7 @@ class pinv_dec(pinv): self.supply_layer = "m1" else: self.supply_layer = "m2" - + self.flip_io=flip_io super().__init__(name, size, beta, self.cell_height, add_wells) def determine_tx_mults(self): @@ -76,9 +76,14 @@ class pinv_dec(pinv): pmos_gate_pos = pmos_gate_pin.lc() self.add_path("poly", [nmos_gate_pos, pmos_gate_pos]) + # Center is completely symmetric. contact_width = self.poly_contact.width - contact_offset = nmos_gate_pin.lc() \ + if self.flip_io: + contact_offset = pmos_gate_pin.rc() \ + + vector(self.poly_extend_active + 0.6 * contact_width, 0) + else: + contact_offset = nmos_gate_pin.lc() \ - vector(self.poly_extend_active + 0.5 * contact_width, 0) via = self.add_via_stack_center(from_layer="poly", to_layer=self.route_layer, @@ -107,8 +112,11 @@ class pinv_dec(pinv): height=self.height - ll.y + 0.5 * self.pwell_contact.height + self.well_enclose_active) if "nwell" in layer: - ll = (self.pmos_inst.ll() - vector(2 * [self.well_enclose_active])).scale(1, 0) - ur = self.pmos_inst.ur() + vector(2 * [self.well_enclose_active]) + poly_offset = 0 + if self.flip_io: + poly_offset = 1.2 * self.poly_contact.width + ll = (self.pmos_inst.ll() - vector(2 * [self.well_enclose_active])).scale(1, 0) - vector(0, poly_offset) + ur = self.pmos_inst.ur() + vector(2 * [self.well_enclose_active + poly_offset]) self.add_rect(layer="nwell", offset=ll, width=ur.x - ll.x, diff --git a/compiler/modules/rom_array_gnd_tap.py b/compiler/modules/rom_array_gnd_tap.py deleted file mode 100644 index bbd7a06d..00000000 --- a/compiler/modules/rom_array_gnd_tap.py +++ /dev/null @@ -1,39 +0,0 @@ - - -from openram.base import design -from openram.base import vector -from openram.sram_factory import factory - -class rom_array_gnd_tap(design): - - def __init__(self, name, length, cell_name=None, prop=None): - super().__init__(name, cell_name, prop) - self.length = length - self.create_layout() - - def create_layout(self): - - self.add_cell() - self.add_boundary() - self.place_gnd_rail() - - - def add_boundary(self): - self.height = self.dummy.height - self.width = self.dummy.width - super().add_boundary() - - def add_cell(self): - self.dummy = factory.create(module_type="rom_dummy_cell") - - def place_gnd_rail(self): - rail_start = vector(-self.dummy.width / 2 ,0) - rail_end = vector(self.dummy.width * self.length, 0) - - self.add_layout_pin_rect_ends( name="gnd", - layer="m1", - start=rail_start, - end=rail_end) - - - diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 4e228660..c123af06 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -58,16 +58,17 @@ class rom_base_array(bitcell_base_array): self.place_precharge() self.place_wordline_contacts() self.place_bitline_contacts() - self.add_boundary() self.route_precharge() + self.add_boundary() + self.place_rails() self.connect_taps() + def add_boundary(self): ll = self.find_lowest_coords() - bottom_offset = - self.zero_cell.nmos.end_to_contact + self.precharge_inst.offset.y m1_offset = self.m1_width self.translate_all(vector(0, ll.y + 0.5 * m1_offset)) ur = self.find_highest_coords() @@ -209,7 +210,7 @@ class rom_base_array(bitcell_base_array): prechrg_pins.append("precharge") prechrg_pins.append("vdd") - self.precharge_inst = self.add_inst(name="decode_array_precharge", mod=self.precharge_array) + self.precharge_inst = self.add_inst(name="bitcell_array_precharge", mod=self.precharge_array) self.connect_inst(prechrg_pins) @@ -390,6 +391,9 @@ class rom_base_array(bitcell_base_array): self.add_path(layer="m1", coordinates=[start, mid1, mid2, end]) + self.add_layout_pin_rect_center(text="precharge_r", layer="m1", offset=mid1) + + def connect_taps(self): array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))] diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index 27fa40f4..fedb27f0 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -17,7 +17,7 @@ class rom_base_bank(design): def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2): super().__init__(name=name) self.word_size = word_size * 8 - self.read_binary(word_size=word_size, data_file=data_file) + self.read_binary(word_size=word_size, data_file=data_file, scramble_bits=True, endian="little") self.num_outputs = self.rows self.num_inputs = ceil(log(self.rows, 2)) @@ -48,7 +48,7 @@ class rom_base_bank(design): sets the row and column size based on the size of binary input, tries to keep array as square as possible, """ - def read_binary(self, data_file, word_size=2, endian="big"): + def read_binary(self, data_file, word_size=2, endian="big", scramble_bits=False): # Read data as hexidecimal text file hex_file = open(data_file, 'r') hex_data = hex_file.read() @@ -72,25 +72,56 @@ class rom_base_bank(design): bits_per_row = self.words_per_row * word_size * 8 + self.cols = bits_per_row + self.rows = int(num_words / (self.words_per_row)) chunked_data = [] for i in range(0, len(bin_data), bits_per_row): - word = bin_data[i:i + bits_per_row] - if len(word) < bits_per_row: - word = [0] * (bits_per_row - len(word)) + word - chunked_data.append(word) - - if endian == "big": - chunked_data.reverse() - + row_data = bin_data[i:i + bits_per_row] + if len(row_data) < bits_per_row: + row_data = [0] * (bits_per_row - len(row_data)) + row_data + chunked_data.append(row_data) + + + # if endian == "big": + + self.data = chunked_data - self.cols = bits_per_row - self.rows = int(num_words / (self.words_per_row)) - debug.info(1, "Read rom binary: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, num_words, self.cols, self.rows, self.words_per_row)) + if scramble_bits: + scrambled_chunked = [] + for row_data in chunked_data: + scambled_data = [] + for bit in range(self.word_size): + for word in range(self.words_per_row): + scambled_data.append(row_data[bit + word * self.word_size]) + scrambled_chunked.append(scambled_data) + self.data = scrambled_chunked + + + + # self.data.reverse() + + debug.info(1, "Read rom binary: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, num_words, self.cols, self.rows, self.words_per_row)) + # self.print_data(chunked_data) + # print("Scrambled") + # self.print_data(scrambled_chunked) + + # self.print_word(self.data, 0, 0) + # self.print_word(self.data, 0, 1) + # self.print_word(self.data, 0, 2) + # self.print_word(self.data, 0, 3) # print("hex: {0}, binary: {1}, chunked: {2}".format(hex_data, bin_data, chunked_data)) + def print_data(self, data_array): + for row in range(len(data_array)): + print(data_array[row]) + def print_word(self, data_array, bl, word): + for bit in range(self.word_size): + print(data_array[bl][word + self.words_per_row * bit], end =" ") + print("") + def create_netlist(self): self.add_modules() self.add_pins() @@ -147,6 +178,20 @@ class rom_base_bank(design): def add_modules(self): print("Creating bank modules") + # TODO: provide technology-specific calculation of these parameters + # in sky130 the address control buffer is composed of 2 size 2 NAND gates, + # with a beta of 3, each of these gates has gate capacitance of 2 min sized inverters, therefor a load of 4 + addr_control_buffer_effort = 4 + # a single min sized nmos makes up 1/4 of the input capacitance of a min sized inverter + bitcell_effort = 0.25 + + # Takes into account inverter sizing + wordline_effort = bitcell_effort * 0.5 + + # a single min sized pmos plus a single min sized nmos have approximately half the gate capacitance of a min inverter + # an additional 0.2 accounts for the long wire capacitance and add delay to gaurentee the read timing + precharge_cell_effort = 0.5 + 0.2 + self.array = factory.create(module_type="rom_base_array", cols=self.cols, rows=self.rows, @@ -163,7 +208,7 @@ class rom_base_bank(design): num_outputs=self.rows, strap_spacing=self.strap_spacing, route_layer=self.route_layer, - cols=self.cols) + fanout=(self.cols)*wordline_effort ) self.column_mux = factory.create(module_type="rom_column_mux_array", @@ -178,18 +223,27 @@ class rom_base_bank(design): num_outputs=self.words_per_row, strap_spacing=self.strap_spacing, route_layer=self.route_layer, - cols=1, + fanout=2, invert_outputs=True ) self.control_logic = factory.create(module_type="rom_control_logic", - num_outputs=(self.rows + self.cols + self.words_per_row) * 0.5, - clk_fanout=(self.col_bits + self.row_bits) * 2, + num_outputs=(self.cols + self.words_per_row * precharge_cell_effort) \ + + (addr_control_buffer_effort * self.col_bits), + clk_fanout=(self.row_bits * addr_control_buffer_effort) + (precharge_cell_effort * self.rows), height=self.column_decode.height ) - self.output_buffer = factory.create(module_type="rom_wordline_driver_array", + self.bitline_inv = factory.create(module_type="rom_wordline_driver_array", + module_name="rom_bitline_inverter", + rows=self.cols, + fanout=4, + invert_outputs=True, + tap_spacing=0, + flip_io=True) + self.output_inv = factory.create(module_type="rom_wordline_driver_array", module_name="rom_output_buffer", rows=self.word_size, - cols=4) + fanout=4, + invert_outputs=True) def create_instances(self): @@ -206,18 +260,21 @@ class rom_base_bank(design): select_lines = ["word_sel_{}".format(word) for word in range(self.words_per_row)] + bitline_bar = ["bl_b_{}".format(bl) for bl in range(self.cols)] pre_buf_outputs = ["rom_out_prebuf_{}".format(bit) for bit in range(self.word_size)] outputs = ["rom_out_{}".format(bl) for bl in range(self.word_size)] array_pins = bitlines + wordlines + prechrg + vdd + gnd - row_decode_pins = addr_msb + wordlines + prechrg + clk + vdd + gnd - col_decode_pins = addr_lsb + select_lines + prechrg + clk + vdd + gnd + row_decode_pins = addr_msb + wordlines + clk + clk + vdd + gnd + col_decode_pins = addr_lsb + select_lines + prechrg + prechrg + vdd + gnd - col_mux_pins = bitlines + select_lines + pre_buf_outputs + gnd + col_mux_pins = bitline_bar + select_lines + pre_buf_outputs + gnd - output_buffer_pins = pre_buf_outputs + outputs + vdd + gnd + bitline_inv_pins = bitlines + bitline_bar + vdd + gnd + + output_buf_pins = pre_buf_outputs + outputs + vdd + gnd self.array_inst = self.add_inst(name="rom_bit_array", mod=self.array) self.connect_inst(array_pins) @@ -234,14 +291,19 @@ class rom_base_bank(design): self.col_decode_inst = self.add_inst(name="rom_column_decoder", mod=self.column_decode) self.connect_inst(col_decode_pins) - self.output_buf_inst = self.add_inst(name="rom_output_buffer", mod=self.output_buffer) - self.connect_inst(output_buffer_pins) + self.bitline_inv_inst = self.add_inst(name="rom_bitline_inverter", mod=self.bitline_inv) + self.connect_inst(bitline_inv_pins) + + self.output_inv_inst = self.add_inst(name="rom_output_inverter", mod=self.output_inv) + self.connect_inst(output_buf_pins) + def place_instances(self): self.place_row_decoder() self.place_data_array() + self.place_bitline_inverter() self.place_col_mux() self.place_col_decoder() self.place_control_logic() @@ -249,7 +311,7 @@ class rom_base_bank(design): def place_row_decoder(self): - self.decode_offset = vector(0, self.control_inst.height - self.decode_array.control_array.height) + self.decode_offset = vector(0, self.control_inst.height ) self.decode_inst.place(offset=self.decode_offset) def place_data_array(self): @@ -263,11 +325,18 @@ class rom_base_bank(design): array_align = self.decode_inst.get_pin("wl_0").cy() - self.array_inst.get_pin("wl_0_0").cy() self.array_inst.place(offset=(self.array_offset + vector(0, array_align))) + def place_bitline_inverter(self): + self.bitline_inv_inst.place(offset=[0,0], rotate=90) + inv_y_offset = self.array_inst.by() - self.bitline_inv_inst.width - 2 * self.m1_pitch + + inv_x_offset = self.array_inst.get_pin("bl_0_0").cx() - self.bitline_inv_inst.get_pin("out_0").cx() + self.inv_offset = vector(inv_x_offset, inv_y_offset) + self.bitline_inv_inst.place(offset=self.inv_offset, rotate=90) + def place_control_logic(self): - - self.control_offset = vector(self.control_inst.width + self.decode_array.control_array.width + 2 * (self.route_layer_pitch + self.route_layer_width), self.col_decode_inst.by() + self.control_logic.height) - self.control_inst.place(offset=self.control_offset, mirror="XY") + self.control_offset = vector(self.col_decode_inst.lx() - self.control_inst.width - 3 * self.m1_pitch, self.decode_inst.by() - self.control_logic.height - self.m1_pitch) + self.control_inst.place(offset=self.control_offset) def place_col_decoder(self): col_decode_y = self.mux_inst.get_pin("sel_0").cy() - self.col_decode_inst.get_pin("wl_0").cy() @@ -275,28 +344,18 @@ class rom_base_bank(design): self.col_decode_inst.place(offset=self.col_decode_offset) def place_col_mux(self): - mux_y_offset = self.array_inst.by() - self.mux_inst.height - 5 * self.route_layer_pitch + mux_y_offset = self.bitline_inv_inst.by() - self.mux_inst.height - 5 * self.route_layer_pitch - mux_x_offset = self.array_inst.get_pin("bl_0_0").cx() - self.mux_inst.get_pin("bl_0").cx() + mux_x_offset = self.bitline_inv_inst.get_pin("out_0").cx() - self.mux_inst.get_pin("bl_0").cx() self.mux_offset = vector(mux_x_offset, mux_y_offset) self.mux_inst.place(offset=self.mux_offset) def place_output_buffer(self): - output_x = self.col_decode_inst.rx() + self.output_buf_inst.height - output_y = self.col_decode_inst.by() + self.output_buf_inst.width - self.output_buf_offset = vector(output_x, output_y) - self.output_buf_inst.place(offset=self.output_buf_offset, rotate=270) + output_x = self.col_decode_inst.rx() + self.output_inv_inst.height + output_y = self.mux_inst.by() - self.word_size * self.m1_pitch + self.output_inv_offset = vector(output_x, output_y) + self.output_inv_inst.place(offset=self.output_inv_offset, rotate=270) - # def create_wl_bus(self): - # bus_x = self.decode_inst.width + ( drc["minwidth_{}".format(self.bus_layer)] + 1.5 * drc["{0}_to_{0}".format(self.bus_layer)] ) - # bus_y = self.array_inst.by() + self.bus_layer_pitch + self.bus_layer_width - # self.wl_interconnects = [] - - # for wl in range(self.rows): - # self.wl_interconnects.append("wl_interconnect_{}".format(wl)) - - # self.wl_bus = self.create_vertical_bus(self.bus_layer, vector(bus_x, bus_y), self.wl_interconnects, self.decode_inst.uy() - self.array_inst.by() ) - def route_decode_outputs(self): # for the row decoder route_pins = [self.array_inst.get_pin("wl_0_{}".format(wl)) for wl in range(self.rows)] @@ -325,88 +384,105 @@ class rom_base_bank(design): start = vector(wl_bus_wire.cx(), end.y) self.add_segment_center(self.interconnect_layer, start, end) - self.add_via_stack_center(start, self.route_layer, self.interconnect_layer ) def route_precharge(self): prechrg_control = self.control_inst.get_pin("prechrg") - row_decode_prechrg = self.decode_inst.get_pin("precharge") - col_decode_prechrg = self.col_decode_inst.get_pin("precharge") + + col_decode_prechrg = self.col_decode_inst.get_pin("precharge_r") + col_decode_clk = self.col_decode_inst.get_pin("clk") array_prechrg = self.array_inst.get_pin("precharge") # Route precharge signal to the row decoder - end = vector(row_decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy()) + # end = vector(row_decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy()) - self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end) + # self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end) - start = end + vector(0.5 * self.interconnect_layer_width, 0) - self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center()) + # start = end + vector(0.5 * self.interconnect_layer_width, 0) + # self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center()) self.add_via_stack_center(from_layer=self.route_stack[0], to_layer=prechrg_control.layer, offset=prechrg_control.center()) # Route precharge to col decoder - start = row_decode_prechrg.center() - vector(0, self.route_layer_pitch + 2 * self.route_layer_width) - mid = vector(col_decode_prechrg.cx(), start.y) - end = vector(col_decode_prechrg.cx(), 0.5 * (self.col_decode_inst.uy() + mid.y) ) - self.add_path(self.route_stack[0], [start, mid, end]) + start = prechrg_control.center() + mid1 = vector(self.control_inst.rx(), prechrg_control.cy()) + mid2 = vector(self.control_inst.rx(), col_decode_prechrg.cy()) + end = col_decode_prechrg.center() + self.add_path(self.route_stack[0], [start, mid1, mid2, end]) self.add_via_stack_center(from_layer=self.route_stack[0], to_layer=col_decode_prechrg.layer, offset=end) - self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center()) + + start = mid1 + mid1 = vector(self.control_inst.rx(), start.y) + mid2 = vector(mid1.x, col_decode_clk.cy()) + end = col_decode_clk.center() + self.add_path(self.route_stack[0], [start, mid1, mid2, end]) + + # self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center()) # Route precharge to main array - end = vector(col_decode_prechrg.cx(), array_prechrg.cy()) - self.add_segment_center(self.route_stack[0], array_prechrg.center(), end) + # end = vector(col_decode_prechrg.cx(), array_prechrg.cy()) + mid = vector(col_decode_prechrg.cx(), array_prechrg.cy() ) + self.add_path(self.route_stack[0], [array_prechrg.center(), mid, col_decode_prechrg.center()]) def route_clock(self): clk_out = self.control_inst.get_pin("clk_out") row_decode_clk = self.decode_inst.get_pin("clk") - col_decode_clk = self.col_decode_inst.get_pin("clk") + self.add_via_stack_center(from_layer=self.route_stack[2], to_layer=clk_out.layer, offset=clk_out.center()) # Route clock to row decoder - end = row_decode_clk.rc() + vector( 2 * self.route_layer_pitch + self.route_layer_width, 0) - self.add_path(self.route_stack[2], [clk_out.center(), end]) + mid = vector(self.control_inst.rx() + self.m1_pitch, clk_out.cy()) + + addr_control_clk = row_decode_clk.rc() + vector( 2 * self.route_layer_pitch + self.route_layer_width, 0) + row_decode_prechrg = self.decode_inst.get_pin("precharge") + + self.add_path(self.route_stack[2], [clk_out.center(), mid, addr_control_clk, row_decode_prechrg.center()]) self.add_via_stack_center(from_layer=self.route_stack[2], to_layer=row_decode_clk.layer, - offset=end) + offset=addr_control_clk) - self.add_segment_center(row_decode_clk.layer, end, row_decode_clk.rc()) + self.add_segment_center(row_decode_clk.layer, addr_control_clk, row_decode_clk.rc()) # Route clock to column decoder - end = col_decode_clk.lc() - vector( 2 * self.route_layer_pitch + self.route_layer_width, 0) - self.add_path(self.route_stack[2], [clk_out.center(), end]) + # end = col_decode_clk.lc() - vector( 2 * self.route_layer_pitch + self.route_layer_width, 0) + # self.add_path(self.route_stack[2], [clk_out.center(), end]) - self.add_via_stack_center(from_layer=self.route_stack[2], - to_layer=row_decode_clk.layer, - offset=end) + # self.add_via_stack_center(from_layer=self.route_stack[2], + # to_layer=row_decode_clk.layer, + # offset=end) - self.add_segment_center(col_decode_clk.layer, end, col_decode_clk.lc()) + # self.add_segment_center(col_decode_clk.layer, end, col_decode_clk.lc()) def route_array_outputs(self): - for i in range(self.cols): - bl_out = self.array_inst.get_pin("bl_0_{}".format(i)).center() + array_out_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.cols)] + inv_in_pins = [self.bitline_inv_inst.get_pin("in_{}".format(bl)) for bl in range(self.cols)] + inv_out_pins = [self.bitline_inv_inst.get_pin("out_{}".format(bl)) for bl in range(self.cols)] + mux_pins = [self.mux_inst.get_pin("bl_{}".format(bl)) for bl in range(self.cols)] + + self.connect_col_pins(self.interconnect_layer, array_out_pins + inv_in_pins, round=True, directions="nonpref") + self.connect_col_pins(self.interconnect_layer, inv_out_pins + mux_pins, round=True, directions="nonpref") + - bl_mux = self.mux_inst.get_pin("bl_{}".format(i)).center() - self.add_path(self.array.bitline_layer, [bl_out, bl_mux]) def route_output_buffers(self): mux = self.mux_inst - buf = self.output_buf_inst + buf = self.output_inv_inst route_nets = [ [mux.get_pin("bl_out_{}".format(bit)), buf.get_pin("in_{}".format(bit))] for bit in range(self.word_size)] channel_ll = vector( route_nets[0][0].cx(), route_nets[0][1].cy() + self.m1_pitch * 3) @@ -429,7 +505,7 @@ class rom_base_bank(design): self.copy_layout_pin(self.control_inst, "clk_in", "clk") for i in range(self.word_size): - self.copy_layout_pin(self.output_buf_inst, "out_{}".format(i), "rom_out_{}".format(i)) + self.copy_layout_pin(self.output_inv_inst, "out_{}".format(i), "rom_out_{}".format(i)) for lsb in range(self.col_bits): name = "addr_{}".format(lsb) self.copy_layout_pin(self.col_decode_inst, "A{}".format(lsb), name) @@ -448,27 +524,7 @@ class rom_base_bank(design): if not inst.mod.name.__contains__("contact"): self.copy_layout_pin(inst, "vdd") self.copy_layout_pin(inst, "gnd") - # gnd_start = vector(self.array_inst.get_pins("gnd")[0].cx(),0) - # decode_gnd = self.decode_inst.get_pin("gnd") - # decode_vdd = self.decode_inst.get_pin("vdd") - # array_vdd = self.array_inst.get_pin("vdd") - - # # self.add_segment_center("m1", gnd_start, decode_gnd.center()) - - - # self.add_power_pin("gnd", decode_vdd.center()) - # self.add_power_pin("vdd", decode_gnd.center()) - - # vdd_start = vector(array_vdd.lx() + 0.5 * self.via1_space, array_vdd.cy()) - # end = vector(decode_vdd.lx(), vdd_start.y) - - # self.add_segment_center(self.interconnect_layer, vdd_start, end) - # self.add_via_stack_center(vdd_start, "m1", self.interconnect_layer) - - # vdd_start = vector(decode_vdd.cx(), vdd_start.y) - - # self.add_segment_center(self.interconnect_layer, vdd_start, decode_vdd.center()) diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index 0668bd19..b1157fc7 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -20,7 +20,7 @@ class rom_control_logic(design): if self.height is not None: self.driver_height = 0.5 * self.height - self.gate_height = 0.25 * self.height + self.gate_height = 0.5 * self.height else: self.gate_height = 20 * self.m1_pitch self.driver_height = self.gate_height @@ -51,16 +51,18 @@ class rom_control_logic(design): self.route_insts() def add_modules(self): - - self.buf_mod = factory.create(module_type="pinvbuf", - module_name="rom_control_logic_pinv", + self.buf_mod = factory.create(module_type="pdriver", + module_name="rom_clock_driver", height=self.gate_height, - route_in_cell=True ) + fanout=self.clk_fanout + 2, + add_wells=True, + ) self.nand_mod = factory.create(module_type="pnand2", module_name="rom_control_nand", height=self.gate_height, add_wells=False) self.driver_mod = factory.create(module_type="pdriver", + module_name="rom_precharge_driver", inverting=True, fanout=self.output_size, height=self.driver_height, @@ -77,34 +79,36 @@ class rom_control_logic(design): def create_instances(self): - self.buf_inst = self.add_inst(name="clk_invbuf", mod=self.buf_mod) - self.connect_inst(["clk_in", "clk_bar", "clk_out", "vdd", "gnd"]) + self.buf_inst = self.add_inst(name="clk_driver", mod=self.buf_mod) + self.connect_inst(["clk_in", "clk_out", "vdd", "gnd"]) self.nand_inst = self.add_inst(name="control_nand", mod=self.nand_mod) self.connect_inst(["CS", "clk_out", "pre_drive", "vdd", "gnd"]) - self.driver_inst = self.add_inst(name="driver_inst", mod=self.driver_mod) + self.driver_inst = self.add_inst(name="precharge_driver", mod=self.driver_mod) self.connect_inst(["pre_drive", "prechrg", "vdd", "gnd"]) def place_instances(self): - buf_correction = drc["minwidth_{}".format(self.route_stack[0])] * 0.5 # nand_y = self.buf_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy() - self.nand_inst.place(offset=[0, self.nand_inst.height + self.buf_mod.inv2.height + buf_correction], mirror="MX") - self.driver_inst.place(offset=[0, self.buf_inst.height + buf_correction]) + self.nand_inst.place(offset=[self.buf_inst.width, 0]) + self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height], mirror="MX") + + offset = self.driver_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy() + print("offset: {}".format(offset)) + self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height - offset], mirror="MX") + def route_insts(self): route_width = drc["minwidth_{}".format(self.route_stack[2])] self.copy_layout_pin(self.buf_inst, "A", "clk_in") - self.copy_layout_pin(self.buf_inst, "Zb", "clkb_out") self.copy_layout_pin(self.buf_inst, "Z", "clk_out") self.copy_layout_pin(self.driver_inst, "Z", "prechrg") self.copy_layout_pin(self.nand_inst, "A", "CS") self.copy_layout_pin(self.buf_inst, "gnd") self.copy_layout_pin(self.driver_inst, "vdd") self.copy_layout_pin(self.buf_inst, "vdd") - # self.copy_layout_pin(self.buf_inst, "vdd") clk = self.buf_inst.get_pin("Z") @@ -114,7 +118,7 @@ class rom_control_logic(design): # Connect buffered clock bar to nand input mid = vector(clk.lx() - route_width - 2 * self.m1_space) - self.add_path(self.route_stack[2], [clk.center(), mid, nand_B.center()]) + self.add_path(self.route_stack[2], [clk.center(), nand_B.center()]) self.add_via_stack_center(from_layer=clk.layer, to_layer=self.route_stack[2], @@ -126,15 +130,17 @@ class rom_control_logic(design): # Connect nand output to precharge driver nand_Z = self.nand_inst.get_pin("Z") - nand_output = vector(nand_Z.cx(), nand_B.cy() + 3 * route_width) driver_A = self.driver_inst.get_pin("A") - self.add_path(self.route_stack[2], [nand_output, driver_A.center()]) + + mid = vector(driver_A.cx(), driver_A.cy() - 4 * route_width) + + self.add_path(self.route_stack[2], [nand_Z.center(), mid, driver_A.center()]) self.add_via_stack_center(from_layer=nand_Z.layer, to_layer=self.route_stack[2], - offset=nand_output) + offset=nand_Z.center()) self.add_via_stack_center(from_layer=driver_A.layer, to_layer=self.route_stack[2], diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index 10d55f85..bb8f0839 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -14,7 +14,7 @@ from openram.tech import drc class rom_decoder(design): - def __init__(self, num_outputs, cols, strap_spacing, name="", route_layer="m1", output_layer="m1", invert_outputs=False): + def __init__(self, num_outputs, fanout, strap_spacing, name="", route_layer="m1", output_layer="m1", invert_outputs=False): # word lines/ rows / inputs in the base array become the address lines / cols / inputs in the decoder # bit lines / cols / outputs in the base array become the word lines / rows / outputs in the decoder @@ -33,7 +33,7 @@ class rom_decoder(design): self.route_layer = route_layer self.output_layer = output_layer self.inv_route_layer = "m2" - self.cols=cols + self.fanout=fanout self.invert_outputs=invert_outputs self.create_netlist() @@ -57,6 +57,17 @@ class rom_decoder(design): self.connect_inputs() self.route_supplies() self.add_boundary() + + def add_boundary(self): + ll = self.find_lowest_coords() + m1_offset = self.m1_width + self.translate_all(vector(0, ll.y)) + ur = self.find_highest_coords() + + ur = vector(ur.x, ur.y) + super().add_boundary(ll, ur) + self.width = ur.x + self.height = ur.y def setup_layout_constants(self): self.inv_route_width = drc["minwidth_{}".format(self.inv_route_layer)] @@ -114,7 +125,7 @@ class rom_decoder(design): self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), rows=self.num_outputs, - cols=ceil(self.cols * 0.5), + fanout=ceil(self.fanout), invert_outputs=self.invert_outputs, tap_spacing=self.strap_spacing) @@ -224,7 +235,7 @@ class rom_decoder(design): def connect_inputs(self): self.copy_layout_pin(self.array_inst, "precharge") - + self.copy_layout_pin(self.array_inst, "precharge_r") for i in range(self.num_inputs): wl = (self.num_inputs - i) * 2 - 1 wl_bar = wl - 1 diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index 4d3fde06..ae2ea848 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -19,16 +19,16 @@ class rom_wordline_driver_array(design): Creates a Wordline Buffer/Inverter array """ - def __init__(self, name, rows, cols, invert_outputs=False, tap_spacing=4): + def __init__(self, name, rows, fanout, invert_outputs=False, tap_spacing=4, flip_io=False): design.__init__(self, name) debug.info(1, "Creating {0}".format(self.name)) - self.add_comment("rows: {0} cols: {1}".format(rows, cols)) + self.add_comment("rows: {0} Buffer size of: {1}".format(rows, fanout)) self.rows = rows - self.cols = cols + self.fanout = fanout self.invert_outputs=invert_outputs self.tap_spacing = tap_spacing - + self.flip_io = flip_io if OPTS.tech_name == "sky130": self.supply_layer = "m1" else: @@ -51,7 +51,8 @@ class rom_wordline_driver_array(design): self.place_drivers() self.route_layout() self.route_supplies() - self.place_taps() + if self.tap_spacing != 0: + self.place_taps() self.add_boundary() def add_pins(self): @@ -70,13 +71,14 @@ class rom_wordline_driver_array(design): if self.invert_outputs: self.wl_driver = factory.create(module_type="pinv_dec", - size=self.cols, + size=self.fanout, height=b.height, - add_wells=False) + add_wells=False, + flip_io=self.flip_io) else: self.wl_driver = factory.create(module_type="pbuf_dec", - size=self.cols, + size=self.fanout, height=b.height, add_wells=False) @@ -108,7 +110,7 @@ class rom_wordline_driver_array(design): def place_drivers(self): y_offset = 0 for row in range(self.rows): - if row % self.tap_spacing == 0: + if self.tap_spacing != 0 and row % self.tap_spacing == 0: y_offset += self.tap.pitch_offset offset = [0, y_offset] @@ -123,20 +125,34 @@ class rom_wordline_driver_array(design): """ Route all of the signals """ route_width = drc["minwidth_{}".format(self.route_layer)] for row in range(self.rows): - inst = self.wld_inst[row] + if self.flip_io: + row_num = self.rows - row - 1 + else: + row_num = row + inst = self.wld_inst[row_num] self.copy_layout_pin(inst, "vdd") self.copy_layout_pin(inst, "gnd") self.copy_layout_pin(inst, "A", "in_{0}".format(row)) + out_pin = inst.get_pin("Z") # output each WL on the right - wl_offset = inst.get_pin("Z").rc() - vector( 0.5 * route_width, 0) + if self.flip_io: + wl_offset = out_pin.lc() - vector(1.6 * route_width, 0) + + else: + wl_offset = out_pin.rc() - vector( 0.5 * route_width, 0) + end = vector(wl_offset.x, \ self.get_pin("in_{}".format(row)).cy() + 0.5 * route_width) self.add_segment_center(layer=self.route_layer, start=wl_offset, end=end) + if self.flip_io: + self.add_segment_center(layer=self.route_layer, + start=out_pin.lc(), + end=vector(wl_offset.x - 0.5 * route_width, out_pin.cy())) self.add_layout_pin_rect_center(text="out_{}".format(row), layer=self.route_layer, offset=end - vector(0, 0.5 * route_width)) diff --git a/compiler/tests/05_rom_base_bank_1kB_test.py b/compiler/tests/05_rom_base_bank_1kB_test.py index 8f742f94..39a9e41f 100644 --- a/compiler/tests/05_rom_base_bank_1kB_test.py +++ b/compiler/tests/05_rom_base_bank_1kB_test.py @@ -24,8 +24,11 @@ class rom_bank_test(openram_test): debug.info(1, "Testing 1kB rom cell") a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_1kB", word_size=1) - + print('wriitng file') + a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) + + openram.end_openram() # run the test from the command line diff --git a/compiler/tests/05_rom_base_bank_2kB_test.py b/compiler/tests/05_rom_base_bank_2kB_test.py new file mode 100644 index 00000000..d1f59fe7 --- /dev/null +++ b/compiler/tests/05_rom_base_bank_2kB_test.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 + +import openram +from openram import OPTS +from openram.sram_factory import factory +from openram import debug + + +class rom_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + debug.info(1, "Testing 2kB rom cell") + + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_2kB", word_size=1) + print('wriitng file') + a.sp_write(OPTS.openram_temp + 'simulation_file.sp') + self.local_check(a) + + + openram.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) \ No newline at end of file diff --git a/compiler/tests/05_rom_base_bank_4kB_test.py b/compiler/tests/05_rom_base_bank_4kB_test.py new file mode 100644 index 00000000..eb63776b --- /dev/null +++ b/compiler/tests/05_rom_base_bank_4kB_test.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 + +import openram +from openram import OPTS +from openram.sram_factory import factory +from openram import debug + + +class rom_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + debug.info(1, "Testing 4kB rom cell") + + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_4kB", word_size=2) + print('wriitng file') + a.sp_write(OPTS.openram_temp + 'simulation_file.sp') + self.local_check(a) + + + openram.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) \ No newline at end of file diff --git a/compiler/tests/05_rom_base_bank_8kB_test.py b/compiler/tests/05_rom_base_bank_8kB_test.py new file mode 100644 index 00000000..591d5055 --- /dev/null +++ b/compiler/tests/05_rom_base_bank_8kB_test.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2021 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 + +import openram +from openram import OPTS +from openram.sram_factory import factory +from openram import debug + + +class rom_bank_test(openram_test): + + def runTest(self): + config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) + openram.init_openram(config_file, is_unit_test=True) + debug.info(1, "Testing 8kB rom cell") + + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_8kB", word_size=2) + print('wriitng file') + a.sp_write(OPTS.openram_temp + 'simulation_file_8kB.sp') + self.local_check(a) + + + openram.end_openram() + +# run the test from the command line +if __name__ == "__main__": + (OPTS, args) = openram.parse_args() + del sys.argv[1:] + header(__file__, OPTS.tech_name) + unittest.main(testRunner=debugTestRunner()) \ No newline at end of file From ab955f0da8386c5801fda06938d903b6336c5c1d Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 27 Feb 2023 15:10:00 -0800 Subject: [PATCH 51/98] removed data files --- technology/rom_data_64B | 1 - 1 file changed, 1 deletion(-) delete mode 100644 technology/rom_data_64B diff --git a/technology/rom_data_64B b/technology/rom_data_64B deleted file mode 100644 index 7e216561..00000000 --- a/technology/rom_data_64B +++ /dev/null @@ -1 +0,0 @@ -73630b5c3105aeda99f7892feeea277f1fe45fbc1909bce7840e37ee186edefe73630b5c3105aeda99f7892feeea277f1fe45fbc1909bce7840e37ee186edefe \ No newline at end of file From 79efff9ca692ef911fe0f633070f642594d87586 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 27 Feb 2023 15:56:24 -0800 Subject: [PATCH 52/98] code cleanup and updated copyright --- compiler/modules/rom_address_control_array.py | 18 +--- compiler/modules/rom_address_control_buf.py | 36 ++------ compiler/modules/rom_base_array.py | 92 +++---------------- compiler/modules/rom_base_bank.py | 50 ++-------- compiler/modules/rom_base_cell.py | 25 +---- compiler/modules/rom_column_mux.py | 11 +-- compiler/modules/rom_column_mux_array.py | 4 +- compiler/modules/rom_control_logic.py | 17 +--- compiler/modules/rom_decoder.py | 64 ++----------- compiler/modules/rom_dummy_cell.py | 87 ------------------ compiler/modules/rom_poly_tap.py | 38 ++------ compiler/modules/rom_precharge_array.py | 38 ++------ compiler/modules/rom_precharge_cell.py | 17 +--- compiler/modules/rom_wordline_driver_array.py | 11 +-- compiler/tests/05_rom_array_test.py | 2 +- compiler/tests/05_rom_base_bank_1kB_test.py | 4 +- compiler/tests/05_rom_base_bank_2kB_test.py | 2 - compiler/tests/05_rom_base_bank_4kB_test.py | 4 +- compiler/tests/05_rom_base_bank_8kB_test.py | 5 +- compiler/tests/05_rom_base_bank_small_test.py | 3 +- .../tests/05_rom_column_mux_array_test.py | 2 +- compiler/tests/05_rom_control_logic_test.py | 2 +- .../tests/05_rom_decoder_buffer_array_test.py | 2 +- compiler/tests/05_rom_decoder_test.py | 2 +- compiler/tests/05_rom_precharge_array_test.py | 2 +- .../05_rom_wordline_driver_array_test.py | 2 +- 26 files changed, 87 insertions(+), 453 deletions(-) delete mode 100644 compiler/modules/rom_dummy_cell.py diff --git a/compiler/modules/rom_address_control_array.py b/compiler/modules/rom_address_control_array.py index cfb8a278..e02d0443 100644 --- a/compiler/modules/rom_address_control_array.py +++ b/compiler/modules/rom_address_control_array.py @@ -1,11 +1,10 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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 openram.base import design from openram.sram_factory import factory from openram.base import vector @@ -74,13 +73,12 @@ class rom_address_control_array(design): self.add_pin("gnd", "GROUND") def create_instances(self): - + self.buf_insts = [] for col in range(self.cols): - + name = "Xaddr_buf_{0}".format(col) - addr_buf = self.add_inst(name=name, mod=self.addr_control) A_in = "A{0}_in".format(col) @@ -99,24 +97,16 @@ class rom_address_control_array(design): self.buf_insts[col].place(offset=base, mirror="MY") - def copy_pins(self): for i in range(self.cols): self.copy_layout_pin(self.buf_insts[i], "A_out", "A{0}_out".format(i)) self.copy_layout_pin(self.buf_insts[i], "Abar_out", "Abar{0}_out".format(i)) self.copy_layout_pin(self.buf_insts[i], "A_in", "A{0}_in".format(i)) - - def route_clk(self): self.route_horizontal_pins("clk", insts=self.buf_insts, layer=self.route_layer) - - def route_sources(self): self.route_horizontal_pins("vdd", insts=self.buf_insts, layer=self.route_layer) - self.route_horizontal_pins("gnd", insts=self.buf_insts, layer=self.route_layer) - - - + self.route_horizontal_pins("gnd", insts=self.buf_insts, layer=self.route_layer) \ No newline at end of file diff --git a/compiler/modules/rom_address_control_buf.py b/compiler/modules/rom_address_control_buf.py index f486e855..c0950dda 100644 --- a/compiler/modules/rom_address_control_buf.py +++ b/compiler/modules/rom_address_control_buf.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -22,10 +22,7 @@ class rom_address_control_buf(design): self.route_layer = route_layer self.add_wells = add_wells - self.size = size - - if "li" in layer: self.inv_layer = "li" else: @@ -39,7 +36,6 @@ class rom_address_control_buf(design): self.add_pins() self.create_instances() - def create_layout(self): self.width = self.cell.height * 2 self.height = self.inv.width + 2 * self.nand.width @@ -50,10 +46,8 @@ class rom_address_control_buf(design): self.route_sources() self.add_boundary() - def create_modules(self): - # self.inv1_mod = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size, add_wells=False) self.inv = factory.create(module_type="pinv_dec", module_name="inv_array_mod", add_wells=False, size=self.size) # self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", size=self.size, add_wells=True) @@ -62,7 +56,7 @@ class rom_address_control_buf(design): self.cell = factory.create(module_type="rom_base_cell") def add_pins(self): - + self.add_pin("A_in", "INPUT") self.add_pin("A_out", "INOUT") self.add_pin("Abar_out", "OUTPUT") @@ -83,7 +77,7 @@ class rom_address_control_buf(design): self.addr_nand = self.add_inst(name=name, mod=self.nand) inst_A = "clk" - inst_B = "Abar_internal" + inst_B = "Abar_internal" inst_Z = "A_out" self.connect_inst([inst_A, inst_B, inst_Z, "vdd", "gnd"]) @@ -95,39 +89,30 @@ class rom_address_control_buf(design): inst_Z = "Abar_out" self.connect_inst([inst_A, inst_B, inst_Z, "vdd", "gnd"]) - - - def setup_layout_constants(self): self.route_width = drc["minwidth_{}".format(self.route_layer)] self.interconnect_width = drc["minwidth_{}".format(self.inv_layer)] def place_instances(self): - - self.inv_inst.place(offset=vector(self.inv_inst.height,0), rotate=90) self.addr_nand.place(offset=vector(self.addr_nand.height , self.inv_inst.width + self.route_width ), rotate=90) - self.addr_bar_nand.place(offset=vector( self.addr_bar_nand.height, self.addr_nand.width + self.inv_inst.width + self.route_width), rotate=90) - - - def route_gates(self): clk1_pin = self.addr_nand.get_pin("A") clk2_pin = self.addr_bar_nand.get_pin("A") # self.add_label("HERE I AM", "poly", clk_pins.cl()) - + Abar_out = self.addr_bar_nand.get_pin("Z") A_out = self.addr_nand.get_pin("Z") - + Abar_in = self.addr_nand.get_pin("B") Abar_int_out = self.inv_inst.get_pin("Z") Aint_in = self.addr_bar_nand.get_pin("B") A_in = self.inv_inst.get_pin("A") - + # Find the center of the pmos poly/gate poly_right = clk1_pin.cx() + self.poly_enclose_contact + 0.5 * self.contact_width @@ -160,7 +145,7 @@ class rom_address_control_buf(design): self.add_layout_pin_rect_center("A_out", offset=vector(end.x, self.addr_bar_nand.uy() - 0.5 * self.m2_width), layer="m2") - # Route second NAND to output pin + # Route second NAND to output pin self.add_via_stack_center(Abar_out.center(), self.inv_layer, "m2") self.add_segment_center("m2", Abar_out.center(), vector(Abar_out.cx(), self.addr_bar_nand.uy())) self.add_layout_pin_rect_center("Abar_out", offset=vector(Abar_out.cx(), self.addr_bar_nand.uy() - 0.5 * self.m2_width), layer="m2") @@ -170,9 +155,6 @@ class rom_address_control_buf(design): end = vector(Abar_int_out.cx(), Abar_in.cy() + 0.5 * self.interconnect_width) self.add_segment_center(self.inv_layer, Abar_int_out.center(), end) self.copy_layout_pin(self.inv_inst, "A", "A_in") - - - def route_sources(self): @@ -209,6 +191,4 @@ class rom_address_control_buf(design): well_type="p") self.add_via_stack_center(offset=contact_pos, from_layer=self.active_stack[2], - to_layer=self.route_layer) - - + to_layer=self.route_layer) \ No newline at end of file diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index c123af06..c6af1470 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -29,8 +29,6 @@ class rom_base_array(bitcell_base_array): self.data_col_size = self.column_size self.tap_spacing = tap_spacing - - if strap_spacing != 0: self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing) else: @@ -39,7 +37,6 @@ class rom_base_array(bitcell_base_array): self.create_all_wordline_names() self.create_netlist() self.create_layout() - def create_netlist(self): self.add_modules() @@ -47,14 +44,13 @@ class rom_base_array(bitcell_base_array): self.create_cell_instances() self.create_precharge_inst() - def create_layout(self): self.create_layout_constants() self.place_array() if self.tap_direction == "row": self.route_pitch_offsets() - + self.place_precharge() self.place_wordline_contacts() self.place_bitline_contacts() @@ -64,20 +60,15 @@ class rom_base_array(bitcell_base_array): self.place_rails() self.connect_taps() - - - def add_boundary(self): ll = self.find_lowest_coords() m1_offset = self.m1_width self.translate_all(vector(0, ll.y + 0.5 * m1_offset)) ur = self.find_highest_coords() - ur = vector(ur.x, ur.y - self.m1_width) super().add_boundary(vector(0, 0), ur) self.width = ur.x self.height = ur.y - def add_modules(self): @@ -102,13 +93,10 @@ class rom_base_array(bitcell_base_array): strap_layer=self.wordline_layer, tap_direction=self.tap_direction) - def create_layout_constants(self): self.route_width = drc("minwidth_" + self.bitline_layer) - self.route_pitch = drc("{0}_to_{0}".format(self.bitline_layer)) - def add_pins(self): for bl_name in self.get_bitline_names(): self.add_pin(bl_name, "OUTPUT") @@ -123,7 +111,6 @@ class rom_base_array(bitcell_base_array): self.tap_list = [] self.cell_inst = {} self.cell_list = [] - self.current_row = 0 #list of current bitline interconnect nets, starts as the same as the bitline list and is updated when new insts of cells are added self.int_bl_list = self.bitline_names[0].copy() @@ -133,21 +120,17 @@ class rom_base_array(bitcell_base_array): # for each new strap placed, offset the column index refrenced to get correct bit in the data array # cols are bit lines - for col in range(self.column_size): - + if col % self.strap_spacing == 0: self.create_poly_tap(row, col) - new_inst = self.create_cell(row, col) self.cell_inst[row, col] = new_inst row_list.append(new_inst) - - name = "tap_r{0}_c{1}".format(row, self.array_col_size) new_tap = self.add_inst(name=name, mod=self.poly_tap) self.tap_inst[row, self.column_size] = new_tap @@ -155,10 +138,6 @@ class rom_base_array(bitcell_base_array): self.connect_inst([]) self.cell_list.append(row_list) - - - - def create_poly_tap(self, row, col): name = "tap_r{0}_c{1}".format(row, col) @@ -167,7 +146,6 @@ class rom_base_array(bitcell_base_array): self.tap_list.append(new_tap) self.connect_inst([]) - def create_cell(self, row, col): name = "bit_r{0}_c{1}".format(row, col) @@ -182,7 +160,6 @@ class rom_base_array(bitcell_base_array): if self.data[row][col] == 1: self.int_bl_list[col] = "bl_int_{0}_{1}".format(row, col) - bl_h = self.int_bl_list[col] # Final row of dummy nmos that contains only 1s, acts to prevent shorting bl to ground when precharging @@ -198,23 +175,14 @@ class rom_base_array(bitcell_base_array): return new_inst - - def create_precharge_inst(self): prechrg_pins = self.bitline_names[0].copy() - - # for bl in range(self.column_size): - # # if the internal bl was never updated there are no active cells in the bitline, so it should route straight to ground" - # if self.int_bl_list[bl] == prechrg_pins[bl]: - # prechrg_pins[bl] = "gnd" prechrg_pins.append("precharge") prechrg_pins.append("vdd") self.precharge_inst = self.add_inst(name="bitcell_array_precharge", mod=self.precharge_array) self.connect_inst(prechrg_pins) - - def create_all_bitline_names(self): for col in range(self.column_size): for port in self.all_ports: @@ -222,37 +190,30 @@ class rom_base_array(bitcell_base_array): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - - def place_rails(self): via_width = drc("m2_enclose_via1") * 0.5 + drc("minwidth_via1") pitch = drc["{0}_to_{0}".format(self.wordline_layer)] for i in range(self.column_size): drain = self.cell_list[self.row_size][i].get_pin("D") - gnd_pos = drain.center() + vector(0, pitch + via_width + self.route_pitch) self.add_layout_pin_rect_center(text="gnd", layer=self.bitline_layer, offset=gnd_pos) self.route_horizontal_pins("gnd", insts=[self], yside="cy") - self.copy_layout_pin(self.precharge_inst, "vdd") - - - def place_array(self): self.cell_pos = {} self.strap_pos = {} # rows are wordlines pitch_offset = 0 for row in range(self.row_size + 1): - + if row % self.tap_spacing == 0 and self.pitch_match and row != self.row_size: pitch_offset += self.active_contact.width + self.active_space - + cell_y = row * (self.zero_cell.height) + pitch_offset - + cell_x = 0 for col in range(self.column_size): @@ -262,19 +223,15 @@ class rom_base_array(bitcell_base_array): if self.tap_direction == "col": cell_x += self.poly_tap.pitch_offset - + self.cell_pos[row, col] = vector(cell_x, cell_y) self.cell_inst[row, col].place(self.cell_pos[row, col]) cell_x += self.zero_cell.width # self.add_label("debug", "li", self.cell_pos[row, col]) - self.strap_pos[row, self.column_size] = vector(cell_x, cell_y) self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size]) - - - def route_pitch_offsets(self): for row in range(0 , self.row_size, self.tap_spacing): @@ -289,11 +246,8 @@ class rom_base_array(bitcell_base_array): start = vector(drain.cx(), source.cy()) end = drain.center() self.add_segment_center(self.bitline_layer, start, end) - self.place_well_tap(row, col) - - - + def place_well_tap(self, row, col): cell = self.cell_inst[row, col] source = cell.get_pin("S") @@ -309,9 +263,7 @@ class rom_base_array(bitcell_base_array): else: tap_y = source.cy() - self.contact_width - 2 * self.active_enclose_contact - self.active_space - tap_pos = vector(tap_x, tap_y) - self.add_via_center(layers=self.active_stack, offset=tap_pos, implant_type="p", @@ -322,27 +274,17 @@ class rom_base_array(bitcell_base_array): to_layer=self.wordline_layer) self.add_layout_pin_rect_center("gnd", self.wordline_layer, tap_pos) - - def place_precharge(self): - self.precharge_offset = vector(0, - self.precharge_inst.height - self.zero_cell.nmos.end_to_contact - 2 * drc["nwell_enclose_active"] - 3 * self.m1_pitch) - self.precharge_inst.place(offset=self.precharge_offset) - self.copy_layout_pin(self.precharge_inst, "vdd") self.copy_layout_pin(self.precharge_inst, "gate", "precharge") - - - + def place_wordline_contacts(self): for wl in range(self.row_size): - self.copy_layout_pin(self.tap_inst[wl, 0], "poly_tap", self.wordline_names[0][wl]) - # self.add_via_stack_center(poly_via.center(), "m1", self.output_layer) - # self.create_horizontal_pin_bus(self.route_layer, offset=corrected_offset, names=self.wordline_names[0], pitch=self.zero_cell.height, length=None) def place_bitline_contacts(self): @@ -361,11 +303,9 @@ class rom_base_array(bitcell_base_array): output_pos = vector(corrected.x, rail_y) self.add_segment_center(self.bitline_layer, corrected, output_pos) - + self.add_layout_pin_rect_center(self.bitline_names[0][bl], self.bitline_layer, output_pos ) - - def route_precharge(self): for bl in range(self.column_size): bl_pin = self.cell_list[0][bl].get_pin("S") @@ -376,7 +316,7 @@ class rom_base_array(bitcell_base_array): bl_end = vector(bl_start.x, pre_out_pin.cy()) self.add_segment_center(self.bitline_layer, bl_start, bl_end) - + upper_precharge = self.precharge_inst.get_pin("precharge_r") lower_precharge = self.tap_inst[self.row_size, self.column_size ].get_pin("poly_tap") @@ -388,13 +328,11 @@ class rom_base_array(bitcell_base_array): end = lower_precharge.center() mid1 = start + vector(wire_offset, 0) mid2 = end + vector(wire_offset, 0) - + self.add_path(layer="m1", coordinates=[start, mid1, mid2, end]) self.add_layout_pin_rect_center(text="precharge_r", layer="m1", offset=mid1) - - def connect_taps(self): array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))] @@ -404,8 +342,6 @@ class rom_base_array(bitcell_base_array): if self.tap_direction == "col": self.route_vertical_pins("active_tap", insts=self.tap_list, layer=self.supply_stack[0], full_width=False) - - def get_next_cell_in_bl(self, row_start, col): for row in range(row_start + 1, self.row_size): if self.data[row][col] == 1: @@ -421,6 +357,4 @@ class rom_base_array(bitcell_base_array): def create_next_bl_interconnect(self, row, col): """create a new net name for a bitline interconnect""" self.current_row = row - return "bli_{0}_{1}".format(row, col) - - + return "bli_{0}_{1}".format(row, col) \ No newline at end of file diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index fedb27f0..f3d4a506 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -1,3 +1,10 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 Regents of the University of California and The Board +# of Regents for the Oklahoma Agricultural and Mechanical College +# (acting for and on behalf of Oklahoma State University) +# All rights reserved. +# from math import ceil, log, sqrt from openram.base import vector @@ -103,24 +110,7 @@ class rom_base_bank(design): # self.data.reverse() debug.info(1, "Read rom binary: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, num_words, self.cols, self.rows, self.words_per_row)) - # self.print_data(chunked_data) - # print("Scrambled") - # self.print_data(scrambled_chunked) - - # self.print_word(self.data, 0, 0) - # self.print_word(self.data, 0, 1) - # self.print_word(self.data, 0, 2) - # self.print_word(self.data, 0, 3) - # print("hex: {0}, binary: {1}, chunked: {2}".format(hex_data, bin_data, chunked_data)) - def print_data(self, data_array): - for row in range(len(data_array)): - print(data_array[row]) - - def print_word(self, data_array, bl, word): - for bit in range(self.word_size): - print(data_array[bl][word + self.words_per_row * bit], end =" ") - print("") def create_netlist(self): self.add_modules() @@ -129,18 +119,13 @@ class rom_base_bank(design): def create_layout(self): - print("Creating ROM bank instances") self.create_instances() - print("Placing ROM bank instances") self.place_instances() - print("Routing decoders to array") self.route_decode_outputs() - print("Routing precharge signal") self.route_precharge() - print("Routing clock signal") self.route_clock() self.route_array_outputs() self.place_top_level_pins() @@ -177,7 +162,6 @@ class rom_base_bank(design): def add_modules(self): - print("Creating bank modules") # TODO: provide technology-specific calculation of these parameters # in sky130 the address control buffer is composed of 2 size 2 NAND gates, # with a beta of 3, each of these gates has gate capacitance of 2 min sized inverters, therefor a load of 4 @@ -487,16 +471,7 @@ class rom_base_bank(design): channel_ll = vector( route_nets[0][0].cx(), route_nets[0][1].cy() + self.m1_pitch * 3) self.create_horizontal_channel_route(netlist=route_nets, offset=channel_ll, layer_stack=self.m1_stack) - # for bit in range(self.word_size): - # mux_pin = self.mux_inst.get_pin("bl_out_{}".format(bit)) - # buf_pin = self.output_buf_inst.get_pin("in_{}".format(bit)) - # mux_out = vector(mux_pin.cx(), mux_pin.by()) - # buf_in = buf_pin.center() - # mid1 = vector(mux_out.x, buf_in.y + bit * self.m2_pitch) - # mid2 = vector(buf_in.x, mid1.y) - # print("start: {0}, mid: {1}, stop: {2}".format(mux_out, mid1, buf_in)) - # self.add_path(layer="m2", coordinates=[mux_out, mid1, mid2, buf_in]) @@ -523,13 +498,4 @@ class rom_base_bank(design): for inst in self.insts: if not inst.mod.name.__contains__("contact"): self.copy_layout_pin(inst, "vdd") - self.copy_layout_pin(inst, "gnd") - - - - - - - - - + self.copy_layout_pin(inst, "gnd") \ No newline at end of file diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index 3b2aac7d..efe9e40f 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -80,7 +80,7 @@ class rom_base_cell(design): # height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) # make the cells square so the pitch of wordlines will match bitlines - # print("height: {0} width: {1}".format(height, width)) + if width > height: self.width = width self.height = width @@ -150,23 +150,4 @@ class rom_base_cell(design): def short_gate(self): - self.add_segment_center(self.bitline_layer, self.get_pin("D").center(), self.get_pin("S").center()) - - # def place_tap(self): - - # tap_x = self.poly_contact.width * 0.5 - # tap_y = self.via.uy() + drc["{0}_to_{0}".format(self.strap_layer)] * 2 - - # contact_pos = vector(tap_x, tap_y) - # self.add_via_center(layers=self.active_stack, - # offset=contact_pos, - # implant_type="p", - # well_type="p") - # self.add_power_pin(name="gnd", - # loc=contact_pos, - # start_layer=self.active_stack[2]) - - - - - + self.add_segment_center(self.bitline_layer, self.get_pin("D").center(), self.get_pin("S").center()) \ No newline at end of file diff --git a/compiler/modules/rom_column_mux.py b/compiler/modules/rom_column_mux.py index ad776ddf..85fe8489 100644 --- a/compiler/modules/rom_column_mux.py +++ b/compiler/modules/rom_column_mux.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2022 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -207,11 +207,4 @@ class rom_column_mux(pgate): self.add_layout_pin_rect_center(text="gnd", layer=self.supply_stack[0], - offset=active_pos) - - # Add well enclosure over all the tx and contact - # if "pwell" in layer: - # self.add_rect(layer="pwell", - # offset=vector(0, 0), - # width=rbc_width, - # height=self.height) + offset=active_pos) \ No newline at end of file diff --git a/compiler/modules/rom_column_mux_array.py b/compiler/modules/rom_column_mux_array.py index fea8f505..856eea71 100644 --- a/compiler/modules/rom_column_mux_array.py +++ b/compiler/modules/rom_column_mux_array.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2022 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -218,4 +218,4 @@ class rom_column_mux_array(design): """ for i in range(len(self.mux_inst)): if i != column_include_num: - self.graph_inst_exclude.add(self.mux_inst[i]) + self.graph_inst_exclude.add(self.mux_inst[i]) \ No newline at end of file diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index b1157fc7..a469b184 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2022 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -28,7 +28,6 @@ class rom_control_logic(design): self.clk_fanout = clk_fanout - if "li" in layer: self.route_stack = self.li_stack else: @@ -37,7 +36,6 @@ class rom_control_logic(design): self.create_netlist() self.create_layout() self.add_boundary() - def create_netlist(self): self.add_modules() @@ -67,8 +65,7 @@ class rom_control_logic(design): fanout=self.output_size, height=self.driver_height, add_wells=True) - - + def add_pins(self): self.add_pin("clk_in", "INPUT") self.add_pin("CS", "INPUT") @@ -90,17 +87,14 @@ class rom_control_logic(design): def place_instances(self): - # nand_y = self.buf_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy() self.nand_inst.place(offset=[self.buf_inst.width, 0]) self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height], mirror="MX") offset = self.driver_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy() - print("offset: {}".format(offset)) self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height - offset], mirror="MX") - def route_insts(self): - + route_width = drc["minwidth_{}".format(self.route_stack[2])] self.copy_layout_pin(self.buf_inst, "A", "clk_in") self.copy_layout_pin(self.buf_inst, "Z", "clk_out") @@ -114,7 +108,7 @@ class rom_control_logic(design): nand_B = self.nand_inst.get_pin("B") - + # Connect buffered clock bar to nand input mid = vector(clk.lx() - route_width - 2 * self.m1_space) @@ -137,11 +131,10 @@ class rom_control_logic(design): self.add_path(self.route_stack[2], [nand_Z.center(), mid, driver_A.center()]) - self.add_via_stack_center(from_layer=nand_Z.layer, to_layer=self.route_stack[2], offset=nand_Z.center()) - + self.add_via_stack_center(from_layer=driver_A.layer, to_layer=self.route_stack[2], offset=driver_A.center()) \ No newline at end of file diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index bb8f0839..fe817383 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -11,11 +11,9 @@ from openram.base import vector, design from openram import OPTS from openram.tech import drc - - class rom_decoder(design): def __init__(self, num_outputs, fanout, strap_spacing, name="", route_layer="m1", output_layer="m1", invert_outputs=False): - + # word lines/ rows / inputs in the base array become the address lines / cols / inputs in the decoder # bit lines / cols / outputs in the base array become the word lines / rows / outputs in the decoder # array gets rotated 90deg so that rows/cols switch @@ -23,8 +21,6 @@ class rom_decoder(design): self.num_outputs = num_outputs self.num_inputs = ceil(log(num_outputs, 2)) self.create_decode_map() - - # for i in range(2 * self.num_inputs): print(self.decode_map[i]) super().__init__(name) @@ -45,7 +41,6 @@ class rom_decoder(design): self.add_modules() self.add_pins() self.create_instances() - def create_layout(self): self.setup_layout_constants() @@ -57,13 +52,13 @@ class rom_decoder(design): self.connect_inputs() self.route_supplies() self.add_boundary() - + def add_boundary(self): ll = self.find_lowest_coords() m1_offset = self.m1_width self.translate_all(vector(0, ll.y)) ur = self.find_highest_coords() - + ur = vector(ur.x, ur.y) super().add_boundary(ll, ur) self.width = ur.x @@ -77,7 +72,7 @@ class rom_decoder(design): # create decoding map that will be the bitmap for the rom decoder # row/col order in the map will be switched in the placed decoder/ for col in range(self.num_inputs): - + # odd cols are address # even cols are address bar col_array = [] @@ -93,18 +88,14 @@ class rom_decoder(design): bin_digit = int(addr[addr_idx]) col_array.append(bin_digit) - # print("addr {0}, at indx {1}, digit {2}".format(addr, addr_idx, bin_digit)) if bin_digit == 0 : inv_col_array.append(1) else : inv_col_array.append(0) - - self.decode_map.append(col_array) self.decode_map.append(inv_col_array) self.decode_map.reverse() - def add_pins(self): for i in range(self.num_inputs): self.add_pin("A{0}".format(i), "INPUT") @@ -116,20 +107,17 @@ class rom_decoder(design): self.add_pin("vdd", "POWER") self.add_pin("gnd", "GROUND") - def add_modules(self): self.control_array = factory.create(module_type="rom_address_control_array", cols=self.num_inputs) - self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), rows=self.num_outputs, fanout=ceil(self.fanout), invert_outputs=self.invert_outputs, tap_spacing=self.strap_spacing) - self.array_mod = factory.create(module_type="rom_base_array", module_name="{}_array".format(self.name), cols=self.num_outputs, @@ -139,13 +127,11 @@ class rom_decoder(design): bitline_layer=self.output_layer, tap_direction="col") - def create_instances(self): self.create_array_inst() self.create_input_buffer() self.create_wordline_buffer() - def create_input_buffer(self): name = "pre_control_array" @@ -159,17 +145,16 @@ class rom_decoder(design): control_pins.append("A_int_{0}".format(i)) for i in range(self.num_inputs): control_pins.append("Ab_int_{0}".format(i)) - - + + control_pins.append("clk") control_pins.append("vdd") control_pins.append("gnd") self.connect_inst(control_pins) - def create_array_inst(self): self.array_inst = self.add_inst(name="decode_array_inst", mod=self.array_mod) - + array_pins = [] for j in range(self.num_outputs): @@ -192,8 +177,6 @@ class rom_decoder(design): pwr_pins = ["vdd", "gnd"] self.connect_inst(in_pins + out_pins + pwr_pins) - - def place_input_buffer(self): wl = self.array_mod.row_size - 1 align = self.array_inst.get_pin(self.array_mod.wordline_names[0][wl]).cx() - self.buf_inst.get_pin("A0_out").cx() @@ -202,12 +185,10 @@ class rom_decoder(design): self.copy_layout_pin(self.buf_inst, "clk") - - def place_array(self): offset = vector(self.array_mod.height, self.control_array.height + self.m1_width + self.poly_contact.width) self.array_inst.place(offset, rotate=90) - + def place_driver(self): offset = vector(self.array_inst.height + self.m1_width, self.array_inst.by()) @@ -231,7 +212,6 @@ class rom_decoder(design): route_pins = array_pins + driver_pins self.connect_row_pins(self.output_layer, route_pins, round=True) - def connect_inputs(self): self.copy_layout_pin(self.array_inst, "precharge") @@ -263,28 +243,4 @@ class rom_decoder(design): self.copy_layout_pin(self.array_inst, "gnd") self.copy_layout_pin(self.wordline_buf_inst, "gnd") - self.copy_layout_pin(self.buf_inst, "gnd") - - # Extend nwells to connect with eachother - # self.extend_wells() - - - def extend_wells(self): - precharge_well_rx = self.array_inst.get_pins("vdd")[0].cx() + 0.5 * self.nwell_width - precharge_well_lx = precharge_well_rx - self.array_mod.precharge_array.height - 0.5 * self.nwell_width - self.array_mod.precharge_array.well_offset - - - offset = vector(precharge_well_rx ,self.array_inst.by()) - - self.add_label(text="well_right", layer="nwell", offset=offset) - offset = vector(precharge_well_lx ,self.array_inst.by()) - self.add_label(text="well_left", layer="nwell", offset=offset) - vdd_pins=self.buf_inst.get_pins("vdd").copy() - print(vdd_pins) - well_by = vdd_pins[0].cy() - # well_ll = vector(precharge_well_lx, well_by) - well_ll = vector(self.buf_inst.rx(), well_by) - # self.add_rect(layer="nwell", offset=well_ll, height = self.array_inst.by() - well_by, width=precharge_well_rx - self.buf_inst.rx()) - - - + self.copy_layout_pin(self.buf_inst, "gnd") \ No newline at end of file diff --git a/compiler/modules/rom_dummy_cell.py b/compiler/modules/rom_dummy_cell.py deleted file mode 100644 index 8ebd138f..00000000 --- a/compiler/modules/rom_dummy_cell.py +++ /dev/null @@ -1,87 +0,0 @@ -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2021 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 openram.base import design -from openram.base import vector -from openram import OPTS -from openram.sram_factory import factory -from openram.tech import drc - - -class rom_dummy_cell(design): - - def __init__(self, name="", cell_name=None, add_source_contact=False, add_drain_contact=False, route_layer="m1"): - super().__init__(name, cell_name) - self.route_layer = route_layer - self.add_source_contact="li" - self.add_drain_contact="li" - self.create_netlist() - self.create_layout() - - def create_netlist(self): - #creates nmos for layout dimensions - self.add_nmos() - - #set height and width such that the cell will tile perfectly by only ofsetting in the array by its width and height - - - - def create_layout(self): - - - self.setup_drc_offsets() - - self.add_boundary() - self.add_poly() - self.add_metal() - #self.add_label("0,0", self.route_layer) - - - - def add_poly(self): - - poly_x = 0.5 * (self.nmos.poly_height + self.poly_extend_active_spacing) - # 0.5 * self.nmos.contact_width + self.contact_to_gate - - self.poly = self.add_rect_center("poly", vector(poly_x, self.base_width * 0.5), 2 * poly_x, self.poly_width) - - def add_metal(self): - - if self.route_layer == "li": - via = "mcon" - else: - via = "via{}".format(self.route_layer[len(self.route_layer) - 1]) - wire_y = self.height + drc["minwidth_{}".format(via)] * 0.5 - wire_x = 0.5 * (self.width - self.poly_extend_active_spacing) - - wire_start = vector( wire_x, 0) - wire_end = vector(wire_x, wire_y) - - # if self.route_layer == 'm1': - - # if self.drain_contact: - # self.add_via_center(self.li_stack, [wire_x, wire_y]) - # if self.source_contact: - # self.add_via_center(self.li_stack, [self.width, wire_y]) - - self.add_path(self.route_layer, [wire_start, wire_end]) - - # drain_x = 0 - # drain_y = 0.5 * (self.width) - source_x = 0.5 * (self.width - self.poly_extend_active_spacing) - source_y = 0 - source_pos = vector(source_x, source_y) - self.add_layout_pin_rect_center("S", self.route_layer, source_pos) - - drain_pos = vector(source_x, self.height) - self.add_layout_pin_rect_center("D", self.route_layer, drain_pos) - - - - - diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index d5731d93..a31b86d4 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -1,11 +1,10 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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 openram.base import design from openram.base import vector from openram import OPTS @@ -27,11 +26,6 @@ class rom_poly_tap(design): #for layout constants self.dummy = factory.create(module_type="rom_base_cell") - # if self.tx_type == "nmos": - # self.dummy = factory.create(module_type="rom_base_cell") - # else: - # self.dummy = factory.create(module_type="rom_precharge_cell") - self.pmos = factory.create(module_type="ptx", tx_type="pmos") def create_layout(self): @@ -41,12 +35,7 @@ class rom_poly_tap(design): if self.add_tap: self.place_active_tap() self.extend_poly() - - # if self.length != 0: - # self.place_strap() - - def add_boundary(self): contact_width = self.poly_contact.width @@ -57,7 +46,7 @@ class rom_poly_tap(design): super().add_boundary() def place_via(self): - + contact_width = self.poly_contact.width # DRC rule here is hard coded since licon.9 isnt included in skywater130 tech file @@ -71,7 +60,7 @@ class rom_poly_tap(design): contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact if self.tx_type == "nmos": - + # contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact # contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) self.contact_x_offset = 0 @@ -86,15 +75,6 @@ class rom_poly_tap(design): offset=self.contact_offset) self.add_layout_pin_rect_center("poly_tap", self.strap_layer, self.contact_offset) - - # def place_strap(self): - - # strap_start = vector(self.via.lx() , self.via.cy()) - - # strap_end = vector( self.dummy.width * (self.length + 1), self.via.cy()) - - # self.strap = self.add_path(self.strap_layer, (strap_start, strap_end)) - def extend_poly(self): y_offset = 0 if self.tx_type == "pmos": @@ -104,8 +84,6 @@ class rom_poly_tap(design): self.add_segment_center("poly", start, vector(self.via.cx() + self.pitch_offset, self.via.cy() + y_offset)) self.add_segment_center("poly", start, vector(0, self.via.cy() + y_offset)) - - def place_active_tap(self): gap = self.poly_extend_active - 0.5 * ( self.active_contact.height - self.poly_contact.width ) offset = self.active_space - gap @@ -113,17 +91,15 @@ class rom_poly_tap(design): tap_x = self.via.cx() + offset tap_y = self.via.cy() + self.dummy.width * 0.5 contact_pos = vector(tap_x, tap_y) - # edge of the next nmos active_edge = self.dummy.width - self.dummy.cell_inst.height - self.poly_extend_active - + # edge of the active contact tap_edge = tap_x + 0.5 * self.active_contact.height self.pitch_offset += (self.active_space * 2) - (tap_edge - active_edge) + self.contact_x_offset - - if self.tx_type == "nmos": + if self.tx_type == "nmos": self.add_via_center(layers=self.active_stack, offset=contact_pos, implant_type="p", @@ -132,6 +108,4 @@ class rom_poly_tap(design): self.add_power_pin(name="gnd", loc=contact_pos, start_layer=self.active_stack[2]) - self.add_layout_pin_rect_center("active_tap", self.supply_stack[0], contact_pos) - - + self.add_layout_pin_rect_center("active_tap", self.supply_stack[0], contact_pos) \ No newline at end of file diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index e3de7ed4..6b5c13e9 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -13,8 +13,6 @@ from openram.sram_factory import factory from openram.base import vector from openram.tech import layer, drc - - class rom_precharge_array(design): """ An array of inverters to create the inverted address lines for the rom decoder @@ -38,7 +36,7 @@ class rom_precharge_array(design): else: self.strap_spacing = 0 - + if strap_spacing != 0: self.num_straps = ceil(self.cols / self.strap_spacing) self.array_col_size = self.cols + self.num_straps @@ -54,8 +52,6 @@ class rom_precharge_array(design): self.create_modules() self.add_pins() self.create_instances() - - def create_layout(self): self.width = self.cols * self.pmos.width @@ -64,11 +60,10 @@ class rom_precharge_array(design): self.create_layout_pins() self.route_supply() self.connect_taps() - + self.add_boundary() self.extend_well() - def add_boundary(self): # self.translate_all(self.well_ll) ur = self.find_highest_coords() @@ -92,7 +87,6 @@ class rom_precharge_array(design): self.add_pin("pre_bl{0}_out".format(col), "OUTPUT") self.add_pin("gate", "INPUT") self.add_pin("vdd", "POWER") - def create_instances(self): self.array_insts = [] @@ -101,13 +95,11 @@ class rom_precharge_array(design): self.create_poly_tap(-1) for col in range(self.cols): - + if col % self.strap_spacing == 0: self.create_poly_tap(col) self.create_precharge_tx(col) - - def create_precharge_tx(self, col): name = "pmos_c{0}".format(col) pmos = self.add_inst(name=name, mod=self.pmos) @@ -131,9 +123,9 @@ class rom_precharge_array(design): # columns are bit lines cell_x = 0 - + for col in range(self.cols): - + if col % self.strap_spacing == 0: self.tap_insts[strap_num].place(vector(cell_x, cell_y + self.poly_tap.height)) strap_num += 1 @@ -141,19 +133,11 @@ class rom_precharge_array(design): if self.tap_direction == "col": cell_x += self.poly_tap.pitch_offset - - # if col % self.strap_spacing == 0 : - # self.tap_insts[strap_num].place(vector(cell_x, cell_y)) - # self.add_label("debug", "li", vector(cell_x, cell_y)) - # cell_x += self.poly_tap.width - self.pmos_insts[col].place(vector(cell_x, cell_y)) self.add_label("debug", "li", vector(cell_x, cell_y)) cell_x += self.pmos.width - print(self.tap_insts) self.tap_insts[strap_num].place(vector(cell_x, cell_y + self.poly_tap.height)) - def create_layout_pins(self): self.copy_layout_pin(self.tap_insts[0], "poly_tap", "gate") @@ -162,7 +146,6 @@ class rom_precharge_array(design): source_pin = self.pmos_insts[col].get_pin("D") bl = "pre_bl{0}_out".format(col) self.add_layout_pin_rect_center(bl, self.route_layer, source_pin.center()) - def route_supply(self): @@ -170,9 +153,6 @@ class rom_precharge_array(design): # vdd = [self.pmos_insts[i].get_pin("vdd") for i in range(self.cols)]routeroute_horizon_horizon self.route_horizontal_pins("vdd", insts=self.pmos_insts, layer=self.strap_layer) - - - def connect_taps(self): array_pins = [self.tap_insts[i].get_pin("poly_tap") for i in range(len(self.tap_insts))] @@ -183,12 +163,8 @@ class rom_precharge_array(design): start = vector(tap_pin.cx(), tap_pin.by()) end = vector(start.x, tap.mod.get_pin("poly_tap").cy()) self.add_segment_center(layer="poly", start=start, end=end) - print(end) offset_start = vector(end.x - self.poly_tap.width + self.poly_extend_active, end.y) offset_end = end + vector(0.5*self.poly_width, 0) - print(self.poly_tap.width) - print(end) - print(offset_start) self.add_segment_center(layer="poly", start=offset_start, end=offset_end) def extend_well(self): @@ -198,4 +174,4 @@ class rom_precharge_array(design): well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width well_ll = vector(0, well_y) - self.add_rect("nwell", well_ll, self.width , self.height - well_y) + self.add_rect("nwell", well_ll, self.width , self.height - well_y) \ No newline at end of file diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index f83a5c51..13cc8c2b 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -13,23 +13,18 @@ from openram import OPTS from openram.sram_factory import factory from openram.tech import drc - class rom_precharge_cell(rom_base_cell): def __init__(self, name="", route_layer="m1", supply_layer="li"): self.supply_layer = supply_layer super().__init__(name=name, bitline_layer=route_layer) - - def create_layout(self): super().create_layout() self.place_tap() self.extend_well() - - def add_modules(self): width = pgate.nearest_bin("pmos", drc["minwidth_tx"]) self.pmos = factory.create(module_type="ptx", @@ -46,7 +41,6 @@ class rom_precharge_cell(rom_base_cell): ) self.connect_inst(["bitline", "gate", "vdd", "vdd"]) - def add_pins(self): pin_list = ["vdd", "gate", "bitline"] dir_list = ["POWER", "INPUT", "OUTPUT"] @@ -66,7 +60,6 @@ class rom_precharge_cell(rom_base_cell): #so that the poly taps are far enough apart self.poly_tap_offset = (self.base_width - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") - def extend_well(self): well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width @@ -75,7 +68,6 @@ class rom_precharge_cell(rom_base_cell): height = self.get_pin("D").cy() + 0.5 * self.nwell_width - well_y self.add_rect("nwell", well_ll, self.width , height) - def place_tap(self): source = self.cell_inst.get_pin("S") @@ -91,13 +83,14 @@ class rom_precharge_cell(rom_base_cell): self.add_via_stack_center(offset=pos, from_layer=self.active_stack[2], to_layer=self.supply_layer) - + bitline_offset = vector( 2 * (drc("minwidth_{}".format(self.bitline_layer)) + drc("{0}_to_{0}".format(self.bitline_layer))) ,0) - + self.add_layout_pin_rect_center("vdd", self.supply_layer, pos - bitline_offset) self.add_path(self.supply_layer, [self.get_pin("vdd").center(), pos, self.get_pin("S").center()]) self.remove_layout_pin("S") + def place_bitline(self): - pass + pass \ No newline at end of file diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index ae2ea848..56df91a9 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -1,6 +1,6 @@ # See LICENSE for licensing information. # -# Copyright (c) 2016-2022 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -13,7 +13,6 @@ from openram.tech import layer from openram.tech import layer_properties as layer_props from openram import OPTS - class rom_wordline_driver_array(design): """ Creates a Wordline Buffer/Inverter array @@ -82,7 +81,6 @@ class rom_wordline_driver_array(design): height=b.height, add_wells=False) - def route_supplies(self): """ Add a pin for each row of vdd/gnd which @@ -117,7 +115,6 @@ class rom_wordline_driver_array(design): self.wld_inst[row].place(offset=offset) y_offset += self.wld_inst[row].height - self.width = self.wl_driver.width self.height = self.wl_driver.height * self.rows @@ -143,7 +140,6 @@ class rom_wordline_driver_array(design): else: wl_offset = out_pin.rc() - vector( 0.5 * route_width, 0) - end = vector(wl_offset.x, \ self.get_pin("in_{}".format(row)).cy() + 0.5 * route_width) self.add_segment_center(layer=self.route_layer, @@ -156,7 +152,6 @@ class rom_wordline_driver_array(design): self.add_layout_pin_rect_center(text="out_{}".format(row), layer=self.route_layer, offset=end - vector(0, 0.5 * route_width)) - def place_taps(self): for wl in range(0 , self.rows, self.tap_spacing): @@ -182,7 +177,6 @@ class rom_wordline_driver_array(design): contact_pos = vector( gnd_pin2.cx(), left_edge) self.place_tap(contact_pos, "p") - def place_tap(self, offset, well_type): self.add_via_center(layers=self.active_stack, offset=offset, @@ -196,5 +190,4 @@ class rom_wordline_driver_array(design): pin = "gnd" else: pin = "vdd" - self.add_layout_pin_rect_center(text=pin, layer=self.supply_layer, offset=offset) - + self.add_layout_pin_rect_center(text=pin, layer=self.supply_layer, offset=offset) \ No newline at end of file diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/05_rom_array_test.py index 8854f667..c7a03ea1 100644 --- a/compiler/tests/05_rom_array_test.py +++ b/compiler/tests/05_rom_array_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. diff --git a/compiler/tests/05_rom_base_bank_1kB_test.py b/compiler/tests/05_rom_base_bank_1kB_test.py index 39a9e41f..e6d9333f 100644 --- a/compiler/tests/05_rom_base_bank_1kB_test.py +++ b/compiler/tests/05_rom_base_bank_1kB_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -24,10 +24,8 @@ class rom_bank_test(openram_test): debug.info(1, "Testing 1kB rom cell") a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_1kB", word_size=1) - print('wriitng file') a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) - openram.end_openram() diff --git a/compiler/tests/05_rom_base_bank_2kB_test.py b/compiler/tests/05_rom_base_bank_2kB_test.py index d1f59fe7..983895de 100644 --- a/compiler/tests/05_rom_base_bank_2kB_test.py +++ b/compiler/tests/05_rom_base_bank_2kB_test.py @@ -24,10 +24,8 @@ class rom_bank_test(openram_test): debug.info(1, "Testing 2kB rom cell") a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_2kB", word_size=1) - print('wriitng file') a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) - openram.end_openram() diff --git a/compiler/tests/05_rom_base_bank_4kB_test.py b/compiler/tests/05_rom_base_bank_4kB_test.py index eb63776b..1d34b3ac 100644 --- a/compiler/tests/05_rom_base_bank_4kB_test.py +++ b/compiler/tests/05_rom_base_bank_4kB_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -24,10 +24,8 @@ class rom_bank_test(openram_test): debug.info(1, "Testing 4kB rom cell") a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_4kB", word_size=2) - print('wriitng file') a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) - openram.end_openram() diff --git a/compiler/tests/05_rom_base_bank_8kB_test.py b/compiler/tests/05_rom_base_bank_8kB_test.py index 591d5055..bceb93b4 100644 --- a/compiler/tests/05_rom_base_bank_8kB_test.py +++ b/compiler/tests/05_rom_base_bank_8kB_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -24,10 +24,9 @@ class rom_bank_test(openram_test): debug.info(1, "Testing 8kB rom cell") a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_8kB", word_size=2) - print('wriitng file') a.sp_write(OPTS.openram_temp + 'simulation_file_8kB.sp') self.local_check(a) - + openram.end_openram() diff --git a/compiler/tests/05_rom_base_bank_small_test.py b/compiler/tests/05_rom_base_bank_small_test.py index 69128d83..1bc4bfa1 100644 --- a/compiler/tests/05_rom_base_bank_small_test.py +++ b/compiler/tests/05_rom_base_bank_small_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. @@ -26,7 +26,6 @@ class rom_bank_test(openram_test): a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_64B", word_size=1) self.local_check(a) - print('wriitng file') a.sp_write(OPTS.openram_temp + 'simulation_file.sp') openram.end_openram() diff --git a/compiler/tests/05_rom_column_mux_array_test.py b/compiler/tests/05_rom_column_mux_array_test.py index 17915852..c937e834 100644 --- a/compiler/tests/05_rom_column_mux_array_test.py +++ b/compiler/tests/05_rom_column_mux_array_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2022 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. diff --git a/compiler/tests/05_rom_control_logic_test.py b/compiler/tests/05_rom_control_logic_test.py index e6c5d173..12b1fbdb 100644 --- a/compiler/tests/05_rom_control_logic_test.py +++ b/compiler/tests/05_rom_control_logic_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. diff --git a/compiler/tests/05_rom_decoder_buffer_array_test.py b/compiler/tests/05_rom_decoder_buffer_array_test.py index 915dfe34..7231863d 100644 --- a/compiler/tests/05_rom_decoder_buffer_array_test.py +++ b/compiler/tests/05_rom_decoder_buffer_array_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. diff --git a/compiler/tests/05_rom_decoder_test.py b/compiler/tests/05_rom_decoder_test.py index b2447fb4..0ecea5cf 100644 --- a/compiler/tests/05_rom_decoder_test.py +++ b/compiler/tests/05_rom_decoder_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. diff --git a/compiler/tests/05_rom_precharge_array_test.py b/compiler/tests/05_rom_precharge_array_test.py index 79bca2b3..1d067709 100644 --- a/compiler/tests/05_rom_precharge_array_test.py +++ b/compiler/tests/05_rom_precharge_array_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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. diff --git a/compiler/tests/05_rom_wordline_driver_array_test.py b/compiler/tests/05_rom_wordline_driver_array_test.py index 36144661..f3175127 100644 --- a/compiler/tests/05_rom_wordline_driver_array_test.py +++ b/compiler/tests/05_rom_wordline_driver_array_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2022 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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 af0209ec96286022ce14276de9da936164723405 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Tue, 28 Feb 2023 21:10:52 -0800 Subject: [PATCH 53/98] passing code style --- compiler/base/hierarchy_layout.py | 4 +- compiler/modules/pinvbuf.py | 6 +- compiler/modules/rom_address_control_array.py | 4 +- compiler/modules/rom_address_control_buf.py | 5 - compiler/modules/rom_base_array.py | 61 ++++----- compiler/modules/rom_base_bank.py | 118 +++++++++--------- compiler/modules/rom_base_cell.py | 40 +++--- compiler/modules/rom_column_mux.py | 2 +- compiler/modules/rom_column_mux_array.py | 10 +- compiler/modules/rom_control_logic.py | 24 ++-- compiler/modules/rom_decoder.py | 28 ++--- compiler/modules/rom_poly_tap.py | 8 +- compiler/modules/rom_precharge_array.py | 14 +-- compiler/modules/rom_precharge_cell.py | 14 +-- compiler/modules/rom_wordline_driver_array.py | 4 +- compiler/tests/05_rom_base_bank_2kB_test.py | 2 +- 16 files changed, 170 insertions(+), 174 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index c1227cc2..00833f77 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -703,7 +703,7 @@ class layout(): bins = {} for pin in pins: y = pin.cy() - if round: + if round: y = round_to_grid(y) try: bins[y].append(pin) @@ -794,7 +794,7 @@ class layout(): bins = {} for pin in pins: x = pin.cx() - if round: + if round: x = round_to_grid(x) try: bins[x].append(pin) diff --git a/compiler/modules/pinvbuf.py b/compiler/modules/pinvbuf.py index c277dd2a..c71c6da9 100644 --- a/compiler/modules/pinvbuf.py +++ b/compiler/modules/pinvbuf.py @@ -142,7 +142,7 @@ class pinvbuf(pgate): # end_point = vector(a4_pin.cx(), a4_pin.by() - self.m1_space - self.contact_space) self.add_path(route_stack[2], [z1_pin.center(), mid_point, end_point]) - + self.add_via_stack_center(from_layer=z1_pin.layer, to_layer=route_stack[2], offset=z1_pin.center()) @@ -151,11 +151,11 @@ class pinvbuf(pgate): to_layer=route_stack[2], offset=end_point) - + self.add_segment_center(a4_pin.layer, end_point, a4_pin.center()) else: # inv1 Z to inv4 A (up and over) - + mid_point = vector(z1_pin.cx(), a4_pin.cy()) self.add_wire(route_stack, [z1_pin.center(), mid_point, a4_pin.center()]) diff --git a/compiler/modules/rom_address_control_array.py b/compiler/modules/rom_address_control_array.py index e02d0443..e4fdf019 100644 --- a/compiler/modules/rom_address_control_array.py +++ b/compiler/modules/rom_address_control_array.py @@ -26,7 +26,7 @@ class rom_address_control_array(design): name = "rom_inv_array_{0}".format(cols) if inv_height == None: self.inv_height = dff.height * 0.5 - else: + else: self.inv_height = inv_height @@ -46,7 +46,7 @@ class rom_address_control_array(design): def create_layout(self): self.width = self.cols * self.addr_control.width - self.height = self.addr_control.height + self.height = self.addr_control.height self.setup_layout_constants() self.place_instances() self.route_clk() diff --git a/compiler/modules/rom_address_control_buf.py b/compiler/modules/rom_address_control_buf.py index c0950dda..b69ccb1b 100644 --- a/compiler/modules/rom_address_control_buf.py +++ b/compiler/modules/rom_address_control_buf.py @@ -130,8 +130,6 @@ class rom_address_control_buf(design): self.add_via_stack_center(from_layer=self.inv_layer, to_layer=self.route_layer, offset=self.addr_bar_nand.get_pin("A").center()) self.add_segment_center(self.route_layer, clk_offset, vector(clk_offset.x, clk2_pin.cy())) - - # Route first NAND output to second NAND input start = A_out.center() end = Aint_in.center() @@ -139,18 +137,15 @@ class rom_address_control_buf(design): self.add_via_stack_center(Aint_in.center(), self.inv_layer, "m2") self.add_via_stack_center(A_out.center(), self.inv_layer, "m2") - # Route first NAND to output pin self.add_segment_center("m2", end, vector(end.x, self.addr_bar_nand.uy())) self.add_layout_pin_rect_center("A_out", offset=vector(end.x, self.addr_bar_nand.uy() - 0.5 * self.m2_width), layer="m2") - # Route second NAND to output pin self.add_via_stack_center(Abar_out.center(), self.inv_layer, "m2") self.add_segment_center("m2", Abar_out.center(), vector(Abar_out.cx(), self.addr_bar_nand.uy())) self.add_layout_pin_rect_center("Abar_out", offset=vector(Abar_out.cx(), self.addr_bar_nand.uy() - 0.5 * self.m2_width), layer="m2") - # Route inverter output to NAND end = vector(Abar_int_out.cx(), Abar_in.cy() + 0.5 * self.interconnect_width) self.add_segment_center(self.inv_layer, Abar_int_out.center(), end) diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index c6af1470..af9d81d4 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -11,7 +11,7 @@ import math from .bitcell_base_array import bitcell_base_array from openram.base import vector from openram import OPTS -from openram.sram_factory import factory +from openram.sram_factory import factory from openram.tech import drc, layer class rom_base_array(bitcell_base_array): @@ -24,13 +24,13 @@ class rom_base_array(bitcell_base_array): self.tap_direction = tap_direction self.pitch_match = pitch_match self.bitline_layer = bitline_layer - self.strap_spacing = strap_spacing + self.strap_spacing = strap_spacing self.wordline_layer = wordline_layer self.data_col_size = self.column_size self.tap_spacing = tap_spacing if strap_spacing != 0: - self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing) + self.array_col_size = self.column_size + math.ceil(self.column_size / strap_spacing) else: self.array_col_size = self.column_size self.create_all_bitline_names() @@ -41,7 +41,7 @@ class rom_base_array(bitcell_base_array): def create_netlist(self): self.add_modules() self.add_pins() - + self.create_cell_instances() self.create_precharge_inst() @@ -68,28 +68,28 @@ class rom_base_array(bitcell_base_array): ur = vector(ur.x, ur.y - self.m1_width) super().add_boundary(vector(0, 0), ur) self.width = ur.x - self.height = ur.y - + self.height = ur.y + def add_modules(self): - self.zero_cell = factory.create(module_name="rom_base_zero_cell", - module_type="rom_base_cell", - bitline_layer=self.bitline_layer, + self.zero_cell = factory.create(module_name="rom_base_zero_cell", + module_type="rom_base_cell", + bitline_layer=self.bitline_layer, bit_value=0) - self.one_cell = factory.create(module_name="rom_base_one_cell", - module_type="rom_base_cell", - bitline_layer=self.bitline_layer, + self.one_cell = factory.create(module_name="rom_base_one_cell", + module_type="rom_base_cell", + bitline_layer=self.bitline_layer, bit_value=1) if self.tap_direction == "row": - self.poly_tap = factory.create(module_type="rom_poly_tap") - else: + self.poly_tap = factory.create(module_type="rom_poly_tap") + else: self.poly_tap = factory.create(module_type="rom_poly_tap", add_tap=True) - self.precharge_array = factory.create(module_type="rom_precharge_array", - cols=self.column_size, - strap_spacing=self.strap_spacing, - route_layer=self.bitline_layer, + self.precharge_array = factory.create(module_type="rom_precharge_array", + cols=self.column_size, + strap_spacing=self.strap_spacing, + route_layer=self.bitline_layer, strap_layer=self.wordline_layer, tap_direction=self.tap_direction) @@ -112,7 +112,8 @@ class rom_base_array(bitcell_base_array): self.cell_inst = {} self.cell_list = [] self.current_row = 0 - #list of current bitline interconnect nets, starts as the same as the bitline list and is updated when new insts of cells are added + # list of current bitline interconnect nets, + # starts as the same as the bitline list and is updated when new insts of cells are added self.int_bl_list = self.bitline_names[0].copy() #When rotated correctly rows are word lines for row in range(self.row_size + 1): @@ -126,7 +127,7 @@ class rom_base_array(bitcell_base_array): self.create_poly_tap(row, col) new_inst = self.create_cell(row, col) - + self.cell_inst[row, col] = new_inst row_list.append(new_inst) @@ -151,7 +152,7 @@ class rom_base_array(bitcell_base_array): # when col = 0, bl_h is connected to precharge, otherwise connect to previous bl connection # when col = col_size - 1 connected column_sizeto gnd otherwise create new bl connection - if row == self.row_size : + if row == self.row_size: bl_l = self.int_bl_list[col] bl_h = "gnd" @@ -168,16 +169,16 @@ class rom_base_array(bitcell_base_array): self.connect_inst([bl_h, bl_l, "precharge", "gnd"]) elif self.data[row][col] == 1: new_inst = self.add_inst(name=name, mod=self.one_cell) - self.connect_inst([bl_h, bl_l, self.wordline_names[0][row], "gnd"]) - else: + self.connect_inst([bl_h, bl_l, self.wordline_names[0][row], "gnd"]) + else: new_inst = self.add_inst(name=name, mod=self.zero_cell) self.connect_inst([bl_h, self.wordline_names[0][row], "gnd"]) - return new_inst + return new_inst def create_precharge_inst(self): prechrg_pins = self.bitline_names[0].copy() - + prechrg_pins.append("precharge") prechrg_pins.append("vdd") self.precharge_inst = self.add_inst(name="bitcell_array_precharge", mod=self.precharge_array) @@ -215,14 +216,14 @@ class rom_base_array(bitcell_base_array): cell_y = row * (self.zero_cell.height) + pitch_offset cell_x = 0 - for col in range(self.column_size): + for col in range(self.column_size): if col % self.strap_spacing == 0: self.strap_pos[row, col] = vector(cell_x, cell_y) self.tap_inst[row, col].place(self.strap_pos[row, col]) if self.tap_direction == "col": - cell_x += self.poly_tap.pitch_offset + cell_x += self.poly_tap.pitch_offset self.cell_pos[row, col] = vector(cell_x, cell_y) self.cell_inst[row, col].place(self.cell_pos[row, col]) @@ -247,7 +248,7 @@ class rom_base_array(bitcell_base_array): end = drain.center() self.add_segment_center(self.bitline_layer, start, end) self.place_well_tap(row, col) - + def place_well_tap(self, row, col): cell = self.cell_inst[row, col] source = cell.get_pin("S") @@ -271,7 +272,7 @@ class rom_base_array(bitcell_base_array): directions="nonpref") self.add_via_stack_center(offset=tap_pos, from_layer=self.active_stack[2], - to_layer=self.wordline_layer) + to_layer=self.wordline_layer) self.add_layout_pin_rect_center("gnd", self.wordline_layer, tap_pos) def place_precharge(self): @@ -279,7 +280,7 @@ class rom_base_array(bitcell_base_array): self.precharge_inst.place(offset=self.precharge_offset) self.copy_layout_pin(self.precharge_inst, "vdd") self.copy_layout_pin(self.precharge_inst, "gate", "precharge") - + def place_wordline_contacts(self): for wl in range(self.row_size): diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index f3d4a506..a8b9f011 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -30,7 +30,7 @@ class rom_base_bank(design): self.num_inputs = ceil(log(self.rows, 2)) self.col_bits = ceil(log(self.words_per_row, 2)) self.row_bits = self.num_inputs - + # self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] self.strap_spacing = strap_spacing self.tap_spacing = 8 @@ -38,7 +38,7 @@ class rom_base_bank(design): self.bitline_layer = "m1" self.wordline_layer = "m2" - + if "li" in layer: self.route_stack = self.m1_stack else: @@ -52,7 +52,7 @@ class rom_base_bank(design): Reads a hexadecimal file from a given directory to be used as the data written to the ROM endian is either "big" or "little" word_size is the number of bytes per word - sets the row and column size based on the size of binary input, tries to keep array as square as possible, + sets the row and column size based on the size of binary input, tries to keep array as square as possible, """ def read_binary(self, data_file, word_size=2, endian="big", scramble_bits=False): @@ -70,7 +70,7 @@ class rom_base_bank(design): bin_data = [int(x) for x in bin_data] # data size in bytes - data_size = len(bin_data) / 8 + data_size = len(bin_data) / 8 num_words = int(data_size / word_size) bytes_per_col = sqrt(num_words) @@ -88,11 +88,11 @@ class rom_base_bank(design): if len(row_data) < bits_per_row: row_data = [0] * (bits_per_row - len(row_data)) + row_data chunked_data.append(row_data) - - + + # if endian == "big": - - + + self.data = chunked_data if scramble_bits: scrambled_chunked = [] @@ -104,9 +104,9 @@ class rom_base_bank(design): scambled_data.append(row_data[bit + word * self.word_size]) scrambled_chunked.append(scambled_data) self.data = scrambled_chunked - - - + + + # self.data.reverse() debug.info(1, "Read rom binary: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, num_words, self.cols, self.rows, self.words_per_row)) @@ -117,7 +117,7 @@ class rom_base_bank(design): self.add_pins() - + def create_layout(self): self.create_instances() self.place_instances() @@ -144,7 +144,7 @@ class rom_base_bank(design): self.interconnect_layer_pitch = drc["{0}_to_{0}".format(self.interconnect_layer)] def add_pins(self): - + self.add_pin("clk", "INPUT") self.add_pin("CS", "INPUT") @@ -163,59 +163,59 @@ class rom_base_bank(design): def add_modules(self): # TODO: provide technology-specific calculation of these parameters - # in sky130 the address control buffer is composed of 2 size 2 NAND gates, + # in sky130 the address control buffer is composed of 2 size 2 NAND gates, # with a beta of 3, each of these gates has gate capacitance of 2 min sized inverters, therefor a load of 4 addr_control_buffer_effort = 4 # a single min sized nmos makes up 1/4 of the input capacitance of a min sized inverter bitcell_effort = 0.25 - # Takes into account inverter sizing + # Takes into account inverter sizing wordline_effort = bitcell_effort * 0.5 # a single min sized pmos plus a single min sized nmos have approximately half the gate capacitance of a min inverter # an additional 0.2 accounts for the long wire capacitance and add delay to gaurentee the read timing precharge_cell_effort = 0.5 + 0.2 - self.array = factory.create(module_type="rom_base_array", - cols=self.cols, - rows=self.rows, - strap_spacing=self.strap_spacing, - bitmap=self.data, + self.array = factory.create(module_type="rom_base_array", + cols=self.cols, + rows=self.rows, + strap_spacing=self.strap_spacing, + bitmap=self.data, bitline_layer=self.bitline_layer, wordline_layer=self.wordline_layer, pitch_match=True, - tap_spacing=self.tap_spacing) - - - self.decode_array = factory.create(module_name="rom_row_decode", - module_type="rom_decoder", - num_outputs=self.rows, - strap_spacing=self.strap_spacing, - route_layer=self.route_layer, + tap_spacing=self.tap_spacing) + + + self.decode_array = factory.create(module_name="rom_row_decode", + module_type="rom_decoder", + num_outputs=self.rows, + strap_spacing=self.strap_spacing, + route_layer=self.route_layer, fanout=(self.cols)*wordline_effort ) - - self.column_mux = factory.create(module_type="rom_column_mux_array", + + self.column_mux = factory.create(module_type="rom_column_mux_array", columns=self.cols, word_size=self.word_size, tap_spacing=self.strap_spacing, bitline_layer=self.interconnect_layer, input_layer=self.bitline_layer) - + self.column_decode = factory.create(module_name="rom_column_decode", - module_type="rom_decoder", - num_outputs=self.words_per_row, - strap_spacing=self.strap_spacing, - route_layer=self.route_layer, + module_type="rom_decoder", + num_outputs=self.words_per_row, + strap_spacing=self.strap_spacing, + route_layer=self.route_layer, fanout=2, invert_outputs=True ) - self.control_logic = factory.create(module_type="rom_control_logic", + self.control_logic = factory.create(module_type="rom_control_logic", num_outputs=(self.cols + self.words_per_row * precharge_cell_effort) \ - + (addr_control_buffer_effort * self.col_bits), + + (addr_control_buffer_effort * self.col_bits), clk_fanout=(self.row_bits * addr_control_buffer_effort) + (precharge_cell_effort * self.rows), height=self.column_decode.height ) - + self.bitline_inv = factory.create(module_type="rom_wordline_driver_array", module_name="rom_bitline_inverter", rows=self.cols, @@ -247,7 +247,7 @@ class rom_base_bank(design): bitline_bar = ["bl_b_{}".format(bl) for bl in range(self.cols)] pre_buf_outputs = ["rom_out_prebuf_{}".format(bit) for bit in range(self.word_size)] outputs = ["rom_out_{}".format(bl) for bl in range(self.word_size)] - + array_pins = bitlines + wordlines + prechrg + vdd + gnd @@ -283,7 +283,7 @@ class rom_base_bank(design): - + def place_instances(self): self.place_row_decoder() self.place_data_array() @@ -297,10 +297,10 @@ class rom_base_bank(design): def place_row_decoder(self): self.decode_offset = vector(0, self.control_inst.height ) self.decode_inst.place(offset=self.decode_offset) - + def place_data_array(self): # We approximate the correct position for the array - array_x = self.decode_inst.width + (2) * ( self.route_layer_width + self.route_layer_pitch ) + array_x = self.decode_inst.width + (2) * ( self.route_layer_width + self.route_layer_pitch ) array_y = self.decode_array.buf_inst.height - self.array.precharge_inst.cy() - self.array.zero_cell.height * 0.5 self.array_offset = vector(array_x ,array_y) self.array_inst.place(offset=self.array_offset) @@ -308,7 +308,7 @@ class rom_base_bank(design): # now move array to correct alignment with decoder array_align = self.decode_inst.get_pin("wl_0").cy() - self.array_inst.get_pin("wl_0_0").cy() self.array_inst.place(offset=(self.array_offset + vector(0, array_align))) - + def place_bitline_inverter(self): self.bitline_inv_inst.place(offset=[0,0], rotate=90) inv_y_offset = self.array_inst.by() - self.bitline_inv_inst.width - 2 * self.m1_pitch @@ -316,14 +316,14 @@ class rom_base_bank(design): inv_x_offset = self.array_inst.get_pin("bl_0_0").cx() - self.bitline_inv_inst.get_pin("out_0").cx() self.inv_offset = vector(inv_x_offset, inv_y_offset) self.bitline_inv_inst.place(offset=self.inv_offset, rotate=90) - + def place_control_logic(self): self.control_offset = vector(self.col_decode_inst.lx() - self.control_inst.width - 3 * self.m1_pitch, self.decode_inst.by() - self.control_logic.height - self.m1_pitch) self.control_inst.place(offset=self.control_offset) def place_col_decoder(self): - col_decode_y = self.mux_inst.get_pin("sel_0").cy() - self.col_decode_inst.get_pin("wl_0").cy() + col_decode_y = self.mux_inst.get_pin("sel_0").cy() - self.col_decode_inst.get_pin("wl_0").cy() self.col_decode_offset = vector(self.decode_inst.width - self.col_decode_inst.width, col_decode_y) self.col_decode_inst.place(offset=self.col_decode_offset) @@ -333,13 +333,13 @@ class rom_base_bank(design): mux_x_offset = self.bitline_inv_inst.get_pin("out_0").cx() - self.mux_inst.get_pin("bl_0").cx() self.mux_offset = vector(mux_x_offset, mux_y_offset) self.mux_inst.place(offset=self.mux_offset) - + def place_output_buffer(self): - output_x = self.col_decode_inst.rx() + self.output_inv_inst.height + output_x = self.col_decode_inst.rx() + self.output_inv_inst.height output_y = self.mux_inst.by() - self.word_size * self.m1_pitch self.output_inv_offset = vector(output_x, output_y) self.output_inv_inst.place(offset=self.output_inv_offset, rotate=270) - + def route_decode_outputs(self): # for the row decoder route_pins = [self.array_inst.get_pin("wl_0_{}".format(wl)) for wl in range(self.rows)] @@ -369,11 +369,11 @@ class rom_base_bank(design): self.add_segment_center(self.interconnect_layer, start, end) - + def route_precharge(self): prechrg_control = self.control_inst.get_pin("prechrg") - + col_decode_prechrg = self.col_decode_inst.get_pin("precharge_r") col_decode_clk = self.col_decode_inst.get_pin("clk") array_prechrg = self.array_inst.get_pin("precharge") @@ -401,19 +401,19 @@ class rom_base_bank(design): self.add_via_stack_center(from_layer=self.route_stack[0], to_layer=col_decode_prechrg.layer, offset=end) - + start = mid1 mid1 = vector(self.control_inst.rx(), start.y) mid2 = vector(mid1.x, col_decode_clk.cy()) end = col_decode_clk.center() self.add_path(self.route_stack[0], [start, mid1, mid2, end]) - # self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center()) + # self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center()) # Route precharge to main array # end = vector(col_decode_prechrg.cx(), array_prechrg.cy()) mid = vector(col_decode_prechrg.cx(), array_prechrg.cy() ) - self.add_path(self.route_stack[0], [array_prechrg.center(), mid, col_decode_prechrg.center()]) + self.add_path(self.route_stack[0], [array_prechrg.center(), mid, col_decode_prechrg.center()]) def route_clock(self): @@ -423,8 +423,8 @@ class rom_base_bank(design): self.add_via_stack_center(from_layer=self.route_stack[2], to_layer=clk_out.layer, offset=clk_out.center()) - - # Route clock to row decoder + + # Route clock to row decoder mid = vector(self.control_inst.rx() + self.m1_pitch, clk_out.cy()) addr_control_clk = row_decode_clk.rc() + vector( 2 * self.route_layer_pitch + self.route_layer_width, 0) @@ -474,7 +474,7 @@ class rom_base_bank(design): - + def place_top_level_pins(self): self.copy_layout_pin(self.control_inst, "CS") self.copy_layout_pin(self.control_inst, "clk_in", "clk") @@ -487,10 +487,10 @@ class rom_base_bank(design): for msb in range(self.col_bits, self.row_bits + self.col_bits): name = "addr_{}".format(msb) - pin_num = msb - self.col_bits + pin_num = msb - self.col_bits self.copy_layout_pin(self.decode_inst, "A{}".format(pin_num), name) - - + + def route_supplies(self): diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index efe9e40f..b19bcd88 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -23,15 +23,15 @@ class rom_base_cell(design): self.create_netlist() self.create_layout() - - def create_netlist(self): + + def create_netlist(self): self.add_pins() self.add_modules() - - + + def create_layout(self): - + self.create_tx() self.setup_drc_offsets() self.add_boundary() @@ -41,22 +41,22 @@ class rom_base_cell(design): if self.bit_value == 0: self.short_gate() - + # Calculates offsets of cell width and height so that tiling of cells does not violate any drc rules def setup_drc_offsets(self): - - + + self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active) #nmos contact to gate distance - self.contact_to_gate = 0.5 * (self.nmos.width - 2 * self.nmos.contact_width - self.nmos.poly_width - 2 * self.active_enclose_contact) + self.contact_to_gate = 0.5 * (self.nmos.width - 2 * self.nmos.contact_width - self.nmos.poly_width - 2 * self.active_enclose_contact) #height offset to account for active-to-active spacing between adjacent bitlines self.poly_extend_active_spacing = abs( 2 * self.nmos.poly_extend_active - drc("active_to_active") ) - #contact to contact distance, minimum cell width before drc offsets + #contact to contact distance, minimum cell width before drc offsets self.base_width = self.nmos.width - 2 * self.active_enclose_contact - self.nmos.contact_width #width offset to account for active-to-active spacing between cells on the same bitline @@ -66,19 +66,19 @@ class rom_base_cell(design): # width offset to account for poly-active spacing between base and dummy cells on the same bitline self.poly_active_offset = 0.5 * (self.base_width - 2 * self.cell_diffusion_offset - (self.poly_width + 2 * self.active_enclose_contact + self.nmos.contact_width)) - self.poly_to_active - #so that the poly taps are far enough apart + #so that the poly taps are far enough apart self.poly_tap_offset = (self.base_width - self.cell_diffusion_offset - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") - + def add_boundary(self): height = self.cell_inst.width + self.active_space - #cell width with offsets applied, height becomes width when the cells are rotated + #cell width with offsets applied, height becomes width when the cells are rotated width = self.cell_inst.height + 2 * self.poly_extend_active # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied # height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) - + # make the cells square so the pitch of wordlines will match bitlines if width > height: @@ -87,10 +87,10 @@ class rom_base_cell(design): else: self.width = height self.height = height - + super().add_boundary() - + def add_modules(self): self.nmos = factory.create(module_type="ptx", @@ -103,14 +103,14 @@ class rom_base_cell(design): def create_tx(self): self.cell_inst = self.add_inst( name=self.name + "_nmos", - mod=self.nmos, + mod=self.nmos, ) if self.bit_value == 0: self.connect_inst(["bl", "wl", "bl", "gnd"]) else: self.connect_inst(["bl_h", "wl", "bl_l", "gnd"]) - + def add_pins(self): if self.bit_value == 0 : pin_list = ["bl", "wl", "gnd"] @@ -119,7 +119,7 @@ class rom_base_cell(design): pin_list = ["bl_h", "bl_l", "wl", "gnd"] dir_list = ["INOUT", "INOUT", "INPUT", "GROUND"] - self.add_pin_list(pin_list, dir_list) + self.add_pin_list(pin_list, dir_list) def place_tx(self): @@ -127,7 +127,7 @@ class rom_base_cell(design): tx_offset = vector(self.poly_extend_active + self.cell_inst.height + self.poly_size,- 0.5 * self.contact_width - self.active_enclose_contact) # add rect of poly to account for offset from drc spacing # self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.poly_width) - + self.cell_inst.place(tx_offset, rotate=90) # self.add_label("CELL ZERO", self.route_layer) self.copy_layout_pin(self.cell_inst, "S", "S") diff --git a/compiler/modules/rom_column_mux.py b/compiler/modules/rom_column_mux.py index 85fe8489..1830c53b 100644 --- a/compiler/modules/rom_column_mux.py +++ b/compiler/modules/rom_column_mux.py @@ -42,7 +42,7 @@ class rom_column_mux(pgate): def create_layout(self): - + self.pin_layer = self.input_layer self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer)) self.pin_width = getattr(self, "{}_width".format(self.pin_layer)) diff --git a/compiler/modules/rom_column_mux_array.py b/compiler/modules/rom_column_mux_array.py index 856eea71..60e0da6b 100644 --- a/compiler/modules/rom_column_mux_array.py +++ b/compiler/modules/rom_column_mux_array.py @@ -54,14 +54,14 @@ class rom_column_mux_array(design): 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.add_layout_pins() if "pwell" in layer: self.add_enclosure(self.mux_inst, "pwell") - + self.add_boundary() self.DRC_LVS() @@ -154,7 +154,7 @@ class rom_column_mux_array(design): 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 @@ -209,8 +209,8 @@ class rom_column_mux_array(design): def add_taps(self): pass - - + + def graph_exclude_columns(self, column_include_num): """ Excludes all columns muxes unrelated to the target bit being simulated. diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index a469b184..af8b81a0 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -25,7 +25,7 @@ class rom_control_logic(design): self.gate_height = 20 * self.m1_pitch self.driver_height = self.gate_height - + self.clk_fanout = clk_fanout if "li" in layer: @@ -49,21 +49,21 @@ class rom_control_logic(design): self.route_insts() def add_modules(self): - self.buf_mod = factory.create(module_type="pdriver", - module_name="rom_clock_driver", + self.buf_mod = factory.create(module_type="pdriver", + module_name="rom_clock_driver", height=self.gate_height, fanout=self.clk_fanout + 2, add_wells=True, ) - self.nand_mod = factory.create(module_type="pnand2", - module_name="rom_control_nand", - height=self.gate_height, + self.nand_mod = factory.create(module_type="pnand2", + module_name="rom_control_nand", + height=self.gate_height, add_wells=False) - self.driver_mod = factory.create(module_type="pdriver", - module_name="rom_precharge_driver", - inverting=True, - fanout=self.output_size, - height=self.driver_height, + self.driver_mod = factory.create(module_type="pdriver", + module_name="rom_precharge_driver", + inverting=True, + fanout=self.output_size, + height=self.driver_height, add_wells=True) def add_pins(self): @@ -75,7 +75,7 @@ class rom_control_logic(design): self.add_pin("gnd", "GROUND") def create_instances(self): - + self.buf_inst = self.add_inst(name="clk_driver", mod=self.buf_mod) self.connect_inst(["clk_in", "clk_out", "vdd", "gnd"]) diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index fe817383..41b3902f 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -21,7 +21,7 @@ class rom_decoder(design): self.num_outputs = num_outputs self.num_inputs = ceil(log(num_outputs, 2)) self.create_decode_map() - + super().__init__(name) b = factory.create(module_type=OPTS.bitcell) @@ -48,7 +48,7 @@ class rom_decoder(design): self.place_input_buffer() self.place_driver() self.route_outputs() - + self.connect_inputs() self.route_supplies() self.add_boundary() @@ -62,7 +62,7 @@ class rom_decoder(design): ur = vector(ur.x, ur.y) super().add_boundary(ll, ur) self.width = ur.x - self.height = ur.y + self.height = ur.y def setup_layout_constants(self): self.inv_route_width = drc["minwidth_{}".format(self.inv_route_layer)] @@ -87,7 +87,7 @@ class rom_decoder(design): else: bin_digit = int(addr[addr_idx]) - col_array.append(bin_digit) + col_array.append(bin_digit) if bin_digit == 0 : inv_col_array.append(1) else : inv_col_array.append(0) @@ -109,19 +109,19 @@ class rom_decoder(design): def add_modules(self): - self.control_array = factory.create(module_type="rom_address_control_array", + self.control_array = factory.create(module_type="rom_address_control_array", cols=self.num_inputs) - self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), - rows=self.num_outputs, + self.wordline_buf = factory.create(module_type="rom_wordline_driver_array", module_name="{}_wordline_buffer".format(self.name), + rows=self.num_outputs, fanout=ceil(self.fanout), invert_outputs=self.invert_outputs, tap_spacing=self.strap_spacing) - - self.array_mod = factory.create(module_type="rom_base_array", - module_name="{}_array".format(self.name), - cols=self.num_outputs, - rows=2 * self.num_inputs, + + self.array_mod = factory.create(module_type="rom_base_array", + module_name="{}_array".format(self.name), + cols=self.num_outputs, + rows=2 * self.num_inputs, bitmap=self.decode_map, strap_spacing = self.strap_spacing, bitline_layer=self.output_layer, @@ -190,7 +190,7 @@ class rom_decoder(design): self.array_inst.place(offset, rotate=90) def place_driver(self): - + offset = vector(self.array_inst.height + self.m1_width, self.array_inst.by()) self.wordline_buf_inst.place(offset) @@ -226,7 +226,7 @@ class rom_decoder(design): addr_bar_out_pin = self.buf_inst.get_pin("Abar{}_out".format(i)) addr_middle = vector(addr_pin.cx(), addr_out_pin.cy()) - + addr_bar_middle = vector(addr_bar_pin.cx(), addr_bar_out_pin.cy()) self.add_path(self.inv_route_layer, [addr_out_pin.center(), addr_middle, addr_pin.center()]) diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index a31b86d4..d7a1b3b2 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -37,11 +37,11 @@ class rom_poly_tap(design): self.extend_poly() def add_boundary(self): - contact_width = self.poly_contact.width + contact_width = self.poly_contact.width # offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact) self.height = self.dummy.height - self.width = contact_width + self.pitch_offset + self.width = contact_width + self.pitch_offset super().add_boundary() @@ -89,7 +89,7 @@ class rom_poly_tap(design): offset = self.active_space - gap # tap_x = self.via.cx() + self.contact_width + self.active_enclose_contact + self.poly_enclose_contact tap_x = self.via.cx() + offset - tap_y = self.via.cy() + self.dummy.width * 0.5 + tap_y = self.via.cy() + self.dummy.width * 0.5 contact_pos = vector(tap_x, tap_y) # edge of the next nmos @@ -105,7 +105,7 @@ class rom_poly_tap(design): implant_type="p", well_type="p", directions="nonpref") - self.add_power_pin(name="gnd", + self.add_power_pin(name="gnd", loc=contact_pos, start_layer=self.active_stack[2]) self.add_layout_pin_rect_center("active_tap", self.supply_stack[0], contact_pos) \ No newline at end of file diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index 6b5c13e9..efaa1b23 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -32,14 +32,14 @@ class rom_precharge_array(design): name = "rom_inv_array_{0}".format(cols) if strap_spacing != None: - self.strap_spacing = strap_spacing + self.strap_spacing = strap_spacing else: self.strap_spacing = 0 if strap_spacing != 0: self.num_straps = ceil(self.cols / self.strap_spacing) - self.array_col_size = self.cols + self.num_straps + self.array_col_size = self.cols + self.num_straps else: self.num_straps = 0 self.array_col_size = self.cols @@ -54,7 +54,7 @@ class rom_precharge_array(design): self.create_instances() def create_layout(self): - self.width = self.cols * self.pmos.width + self.width = self.cols * self.pmos.width self.height = self.pmos.width self.place_instances() self.create_layout_pins() @@ -70,7 +70,7 @@ class rom_precharge_array(design): self.add_label(layer="nwell", text="upper right",offset=ur) # ur = vector(ur.x, ur.y - self.well_ll.y) super().add_boundary(vector(0, 0), ur) - self.height = ur.y + self.height = ur.y self.width = ur.x def create_modules(self): @@ -118,8 +118,8 @@ class rom_precharge_array(design): self.add_label("ZERO", self.route_layer) self.array_pos = [] - strap_num = 0 - cell_y = 0 + strap_num = 0 + cell_y = 0 # columns are bit lines cell_x = 0 @@ -163,7 +163,7 @@ class rom_precharge_array(design): start = vector(tap_pin.cx(), tap_pin.by()) end = vector(start.x, tap.mod.get_pin("poly_tap").cy()) self.add_segment_center(layer="poly", start=start, end=end) - offset_start = vector(end.x - self.poly_tap.width + self.poly_extend_active, end.y) + offset_start = vector(end.x - self.poly_tap.width + self.poly_extend_active, end.y) offset_end = end + vector(0.5*self.poly_width, 0) self.add_segment_center(layer="poly", start=offset_start, end=offset_end) diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 13cc8c2b..90146d99 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -21,7 +21,7 @@ class rom_precharge_cell(rom_base_cell): def create_layout(self): super().create_layout() - + self.place_tap() self.extend_well() @@ -37,27 +37,27 @@ class rom_precharge_cell(rom_base_cell): def create_tx(self): self.cell_inst = self.add_inst( name="precharge_pmos", - mod=self.pmos, + mod=self.pmos, ) self.connect_inst(["bitline", "gate", "vdd", "vdd"]) - def add_pins(self): + def add_pins(self): pin_list = ["vdd", "gate", "bitline"] dir_list = ["POWER", "INPUT", "OUTPUT"] - self.add_pin_list(pin_list, dir_list) + self.add_pin_list(pin_list, dir_list) def setup_drc_offsets(self): self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active) - #contact to contact distance, minimum cell width before drc offsets + #contact to contact distance, minimum cell width before drc offsets self.base_width = self.pmos.width - 2 * self.active_enclose_contact - self.pmos.contact_width # width offset to account for poly-active spacing between base and dummy cells on the same bitline self.poly_active_offset = 0.5 * (self.base_width - (self.poly_width + 2 * self.active_enclose_contact + self.pmos.contact_width)) - self.poly_to_active - #so that the poly taps are far enough apart + #so that the poly taps are far enough apart self.poly_tap_offset = (self.base_width - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") def extend_well(self): @@ -82,7 +82,7 @@ class rom_precharge_cell(rom_base_cell): directions="nonpref") self.add_via_stack_center(offset=pos, from_layer=self.active_stack[2], - to_layer=self.supply_layer) + to_layer=self.supply_layer) bitline_offset = vector( 2 * (drc("minwidth_{}".format(self.bitline_layer)) + drc("{0}_to_{0}".format(self.bitline_layer))) ,0) diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index 56df91a9..7dfc2d1a 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -74,7 +74,7 @@ class rom_wordline_driver_array(design): height=b.height, add_wells=False, flip_io=self.flip_io) - + else: self.wl_driver = factory.create(module_type="pbuf_dec", size=self.fanout, @@ -136,7 +136,7 @@ class rom_wordline_driver_array(design): # output each WL on the right if self.flip_io: wl_offset = out_pin.lc() - vector(1.6 * route_width, 0) - + else: wl_offset = out_pin.rc() - vector( 0.5 * route_width, 0) diff --git a/compiler/tests/05_rom_base_bank_2kB_test.py b/compiler/tests/05_rom_base_bank_2kB_test.py index 983895de..b5087f3d 100644 --- a/compiler/tests/05_rom_base_bank_2kB_test.py +++ b/compiler/tests/05_rom_base_bank_2kB_test.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # See LICENSE for licensing information. # -# Copyright (c) 2016-2021 Regents of the University of California and The Board +# Copyright (c) 2016-2023 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 0cb4459b4b4070a1e2361fbd74112c0e479d2147 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Wed, 1 Mar 2023 13:52:53 -0800 Subject: [PATCH 54/98] changed ROM test data path --- compiler/tests/05_rom_base_bank_1kB_test.py | 3 ++- compiler/tests/05_rom_base_bank_2kB_test.py | 3 ++- compiler/tests/05_rom_base_bank_4kB_test.py | 3 ++- compiler/tests/05_rom_base_bank_8kB_test.py | 3 ++- compiler/tests/05_rom_base_bank_small_test.py | 3 ++- compiler/tests/configs/config.py | 2 ++ compiler/tests/configs/rom_data/rom_data_1kB | 1 + compiler/tests/configs/rom_data/rom_data_2kB | 1 + compiler/tests/configs/rom_data/rom_data_4kB | 1 + compiler/tests/configs/rom_data/rom_data_64B | 1 + compiler/tests/configs/rom_data/rom_data_8kB | 1 + 11 files changed, 17 insertions(+), 5 deletions(-) create mode 100644 compiler/tests/configs/rom_data/rom_data_1kB create mode 100644 compiler/tests/configs/rom_data/rom_data_2kB create mode 100644 compiler/tests/configs/rom_data/rom_data_4kB create mode 100644 compiler/tests/configs/rom_data/rom_data_64B create mode 100644 compiler/tests/configs/rom_data/rom_data_8kB diff --git a/compiler/tests/05_rom_base_bank_1kB_test.py b/compiler/tests/05_rom_base_bank_1kB_test.py index e6d9333f..2cfb1b81 100644 --- a/compiler/tests/05_rom_base_bank_1kB_test.py +++ b/compiler/tests/05_rom_base_bank_1kB_test.py @@ -23,7 +23,8 @@ class rom_bank_test(openram_test): openram.init_openram(config_file, is_unit_test=True) debug.info(1, "Testing 1kB rom cell") - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_1kB", word_size=1) + test_data = "{0}/{1}/rom_data_1kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 1) a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) diff --git a/compiler/tests/05_rom_base_bank_2kB_test.py b/compiler/tests/05_rom_base_bank_2kB_test.py index b5087f3d..c4f1c08a 100644 --- a/compiler/tests/05_rom_base_bank_2kB_test.py +++ b/compiler/tests/05_rom_base_bank_2kB_test.py @@ -23,7 +23,8 @@ class rom_bank_test(openram_test): openram.init_openram(config_file, is_unit_test=True) debug.info(1, "Testing 2kB rom cell") - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_2kB", word_size=1) + test_data = "{0}/{1}/rom_data_2kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 1) a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) diff --git a/compiler/tests/05_rom_base_bank_4kB_test.py b/compiler/tests/05_rom_base_bank_4kB_test.py index 1d34b3ac..90547d57 100644 --- a/compiler/tests/05_rom_base_bank_4kB_test.py +++ b/compiler/tests/05_rom_base_bank_4kB_test.py @@ -23,7 +23,8 @@ class rom_bank_test(openram_test): openram.init_openram(config_file, is_unit_test=True) debug.info(1, "Testing 4kB rom cell") - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_4kB", word_size=2) + test_data = "{0}/{1}/rom_data_4kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 2) a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) diff --git a/compiler/tests/05_rom_base_bank_8kB_test.py b/compiler/tests/05_rom_base_bank_8kB_test.py index bceb93b4..3cf86b27 100644 --- a/compiler/tests/05_rom_base_bank_8kB_test.py +++ b/compiler/tests/05_rom_base_bank_8kB_test.py @@ -23,7 +23,8 @@ class rom_bank_test(openram_test): openram.init_openram(config_file, is_unit_test=True) debug.info(1, "Testing 8kB rom cell") - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_8kB", word_size=2) + test_data = "{0}/{1}/rom_data_8kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 2) a.sp_write(OPTS.openram_temp + 'simulation_file_8kB.sp') self.local_check(a) diff --git a/compiler/tests/05_rom_base_bank_small_test.py b/compiler/tests/05_rom_base_bank_small_test.py index 1bc4bfa1..dbda8b41 100644 --- a/compiler/tests/05_rom_base_bank_small_test.py +++ b/compiler/tests/05_rom_base_bank_small_test.py @@ -23,7 +23,8 @@ class rom_bank_test(openram_test): openram.init_openram(config_file, is_unit_test=True) debug.info(1, "Testing 32 byte rom cell") - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file="/openram/technology/rom_data_64B", word_size=1) + test_data = "{0}/{1}/rom_data_64B".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) + a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 1) self.local_check(a) a.sp_write(OPTS.openram_temp + 'simulation_file.sp') diff --git a/compiler/tests/configs/config.py b/compiler/tests/configs/config.py index e95a1f7c..52bdbf2d 100644 --- a/compiler/tests/configs/config.py +++ b/compiler/tests/configs/config.py @@ -17,3 +17,5 @@ check_lvsdrc = True #route_supplies = False output_name = "sram" + +rom_data_dir = "tests/configs/rom_data" \ No newline at end of file diff --git a/compiler/tests/configs/rom_data/rom_data_1kB b/compiler/tests/configs/rom_data/rom_data_1kB new file mode 100644 index 00000000..11006ecd --- /dev/null +++ b/compiler/tests/configs/rom_data/rom_data_1kB @@ -0,0 +1 @@ +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/compiler/tests/configs/rom_data/rom_data_2kB b/compiler/tests/configs/rom_data/rom_data_2kB new file mode 100644 index 00000000..74e92aba --- /dev/null +++ b/compiler/tests/configs/rom_data/rom_data_2kB @@ -0,0 +1 @@ +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/compiler/tests/configs/rom_data/rom_data_4kB b/compiler/tests/configs/rom_data/rom_data_4kB new file mode 100644 index 00000000..606b2b3f --- /dev/null +++ b/compiler/tests/configs/rom_data/rom_data_4kB @@ -0,0 +1 @@ +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/compiler/tests/configs/rom_data/rom_data_64B b/compiler/tests/configs/rom_data/rom_data_64B new file mode 100644 index 00000000..f92d10d5 --- /dev/null +++ b/compiler/tests/configs/rom_data/rom_data_64B @@ -0,0 +1 @@ +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFF \ No newline at end of file diff --git a/compiler/tests/configs/rom_data/rom_data_8kB b/compiler/tests/configs/rom_data/rom_data_8kB new file mode 100644 index 00000000..246571be --- /dev/null +++ b/compiler/tests/configs/rom_data/rom_data_8kB @@ -0,0 +1 @@ +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file From 90cf382a4398c71932c95a3aa5ecf6eda4fd4699 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Wed, 1 Mar 2023 14:21:29 -0800 Subject: [PATCH 55/98] removed hardcoded DRC rule --- compiler/modules/rom_poly_tap.py | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index d7a1b3b2..7176b9e9 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -52,20 +52,15 @@ class rom_poly_tap(design): # DRC rule here is hard coded since licon.9 isnt included in skywater130 tech file # poly contact spacing to P-diffusion < 0.235um (licon.9 + psdm.5a) - if OPTS.tech_name == "sky130": - self.contact_x_offset = 0.235 - (contact_width - self.pmos.contact_width) * 0.5 - self.poly_extend_active - else: - assert(False) + # if OPTS.tech_name == "sky130": + # self.contact_x_offset = 0.235 - (contact_width - self.pmos.contact_width) * 0.5 - self.poly_extend_active + # else: + # assert(False) contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact - if self.tx_type == "nmos": + self.contact_x_offset = 0 - # contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact - # contact_y = self.dummy.poly.offset.x + (self.poly_width * 0.5) - self.contact_x_offset = 0 - # else: - # contact_y = self.pmos.poly_positions[0].x - self.pmos.active_offset.x contact_x = contact_width * 0.5 + self.contact_x_offset self.contact_offset = vector(contact_x, contact_y) From 92251fe61e7015e344815eb26eba205b8b3a9832 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Wed, 1 Mar 2023 15:49:43 -0800 Subject: [PATCH 56/98] more code cleaning --- compiler/modules/rom_address_control_array.py | 4 +- compiler/modules/rom_address_control_buf.py | 4 -- compiler/modules/rom_base_array.py | 29 ++------------- compiler/modules/rom_base_bank.py | 6 ++- compiler/modules/rom_base_cell.py | 30 +-------------- compiler/modules/rom_column_mux.py | 37 ------------------- compiler/modules/rom_column_mux_array.py | 12 ------ compiler/modules/rom_decoder.py | 11 ++---- compiler/modules/rom_poly_tap.py | 3 -- compiler/modules/rom_precharge_array.py | 2 - compiler/modules/rom_precharge_cell.py | 10 ----- compiler/modules/rom_wordline_driver_array.py | 2 - 12 files changed, 13 insertions(+), 137 deletions(-) diff --git a/compiler/modules/rom_address_control_array.py b/compiler/modules/rom_address_control_array.py index e4fdf019..e6226e06 100644 --- a/compiler/modules/rom_address_control_array.py +++ b/compiler/modules/rom_address_control_array.py @@ -56,10 +56,8 @@ class rom_address_control_array(design): def create_modules(self): - self.addr_control = factory.create(module_type="rom_address_control_buf", size=self.inv_height) - # For layout constants - # self.poly_tap = factory.create(module_type="rom_poly_tap", strap_length=0) + def add_pins(self): for col in range(self.cols): diff --git a/compiler/modules/rom_address_control_buf.py b/compiler/modules/rom_address_control_buf.py index b69ccb1b..9e092ff0 100644 --- a/compiler/modules/rom_address_control_buf.py +++ b/compiler/modules/rom_address_control_buf.py @@ -41,16 +41,13 @@ class rom_address_control_buf(design): self.height = self.inv.width + 2 * self.nand.width self.setup_layout_constants() self.place_instances() - # self.place_vias() self.route_gates() self.route_sources() self.add_boundary() def create_modules(self): - # self.inv1_mod = factory.create(module_type="pinv", module_name="inv_array_end_mod", height=self.inv_size, add_wells=False) self.inv = factory.create(module_type="pinv_dec", module_name="inv_array_mod", add_wells=False, size=self.size) - # self.end_inv = factory.create(module_type="pinv", module_name="inv_array_end_mod", size=self.size, add_wells=True) self.nand = factory.create(module_type="nand2_dec", height=self.inv.height) # For layout constants self.cell = factory.create(module_type="rom_base_cell") @@ -101,7 +98,6 @@ class rom_address_control_buf(design): def route_gates(self): clk1_pin = self.addr_nand.get_pin("A") clk2_pin = self.addr_bar_nand.get_pin("A") - # self.add_label("HERE I AM", "poly", clk_pins.cl()) Abar_out = self.addr_bar_nand.get_pin("Z") A_out = self.addr_nand.get_pin("Z") diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index af9d81d4..99171450 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -115,21 +115,17 @@ class rom_base_array(bitcell_base_array): # list of current bitline interconnect nets, # starts as the same as the bitline list and is updated when new insts of cells are added self.int_bl_list = self.bitline_names[0].copy() - #When rotated correctly rows are word lines + for row in range(self.row_size + 1): row_list = [] - # for each new strap placed, offset the column index refrenced to get correct bit in the data array - # cols are bit lines for col in range(self.column_size): if col % self.strap_spacing == 0: self.create_poly_tap(row, col) new_inst = self.create_cell(row, col) - self.cell_inst[row, col] = new_inst - row_list.append(new_inst) name = "tap_r{0}_c{1}".format(row, self.array_col_size) @@ -206,8 +202,8 @@ class rom_base_array(bitcell_base_array): def place_array(self): self.cell_pos = {} self.strap_pos = {} - # rows are wordlines pitch_offset = 0 + for row in range(self.row_size + 1): if row % self.tap_spacing == 0 and self.pitch_match and row != self.row_size: @@ -228,7 +224,6 @@ class rom_base_array(bitcell_base_array): self.cell_pos[row, col] = vector(cell_x, cell_y) self.cell_inst[row, col].place(self.cell_pos[row, col]) cell_x += self.zero_cell.width - # self.add_label("debug", "li", self.cell_pos[row, col]) self.strap_pos[row, self.column_size] = vector(cell_x, cell_y) self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size]) @@ -338,24 +333,6 @@ class rom_base_array(bitcell_base_array): array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))] self.connect_row_pins(layer=self.wordline_layer, pins=array_pins, name=None, round=False) - # self.connect_row_pins(layer="poly", pins=array_pins, name=None, round=False) if self.tap_direction == "col": - self.route_vertical_pins("active_tap", insts=self.tap_list, layer=self.supply_stack[0], full_width=False) - - def get_next_cell_in_bl(self, row_start, col): - for row in range(row_start + 1, self.row_size): - if self.data[row][col] == 1: - return row - return -1 - - - - def get_current_bl_interconnect(self, col): - """Get interconnect net for bitline(col) currently being connected """ - return "bli_{0}_{1}".format(self.current_row, col) - - def create_next_bl_interconnect(self, row, col): - """create a new net name for a bitline interconnect""" - self.current_row = row - return "bli_{0}_{1}".format(row, col) \ No newline at end of file + self.route_vertical_pins("active_tap", insts=self.tap_list, layer=self.supply_stack[0], full_width=False) \ No newline at end of file diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index a8b9f011..f8ab2eff 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -11,7 +11,7 @@ from openram.base import vector from openram.base import design from openram import OPTS, debug from openram.sram_factory import factory -from openram.tech import drc, layer +from openram.tech import drc, layer, parameter class rom_base_bank(design): @@ -165,7 +165,9 @@ class rom_base_bank(design): # TODO: provide technology-specific calculation of these parameters # in sky130 the address control buffer is composed of 2 size 2 NAND gates, # with a beta of 3, each of these gates has gate capacitance of 2 min sized inverters, therefor a load of 4 - addr_control_buffer_effort = 4 + + + addr_control_buffer_effort = parameter['beta'] + 1 # a single min sized nmos makes up 1/4 of the input capacitance of a min sized inverter bitcell_effort = 0.25 diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index b19bcd88..7663b420 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -23,13 +23,10 @@ class rom_base_cell(design): self.create_netlist() self.create_layout() - - def create_netlist(self): self.add_pins() self.add_modules() - def create_layout(self): self.create_tx() @@ -41,34 +38,10 @@ class rom_base_cell(design): if self.bit_value == 0: self.short_gate() - - - # Calculates offsets of cell width and height so that tiling of cells does not violate any drc rules def setup_drc_offsets(self): - - self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active) - #nmos contact to gate distance - self.contact_to_gate = 0.5 * (self.nmos.width - 2 * self.nmos.contact_width - self.nmos.poly_width - 2 * self.active_enclose_contact) - - #height offset to account for active-to-active spacing between adjacent bitlines - self.poly_extend_active_spacing = abs( 2 * self.nmos.poly_extend_active - drc("active_to_active") ) - - #contact to contact distance, minimum cell width before drc offsets - self.base_width = self.nmos.width - 2 * self.active_enclose_contact - self.nmos.contact_width - - #width offset to account for active-to-active spacing between cells on the same bitline - #this is calculated as a negative value - self.cell_diffusion_offset = ((self.base_width - 2 * self.active_enclose_contact - self.nmos.contact_width) - drc("active_to_active")) * 0.5 - - # width offset to account for poly-active spacing between base and dummy cells on the same bitline - self.poly_active_offset = 0.5 * (self.base_width - 2 * self.cell_diffusion_offset - (self.poly_width + 2 * self.active_enclose_contact + self.nmos.contact_width)) - self.poly_to_active - - #so that the poly taps are far enough apart - self.poly_tap_offset = (self.base_width - self.cell_diffusion_offset - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") - def add_boundary(self): @@ -76,8 +49,7 @@ class rom_base_cell(design): #cell width with offsets applied, height becomes width when the cells are rotated width = self.cell_inst.height + 2 * self.poly_extend_active - # cell height with offsets applied, width becomes height when the cells are rotated, if the offsets are positive (greater than 0) they are not applied - # height = self.base_width - min(self.cell_diffusion_offset, 0) - min(self.poly_active_offset, 0) - min(self.poly_tap_offset, 0) + # make the cells square so the pitch of wordlines will match bitlines diff --git a/compiler/modules/rom_column_mux.py b/compiler/modules/rom_column_mux.py index 1830c53b..43d3bdab 100644 --- a/compiler/modules/rom_column_mux.py +++ b/compiler/modules/rom_column_mux.py @@ -30,19 +30,12 @@ class rom_column_mux(pgate): self.output_layer= output_layer super().__init__(name) - - - def get_bl_names(self): - return "bl" - - def create_netlist(self): self.add_pins() self.add_ptx() def create_layout(self): - self.pin_layer = self.input_layer self.pin_pitch = getattr(self, "{}_pitch".format(self.pin_layer)) self.pin_width = getattr(self, "{}_width".format(self.pin_layer)) @@ -54,7 +47,6 @@ class rom_column_mux(pgate): else: self.col_mux_stack = self.m1_stack - self.place_ptx() self.width = self.bitcell.width @@ -108,14 +100,6 @@ class rom_column_mux(pgate): + vector(0.5 * self.bitcell.width- 0.5 * self.nmos.active_width, 0) self.nmos_lower.place(nmos_lower_position) - # # This aligns it directly above the other tx with gates abutting - # nmos_upper_position = nmos_lower_position \ - # + vector(0, self.nmos.active_height + max(self.active_space, self.poly_space)) - # self.nmos_upper.place(nmos_upper_position) - - # if cell_props.pgate.add_implants: - # self.extend_implants() - def connect_poly(self): """ Connect the poly gate of the two pass transistors """ @@ -137,7 +121,6 @@ class rom_column_mux(pgate): """ Connect the bitlines to the mux transistors """ bl_pin = self.get_pin("bl") - # br_pin = self.get_pin("br") bl_out_pin = self.get_pin("bl_out") nmos_lower_s_pin = self.nmos_lower.get_pin("S") @@ -166,31 +149,11 @@ class rom_column_mux(pgate): self.add_path(self.output_layer, [bl_out_pin.uc(), mid1, mid2, nmos_lower_d_pin.center()]) - - - def extend_implants(self): - """ - Add top-to-bottom implants for adjacency issues in s8. - """ - # Route to the bottom - ll = (self.nmos_lower.ll() - vector(2 * [self.implant_enclose_active])).scale(1, 0) - # Don't route to the top - ur = self.nmos_upper.ur() + vector(self.implant_enclose_active, 0) - self.add_rect("nimplant", - ll, - ur.x - ll.x, - ur.y - ll.y) - def add_pn_wells(self): """ Add a well and implant over the whole cell. Also, add the pwell contact (if it exists) """ - # if(cell_props.use_strap == True and OPTS.num_ports == 1): - # strap = factory.create(module_type=cell_props.strap_module, version=cell_props.strap_version) - # rbc_width = self.bitcell.width + strap.width - # else: - # rbc_width = self.bitcell.width # Add it to the right, aligned in between the two tx active_pos = vector(self.bitcell.width, self.nmos_lower.uy() + self.active_contact.height + self.active_space) diff --git a/compiler/modules/rom_column_mux_array.py b/compiler/modules/rom_column_mux_array.py index 60e0da6b..31f6bbee 100644 --- a/compiler/modules/rom_column_mux_array.py +++ b/compiler/modules/rom_column_mux_array.py @@ -30,7 +30,6 @@ class rom_column_mux_array(design): self.words_per_row = int(self.columns / self.word_size) self.input_layer = input_layer self.tap_spacing = tap_spacing - # self.sel_layer = layer_props.column_mux_array.select_layer self.sel_layer = sel_layer self.sel_pitch = getattr(self, self.sel_layer + "_pitch") @@ -107,12 +106,6 @@ class rom_column_mux_array(design): # For every column, add a pass gate for col_num, xoffset in enumerate(self.offsets[0:self.columns]): - # if self.cell.mirror.y and (col_num + self.column_offset) % 2: - # mirror = "MY" - # xoffset = xoffset + self.mux.width - # else: - # mirror = "" - offset = vector(xoffset, self.route_height) self.mux_inst[col_num].place(offset=offset) @@ -206,11 +199,6 @@ class rom_column_mux_array(design): offset=bl_out_offset_begin, directions=self.via_directions) - - def add_taps(self): - pass - - def graph_exclude_columns(self, column_include_num): """ Excludes all columns muxes unrelated to the target bit being simulated. diff --git a/compiler/modules/rom_decoder.py b/compiler/modules/rom_decoder.py index 41b3902f..760af8c4 100644 --- a/compiler/modules/rom_decoder.py +++ b/compiler/modules/rom_decoder.py @@ -14,9 +14,10 @@ from openram.tech import drc class rom_decoder(design): def __init__(self, num_outputs, fanout, strap_spacing, name="", route_layer="m1", output_layer="m1", invert_outputs=False): - # word lines/ rows / inputs in the base array become the address lines / cols / inputs in the decoder - # bit lines / cols / outputs in the base array become the word lines / rows / outputs in the decoder - # array gets rotated 90deg so that rows/cols switch + # word lines in the base array become the address lines/cols in the decoder + # bit lines in the base array become the word lines/rows in the decoder + # array gets rotated 90deg so rows/cols switch + self.strap_spacing=strap_spacing self.num_outputs = num_outputs self.num_inputs = ceil(log(num_outputs, 2)) @@ -204,8 +205,6 @@ class rom_decoder(design): self.copy_layout_pin(self.wordline_buf_inst, "out_{}".format(j), "wl_{}".format(j)) offset = self.wordline_buf_inst.get_pin("out_{}".format(j)).center() - # self.add_via_stack_center(offset, self.output_layer, self.wordline_buf.route_layer) - array_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.num_outputs)] driver_pins = [self.wordline_buf_inst.get_pin("in_{}".format(bl)) for bl in range(self.num_outputs)] @@ -233,8 +232,6 @@ class rom_decoder(design): self.add_path(self.inv_route_layer, [addr_bar_out_pin.center(), addr_bar_middle, addr_bar_pin.center()]) self.copy_layout_pin(self.buf_inst, "A{}_in".format(i), "A{}".format(i)) - # self.add_segment_center(self.inv_route_layer, addr_bar_middle + vector(0, self.inv_route_width * 0.5), addr_bar_out_pin.center() + vector(0, self.inv_route_width * 0.5), self.inv_route_width) - def route_supplies(self): self.copy_layout_pin(self.array_inst, "vdd") diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index 7176b9e9..df698ca6 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -38,8 +38,6 @@ class rom_poly_tap(design): def add_boundary(self): contact_width = self.poly_contact.width - - # offset = self.active_space - (contact_width - self.active_enclose_contact - self.active_extend_contact) self.height = self.dummy.height self.width = contact_width + self.pitch_offset @@ -82,7 +80,6 @@ class rom_poly_tap(design): def place_active_tap(self): gap = self.poly_extend_active - 0.5 * ( self.active_contact.height - self.poly_contact.width ) offset = self.active_space - gap - # tap_x = self.via.cx() + self.contact_width + self.active_enclose_contact + self.poly_enclose_contact tap_x = self.via.cx() + offset tap_y = self.via.cy() + self.dummy.width * 0.5 contact_pos = vector(tap_x, tap_y) diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index efaa1b23..8bd1b976 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -149,8 +149,6 @@ class rom_precharge_array(design): def route_supply(self): - # self.vdd = self.add_layout_pin_segment_center("vdd", self.supply_layer, start, end) - # vdd = [self.pmos_insts[i].get_pin("vdd") for i in range(self.cols)]routeroute_horizon_horizon self.route_horizontal_pins("vdd", insts=self.pmos_insts, layer=self.strap_layer) def connect_taps(self): diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 90146d99..4489ccc9 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -51,20 +51,10 @@ class rom_precharge_cell(rom_base_cell): self.poly_size = (self.cell_inst.width + self.active_space) - (self.cell_inst.height + 2 * self.poly_extend_active) - #contact to contact distance, minimum cell width before drc offsets - self.base_width = self.pmos.width - 2 * self.active_enclose_contact - self.pmos.contact_width - - # width offset to account for poly-active spacing between base and dummy cells on the same bitline - self.poly_active_offset = 0.5 * (self.base_width - (self.poly_width + 2 * self.active_enclose_contact + self.pmos.contact_width)) - self.poly_to_active - - #so that the poly taps are far enough apart - self.poly_tap_offset = (self.base_width - self.poly_contact.width - self.poly_active_offset) - drc("poly_to_poly") - def extend_well(self): well_y = self.get_pin("vdd").cy() - 0.5 * self.nwell_width well_ll = vector(0, well_y) - # height = self.active_width + 2 * self.well_enclose_active height = self.get_pin("D").cy() + 0.5 * self.nwell_width - well_y self.add_rect("nwell", well_ll, self.width , height) diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index 7dfc2d1a..7acdaf9c 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -88,8 +88,6 @@ class rom_wordline_driver_array(design): """ if layer_props.wordline_driver.vertical_supply: - # self.route_vertical_pins("vdd", self.wld_inst) - # self.route_vertical_pins("gnd", self.wld_inst) self.route_vertical_pins("vdd", [self], layer=self.supply_layer) self.route_vertical_pins("gnd", [self], layer=self.supply_layer) else: From 382c91f342a1ff366a9d6e72b069cf50c35a1a03 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Wed, 1 Mar 2023 16:44:48 -0800 Subject: [PATCH 57/98] precharge array test passing sky130 --- compiler/modules/rom_base_array.py | 2 +- compiler/modules/rom_base_cell.py | 2 +- compiler/modules/rom_precharge_array.py | 18 ++++++++++-------- compiler/modules/rom_precharge_cell.py | 6 +++--- compiler/tests/05_rom_base_bank_small_test.py | 2 +- compiler/tests/05_rom_decoder_test.py | 2 +- compiler/tests/05_rom_precharge_array_test.py | 2 +- .../tests/05_rom_wordline_driver_array_test.py | 2 +- 8 files changed, 19 insertions(+), 17 deletions(-) diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 99171450..dd4c80d4 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -89,7 +89,7 @@ class rom_base_array(bitcell_base_array): self.precharge_array = factory.create(module_type="rom_precharge_array", cols=self.column_size, strap_spacing=self.strap_spacing, - route_layer=self.bitline_layer, + bitline_layer=self.bitline_layer, strap_layer=self.wordline_layer, tap_direction=self.tap_direction) diff --git a/compiler/modules/rom_base_cell.py b/compiler/modules/rom_base_cell.py index 7663b420..28fc07f0 100644 --- a/compiler/modules/rom_base_cell.py +++ b/compiler/modules/rom_base_cell.py @@ -101,7 +101,7 @@ class rom_base_cell(design): # self.add_rect_center("poly", poly_offset, self.poly_extend_active_spacing, self.poly_width) self.cell_inst.place(tx_offset, rotate=90) - # self.add_label("CELL ZERO", self.route_layer) + self.copy_layout_pin(self.cell_inst, "S", "S") self.copy_layout_pin(self.cell_inst, "D", "D") self.source_pos = self.cell_inst.get_pin("S").center() diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index 8bd1b976..e034d402 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -17,17 +17,22 @@ class rom_precharge_array(design): """ An array of inverters to create the inverted address lines for the rom decoder """ - def __init__(self, cols, name="", route_layer="li", strap_spacing=None, strap_layer="m2", tap_direction="row"): + def __init__(self, cols, name="", bitline_layer=None, strap_spacing=None, strap_layer="m2", tap_direction="row"): self.cols = cols - self.route_layer = route_layer self.strap_layer = strap_layer self.tap_direction = tap_direction - if self.route_layer == "m1" : + if "li" in layer: self.supply_layer = "li" else: self.supply_layer = "m1" + if bitline_layer is not None: + self.bitline_layer = bitline_layer + else: + self.bitline_layer = self.supply_layer + + if name=="": name = "rom_inv_array_{0}".format(cols) @@ -65,17 +70,15 @@ class rom_precharge_array(design): self.extend_well() def add_boundary(self): - # self.translate_all(self.well_ll) ur = self.find_highest_coords() self.add_label(layer="nwell", text="upper right",offset=ur) - # ur = vector(ur.x, ur.y - self.well_ll.y) super().add_boundary(vector(0, 0), ur) self.height = ur.y self.width = ur.x def create_modules(self): - self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", route_layer=self.route_layer, supply_layer=self.supply_layer) + self.pmos = factory.create(module_type="rom_precharge_cell", module_name="precharge_cell", bitline_layer=self.bitline_layer, supply_layer=self.supply_layer) # For layout constants self.dummy = factory.create(module_type="rom_base_cell") @@ -115,7 +118,6 @@ class rom_precharge_array(design): self.connect_inst([]) def place_instances(self): - self.add_label("ZERO", self.route_layer) self.array_pos = [] strap_num = 0 @@ -145,7 +147,7 @@ class rom_precharge_array(design): for col in range(self.cols): source_pin = self.pmos_insts[col].get_pin("D") bl = "pre_bl{0}_out".format(col) - self.add_layout_pin_rect_center(bl, self.route_layer, source_pin.center()) + self.add_layout_pin_rect_center(bl, self.bitline_layer, source_pin.center()) def route_supply(self): diff --git a/compiler/modules/rom_precharge_cell.py b/compiler/modules/rom_precharge_cell.py index 4489ccc9..3d4730aa 100644 --- a/compiler/modules/rom_precharge_cell.py +++ b/compiler/modules/rom_precharge_cell.py @@ -15,9 +15,9 @@ from openram.tech import drc class rom_precharge_cell(rom_base_cell): - def __init__(self, name="", route_layer="m1", supply_layer="li"): + def __init__(self, name="", bitline_layer="m1", supply_layer="li"): self.supply_layer = supply_layer - super().__init__(name=name, bitline_layer=route_layer) + super().__init__(name=name, bitline_layer=bitline_layer) def create_layout(self): super().create_layout() @@ -74,7 +74,7 @@ class rom_precharge_cell(rom_base_cell): from_layer=self.active_stack[2], to_layer=self.supply_layer) - bitline_offset = vector( 2 * (drc("minwidth_{}".format(self.bitline_layer)) + drc("{0}_to_{0}".format(self.bitline_layer))) ,0) + bitline_offset = vector( 1.5 * (drc("minwidth_{}".format(self.bitline_layer)) + drc("{0}_to_{0}".format(self.bitline_layer))) ,0) self.add_layout_pin_rect_center("vdd", self.supply_layer, pos - bitline_offset) diff --git a/compiler/tests/05_rom_base_bank_small_test.py b/compiler/tests/05_rom_base_bank_small_test.py index dbda8b41..e752db77 100644 --- a/compiler/tests/05_rom_base_bank_small_test.py +++ b/compiler/tests/05_rom_base_bank_small_test.py @@ -21,7 +21,7 @@ class rom_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) openram.init_openram(config_file, is_unit_test=True) - debug.info(1, "Testing 32 byte rom cell") + debug.info(1, "Testing 64 byte rom cell") test_data = "{0}/{1}/rom_data_64B".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 1) diff --git a/compiler/tests/05_rom_decoder_test.py b/compiler/tests/05_rom_decoder_test.py index 0ecea5cf..d6e5d27a 100644 --- a/compiler/tests/05_rom_decoder_test.py +++ b/compiler/tests/05_rom_decoder_test.py @@ -25,7 +25,7 @@ class rom_decoder_test(openram_test): debug.info(2, "Testing 2x4 decoder for rom cell") - a = factory.create(module_type="rom_decoder", num_outputs=16, strap_spacing=4, cols=16) + a = factory.create(module_type="rom_decoder", num_outputs=16, strap_spacing=4, fanout=16) self.local_check(a) openram.end_openram() diff --git a/compiler/tests/05_rom_precharge_array_test.py b/compiler/tests/05_rom_precharge_array_test.py index 1d067709..7d585e66 100644 --- a/compiler/tests/05_rom_precharge_array_test.py +++ b/compiler/tests/05_rom_precharge_array_test.py @@ -13,7 +13,7 @@ import sys, os import openram from openram import OPTS from openram.sram_factory import factory -import debug +from openram import debug class rom_precharge_test(openram_test): diff --git a/compiler/tests/05_rom_wordline_driver_array_test.py b/compiler/tests/05_rom_wordline_driver_array_test.py index f3175127..f3da0e75 100644 --- a/compiler/tests/05_rom_wordline_driver_array_test.py +++ b/compiler/tests/05_rom_wordline_driver_array_test.py @@ -24,7 +24,7 @@ class wordline_driver_array_test(openram_test): # check wordline driver for single port debug.info(2, "Checking driver") - tx = factory.create(module_type="rom_wordline_driver_array", rows=8, cols=32) + tx = factory.create(module_type="rom_wordline_driver_array", rows=8, fanout=32) self.local_check(tx) openram.end_openram() From 2d5199961dc57f9a3d0262c95dd806dd408d0506 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 2 Mar 2023 22:47:47 -0800 Subject: [PATCH 58/98] revert changes to pinvbuf --- compiler/modules/pinvbuf.py | 36 ++++++--------------------- compiler/modules/rom_control_logic.py | 1 + 2 files changed, 9 insertions(+), 28 deletions(-) diff --git a/compiler/modules/pinvbuf.py b/compiler/modules/pinvbuf.py index c71c6da9..f05a2e5b 100644 --- a/compiler/modules/pinvbuf.py +++ b/compiler/modules/pinvbuf.py @@ -17,14 +17,13 @@ class pinvbuf(pgate): This is a simple inverter/buffer used for driving loads. It is used in the column decoder for 1:2 decoding and as the clock buffer. """ - def __init__(self, name, size=4, height=None, route_in_cell=False): + def __init__(self, name, size=4, height=None): debug.info(1, "creating pinvbuf {}".format(name)) self.add_comment("size: {}".format(size)) self.stage_effort = 4 self.row_height = height - self.route_in_cell = route_in_cell # FIXME: Change the number of stages to support high drives. # stage effort of 4 or less @@ -135,33 +134,14 @@ class pinvbuf(pgate): z1_pin = self.inv1_inst.get_pin("Z") a4_pin = self.inv4_inst.get_pin("A") - if self.route_in_cell: - # inv1 Z to inv4 A (under and up) - mid_point = vector(a4_pin.cx(), z1_pin.cy()) - end_point = a4_pin.center() - # end_point = vector(a4_pin.cx(), a4_pin.by() - self.m1_space - self.contact_space) - self.add_path(route_stack[2], - [z1_pin.center(), mid_point, end_point]) - self.add_via_stack_center(from_layer=z1_pin.layer, - to_layer=route_stack[2], - offset=z1_pin.center()) - - self.add_via_stack_center(from_layer=a4_pin.layer, - to_layer=route_stack[2], - offset=end_point) - - - self.add_segment_center(a4_pin.layer, end_point, a4_pin.center()) - else: - # inv1 Z to inv4 A (up and over) - - mid_point = vector(z1_pin.cx(), a4_pin.cy()) - self.add_wire(route_stack, - [z1_pin.center(), mid_point, a4_pin.center()]) - self.add_via_stack_center(from_layer=z1_pin.layer, - to_layer=route_stack[2], - offset=z1_pin.center()) + # inv1 Z to inv4 A (up and over) + mid_point = vector(z1_pin.cx(), a4_pin.cy()) + self.add_wire(route_stack, + [z1_pin.center(), mid_point, a4_pin.center()]) + self.add_via_stack_center(from_layer=z1_pin.layer, + to_layer=route_stack[2], + offset=z1_pin.center()) def add_layout_pins(self): diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index af8b81a0..a6dca49d 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -90,6 +90,7 @@ class rom_control_logic(design): self.nand_inst.place(offset=[self.buf_inst.width, 0]) self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height], mirror="MX") + # hack to get around the fact these modules dont tile properly offset = self.driver_inst.get_pin("vdd").cy() - self.nand_inst.get_pin("vdd").cy() self.driver_inst.place(offset=[0, self.buf_inst.height + self.driver_inst.height - offset], mirror="MX") From 41f0b9a412a9e6a43e488f3e5ae077635d0d5387 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Wed, 8 Mar 2023 00:08:43 -0800 Subject: [PATCH 59/98] rom compiler top level --- __init__.py | 3 + compiler/modules/__init__.py | 1 + compiler/modules/rom_base_array.py | 4 +- compiler/modules/rom_base_bank.py | 199 ++++++++++++++++------------- compiler/options.py | 8 ++ compiler/rom.py | 160 +++++++++++++++++++++++ compiler/rom_config.py | 123 ++++++++++++++++++ rom_compiler.py | 72 +++++++++++ 8 files changed, 481 insertions(+), 89 deletions(-) create mode 100644 compiler/rom.py create mode 100644 compiler/rom_config.py create mode 100755 rom_compiler.py diff --git a/__init__.py b/__init__.py index 746ce73b..dd5751d5 100644 --- a/__init__.py +++ b/__init__.py @@ -44,3 +44,6 @@ from .globals import * # sram_config should be imported before sram from .sram_config import * from .sram import * + +from .rom_config import * +from .rom import * diff --git a/compiler/modules/__init__.py b/compiler/modules/__init__.py index ae748da9..3a514e7e 100755 --- a/compiler/modules/__init__.py +++ b/compiler/modules/__init__.py @@ -72,6 +72,7 @@ from .replica_pbitcell import * from .row_cap_array import * from .row_cap_bitcell_1port import * from .row_cap_bitcell_2port import * +from .rom_base_bank import * from .sense_amp_array import * from .sense_amp import * from .tri_gate_array import * diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index dd4c80d4..239af428 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -10,7 +10,7 @@ import math from .bitcell_base_array import bitcell_base_array from openram.base import vector -from openram import OPTS +from openram import OPTS, debug from openram.sram_factory import factory from openram.tech import drc, layer @@ -35,6 +35,7 @@ class rom_base_array(bitcell_base_array): self.array_col_size = self.column_size self.create_all_bitline_names() self.create_all_wordline_names() + # debug.info(1, "ROM array with rows: {0}, cols: {1}".format(self.row_size, self.column_size)) self.create_netlist() self.create_layout() @@ -148,6 +149,7 @@ class rom_base_array(bitcell_base_array): # when col = 0, bl_h is connected to precharge, otherwise connect to previous bl connection # when col = col_size - 1 connected column_sizeto gnd otherwise create new bl connection + # debug.info(1, "Create cell: r{0}, c{1}".format(row, col)) if row == self.row_size: bl_l = self.int_bl_list[col] diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index f8ab2eff..2619a587 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -6,10 +6,11 @@ # All rights reserved. # +import datetime from math import ceil, log, sqrt from openram.base import vector from openram.base import design -from openram import OPTS, debug +from openram import OPTS, debug, print_time from openram.sram_factory import factory from openram.tech import drc, layer, parameter @@ -21,120 +22,82 @@ class rom_base_bank(design): word size is in bytes """ - def __init__(self, strap_spacing=0, data_file=None, name="", word_size=2): + def __init__(self, name, rom_config): super().__init__(name=name) - self.word_size = word_size * 8 - self.read_binary(word_size=word_size, data_file=data_file, scramble_bits=True, endian="little") + self.rom_config = rom_config + rom_config.set_local_config(self) + self.word_size = self.word_bits + # self.read_binary(word_size=word_size, data_file=data_file, scramble_bits=True, endian="little") + # debug.info(1, "Rom data: {}".format(self.data)) self.num_outputs = self.rows self.num_inputs = ceil(log(self.rows, 2)) self.col_bits = ceil(log(self.words_per_row, 2)) self.row_bits = self.num_inputs - # self.data = [[0, 1, 0, 1], [1, 1, 1, 1], [1, 1, 0, 0], [0, 0, 1, 0]] - self.strap_spacing = strap_spacing - self.tap_spacing = 8 + self.tap_spacing = self.strap_spacing + + try: + from openram.tech import power_grid + self.supply_stack = power_grid + except ImportError: + # if no power_grid is specified by tech we use sensible defaults + # Route a M3/M4 grid + self.supply_stack = self.m3_stack + self.interconnect_layer = "m1" self.bitline_layer = "m1" self.wordline_layer = "m2" - if "li" in layer: self.route_stack = self.m1_stack else: self.route_stack = self.m2_stack self.route_layer = self.route_stack[0] - self.setup_layout_constants() - self.create_netlist() - if not OPTS.netlist_only: - self.create_layout() - """ - Reads a hexadecimal file from a given directory to be used as the data written to the ROM - endian is either "big" or "little" - word_size is the number of bytes per word - sets the row and column size based on the size of binary input, tries to keep array as square as possible, - """ - - def read_binary(self, data_file, word_size=2, endian="big", scramble_bits=False): - # Read data as hexidecimal text file - hex_file = open(data_file, 'r') - hex_data = hex_file.read() - - # Convert from hex into an int - data_int = int(hex_data, 16) - # Then from int into a right aligned, zero padded string - bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4) - - # Then turn the string into a list of ints - bin_data = list(bin_string) - bin_data = [int(x) for x in bin_data] - - # data size in bytes - data_size = len(bin_data) / 8 - num_words = int(data_size / word_size) - - bytes_per_col = sqrt(num_words) - - self.words_per_row = int(ceil(bytes_per_col /(2*word_size))) - - bits_per_row = self.words_per_row * word_size * 8 - - self.cols = bits_per_row - self.rows = int(num_words / (self.words_per_row)) - chunked_data = [] - - for i in range(0, len(bin_data), bits_per_row): - row_data = bin_data[i:i + bits_per_row] - if len(row_data) < bits_per_row: - row_data = [0] * (bits_per_row - len(row_data)) + row_data - chunked_data.append(row_data) - - - # if endian == "big": - - - self.data = chunked_data - if scramble_bits: - scrambled_chunked = [] - - for row_data in chunked_data: - scambled_data = [] - for bit in range(self.word_size): - for word in range(self.words_per_row): - scambled_data.append(row_data[bit + word * self.word_size]) - scrambled_chunked.append(scambled_data) - self.data = scrambled_chunked - - - - # self.data.reverse() - - debug.info(1, "Read rom binary: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, num_words, self.cols, self.rows, self.words_per_row)) def create_netlist(self): + start_time = datetime.datetime.now() self.add_modules() self.add_pins() - - + self.create_instances() + if not OPTS.is_unit_test: + print_time("Submodules", datetime.datetime.now(), start_time) def create_layout(self): - self.create_instances() + + start_time = datetime.datetime.now() + + self.setup_layout_constants() self.place_instances() + if not OPTS.is_unit_test: + print_time("Placement", datetime.datetime.now(), start_time) + + start_time = datetime.datetime.now() + self.route_layout() + if not OPTS.is_unit_test: + print_time("Routing", datetime.datetime.now(), start_time) + + self.height = self.array_inst.height + self.width = self.array_inst.width + self.add_boundary() + + start_time = datetime.datetime.now() + if not OPTS.is_unit_test: + # We only enable final verification if we have routed the design + # Only run this if not a unit test, because unit test will also verify it. + self.DRC_LVS(final_verification=OPTS.route_supplies, force_check=OPTS.check_lvsdrc) + print_time("Verification", datetime.datetime.now(), start_time) + + def route_layout(self): self.route_decode_outputs() - self.route_precharge() - self.route_clock() self.route_array_outputs() self.place_top_level_pins() self.route_supplies() self.route_output_buffers() - self.height = self.array_inst.height - self.width = self.array_inst.width - self.add_boundary() - def setup_layout_constants(self): self.route_layer_width = drc["minwidth_{}".format(self.route_stack[0])] @@ -166,7 +129,7 @@ class rom_base_bank(design): # in sky130 the address control buffer is composed of 2 size 2 NAND gates, # with a beta of 3, each of these gates has gate capacitance of 2 min sized inverters, therefor a load of 4 - + addr_control_buffer_effort = parameter['beta'] + 1 # a single min sized nmos makes up 1/4 of the input capacitance of a min sized inverter bitcell_effort = 0.25 @@ -492,12 +455,72 @@ class rom_base_bank(design): pin_num = msb - self.col_bits self.copy_layout_pin(self.decode_inst, "A{}".format(pin_num), name) - - - def route_supplies(self): for inst in self.insts: if not inst.mod.name.__contains__("contact"): self.copy_layout_pin(inst, "vdd") - self.copy_layout_pin(inst, "gnd") \ No newline at end of file + self.copy_layout_pin(inst, "gnd") + + # """ + # Reads a hexadecimal file from a given directory to be used as the data written to the ROM + # endian is either "big" or "little" + # word_size is the number of bytes per word + # sets the row and column size based on the size of binary input, tries to keep array as square as possible, + # """ + + # def read_binary(self, data_file, word_size=2, endian="big", scramble_bits=False): + # # Read data as hexidecimal text file + # hex_file = open(data_file, 'r') + # hex_data = hex_file.read() + + # # Convert from hex into an int + # data_int = int(hex_data, 16) + # # Then from int into a right aligned, zero padded string + # bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4) + + # # Then turn the string into a list of ints + # bin_data = list(bin_string) + # bin_data = [int(x) for x in bin_data] + + # # data size in bytes + # data_size = len(bin_data) / 8 + # num_words = int(data_size / word_size) + + # bytes_per_col = sqrt(num_words) + + # self.words_per_row = int(ceil(bytes_per_col /(2*word_size))) + + # bits_per_row = self.words_per_row * word_size * 8 + + # self.cols = bits_per_row + # self.rows = int(num_words / (self.words_per_row)) + # chunked_data = [] + + # for i in range(0, len(bin_data), bits_per_row): + # row_data = bin_data[i:i + bits_per_row] + # if len(row_data) < bits_per_row: + # row_data = [0] * (bits_per_row - len(row_data)) + row_data + # chunked_data.append(row_data) + + + # # if endian == "big": + + + # self.data = chunked_data + # if scramble_bits: + # scrambled_chunked = [] + + # for row_data in chunked_data: + # scambled_data = [] + # for bit in range(self.word_size): + # for word in range(self.words_per_row): + # scambled_data.append(row_data[bit + word * self.word_size]) + # scrambled_chunked.append(scambled_data) + # self.data = scrambled_chunked + + + + # # self.data.reverse() + + # debug.info(1, "Read rom binary: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, num_words, self.cols, self.rows, self.words_per_row)) diff --git a/compiler/options.py b/compiler/options.py index 14dc7b57..92427ac0 100644 --- a/compiler/options.py +++ b/compiler/options.py @@ -53,6 +53,14 @@ class options(optparse.Values): num_spare_rows = 0 num_spare_cols = 0 + ################### + # ROM configuration options + ################### + rom_endian = "little" + rom_data = None + strap_spacing = 8 + scramble_bits = True + ################### # Optimization options ################### diff --git a/compiler/rom.py b/compiler/rom.py new file mode 100644 index 00000000..53d7f435 --- /dev/null +++ b/compiler/rom.py @@ -0,0 +1,160 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 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 os +import shutil +import datetime +from openram import debug +from openram import rom_config as config +from openram import OPTS, print_time + + +class rom(): + """ + This is not a design module, but contains an ROM design instance. + """ + def __init__(self, rom_config=None, name=None): + + # Create default configs if custom config isn't provided + if rom_config is None: + rom_config = config(rom_data=OPTS.rom_data, + word_size=OPTS.word_size, + words_per_row=OPTS.words_per_row, + rom_endian=OPTS.rom_endian, + strap_spacing=OPTS.strap_spacing) + + if name is None: + name = OPTS.output_name + + rom_config.set_local_config(self) + + # reset the static duplicate name checker for unit tests + # in case we create more than one ROM + from openram.base import design + design.name_map=[] + + debug.info(2, "create rom of size {0} with {1} num of words".format(self.word_size, + self.num_words)) + start_time = datetime.datetime.now() + + self.name = name + + import openram.modules.rom_base_bank as rom + + self.r = rom(name, rom_config) + + self.r.create_netlist() + if not OPTS.netlist_only: + self.r.create_layout() + + if not OPTS.is_unit_test: + print_time("ROM creation", datetime.datetime.now(), start_time) + + def sp_write(self, name, lvs=False, trim=False): + self.r.sp_write(name, lvs, trim) + + def gds_write(self, name): + self.r.gds_write(name) + + def verilog_write(self, name): + self.r.verilog_write(name) + + def extended_config_write(self, name): + """Dump config file with all options. + Include defaults and anything changed by input config.""" + f = open(name, "w") + var_dict = dict((name, getattr(OPTS, name)) for name in dir(OPTS) if not name.startswith('__') and not callable(getattr(OPTS, name))) + for var_name, var_value in var_dict.items(): + if isinstance(var_value, str): + f.write(str(var_name) + " = " + "\"" + str(var_value) + "\"\n") + else: + f.write(str(var_name) + " = " + str(var_value)+ "\n") + f.close() + + def save(self): + """ Save all the output files while reporting time to do it as well. """ + + # Import this at the last minute so that the proper tech file + # is loaded and the right tools are selected + from openram import verify + + # Save the spice file + start_time = datetime.datetime.now() + spname = OPTS.output_path + self.r.name + ".sp" + debug.print_raw("SP: Writing to {0}".format(spname)) + self.sp_write(spname) + + print_time("Spice writing", datetime.datetime.now(), start_time) + + if not OPTS.netlist_only: + # Write the layout + start_time = datetime.datetime.now() + gdsname = OPTS.output_path + self.r.name + ".gds" + debug.print_raw("GDS: Writing to {0}".format(gdsname)) + self.gds_write(gdsname) + if OPTS.check_lvsdrc: + verify.write_drc_script(cell_name=self.r.name, + gds_name=os.path.basename(gdsname), + extract=True, + final_verification=True, + output_path=OPTS.output_path) + print_time("GDS", datetime.datetime.now(), start_time) + + # Save the LVS file + start_time = datetime.datetime.now() + lvsname = OPTS.output_path + self.r.name + ".lvs.sp" + debug.print_raw("LVS: Writing to {0}".format(lvsname)) + self.sp_write(lvsname, lvs=True) + if not OPTS.netlist_only and OPTS.check_lvsdrc: + verify.write_lvs_script(cell_name=self.r.name, + gds_name=os.path.basename(gdsname), + sp_name=os.path.basename(lvsname), + final_verification=True, + output_path=OPTS.output_path) + print_time("LVS writing", datetime.datetime.now(), start_time) + + # Save the extracted spice file + if OPTS.use_pex: + start_time = datetime.datetime.now() + # Output the extracted design if requested + pexname = OPTS.output_path + self.r.name + ".pex.sp" + spname = OPTS.output_path + self.r.name + ".sp" + verify.run_pex(self.r.name, gdsname, spname, output=pexname) + sp_file = pexname + print_time("Extraction", datetime.datetime.now(), start_time) + else: + # Use generated spice file for characterization + sp_file = spname + + # Save a functional simulation file + + # TODO: Characterize the design + + + # Write the config file + start_time = datetime.datetime.now() + from shutil import copyfile + copyfile(OPTS.config_file, OPTS.output_path + OPTS.output_name + '.py') + debug.print_raw("Config: Writing to {0}".format(OPTS.output_path + OPTS.output_name + '.py')) + print_time("Config", datetime.datetime.now(), start_time) + + # TODO: Write the datasheet + + # TODO: Write a verilog model + # start_time = datetime.datetime.now() + # vname = OPTS.output_path + self.r.name + '.v' + # debug.print_raw("Verilog: Writing to {0}".format(vname)) + # self.verilog_write(vname) + # print_time("Verilog", datetime.datetime.now(), start_time) + + # Write out options if specified + if OPTS.output_extended_config: + start_time = datetime.datetime.now() + oname = OPTS.output_path + OPTS.output_name + "_extended.py" + debug.print_raw("Extended Config: Writing to {0}".format(oname)) + self.extended_config_write(oname) + print_time("Extended Config", datetime.datetime.now(), start_time) diff --git a/compiler/rom_config.py b/compiler/rom_config.py new file mode 100644 index 00000000..9e67e37a --- /dev/null +++ b/compiler/rom_config.py @@ -0,0 +1,123 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 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 typing import List +from math import log, sqrt, ceil +from openram import debug +from openram.sram_factory import factory +from openram import OPTS + + + +class rom_config: + """ This is a structure that is used to hold the ROM configuration options. """ + + def __init__(self, word_size, rom_data, words_per_row=None, rom_endian="little", scramble_bits=True, strap_spacing=8): + self.word_size = word_size + self.word_bits = self.word_size * 8 + self.rom_data = rom_data + self.strap_spacing = strap_spacing + # TODO: This currently does nothing. It should change the behavior of the chunk funciton. + self.endian = rom_endian + + # This should pretty much always be true. If you want to make silicon art you might set to false + self.scramble_bits = scramble_bits + # This will get over-written when we determine the organization + self.words_per_row = words_per_row + + self.compute_sizes() + + def __str__(self): + """ override print function output """ + config_items = ["word_size", + "num_words", + "words_per_row", + "endian", + "strap_spacing", + "rom_data"] + str = "" + for item in config_items: + val = getattr(self, item) + str += "{} : {}\n".format(item, val) + return str + + def set_local_config(self, module): + """ Copy all of the member variables to the given module for convenience """ + + members = [attr for attr in dir(self) if not callable(getattr(self, attr)) and not attr.startswith("__")] + + # Copy all the variables to the local module + for member in members: + setattr(module, member, getattr(self, member)) + + def compute_sizes(self): + """ Computes the organization of the memory using data size by trying to make it a rectangle.""" + + # Read data as hexidecimal text file + hex_file = open(self.rom_data, 'r') + hex_data = hex_file.read() + + # Convert from hex into an int + data_int = int(hex_data, 16) + # Then from int into a right aligned, zero padded string + bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4) + + # Then turn the string into a list of ints + bin_data = list(bin_string) + raw_data = [int(x) for x in bin_data] + + # data size in bytes + data_size = len(raw_data) / 8 + self.num_words = int(data_size / self.word_size) + + # If this was hard coded, don't dynamically compute it! + if not self.words_per_row: + + # Row size if the array was square + bytes_per_row = sqrt(self.num_words) + + # Heuristic to value longer wordlines over long bitlines. + # The extra factor of 2 in the denominator should make the array less square + self.words_per_row = int(ceil(bytes_per_row /(2*self.word_size))) + + self.cols = self.words_per_row * self.word_size * 8 + self.rows = int(self.num_words / self.words_per_row) + + self.chunk_data(raw_data) + + # Set word_per_row in OPTS + OPTS.words_per_row = self.words_per_row + debug.info(1, "Read rom data file: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, self.num_words, self.cols, self.rows, self.words_per_row)) + + + def chunk_data(self, raw_data: List[int]): + """ + Chunks a flat list of bits into rows based on the calculated ROM sizes. Handles scrambling of data + """ + bits_per_row = self.cols + + chunked_data = [] + + for i in range(0, len(raw_data), bits_per_row): + row_data = raw_data[i:i + bits_per_row] + if len(row_data) < bits_per_row: + row_data = [0] * (bits_per_row - len(row_data)) + row_data + chunked_data.append(row_data) + + self.data = chunked_data + + if self.scramble_bits: + scrambled_chunked = [] + + for row_data in chunked_data: + scambled_data = [] + for bit in range(self.word_bits): + for word in range(self.words_per_row): + scambled_data.append(row_data[bit + word * self.word_bits]) + scrambled_chunked.append(scambled_data) + self.data = scrambled_chunked + diff --git a/rom_compiler.py b/rom_compiler.py new file mode 100755 index 00000000..f09c1c0a --- /dev/null +++ b/rom_compiler.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 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. +# + +""" +ROM Compiler + +The output files append the given suffixes to the output name: +a spice (.sp) file for circuit simulation +a GDS2 (.gds) file containing the layout +""" + + +import sys +import os +import datetime + +# You don't need the next two lines if you're sure that openram package is installed +from common import * +make_openram_package() +import openram + + +(OPTS, args) = openram.parse_args() + + +# Check that we are left with a single configuration file as argument. +if len(args) != 1: + print(openram.USAGE) + sys.exit(2) + +# These depend on arguments, so don't load them until now. +from openram import debug + +# Parse config file and set up all the options +openram.init_openram(config_file=args[0]) + +# Only print banner here so it's not in unit tests +openram.print_banner() + +# Keep track of running stats +start_time = datetime.datetime.now() +openram.print_time("Start", start_time) + + +output_extensions = [ "sp", "v"] +# Only output lef/gds if back-end +if not OPTS.netlist_only: + output_extensions.extend(["gds"]) + +output_files = ["{0}{1}.{2}".format(OPTS.output_path, + OPTS.output_name, x) + for x in output_extensions] +debug.print_raw("Output files are: ") +for path in output_files: + debug.print_raw(path) + +from openram import rom + +r = rom() + +# Output the files for the resulting ROM +r.save() + +# Delete temp files etc. +openram.end_openram() +openram.print_time("End", datetime.datetime.now(), start_time) \ No newline at end of file From 577cdcb232f7a302ce67e1ad2645ed7bd4d8837e Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 9 Mar 2023 12:58:04 -0800 Subject: [PATCH 60/98] example configs --- macros/configs/example_config_rom.py | 17 +++++++++++++++++ macros/rom_example_data/rom_data_1kB | 1 + 2 files changed, 18 insertions(+) create mode 100644 macros/configs/example_config_rom.py create mode 100644 macros/rom_example_data/rom_data_1kB diff --git a/macros/configs/example_config_rom.py b/macros/configs/example_config_rom.py new file mode 100644 index 00000000..294a6554 --- /dev/null +++ b/macros/configs/example_config_rom.py @@ -0,0 +1,17 @@ +# See LICENSE for licensing information. +# +# Copyright (c) 2016-2023 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. +# + +word_size = 1 + +nominal_corner_only = True + +output_name = "rom" + +spice_name = "ngspice" + +rom_data = "/home/jswalker/PrivateRAM/macros/rom_example_data/rom_data_1kB" \ No newline at end of file diff --git a/macros/rom_example_data/rom_data_1kB b/macros/rom_example_data/rom_data_1kB new file mode 100644 index 00000000..11006ecd --- /dev/null +++ b/macros/rom_example_data/rom_data_1kB @@ -0,0 +1 @@ +FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file From 879c14b8285e7ee877cdd9677843f757176b0e41 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 9 Mar 2023 12:58:44 -0800 Subject: [PATCH 61/98] sky130 only --- macros/configs/example_config_rom.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/macros/configs/example_config_rom.py b/macros/configs/example_config_rom.py index 294a6554..43c59c72 100644 --- a/macros/configs/example_config_rom.py +++ b/macros/configs/example_config_rom.py @@ -8,6 +8,8 @@ word_size = 1 +tech_name = "sky130" + nominal_corner_only = True output_name = "rom" From cd2314f0082d116b2658bd02f0f76d22537d7251 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 9 Mar 2023 13:36:26 -0800 Subject: [PATCH 62/98] better name --- .../{example_config_rom.py => example_config_rom_1kb_sky130.py} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename macros/configs/{example_config_rom.py => example_config_rom_1kb_sky130.py} (83%) diff --git a/macros/configs/example_config_rom.py b/macros/configs/example_config_rom_1kb_sky130.py similarity index 83% rename from macros/configs/example_config_rom.py rename to macros/configs/example_config_rom_1kb_sky130.py index 43c59c72..3ffd1a57 100644 --- a/macros/configs/example_config_rom.py +++ b/macros/configs/example_config_rom_1kb_sky130.py @@ -16,4 +16,4 @@ output_name = "rom" spice_name = "ngspice" -rom_data = "/home/jswalker/PrivateRAM/macros/rom_example_data/rom_data_1kB" \ No newline at end of file +rom_data = "macros/rom_example_data/rom_data_1kB" \ No newline at end of file From b50ec272da9533e8c0f6085b32d661e017bbb4c1 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 9 Mar 2023 14:12:14 -0800 Subject: [PATCH 63/98] updated top level rom unit tests --- compiler/modules/rom_base_bank.py | 4 +++ compiler/rom.py | 1 + compiler/tests/05_rom_base_bank_1kB_test.py | 10 ++++-- compiler/tests/05_rom_base_bank_2kB_test.py | 38 -------------------- compiler/tests/05_rom_base_bank_4kB_test.py | 9 ++++- compiler/tests/05_rom_base_bank_8kB_test.py | 39 --------------------- 6 files changed, 21 insertions(+), 80 deletions(-) delete mode 100644 compiler/tests/05_rom_base_bank_2kB_test.py delete mode 100644 compiler/tests/05_rom_base_bank_8kB_test.py diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_base_bank.py index 2619a587..c36f8321 100644 --- a/compiler/modules/rom_base_bank.py +++ b/compiler/modules/rom_base_bank.py @@ -55,6 +55,10 @@ class rom_base_bank(design): self.route_stack = self.m2_stack self.route_layer = self.route_stack[0] + if OPTS.is_unit_test: + self.create_netlist() + self.create_layout() + def create_netlist(self): start_time = datetime.datetime.now() diff --git a/compiler/rom.py b/compiler/rom.py index 53d7f435..8180b36c 100644 --- a/compiler/rom.py +++ b/compiler/rom.py @@ -25,6 +25,7 @@ class rom(): word_size=OPTS.word_size, words_per_row=OPTS.words_per_row, rom_endian=OPTS.rom_endian, + scramble_bits=OPTS.scramble_bits strap_spacing=OPTS.strap_spacing) if name is None: diff --git a/compiler/tests/05_rom_base_bank_1kB_test.py b/compiler/tests/05_rom_base_bank_1kB_test.py index 2cfb1b81..be3fcb3a 100644 --- a/compiler/tests/05_rom_base_bank_1kB_test.py +++ b/compiler/tests/05_rom_base_bank_1kB_test.py @@ -22,9 +22,15 @@ class rom_bank_test(openram_test): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) openram.init_openram(config_file, is_unit_test=True) debug.info(1, "Testing 1kB rom cell") - test_data = "{0}/{1}/rom_data_1kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 1) + + from openram import rom_config + + conf = rom_config(strap_spacing = 8, + rom_data = test_data, + word_size = 1) + + a = factory.create(module_type="rom_base_bank", rom_config=conf) a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) diff --git a/compiler/tests/05_rom_base_bank_2kB_test.py b/compiler/tests/05_rom_base_bank_2kB_test.py deleted file mode 100644 index c4f1c08a..00000000 --- a/compiler/tests/05_rom_base_bank_2kB_test.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2023 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 - -import openram -from openram import OPTS -from openram.sram_factory import factory -from openram import debug - - -class rom_bank_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - openram.init_openram(config_file, is_unit_test=True) - debug.info(1, "Testing 2kB rom cell") - - test_data = "{0}/{1}/rom_data_2kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 1) - a.sp_write(OPTS.openram_temp + 'simulation_file.sp') - self.local_check(a) - - openram.end_openram() - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = openram.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file diff --git a/compiler/tests/05_rom_base_bank_4kB_test.py b/compiler/tests/05_rom_base_bank_4kB_test.py index 90547d57..b9a37a21 100644 --- a/compiler/tests/05_rom_base_bank_4kB_test.py +++ b/compiler/tests/05_rom_base_bank_4kB_test.py @@ -24,7 +24,14 @@ class rom_bank_test(openram_test): debug.info(1, "Testing 4kB rom cell") test_data = "{0}/{1}/rom_data_4kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 2) + + from openram import rom_config + + conf = rom_config(strap_spacing = 8, + rom_data = test_data, + word_size = 2) + + a = factory.create(module_type="rom_base_bank", rom_config=conf) a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) diff --git a/compiler/tests/05_rom_base_bank_8kB_test.py b/compiler/tests/05_rom_base_bank_8kB_test.py deleted file mode 100644 index 3cf86b27..00000000 --- a/compiler/tests/05_rom_base_bank_8kB_test.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2023 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 - -import openram -from openram import OPTS -from openram.sram_factory import factory -from openram import debug - - -class rom_bank_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - openram.init_openram(config_file, is_unit_test=True) - debug.info(1, "Testing 8kB rom cell") - - test_data = "{0}/{1}/rom_data_8kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 2) - a.sp_write(OPTS.openram_temp + 'simulation_file_8kB.sp') - self.local_check(a) - - - openram.end_openram() - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = openram.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file From eec0f02bb87ff53535f5a684717edcd0042b4f5e Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 9 Mar 2023 14:20:02 -0800 Subject: [PATCH 64/98] skip test file --- compiler/rom.py | 2 +- compiler/tests/05_rom_base_bank_small_test.py | 38 ------------------- compiler/tests/skip_tests_freepdk45.txt | 9 +++++ 3 files changed, 10 insertions(+), 39 deletions(-) delete mode 100644 compiler/tests/05_rom_base_bank_small_test.py create mode 100644 compiler/tests/skip_tests_freepdk45.txt diff --git a/compiler/rom.py b/compiler/rom.py index 8180b36c..0c84c8f0 100644 --- a/compiler/rom.py +++ b/compiler/rom.py @@ -25,7 +25,7 @@ class rom(): word_size=OPTS.word_size, words_per_row=OPTS.words_per_row, rom_endian=OPTS.rom_endian, - scramble_bits=OPTS.scramble_bits + scramble_bits=OPTS.scramble_bits, strap_spacing=OPTS.strap_spacing) if name is None: diff --git a/compiler/tests/05_rom_base_bank_small_test.py b/compiler/tests/05_rom_base_bank_small_test.py deleted file mode 100644 index e752db77..00000000 --- a/compiler/tests/05_rom_base_bank_small_test.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2023 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 - -import openram -from openram import OPTS -from openram.sram_factory import factory -from openram import debug - - -class rom_bank_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - openram.init_openram(config_file, is_unit_test=True) - debug.info(1, "Testing 64 byte rom cell") - - test_data = "{0}/{1}/rom_data_64B".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) - a = factory.create(module_type="rom_base_bank", strap_spacing = 8, data_file = test_data, word_size = 1) - - self.local_check(a) - a.sp_write(OPTS.openram_temp + 'simulation_file.sp') - openram.end_openram() - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = openram.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/skip_tests_freepdk45.txt b/compiler/tests/skip_tests_freepdk45.txt new file mode 100644 index 00000000..2e0734d5 --- /dev/null +++ b/compiler/tests/skip_tests_freepdk45.txt @@ -0,0 +1,9 @@ +05_rom_base_bank_1kB_test.py +05_rom_base_bank_4kB_test.py +05_rom_array_test.py +05_rom_decoder_test.py +05_rom_precharge_array_test.py +05_rom_wordline_driver_array_test.py +05_rom_decoder_buffer_array_test.py +05_rom_column_mux_array_test.py +05_rom_control_logic_test.py \ No newline at end of file From 041c738cb261f8b03317c250a6c3cbfaeb0bb2c8 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Mar 2023 11:27:53 -0700 Subject: [PATCH 65/98] Rework macros to run ROM tests too. --- macros/Makefile | 47 +++++++++++++------ .../example_1kbyte.dat} | 0 .../sky130_rom_1kbyte.py} | 11 +++-- .../example_config_1rw_1r_scn4m_subm.py | 0 .../example_config_1rw_1w_scn4m_subm.py | 0 .../example_config_1rw_2mux_scn4m_subm.py | 0 .../example_config_1w_1r_scn4m_subm.py | 0 .../example_config_2rw_scn4m_subm.py | 0 .../example_config_big_scn4m_subm.py | 0 .../example_config_freepdk45.py | 0 .../example_config_giant_scn4m_subm.py | 0 .../example_config_medium_scn4m_subm.py | 0 .../example_config_scn4m_subm.py | 0 .../freepdk45_sram_1rw1r_32x2048_8.py | 0 ...scn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py | 0 .../scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py | 0 .../scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py | 0 ...n4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py | 0 .../scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py | 0 .../scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py | 0 .../sky130_sram_1kbyte_1r1w_8x1024_8.py | 0 .../sky130_sram_1kbyte_1rw1r_32x256_8.py | 0 .../sky130_sram_1kbyte_1rw1r_8x1024_8.py | 0 .../sky130_sram_1kbyte_1rw_32x256_8.py | 0 .../sky130_sram_1rw1r_tiny.py | 0 .../sky130_sram_1rw_tiny.py | 0 .../sky130_sram_2kbyte_1rw1r_32x512_8.py | 0 .../sky130_sram_2kbyte_1rw_32x512_8.py | 0 .../sky130_sram_4kbyte_1rw1r_32x1024_8.py | 0 .../sky130_sram_4kbyte_1rw_32x1024_8.py | 0 .../sky130_sram_4kbyte_1rw_64x512_8.py | 0 .../sky130_sram_common.py | 0 openram.mk | 7 +-- 33 files changed, 43 insertions(+), 22 deletions(-) rename macros/{rom_example_data/rom_data_1kB => rom_configs/example_1kbyte.dat} (100%) rename macros/{configs/example_config_rom_1kb_sky130.py => rom_configs/sky130_rom_1kbyte.py} (59%) rename macros/{configs => sram_configs}/example_config_1rw_1r_scn4m_subm.py (100%) rename macros/{configs => sram_configs}/example_config_1rw_1w_scn4m_subm.py (100%) rename macros/{configs => sram_configs}/example_config_1rw_2mux_scn4m_subm.py (100%) rename macros/{configs => sram_configs}/example_config_1w_1r_scn4m_subm.py (100%) rename macros/{configs => sram_configs}/example_config_2rw_scn4m_subm.py (100%) rename macros/{configs => sram_configs}/example_config_big_scn4m_subm.py (100%) rename macros/{configs => sram_configs}/example_config_freepdk45.py (100%) rename macros/{configs => sram_configs}/example_config_giant_scn4m_subm.py (100%) rename macros/{configs => sram_configs}/example_config_medium_scn4m_subm.py (100%) rename macros/{configs => sram_configs}/example_config_scn4m_subm.py (100%) rename macros/{configs => sram_configs}/freepdk45_sram_1rw1r_32x2048_8.py (100%) rename macros/{configs => sram_configs}/scn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py (100%) rename macros/{configs => sram_configs}/scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py (100%) rename macros/{configs => sram_configs}/scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py (100%) rename macros/{configs => sram_configs}/scn4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py (100%) rename macros/{configs => sram_configs}/scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py (100%) rename macros/{configs => sram_configs}/scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_1kbyte_1r1w_8x1024_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_1kbyte_1rw1r_32x256_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_1kbyte_1rw1r_8x1024_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_1kbyte_1rw_32x256_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_1rw1r_tiny.py (100%) rename macros/{configs => sram_configs}/sky130_sram_1rw_tiny.py (100%) rename macros/{configs => sram_configs}/sky130_sram_2kbyte_1rw1r_32x512_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_2kbyte_1rw_32x512_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_4kbyte_1rw1r_32x1024_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_4kbyte_1rw_32x1024_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_4kbyte_1rw_64x512_8.py (100%) rename macros/{configs => sram_configs}/sky130_sram_common.py (100%) diff --git a/macros/Makefile b/macros/Makefile index 94e0bf43..c932e220 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -17,29 +17,38 @@ endif # Verbosity OPENRAM_OPTS += -v --keeptemp -CONFIG_DIR = configs -SRCS=$(filter-out disabled-% %_common.py,$(sort $(notdir $(wildcard $(CONFIG_DIR)/*.py)))) -DIRS=$(basename $(SRCS)) -STAMPS=$(addsuffix .ok,$(DIRS)) +SRAM_CONFIG_DIR = sram_configs +SRAM_SRCS=$(filter-out disabled-% %_common.py,$(sort $(notdir $(wildcard $(SRAM_CONFIG_DIR)/*.py)))) +SRAM_DIRS=$(basename $(SRAM_SRCS)) +SRAM_STAMPS=$(addsuffix .ok,$(SRAM_DIRS)) + +ROM_CONFIG_DIR = rom_configs +ROM_SRCS=$(filter-out disabled-% %_common.py,$(sort $(notdir $(wildcard $(ROM_CONFIG_DIR)/*.py)))) +ROM_DIRS=$(basename $(ROM_SRCS)) +ROM_STAMPS=$(addsuffix .ok,$(ROM_DIRS)) configs: @echo @echo "Using OpenRAM at $(OPENRAM_HOME)" @echo " (which is version $$(cd $(OPENRAM_HOME); git describe --tags))" @echo - @echo "Configurations:" - @for D in $(DIRS); do echo " - $$D"; done + @echo "SRAM Configurations:" + @for D in $(SRAM_DIRS); do echo " - $$D"; done + @echo "ROM Configurations:" + @for D in $(ROM_DIRS); do echo " - $$D"; done @echo .PHONY: configs BROKEN := -WORKING_STAMPS=$(filter-out $(addsuffix .ok, $(BROKEN)), $(STAMPS)) -EXAMPLE_STAMPS=$(filter example%, $(WORKING_STAMPS)) -SKY130_STAMPS=$(filter sky130%, $(WORKING_STAMPS)) -FREEPDK45_STAMPS=$(filter freepdk45%, $(WORKING_STAMPS)) -SCN4M_SUBM_STAMPS=$(filter scn4m_subm%, $(WORKING_STAMPS)) +WORKING_SRAM_STAMPS=$(filter-out $(addsuffix .ok, $(BROKEN)), $(SRAM_STAMPS)) +WORKING_ROM_STAMPS=$(filter-out $(addsuffix .ok, $(BROKEN)), $(ROM_STAMPS)) + +EXAMPLE_STAMPS=$(filter example%, $(WORKING_SRAM_STAMPS)) $(filter example%, $(WORKING_ROM_STAMPS)) +SKY130_STAMPS=$(filter sky130%, $(WORKING_SRAM_STAMPS)) $(filter sky130%, $(WORKING_ROM_STAMPS)) +FREEPDK45_STAMPS=$(filter freepdk45%, $(WORKING_STAMPS)) $(filter freepdk45%, $(WORKING_ROM_STAMPS)) +SCN4M_SUBM_STAMPS=$(filter scn4m_subm%, $(WORKING_STAMPS)) $(filter scn4m_subm%, $(WORKING_ROM_STAMPS)) all: | configs @echo @@ -60,12 +69,22 @@ freepdk45: $(FREEPDK45_STAMPS) scn4m_subm: $(SCN4M_SUBM_STAMPS) .PHONY: scn4m_subm + +rom: $(WORKING_ROM_STAMPS) +.PHONY: rom + +sram: $(WORKING_SRAM_STAMPS) +.PHONY: sram -OPENRAM_TMP=$(MACRO_DIR)/$*/tmp -%.ok: configs/%.py +%.ok: sram_configs/%.py @echo "Building $*" @mkdir -p $* - @python3 -u $(OPENRAM_COMPILER) $(OPENRAM_OPTS) -o $* -p $(MACRO_DIR)/$* $(MACRO_DIR)/$< && touch $@ + @python3 -u $(SRAM_COMPILER) $(OPENRAM_OPTS) -o $* -p $(MACRO_DIR)/$* $(MACRO_DIR)/$< && touch $@ + +%.ok: rom_configs/%.py + @echo "Building $*" + @mkdir -p $* + @python3 -u $(ROM_COMPILER) $(OPENRAM_OPTS) -o $* -p $(MACRO_DIR)/$* $(MACRO_DIR)/$< && touch $@ .DELETE_ON_ERROR: $(STAMPS) diff --git a/macros/rom_example_data/rom_data_1kB b/macros/rom_configs/example_1kbyte.dat similarity index 100% rename from macros/rom_example_data/rom_data_1kB rename to macros/rom_configs/example_1kbyte.dat diff --git a/macros/configs/example_config_rom_1kb_sky130.py b/macros/rom_configs/sky130_rom_1kbyte.py similarity index 59% rename from macros/configs/example_config_rom_1kb_sky130.py rename to macros/rom_configs/sky130_rom_1kbyte.py index 3ffd1a57..f9de5f55 100644 --- a/macros/configs/example_config_rom_1kb_sky130.py +++ b/macros/rom_configs/sky130_rom_1kbyte.py @@ -8,12 +8,13 @@ word_size = 1 -tech_name = "sky130" - nominal_corner_only = True -output_name = "rom" -spice_name = "ngspice" +rom_data = "rom_configs/example_1kbyte.dat" -rom_data = "macros/rom_example_data/rom_data_1kB" \ No newline at end of file +output_name = "rom_1kbyte" +output_path = "macro/{output_name}".format(**locals()) + +import os +exec(open(os.path.join(os.path.dirname(__file__), 'sky130_rom_common.py')).read()) diff --git a/macros/configs/example_config_1rw_1r_scn4m_subm.py b/macros/sram_configs/example_config_1rw_1r_scn4m_subm.py similarity index 100% rename from macros/configs/example_config_1rw_1r_scn4m_subm.py rename to macros/sram_configs/example_config_1rw_1r_scn4m_subm.py diff --git a/macros/configs/example_config_1rw_1w_scn4m_subm.py b/macros/sram_configs/example_config_1rw_1w_scn4m_subm.py similarity index 100% rename from macros/configs/example_config_1rw_1w_scn4m_subm.py rename to macros/sram_configs/example_config_1rw_1w_scn4m_subm.py diff --git a/macros/configs/example_config_1rw_2mux_scn4m_subm.py b/macros/sram_configs/example_config_1rw_2mux_scn4m_subm.py similarity index 100% rename from macros/configs/example_config_1rw_2mux_scn4m_subm.py rename to macros/sram_configs/example_config_1rw_2mux_scn4m_subm.py diff --git a/macros/configs/example_config_1w_1r_scn4m_subm.py b/macros/sram_configs/example_config_1w_1r_scn4m_subm.py similarity index 100% rename from macros/configs/example_config_1w_1r_scn4m_subm.py rename to macros/sram_configs/example_config_1w_1r_scn4m_subm.py diff --git a/macros/configs/example_config_2rw_scn4m_subm.py b/macros/sram_configs/example_config_2rw_scn4m_subm.py similarity index 100% rename from macros/configs/example_config_2rw_scn4m_subm.py rename to macros/sram_configs/example_config_2rw_scn4m_subm.py diff --git a/macros/configs/example_config_big_scn4m_subm.py b/macros/sram_configs/example_config_big_scn4m_subm.py similarity index 100% rename from macros/configs/example_config_big_scn4m_subm.py rename to macros/sram_configs/example_config_big_scn4m_subm.py diff --git a/macros/configs/example_config_freepdk45.py b/macros/sram_configs/example_config_freepdk45.py similarity index 100% rename from macros/configs/example_config_freepdk45.py rename to macros/sram_configs/example_config_freepdk45.py diff --git a/macros/configs/example_config_giant_scn4m_subm.py b/macros/sram_configs/example_config_giant_scn4m_subm.py similarity index 100% rename from macros/configs/example_config_giant_scn4m_subm.py rename to macros/sram_configs/example_config_giant_scn4m_subm.py diff --git a/macros/configs/example_config_medium_scn4m_subm.py b/macros/sram_configs/example_config_medium_scn4m_subm.py similarity index 100% rename from macros/configs/example_config_medium_scn4m_subm.py rename to macros/sram_configs/example_config_medium_scn4m_subm.py diff --git a/macros/configs/example_config_scn4m_subm.py b/macros/sram_configs/example_config_scn4m_subm.py similarity index 100% rename from macros/configs/example_config_scn4m_subm.py rename to macros/sram_configs/example_config_scn4m_subm.py diff --git a/macros/configs/freepdk45_sram_1rw1r_32x2048_8.py b/macros/sram_configs/freepdk45_sram_1rw1r_32x2048_8.py similarity index 100% rename from macros/configs/freepdk45_sram_1rw1r_32x2048_8.py rename to macros/sram_configs/freepdk45_sram_1rw1r_32x2048_8.py diff --git a/macros/configs/scn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py b/macros/sram_configs/scn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py similarity index 100% rename from macros/configs/scn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py rename to macros/sram_configs/scn4m_subm_sram_16kbyte_1rw1r_32x4096_8.py diff --git a/macros/configs/scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py b/macros/sram_configs/scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py similarity index 100% rename from macros/configs/scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py rename to macros/sram_configs/scn4m_subm_sram_1kbyte_1rw1r_32x256_8.py diff --git a/macros/configs/scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py b/macros/sram_configs/scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py similarity index 100% rename from macros/configs/scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py rename to macros/sram_configs/scn4m_subm_sram_2kbyte_1rw1r_32x512_8.py diff --git a/macros/configs/scn4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py b/macros/sram_configs/scn4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py similarity index 100% rename from macros/configs/scn4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py rename to macros/sram_configs/scn4m_subm_sram_32kbyte_1rw1r_2x32x4096_8.py diff --git a/macros/configs/scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py b/macros/sram_configs/scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py similarity index 100% rename from macros/configs/scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py rename to macros/sram_configs/scn4m_subm_sram_4kbyte_1rw1r_32x1024_8.py diff --git a/macros/configs/scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py b/macros/sram_configs/scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py similarity index 100% rename from macros/configs/scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py rename to macros/sram_configs/scn4m_subm_sram_8kbyte_1rw1r_32x2048_8.py diff --git a/macros/configs/sky130_sram_1kbyte_1r1w_8x1024_8.py b/macros/sram_configs/sky130_sram_1kbyte_1r1w_8x1024_8.py similarity index 100% rename from macros/configs/sky130_sram_1kbyte_1r1w_8x1024_8.py rename to macros/sram_configs/sky130_sram_1kbyte_1r1w_8x1024_8.py diff --git a/macros/configs/sky130_sram_1kbyte_1rw1r_32x256_8.py b/macros/sram_configs/sky130_sram_1kbyte_1rw1r_32x256_8.py similarity index 100% rename from macros/configs/sky130_sram_1kbyte_1rw1r_32x256_8.py rename to macros/sram_configs/sky130_sram_1kbyte_1rw1r_32x256_8.py diff --git a/macros/configs/sky130_sram_1kbyte_1rw1r_8x1024_8.py b/macros/sram_configs/sky130_sram_1kbyte_1rw1r_8x1024_8.py similarity index 100% rename from macros/configs/sky130_sram_1kbyte_1rw1r_8x1024_8.py rename to macros/sram_configs/sky130_sram_1kbyte_1rw1r_8x1024_8.py diff --git a/macros/configs/sky130_sram_1kbyte_1rw_32x256_8.py b/macros/sram_configs/sky130_sram_1kbyte_1rw_32x256_8.py similarity index 100% rename from macros/configs/sky130_sram_1kbyte_1rw_32x256_8.py rename to macros/sram_configs/sky130_sram_1kbyte_1rw_32x256_8.py diff --git a/macros/configs/sky130_sram_1rw1r_tiny.py b/macros/sram_configs/sky130_sram_1rw1r_tiny.py similarity index 100% rename from macros/configs/sky130_sram_1rw1r_tiny.py rename to macros/sram_configs/sky130_sram_1rw1r_tiny.py diff --git a/macros/configs/sky130_sram_1rw_tiny.py b/macros/sram_configs/sky130_sram_1rw_tiny.py similarity index 100% rename from macros/configs/sky130_sram_1rw_tiny.py rename to macros/sram_configs/sky130_sram_1rw_tiny.py diff --git a/macros/configs/sky130_sram_2kbyte_1rw1r_32x512_8.py b/macros/sram_configs/sky130_sram_2kbyte_1rw1r_32x512_8.py similarity index 100% rename from macros/configs/sky130_sram_2kbyte_1rw1r_32x512_8.py rename to macros/sram_configs/sky130_sram_2kbyte_1rw1r_32x512_8.py diff --git a/macros/configs/sky130_sram_2kbyte_1rw_32x512_8.py b/macros/sram_configs/sky130_sram_2kbyte_1rw_32x512_8.py similarity index 100% rename from macros/configs/sky130_sram_2kbyte_1rw_32x512_8.py rename to macros/sram_configs/sky130_sram_2kbyte_1rw_32x512_8.py diff --git a/macros/configs/sky130_sram_4kbyte_1rw1r_32x1024_8.py b/macros/sram_configs/sky130_sram_4kbyte_1rw1r_32x1024_8.py similarity index 100% rename from macros/configs/sky130_sram_4kbyte_1rw1r_32x1024_8.py rename to macros/sram_configs/sky130_sram_4kbyte_1rw1r_32x1024_8.py diff --git a/macros/configs/sky130_sram_4kbyte_1rw_32x1024_8.py b/macros/sram_configs/sky130_sram_4kbyte_1rw_32x1024_8.py similarity index 100% rename from macros/configs/sky130_sram_4kbyte_1rw_32x1024_8.py rename to macros/sram_configs/sky130_sram_4kbyte_1rw_32x1024_8.py diff --git a/macros/configs/sky130_sram_4kbyte_1rw_64x512_8.py b/macros/sram_configs/sky130_sram_4kbyte_1rw_64x512_8.py similarity index 100% rename from macros/configs/sky130_sram_4kbyte_1rw_64x512_8.py rename to macros/sram_configs/sky130_sram_4kbyte_1rw_64x512_8.py diff --git a/macros/configs/sky130_sram_common.py b/macros/sram_configs/sky130_sram_common.py similarity index 100% rename from macros/configs/sky130_sram_common.py rename to macros/sram_configs/sky130_sram_common.py diff --git a/openram.mk b/openram.mk index 60b59f17..b86e4a94 100644 --- a/openram.mk +++ b/openram.mk @@ -1,11 +1,12 @@ OPENRAM_HOME := $(abspath $(TOP_DIR)/compiler) OPENRAM_TECH := $(abspath $(TOP_DIR)/technology) -OPENRAM_COMPILER := $(abspath $(TOP_DIR)/sram_compiler.py) +SRAM_COMPILER := $(abspath $(TOP_DIR)/sram_compiler.py) +ROM_COMPILER := $(abspath $(TOP_DIR)/rom_compiler.py) PDK_ROOT ?= $(TOP_DIR) -ifeq (,$(wildcard $(OPENRAM_COMPILER))) -$(error Did not find '$(OPENRAM_COMPILER)' in '$(OPENRAM_HOME)' (from $$OPENRAM_HOME)) +ifeq (,$(wildcard $(SRAM_COMPILER))) +$(error Did not find '$(SRAM_COMPILER)' in '$(OPENRAM_HOME)' (from $$OPENRAM_HOME)) endif export OPENRAM_HOME export OPENRAM_TECH From fe65a2043143ddc5bb17ee5673474b83cb2f2dc2 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Mar 2023 14:44:50 -0700 Subject: [PATCH 66/98] Rename ROM unit tests. --- compiler/modules/{rom_base_bank.py => rom_bank.py} | 0 .../{05_rom_decoder_test.py => 06_rom_decoder_test.py} | 0 ...n_mux_array_test.py => 07_rom_column_mux_array_test.py} | 0 ...r_array_test.py => 08_rom_decoder_buffer_array_test.py} | 0 ...charge_array_test.py => 08_rom_precharge_array_test.py} | 0 ..._array_test.py => 10_rom_wordline_driver_array_test.py} | 0 .../tests/{05_rom_array_test.py => 14_rom_array_test.py} | 0 ..._control_logic_test.py => 16_rom_control_logic_test.py} | 0 ...5_rom_base_bank_1kB_test.py => 19_rom_bank_1kb_test.py} | 4 ++-- ...5_rom_base_bank_4kB_test.py => 19_rom_bank_4kb_test.py} | 4 ++-- macros/rom_configs/sky130_rom_common.py | 7 +++++++ 11 files changed, 11 insertions(+), 4 deletions(-) rename compiler/modules/{rom_base_bank.py => rom_bank.py} (100%) rename compiler/tests/{05_rom_decoder_test.py => 06_rom_decoder_test.py} (100%) rename compiler/tests/{05_rom_column_mux_array_test.py => 07_rom_column_mux_array_test.py} (100%) rename compiler/tests/{05_rom_decoder_buffer_array_test.py => 08_rom_decoder_buffer_array_test.py} (100%) rename compiler/tests/{05_rom_precharge_array_test.py => 08_rom_precharge_array_test.py} (100%) rename compiler/tests/{05_rom_wordline_driver_array_test.py => 10_rom_wordline_driver_array_test.py} (100%) rename compiler/tests/{05_rom_array_test.py => 14_rom_array_test.py} (100%) rename compiler/tests/{05_rom_control_logic_test.py => 16_rom_control_logic_test.py} (100%) rename compiler/tests/{05_rom_base_bank_1kB_test.py => 19_rom_bank_1kb_test.py} (91%) rename compiler/tests/{05_rom_base_bank_4kB_test.py => 19_rom_bank_4kb_test.py} (91%) create mode 100644 macros/rom_configs/sky130_rom_common.py diff --git a/compiler/modules/rom_base_bank.py b/compiler/modules/rom_bank.py similarity index 100% rename from compiler/modules/rom_base_bank.py rename to compiler/modules/rom_bank.py diff --git a/compiler/tests/05_rom_decoder_test.py b/compiler/tests/06_rom_decoder_test.py similarity index 100% rename from compiler/tests/05_rom_decoder_test.py rename to compiler/tests/06_rom_decoder_test.py diff --git a/compiler/tests/05_rom_column_mux_array_test.py b/compiler/tests/07_rom_column_mux_array_test.py similarity index 100% rename from compiler/tests/05_rom_column_mux_array_test.py rename to compiler/tests/07_rom_column_mux_array_test.py diff --git a/compiler/tests/05_rom_decoder_buffer_array_test.py b/compiler/tests/08_rom_decoder_buffer_array_test.py similarity index 100% rename from compiler/tests/05_rom_decoder_buffer_array_test.py rename to compiler/tests/08_rom_decoder_buffer_array_test.py diff --git a/compiler/tests/05_rom_precharge_array_test.py b/compiler/tests/08_rom_precharge_array_test.py similarity index 100% rename from compiler/tests/05_rom_precharge_array_test.py rename to compiler/tests/08_rom_precharge_array_test.py diff --git a/compiler/tests/05_rom_wordline_driver_array_test.py b/compiler/tests/10_rom_wordline_driver_array_test.py similarity index 100% rename from compiler/tests/05_rom_wordline_driver_array_test.py rename to compiler/tests/10_rom_wordline_driver_array_test.py diff --git a/compiler/tests/05_rom_array_test.py b/compiler/tests/14_rom_array_test.py similarity index 100% rename from compiler/tests/05_rom_array_test.py rename to compiler/tests/14_rom_array_test.py diff --git a/compiler/tests/05_rom_control_logic_test.py b/compiler/tests/16_rom_control_logic_test.py similarity index 100% rename from compiler/tests/05_rom_control_logic_test.py rename to compiler/tests/16_rom_control_logic_test.py diff --git a/compiler/tests/05_rom_base_bank_1kB_test.py b/compiler/tests/19_rom_bank_1kb_test.py similarity index 91% rename from compiler/tests/05_rom_base_bank_1kB_test.py rename to compiler/tests/19_rom_bank_1kb_test.py index be3fcb3a..f0a61dee 100644 --- a/compiler/tests/05_rom_base_bank_1kB_test.py +++ b/compiler/tests/19_rom_bank_1kb_test.py @@ -30,7 +30,7 @@ class rom_bank_test(openram_test): rom_data = test_data, word_size = 1) - a = factory.create(module_type="rom_base_bank", rom_config=conf) + a = factory.create(module_type="rom_bank", rom_config=conf) a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) @@ -41,4 +41,4 @@ if __name__ == "__main__": (OPTS, args) = openram.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file + unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/05_rom_base_bank_4kB_test.py b/compiler/tests/19_rom_bank_4kb_test.py similarity index 91% rename from compiler/tests/05_rom_base_bank_4kB_test.py rename to compiler/tests/19_rom_bank_4kb_test.py index b9a37a21..7fa2005d 100644 --- a/compiler/tests/05_rom_base_bank_4kB_test.py +++ b/compiler/tests/19_rom_bank_4kb_test.py @@ -31,7 +31,7 @@ class rom_bank_test(openram_test): rom_data = test_data, word_size = 2) - a = factory.create(module_type="rom_base_bank", rom_config=conf) + a = factory.create(module_type="rom_bank", rom_config=conf) a.sp_write(OPTS.openram_temp + 'simulation_file.sp') self.local_check(a) @@ -42,4 +42,4 @@ if __name__ == "__main__": (OPTS, args) = openram.parse_args() del sys.argv[1:] header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) \ No newline at end of file + unittest.main(testRunner=debugTestRunner()) diff --git a/macros/rom_configs/sky130_rom_common.py b/macros/rom_configs/sky130_rom_common.py new file mode 100644 index 00000000..40ebd414 --- /dev/null +++ b/macros/rom_configs/sky130_rom_common.py @@ -0,0 +1,7 @@ + +tech_name = "sky130" +nominal_corner_only = True + +#route_supplies = "ring" +check_lvsdrc = True + From d2b5be01303b72dc22da0082398370cb20c20e70 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Mar 2023 14:52:43 -0700 Subject: [PATCH 67/98] Add exclude tests for ROMs --- compiler/tests/Makefile | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index dd2d9738..7baa5f1f 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -63,7 +63,25 @@ BROKEN_STAMPS = \ %/50_riscv_512b_1rw_func_test.ok \ %/50_riscv_8k_1rw1r_func_test.ok \ %/50_riscv_8k_1rw_func_test.ok \ + freepdk45/06_rom_decoder_test.ok \ + freepdk45/07_rom_column_mux_array_test.ok \ + freepdk45/08_rom_decoder_buffer_array_test.ok \ + freepdk45/08_rom_precharge_array_test.ok \ + freepdk45/10_rom_wordline_driver_array_test.ok \ + freepdk45/14_rom_array_test.ok \ + freepdk45/16_rom_control_logic_test.ok \ + freepdk45/19_rom_bank_1kb_test.ok \ + freepdk45/19_rom_bank_4kb_test.ok \ freepdk45/21_xyce_delay_test.ok \ + scn4m_subm/06_rom_decoder_test.ok \ + scn4m_subm/07_rom_column_mux_array_test.ok \ + scn4m_subm/08_rom_decoder_buffer_array_test.ok \ + scn4m_subm/08_rom_precharge_array_test.ok \ + scn4m_subm/10_rom_wordline_driver_array_test.ok \ + scn4m_subm/14_rom_array_test.ok \ + scn4m_subm/16_rom_control_logic_test.ok \ + scn4m_subm/19_rom_bank_1kb_test.ok \ + scn4m_subm/19_rom_bank_4kb_test.ok \ scn4m_subm/19_single_bank_global_bitline_test.ok \ scn4m_subm/21_xyce_delay_test.ok \ sky130/01_library_test.ok \ From 56e14113aa7ce1487bb0ca796dc1560bfe1b7602 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Mar 2023 14:53:07 -0700 Subject: [PATCH 68/98] Change rom_base_bank name and top pin names --- compiler/modules/__init__.py | 2 +- compiler/modules/rom_bank.py | 90 ++++--------------------- compiler/rom.py | 2 +- macros/Makefile | 8 ++- macros/rom_configs/sky130_rom_common.py | 3 +- 5 files changed, 23 insertions(+), 82 deletions(-) diff --git a/compiler/modules/__init__.py b/compiler/modules/__init__.py index 3a514e7e..2f7d257a 100755 --- a/compiler/modules/__init__.py +++ b/compiler/modules/__init__.py @@ -72,7 +72,7 @@ from .replica_pbitcell import * from .row_cap_array import * from .row_cap_bitcell_1port import * from .row_cap_bitcell_2port import * -from .rom_base_bank import * +from .rom_bank import * from .sense_amp_array import * from .sense_amp import * from .tri_gate_array import * diff --git a/compiler/modules/rom_bank.py b/compiler/modules/rom_bank.py index c36f8321..451ed0d9 100644 --- a/compiler/modules/rom_bank.py +++ b/compiler/modules/rom_bank.py @@ -7,14 +7,14 @@ # import datetime -from math import ceil, log, sqrt +from math import ceil, log from openram.base import vector from openram.base import design -from openram import OPTS, debug, print_time +from openram import OPTS, print_time from openram.sram_factory import factory from openram.tech import drc, layer, parameter -class rom_base_bank(design): +class rom_bank(design): """ Rom data bank with row and column decoder + control logic @@ -113,14 +113,14 @@ class rom_base_bank(design): def add_pins(self): self.add_pin("clk", "INPUT") - self.add_pin("CS", "INPUT") + self.add_pin("cs", "INPUT") for i in range(self.row_bits + self.col_bits): - self.add_pin("addr_{}".format(i), "INPUT") + self.add_pin("addr[{}]".format(i), "INPUT") out_pins = [] for j in range(self.word_size): - out_pins.append("rom_out_{}".format(j)) + out_pins.append("dout[{}]".format(j)) self.add_pin_list(out_pins, "OUTPUT") self.add_pin("vdd", "POWER") @@ -208,14 +208,14 @@ class rom_base_bank(design): bitlines = ["bl_{}".format(bl) for bl in range(self.cols)] wordlines = ["wl_{}".format(wl) for wl in range(self.rows)] - addr_msb = ["addr_{}".format(addr + self.col_bits) for addr in range(self.row_bits)] - addr_lsb = ["addr_{}".format(addr) for addr in range(self.col_bits)] + addr_msb = ["addr[{}]".format(addr + self.col_bits) for addr in range(self.row_bits)] + addr_lsb = ["addr[{}]".format(addr) for addr in range(self.col_bits)] select_lines = ["word_sel_{}".format(word) for word in range(self.words_per_row)] bitline_bar = ["bl_b_{}".format(bl) for bl in range(self.cols)] pre_buf_outputs = ["rom_out_prebuf_{}".format(bit) for bit in range(self.word_size)] - outputs = ["rom_out_{}".format(bl) for bl in range(self.word_size)] + outputs = ["dout[{}]".format(bl) for bl in range(self.word_size)] array_pins = bitlines + wordlines + prechrg + vdd + gnd @@ -236,7 +236,7 @@ class rom_base_bank(design): self.connect_inst(row_decode_pins) self.control_inst = self.add_inst(name="rom_control", mod=self.control_logic) - self.connect_inst(["clk", "CS", "precharge", "clk_int", "vdd", "gnd"]) + self.connect_inst(["clk", "cs", "precharge", "clk_int", "vdd", "gnd"]) self.mux_inst = self.add_inst(name="rom_column_mux", mod=self.column_mux) self.connect_inst(col_mux_pins) @@ -445,17 +445,17 @@ class rom_base_bank(design): def place_top_level_pins(self): - self.copy_layout_pin(self.control_inst, "CS") + self.copy_layout_pin(self.control_inst, "CS", "cs") self.copy_layout_pin(self.control_inst, "clk_in", "clk") for i in range(self.word_size): - self.copy_layout_pin(self.output_inv_inst, "out_{}".format(i), "rom_out_{}".format(i)) + self.copy_layout_pin(self.output_inv_inst, "out_{}".format(i), "dout[{}]".format(i)) for lsb in range(self.col_bits): - name = "addr_{}".format(lsb) + name = "addr[{}]".format(lsb) self.copy_layout_pin(self.col_decode_inst, "A{}".format(lsb), name) for msb in range(self.col_bits, self.row_bits + self.col_bits): - name = "addr_{}".format(msb) + name = "addr[{}]".format(msb) pin_num = msb - self.col_bits self.copy_layout_pin(self.decode_inst, "A{}".format(pin_num), name) @@ -466,65 +466,3 @@ class rom_base_bank(design): self.copy_layout_pin(inst, "vdd") self.copy_layout_pin(inst, "gnd") - # """ - # Reads a hexadecimal file from a given directory to be used as the data written to the ROM - # endian is either "big" or "little" - # word_size is the number of bytes per word - # sets the row and column size based on the size of binary input, tries to keep array as square as possible, - # """ - - # def read_binary(self, data_file, word_size=2, endian="big", scramble_bits=False): - # # Read data as hexidecimal text file - # hex_file = open(data_file, 'r') - # hex_data = hex_file.read() - - # # Convert from hex into an int - # data_int = int(hex_data, 16) - # # Then from int into a right aligned, zero padded string - # bin_string = bin(data_int)[2:].zfill(len(hex_data) * 4) - - # # Then turn the string into a list of ints - # bin_data = list(bin_string) - # bin_data = [int(x) for x in bin_data] - - # # data size in bytes - # data_size = len(bin_data) / 8 - # num_words = int(data_size / word_size) - - # bytes_per_col = sqrt(num_words) - - # self.words_per_row = int(ceil(bytes_per_col /(2*word_size))) - - # bits_per_row = self.words_per_row * word_size * 8 - - # self.cols = bits_per_row - # self.rows = int(num_words / (self.words_per_row)) - # chunked_data = [] - - # for i in range(0, len(bin_data), bits_per_row): - # row_data = bin_data[i:i + bits_per_row] - # if len(row_data) < bits_per_row: - # row_data = [0] * (bits_per_row - len(row_data)) + row_data - # chunked_data.append(row_data) - - - # # if endian == "big": - - - # self.data = chunked_data - # if scramble_bits: - # scrambled_chunked = [] - - # for row_data in chunked_data: - # scambled_data = [] - # for bit in range(self.word_size): - # for word in range(self.words_per_row): - # scambled_data.append(row_data[bit + word * self.word_size]) - # scrambled_chunked.append(scambled_data) - # self.data = scrambled_chunked - - - - # # self.data.reverse() - - # debug.info(1, "Read rom binary: length {0} bytes, {1} words, set number of cols to {2}, rows to {3}, with {4} words per row".format(data_size, num_words, self.cols, self.rows, self.words_per_row)) diff --git a/compiler/rom.py b/compiler/rom.py index 0c84c8f0..b4f41889 100644 --- a/compiler/rom.py +++ b/compiler/rom.py @@ -44,7 +44,7 @@ class rom(): self.name = name - import openram.modules.rom_base_bank as rom + import openram.modules.rom_bank as rom self.r = rom(name, rom_config) diff --git a/macros/Makefile b/macros/Makefile index c932e220..e555f3a0 100644 --- a/macros/Makefile +++ b/macros/Makefile @@ -86,7 +86,7 @@ sram: $(WORKING_SRAM_STAMPS) @mkdir -p $* @python3 -u $(ROM_COMPILER) $(OPENRAM_OPTS) -o $* -p $(MACRO_DIR)/$* $(MACRO_DIR)/$< && touch $@ -.DELETE_ON_ERROR: $(STAMPS) +.DELETE_ON_ERROR: $(WORKING_SRAM_STAMPS) $(WORKING_ROM_STAMPS) $(DIRS): @$(MAKE) --no-print-directory $@.ok @@ -94,6 +94,8 @@ $(DIRS): .PHONY: $(DIRS) clean: - rm -rf $(STAMPS) - rm -rf $(DIRS) + rm -rf $(WORKING_SRAM_STAMPS) + rm -rf $(WORKING_ROM_STAMPS) + rm -rf $(SRAM_DIRS) + rm -rf $(ROM_DIRS) .PHONY: clean diff --git a/macros/rom_configs/sky130_rom_common.py b/macros/rom_configs/sky130_rom_common.py index 40ebd414..81f4c756 100644 --- a/macros/rom_configs/sky130_rom_common.py +++ b/macros/rom_configs/sky130_rom_common.py @@ -3,5 +3,6 @@ tech_name = "sky130" nominal_corner_only = True #route_supplies = "ring" -check_lvsdrc = True +#check_lvsdrc = True +check_lvsdrc = False From 09f9c4cc20219b933ebab9565524d76785ffdb6f Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 13 Mar 2023 15:22:29 -0700 Subject: [PATCH 69/98] some rom bank cleanup --- compiler/modules/rom_bank.py | 38 ------------------------------------ 1 file changed, 38 deletions(-) diff --git a/compiler/modules/rom_bank.py b/compiler/modules/rom_bank.py index 451ed0d9..969fa43c 100644 --- a/compiler/modules/rom_bank.py +++ b/compiler/modules/rom_bank.py @@ -28,8 +28,6 @@ class rom_bank(design): rom_config.set_local_config(self) self.word_size = self.word_bits - # self.read_binary(word_size=word_size, data_file=data_file, scramble_bits=True, endian="little") - # debug.info(1, "Rom data: {}".format(self.data)) self.num_outputs = self.rows self.num_inputs = ceil(log(self.rows, 2)) self.col_bits = ceil(log(self.words_per_row, 2)) @@ -250,9 +248,6 @@ class rom_bank(design): self.output_inv_inst = self.add_inst(name="rom_output_inverter", mod=self.output_inv) self.connect_inst(output_buf_pins) - - - def place_instances(self): self.place_row_decoder() self.place_data_array() @@ -323,8 +318,6 @@ class rom_bank(design): sel_pins.extend(col_decode_pins) self.connect_row_pins(self.wordline_layer, sel_pins, round=True) - - def route_array_inputs(self): for wl in range(self.rows): @@ -347,15 +340,6 @@ class rom_bank(design): col_decode_clk = self.col_decode_inst.get_pin("clk") array_prechrg = self.array_inst.get_pin("precharge") - - # Route precharge signal to the row decoder - # end = vector(row_decode_prechrg.cx() - 0.5 * self.interconnect_layer_width, prechrg_control.cy()) - - # self.add_segment_center(self.interconnect_layer, prechrg_control.center(), end) - - # start = end + vector(0.5 * self.interconnect_layer_width, 0) - # self.add_segment_center(self.interconnect_layer, start, row_decode_prechrg.center()) - self.add_via_stack_center(from_layer=self.route_stack[0], to_layer=prechrg_control.layer, offset=prechrg_control.center()) @@ -377,10 +361,8 @@ class rom_bank(design): end = col_decode_clk.center() self.add_path(self.route_stack[0], [start, mid1, mid2, end]) - # self.add_segment_center(col_decode_prechrg.layer, end, col_decode_prechrg.center()) # Route precharge to main array - # end = vector(col_decode_prechrg.cx(), array_prechrg.cy()) mid = vector(col_decode_prechrg.cx(), array_prechrg.cy() ) self.add_path(self.route_stack[0], [array_prechrg.center(), mid, col_decode_prechrg.center()]) @@ -407,19 +389,6 @@ class rom_bank(design): self.add_segment_center(row_decode_clk.layer, addr_control_clk, row_decode_clk.rc()) - # Route clock to column decoder - # end = col_decode_clk.lc() - vector( 2 * self.route_layer_pitch + self.route_layer_width, 0) - # self.add_path(self.route_stack[2], [clk_out.center(), end]) - - # self.add_via_stack_center(from_layer=self.route_stack[2], - # to_layer=row_decode_clk.layer, - # offset=end) - - # self.add_segment_center(col_decode_clk.layer, end, col_decode_clk.lc()) - - - - def route_array_outputs(self): array_out_pins = [self.array_inst.get_pin("bl_0_{}".format(bl)) for bl in range(self.cols)] inv_in_pins = [self.bitline_inv_inst.get_pin("in_{}".format(bl)) for bl in range(self.cols)] @@ -429,10 +398,6 @@ class rom_bank(design): self.connect_col_pins(self.interconnect_layer, array_out_pins + inv_in_pins, round=True, directions="nonpref") self.connect_col_pins(self.interconnect_layer, inv_out_pins + mux_pins, round=True, directions="nonpref") - - - - def route_output_buffers(self): mux = self.mux_inst buf = self.output_inv_inst @@ -441,9 +406,6 @@ class rom_bank(design): channel_ll = vector( route_nets[0][0].cx(), route_nets[0][1].cy() + self.m1_pitch * 3) self.create_horizontal_channel_route(netlist=route_nets, offset=channel_ll, layer_stack=self.m1_stack) - - - def place_top_level_pins(self): self.copy_layout_pin(self.control_inst, "CS", "cs") self.copy_layout_pin(self.control_inst, "clk_in", "clk") From 7fe5ed5c41c0b5d45c1c2f9af8ef7ba0f3383dc4 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 13 Mar 2023 16:09:05 -0700 Subject: [PATCH 70/98] edge routing --- compiler/modules/rom_bank.py | 57 +++++++++++++++++++++---- macros/rom_configs/sky130_rom_1kbyte.py | 5 +-- 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/compiler/modules/rom_bank.py b/compiler/modules/rom_bank.py index 969fa43c..25310297 100644 --- a/compiler/modules/rom_bank.py +++ b/compiler/modules/rom_bank.py @@ -13,6 +13,8 @@ from openram.base import design from openram import OPTS, print_time from openram.sram_factory import factory from openram.tech import drc, layer, parameter +from openram.router import router_tech + class rom_bank(design): @@ -75,16 +77,15 @@ class rom_bank(design): if not OPTS.is_unit_test: print_time("Placement", datetime.datetime.now(), start_time) + self.height = self.array_inst.height + self.width = self.array_inst.width + self.add_boundary() start_time = datetime.datetime.now() self.route_layout() if not OPTS.is_unit_test: print_time("Routing", datetime.datetime.now(), start_time) - self.height = self.array_inst.height - self.width = self.array_inst.width - self.add_boundary() - start_time = datetime.datetime.now() if not OPTS.is_unit_test: # We only enable final verification if we have routed the design @@ -101,6 +102,23 @@ class rom_bank(design): self.route_supplies() self.route_output_buffers() + rt = router_tech(self.supply_stack, 1) + init_bbox = self.get_bbox(side="ring", + margin=rt.track_width) + + # We need the initial bbox for the supply rings later + # because the perimeter pins will change the bbox + # Route the pins to the perimeter + if OPTS.perimeter_pins: + # We now route the escape routes far enough out so that they will + # reach past the power ring or stripes on the sides + bbox = self.get_bbox(side="ring", + margin=11*rt.track_width) + self.route_escape_pins(bbox) + + self.route_supplies() + + def setup_layout_constants(self): self.route_layer_width = drc["minwidth_{}".format(self.route_stack[0])] self.route_layer_pitch = drc["{0}_to_{0}".format(self.route_stack[0])] @@ -407,19 +425,20 @@ class rom_bank(design): self.create_horizontal_channel_route(netlist=route_nets, offset=channel_ll, layer_stack=self.m1_stack) def place_top_level_pins(self): - self.copy_layout_pin(self.control_inst, "CS", "cs") - self.copy_layout_pin(self.control_inst, "clk_in", "clk") + self.add_io_pin(self.control_inst, "CS", "cs") + self.add_io_pin(self.control_inst, "clk_in", "clk") for i in range(self.word_size): - self.copy_layout_pin(self.output_inv_inst, "out_{}".format(i), "dout[{}]".format(i)) + self.add_io_pin(self.output_inv_inst, "out_{}".format(i), "dout[{}]".format(i)) + for lsb in range(self.col_bits): name = "addr[{}]".format(lsb) - self.copy_layout_pin(self.col_decode_inst, "A{}".format(lsb), name) + self.add_io_pin(self.col_decode_inst, "A{}".format(lsb), name) for msb in range(self.col_bits, self.row_bits + self.col_bits): name = "addr[{}]".format(msb) pin_num = msb - self.col_bits - self.copy_layout_pin(self.decode_inst, "A{}".format(pin_num), name) + self.add_io_pin(self.decode_inst, "A{}".format(pin_num), name) def route_supplies(self): @@ -428,3 +447,23 @@ class rom_bank(design): self.copy_layout_pin(inst, "vdd") self.copy_layout_pin(inst, "gnd") + def route_escape_pins(self, bbox): + + pins_to_route = [] + + for bit in range(self.col_bits): + pins_to_route.append("addr[{0}]".format(bit)) + + for bit in range(self.row_bits): + pins_to_route.append("addr[{0}]".format(bit + self.col_bits)) + + for bit in range(self.word_size): + pins_to_route.append("dout[{0}]".format(bit)) + + pins_to_route.append("clk") + pins_to_route.append("cs") + from openram.router import signal_escape_router as router + rtr=router(layers=self.m3_stack, + design=self, + bbox=bbox) + rtr.escape_route(pins_to_route) \ No newline at end of file diff --git a/macros/rom_configs/sky130_rom_1kbyte.py b/macros/rom_configs/sky130_rom_1kbyte.py index f9de5f55..1f598070 100644 --- a/macros/rom_configs/sky130_rom_1kbyte.py +++ b/macros/rom_configs/sky130_rom_1kbyte.py @@ -8,10 +8,9 @@ word_size = 1 -nominal_corner_only = True +check_lvsdrc = True - -rom_data = "rom_configs/example_1kbyte.dat" +rom_data = "macros/rom_configs/example_1kbyte.dat" output_name = "rom_1kbyte" output_path = "macro/{output_name}".format(**locals()) From 4c34a54d32eaf1e7b01f251cfebda85e458bb64b Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 13 Mar 2023 17:05:57 -0700 Subject: [PATCH 71/98] top level boundary fixes --- compiler/modules/rom_bank.py | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/compiler/modules/rom_bank.py b/compiler/modules/rom_bank.py index 25310297..e8b03f64 100644 --- a/compiler/modules/rom_bank.py +++ b/compiler/modules/rom_bank.py @@ -77,8 +77,6 @@ class rom_bank(design): if not OPTS.is_unit_test: print_time("Placement", datetime.datetime.now(), start_time) - self.height = self.array_inst.height - self.width = self.array_inst.width self.add_boundary() start_time = datetime.datetime.now() @@ -93,6 +91,17 @@ class rom_bank(design): self.DRC_LVS(final_verification=OPTS.route_supplies, force_check=OPTS.check_lvsdrc) print_time("Verification", datetime.datetime.now(), start_time) + def add_boundary(self): + + ll = self.find_lowest_coords() + m1_offset = self.m1_width + self.translate_all(vector(0, ll.y)) + ur = self.find_highest_coords() + ur = vector(ur.x, ur.y) + super().add_boundary(vector(0, 0), ur) + self.width = ur.x + self.height = ur.y + def route_layout(self): self.route_decode_outputs() self.route_precharge() From 2075d244cb36a966fd99ae94236ba720f6e5c89e Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Mar 2023 14:55:23 -0700 Subject: [PATCH 72/98] Change ROM test permissions to include x --- compiler/tests/06_rom_decoder_test.py | 0 compiler/tests/07_rom_column_mux_array_test.py | 0 compiler/tests/08_rom_decoder_buffer_array_test.py | 0 compiler/tests/08_rom_precharge_array_test.py | 0 compiler/tests/10_rom_wordline_driver_array_test.py | 0 compiler/tests/14_rom_array_test.py | 0 compiler/tests/16_rom_control_logic_test.py | 0 compiler/tests/19_rom_bank_1kb_test.py | 0 compiler/tests/19_rom_bank_4kb_test.py | 0 9 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 compiler/tests/06_rom_decoder_test.py mode change 100644 => 100755 compiler/tests/07_rom_column_mux_array_test.py mode change 100644 => 100755 compiler/tests/08_rom_decoder_buffer_array_test.py mode change 100644 => 100755 compiler/tests/08_rom_precharge_array_test.py mode change 100644 => 100755 compiler/tests/10_rom_wordline_driver_array_test.py mode change 100644 => 100755 compiler/tests/14_rom_array_test.py mode change 100644 => 100755 compiler/tests/16_rom_control_logic_test.py mode change 100644 => 100755 compiler/tests/19_rom_bank_1kb_test.py mode change 100644 => 100755 compiler/tests/19_rom_bank_4kb_test.py diff --git a/compiler/tests/06_rom_decoder_test.py b/compiler/tests/06_rom_decoder_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/07_rom_column_mux_array_test.py b/compiler/tests/07_rom_column_mux_array_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/08_rom_decoder_buffer_array_test.py b/compiler/tests/08_rom_decoder_buffer_array_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/08_rom_precharge_array_test.py b/compiler/tests/08_rom_precharge_array_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/10_rom_wordline_driver_array_test.py b/compiler/tests/10_rom_wordline_driver_array_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/14_rom_array_test.py b/compiler/tests/14_rom_array_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/16_rom_control_logic_test.py b/compiler/tests/16_rom_control_logic_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/19_rom_bank_1kb_test.py b/compiler/tests/19_rom_bank_1kb_test.py old mode 100644 new mode 100755 diff --git a/compiler/tests/19_rom_bank_4kb_test.py b/compiler/tests/19_rom_bank_4kb_test.py old mode 100644 new mode 100755 From af0a6d32fb8ea8dab917b6108362a034c3d7a902 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Mar 2023 14:55:46 -0700 Subject: [PATCH 73/98] Remove old skip tests --- compiler/tests/skip_tests_freepdk45.txt | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 compiler/tests/skip_tests_freepdk45.txt diff --git a/compiler/tests/skip_tests_freepdk45.txt b/compiler/tests/skip_tests_freepdk45.txt deleted file mode 100644 index 2e0734d5..00000000 --- a/compiler/tests/skip_tests_freepdk45.txt +++ /dev/null @@ -1,9 +0,0 @@ -05_rom_base_bank_1kB_test.py -05_rom_base_bank_4kB_test.py -05_rom_array_test.py -05_rom_decoder_test.py -05_rom_precharge_array_test.py -05_rom_wordline_driver_array_test.py -05_rom_decoder_buffer_array_test.py -05_rom_column_mux_array_test.py -05_rom_control_logic_test.py \ No newline at end of file From 7c453e80be5e73ee55a700114fc6837c298e0e50 Mon Sep 17 00:00:00 2001 From: mrg Date: Mon, 13 Mar 2023 16:42:24 -0700 Subject: [PATCH 74/98] Simplify ROM test. --- compiler/tests/19_rom_bank_4kb_test.py | 45 ------------------- ...m_bank_1kb_test.py => 19_rom_bank_test.py} | 4 +- compiler/tests/configs/config.py | 3 +- compiler/tests/configs/rom_data/rom_data_1kB | 1 - compiler/tests/configs/rom_data/rom_data_2kB | 1 - compiler/tests/configs/rom_data/rom_data_4kB | 1 - compiler/tests/configs/rom_data/rom_data_8kB | 1 - .../tests/configs/{rom_data => }/rom_data_64B | 0 8 files changed, 3 insertions(+), 53 deletions(-) delete mode 100755 compiler/tests/19_rom_bank_4kb_test.py rename compiler/tests/{19_rom_bank_1kb_test.py => 19_rom_bank_test.py} (92%) delete mode 100644 compiler/tests/configs/rom_data/rom_data_1kB delete mode 100644 compiler/tests/configs/rom_data/rom_data_2kB delete mode 100644 compiler/tests/configs/rom_data/rom_data_4kB delete mode 100644 compiler/tests/configs/rom_data/rom_data_8kB rename compiler/tests/configs/{rom_data => }/rom_data_64B (100%) diff --git a/compiler/tests/19_rom_bank_4kb_test.py b/compiler/tests/19_rom_bank_4kb_test.py deleted file mode 100755 index 7fa2005d..00000000 --- a/compiler/tests/19_rom_bank_4kb_test.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 -# See LICENSE for licensing information. -# -# Copyright (c) 2016-2023 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 - -import openram -from openram import OPTS -from openram.sram_factory import factory -from openram import debug - - -class rom_bank_test(openram_test): - - def runTest(self): - config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) - openram.init_openram(config_file, is_unit_test=True) - debug.info(1, "Testing 4kB rom cell") - - test_data = "{0}/{1}/rom_data_4kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) - - from openram import rom_config - - conf = rom_config(strap_spacing = 8, - rom_data = test_data, - word_size = 2) - - a = factory.create(module_type="rom_bank", rom_config=conf) - a.sp_write(OPTS.openram_temp + 'simulation_file.sp') - self.local_check(a) - - openram.end_openram() - -# run the test from the command line -if __name__ == "__main__": - (OPTS, args) = openram.parse_args() - del sys.argv[1:] - header(__file__, OPTS.tech_name) - unittest.main(testRunner=debugTestRunner()) diff --git a/compiler/tests/19_rom_bank_1kb_test.py b/compiler/tests/19_rom_bank_test.py similarity index 92% rename from compiler/tests/19_rom_bank_1kb_test.py rename to compiler/tests/19_rom_bank_test.py index f0a61dee..4a3233e8 100755 --- a/compiler/tests/19_rom_bank_1kb_test.py +++ b/compiler/tests/19_rom_bank_test.py @@ -21,8 +21,8 @@ class rom_bank_test(openram_test): def runTest(self): config_file = "{}/tests/configs/config".format(os.getenv("OPENRAM_HOME")) openram.init_openram(config_file, is_unit_test=True) - debug.info(1, "Testing 1kB rom cell") - test_data = "{0}/{1}/rom_data_1kB".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) + debug.info(1, "Testing rom cell") + test_data = "{0}/{1}/rom_data_64B".format(os.getenv("OPENRAM_HOME"), OPTS.rom_data_dir) from openram import rom_config diff --git a/compiler/tests/configs/config.py b/compiler/tests/configs/config.py index 52bdbf2d..bb0c8894 100644 --- a/compiler/tests/configs/config.py +++ b/compiler/tests/configs/config.py @@ -17,5 +17,4 @@ check_lvsdrc = True #route_supplies = False output_name = "sram" - -rom_data_dir = "tests/configs/rom_data" \ No newline at end of file +rom_data_dir = "tests/configs" diff --git a/compiler/tests/configs/rom_data/rom_data_1kB b/compiler/tests/configs/rom_data/rom_data_1kB deleted file mode 100644 index 11006ecd..00000000 --- a/compiler/tests/configs/rom_data/rom_data_1kB +++ /dev/null @@ -1 +0,0 @@ -FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/compiler/tests/configs/rom_data/rom_data_2kB b/compiler/tests/configs/rom_data/rom_data_2kB deleted file mode 100644 index 74e92aba..00000000 --- a/compiler/tests/configs/rom_data/rom_data_2kB +++ /dev/null @@ -1 +0,0 @@ -FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/compiler/tests/configs/rom_data/rom_data_4kB b/compiler/tests/configs/rom_data/rom_data_4kB deleted file mode 100644 index 606b2b3f..00000000 --- a/compiler/tests/configs/rom_data/rom_data_4kB +++ /dev/null @@ -1 +0,0 @@ -FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/compiler/tests/configs/rom_data/rom_data_8kB b/compiler/tests/configs/rom_data/rom_data_8kB deleted file mode 100644 index 246571be..00000000 --- a/compiler/tests/configs/rom_data/rom_data_8kB +++ /dev/null @@ -1 +0,0 @@ -FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/compiler/tests/configs/rom_data/rom_data_64B b/compiler/tests/configs/rom_data_64B similarity index 100% rename from compiler/tests/configs/rom_data/rom_data_64B rename to compiler/tests/configs/rom_data_64B From fef9902c451f6e0ddd1f3fda1e614bcc734d022b Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 20 Mar 2023 14:35:06 -0700 Subject: [PATCH 75/98] rom base passing tests with top level routing --- compiler/base/hierarchy_layout.py | 4 +- compiler/modules/rom_address_control_array.py | 14 +++- compiler/modules/rom_bank.py | 61 ++++++++++++---- compiler/modules/rom_base_array.py | 69 ++++++++++++------- compiler/modules/rom_column_mux.py | 4 +- compiler/modules/rom_column_mux_array.py | 8 +-- compiler/modules/rom_control_logic.py | 6 +- compiler/modules/rom_poly_tap.py | 25 +++---- compiler/modules/rom_precharge_array.py | 2 +- compiler/modules/rom_wordline_driver_array.py | 60 ++++++++++++---- macros/rom_configs/sky130_rom_common.py | 6 +- 11 files changed, 176 insertions(+), 83 deletions(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 00833f77..d33d552d 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1897,7 +1897,7 @@ class layout(): elif add_vias: self.copy_power_pin(pin, new_name=new_name) - def add_io_pin(self, instance, pin_name, new_name, start_layer=None): + def add_io_pin(self, instance, pin_name, new_name, start_layer=None, directions=None): """ Add a signle input or output pin up to metal 3. """ @@ -1907,7 +1907,7 @@ class layout(): start_layer = pin.layer # Just use the power pin function for now to save code - self.add_power_pin(new_name, pin.center(), start_layer=start_layer) + self.add_power_pin(new_name, pin.center(), start_layer=start_layer, directions=directions) def add_power_pin(self, name, loc, directions=None, start_layer="m1"): # Hack for min area diff --git a/compiler/modules/rom_address_control_array.py b/compiler/modules/rom_address_control_array.py index e6226e06..5fcb33e0 100644 --- a/compiler/modules/rom_address_control_array.py +++ b/compiler/modules/rom_address_control_array.py @@ -107,4 +107,16 @@ class rom_address_control_array(design): def route_sources(self): self.route_horizontal_pins("vdd", insts=self.buf_insts, layer=self.route_layer) - self.route_horizontal_pins("gnd", insts=self.buf_insts, layer=self.route_layer) \ No newline at end of file + self.route_horizontal_pins("gnd", insts=self.buf_insts, layer=self.route_layer) + + tmp_pins = [] + for pin in self.get_pins("vdd"): + edge = vector(pin.lx() + 0.5 * self.route_width, pin.cy()) + tmp_pins.append(self.add_layout_pin_rect_center("vdd_edge", layer=self.route_layer, offset=edge)) + self.copy_layout_pin_shapes("vdd") + self.remove_layout_pin("vdd") + + for pin in tmp_pins: + print("copying pin") + self.copy_layout_pin(self, "vdd_edge", "vdd") + self.remove_layout_pin("vdd_edge") \ No newline at end of file diff --git a/compiler/modules/rom_bank.py b/compiler/modules/rom_bank.py index e8b03f64..b32e1cdf 100644 --- a/compiler/modules/rom_bank.py +++ b/compiler/modules/rom_bank.py @@ -1,3 +1,4 @@ + # See LICENSE for licensing information. # # Copyright (c) 2016-2023 Regents of the University of California and The Board @@ -108,13 +109,12 @@ class rom_bank(design): self.route_clock() self.route_array_outputs() self.place_top_level_pins() - self.route_supplies() self.route_output_buffers() rt = router_tech(self.supply_stack, 1) init_bbox = self.get_bbox(side="ring", margin=rt.track_width) - + self.route_supplies(init_bbox) # We need the initial bbox for the supply rings later # because the perimeter pins will change the bbox # Route the pins to the perimeter @@ -125,7 +125,7 @@ class rom_bank(design): margin=11*rt.track_width) self.route_escape_pins(bbox) - self.route_supplies() + def setup_layout_constants(self): @@ -221,6 +221,7 @@ class rom_bank(design): module_name="rom_output_buffer", rows=self.word_size, fanout=4, + tap_spacing=1, invert_outputs=True) @@ -373,8 +374,8 @@ class rom_bank(design): # Route precharge to col decoder start = prechrg_control.center() - mid1 = vector(self.control_inst.rx(), prechrg_control.cy()) - mid2 = vector(self.control_inst.rx(), col_decode_prechrg.cy()) + mid1 = vector(self.control_inst.rx() + self.interconnect_layer_pitch, prechrg_control.cy()) + mid2 = vector(self.control_inst.rx() + self.interconnect_layer_pitch, col_decode_prechrg.cy()) end = col_decode_prechrg.center() self.add_path(self.route_stack[0], [start, mid1, mid2, end]) @@ -383,7 +384,7 @@ class rom_bank(design): offset=end) start = mid1 - mid1 = vector(self.control_inst.rx(), start.y) + mid1 = vector(self.control_inst.rx() + self.interconnect_layer_pitch, start.y) mid2 = vector(mid1.x, col_decode_clk.cy()) end = col_decode_clk.center() self.add_path(self.route_stack[0], [start, mid1, mid2, end]) @@ -438,7 +439,7 @@ class rom_bank(design): self.add_io_pin(self.control_inst, "clk_in", "clk") for i in range(self.word_size): - self.add_io_pin(self.output_inv_inst, "out_{}".format(i), "dout[{}]".format(i)) + self.add_io_pin(self.output_inv_inst, "out_{}".format(i), "dout[{}]".format(i), directions="nonpref") for lsb in range(self.col_bits): name = "addr[{}]".format(lsb) @@ -449,15 +450,49 @@ class rom_bank(design): pin_num = msb - self.col_bits self.add_io_pin(self.decode_inst, "A{}".format(pin_num), name) - def route_supplies(self): + def route_supplies(self, bbox=None): - for inst in self.insts: - if not inst.mod.name.__contains__("contact"): - self.copy_layout_pin(inst, "vdd") - self.copy_layout_pin(inst, "gnd") + for pin_name in ["vdd", "gnd"]: + for inst in self.insts: + self.copy_power_pins(inst, pin_name) + + if not OPTS.route_supplies: + # Do not route the power supply (leave as must-connect pins) + return + elif OPTS.route_supplies == "grid": + from openram.router import supply_grid_router as router + else: + from openram.router import supply_tree_router as router + rtr=router(layers=self.supply_stack, + design=self, + bbox=bbox, + pin_type=OPTS.supply_pin_type) + + rtr.route() + + if OPTS.supply_pin_type in ["left", "right", "top", "bottom", "ring"]: + # Find the lowest leftest pin for vdd and gnd + for pin_name in ["vdd", "gnd"]: + # Copy the pin shape(s) to rectangles + for pin in self.get_pins(pin_name): + self.add_rect(pin.layer, + pin.ll(), + pin.width(), + pin.height()) + + # Remove the pin shape(s) + self.remove_layout_pin(pin_name) + + # Get new pins + pins = rtr.get_new_pins(pin_name) + for pin in pins: + self.add_layout_pin(pin_name, + pin.layer, + pin.ll(), + pin.width(), + pin.height()) def route_escape_pins(self, bbox): - pins_to_route = [] for bit in range(self.col_bits): diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 239af428..d8c076bc 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -58,7 +58,7 @@ class rom_base_array(bitcell_base_array): self.route_precharge() self.add_boundary() - self.place_rails() + self.route_supplies() self.connect_taps() def add_boundary(self): @@ -86,7 +86,8 @@ class rom_base_array(bitcell_base_array): if self.tap_direction == "row": self.poly_tap = factory.create(module_type="rom_poly_tap") else: - self.poly_tap = factory.create(module_type="rom_poly_tap", add_tap=True) + self.poly_tap = factory.create(module_type="rom_poly_tap", add_active_tap=True) + self.end_poly_tap = factory.create(module_type="rom_poly_tap", place_poly=True) self.precharge_array = factory.create(module_type="rom_precharge_array", cols=self.column_size, strap_spacing=self.strap_spacing, @@ -109,7 +110,8 @@ class rom_base_array(bitcell_base_array): def create_cell_instances(self): self.tap_inst = {} - self.tap_list = [] + self.active_tap_list = [] + self.poly_tap_list = [] self.cell_inst = {} self.cell_list = [] self.current_row = 0 @@ -129,19 +131,25 @@ class rom_base_array(bitcell_base_array): self.cell_inst[row, col] = new_inst row_list.append(new_inst) - name = "tap_r{0}_c{1}".format(row, self.array_col_size) - new_tap = self.add_inst(name=name, mod=self.poly_tap) - self.tap_inst[row, self.column_size] = new_tap - self.tap_list.append(new_tap) - self.connect_inst([]) + self.create_poly_tap(row, self.column_size) + # name = "tap_r{0}_c{1}".format(row, self.array_col_size) + # new_tap = self.add_inst(name=name, mod=self.poly_tap) + # self.tap_inst[row, self.column_size] = new_tap + # self.tap_list.append(new_tap) + # self.connect_inst([]) self.cell_list.append(row_list) def create_poly_tap(self, row, col): name = "tap_r{0}_c{1}".format(row, col) - new_tap = self.add_inst(name=name, mod=self.poly_tap) + if row == self.row_size and self.tap_direction == "col": + new_tap = self.add_inst(name=name, mod=self.end_poly_tap) + else: + new_tap = self.add_inst(name=name, mod=self.poly_tap) + self.active_tap_list.append(new_tap) + self.tap_inst[row, col]=new_tap - self.tap_list.append(new_tap) + self.poly_tap_list.append(new_tap) self.connect_inst([]) def create_cell(self, row, col): @@ -189,15 +197,32 @@ class rom_base_array(bitcell_base_array): # Make a flat list too self.all_bitline_names = [x for sl in zip(*self.bitline_names) for x in sl] - def place_rails(self): + def route_supplies(self): via_width = drc("m2_enclose_via1") * 0.5 + drc("minwidth_via1") pitch = drc["{0}_to_{0}".format(self.wordline_layer)] + drain_l = self.cell_list[self.row_size][0].get_pin("D") + drain_r = self.cell_list[self.row_size][self.column_size - 1].get_pin("D") + gnd_l = drain_l.center() + vector(-0.5 * self.route_width, pitch + via_width + self.route_pitch) + gnd_r = drain_r.center() + vector(0.5 * self.route_width, pitch + via_width + self.route_pitch) + self.add_layout_pin_segment_center(text="gnd", layer=self.bitline_layer, start=gnd_l, end=gnd_r) + + + if self.tap_direction == "row": + self.route_horizontal_pins("gnd", insts=[self], yside="cy") + self.connect_row_pins(layer=self.wordline_layer, pins=self.gnd_taps, name="gnd") + + self.remove_layout_pin("gnd_tap") + + if self.tap_direction == "col": + active_tap_pins = [self.active_tap_list[i].get_pin("active_tap") for i in range(len(self.active_tap_list))] + self.connect_col_pins(layer=self.supply_stack[0], pins=active_tap_pins, name="gnd_tmp") + for pin in self.get_pins("gnd_tmp"): + bottom = vector(pin.cx(), pin.by()) + top = vector(pin.cx(), pin.uy()) + self.add_layout_pin_rect_ends(layer=self.supply_stack[0], start=bottom, end=top, name="gnd") + self.remove_layout_pin("gnd_tmp") + - for i in range(self.column_size): - drain = self.cell_list[self.row_size][i].get_pin("D") - gnd_pos = drain.center() + vector(0, pitch + via_width + self.route_pitch) - self.add_layout_pin_rect_center(text="gnd", layer=self.bitline_layer, offset=gnd_pos) - self.route_horizontal_pins("gnd", insts=[self], yside="cy") self.copy_layout_pin(self.precharge_inst, "vdd") @@ -231,7 +256,7 @@ class rom_base_array(bitcell_base_array): self.tap_inst[row, self.column_size].place(self.strap_pos[row, self.column_size]) def route_pitch_offsets(self): - + self.gnd_taps = [] for row in range(0 , self.row_size, self.tap_spacing): for col in range(self.column_size): @@ -270,12 +295,11 @@ class rom_base_array(bitcell_base_array): self.add_via_stack_center(offset=tap_pos, from_layer=self.active_stack[2], to_layer=self.wordline_layer) - self.add_layout_pin_rect_center("gnd", self.wordline_layer, tap_pos) + self.gnd_taps.append(self.add_layout_pin_rect_center("gnd_tap", self.wordline_layer, tap_pos)) def place_precharge(self): self.precharge_offset = vector(0, - self.precharge_inst.height - self.zero_cell.nmos.end_to_contact - 2 * drc["nwell_enclose_active"] - 3 * self.m1_pitch) self.precharge_inst.place(offset=self.precharge_offset) - self.copy_layout_pin(self.precharge_inst, "vdd") self.copy_layout_pin(self.precharge_inst, "gate", "precharge") def place_wordline_contacts(self): @@ -332,9 +356,6 @@ class rom_base_array(bitcell_base_array): self.add_layout_pin_rect_center(text="precharge_r", layer="m1", offset=mid1) def connect_taps(self): - array_pins = [self.tap_list[i].get_pin("poly_tap") for i in range(len(self.tap_list))] + poly_tap_pins = [self.poly_tap_list[i].get_pin("poly_tap") for i in range(len(self.poly_tap_list))] - self.connect_row_pins(layer=self.wordline_layer, pins=array_pins, name=None, round=False) - - if self.tap_direction == "col": - self.route_vertical_pins("active_tap", insts=self.tap_list, layer=self.supply_stack[0], full_width=False) \ No newline at end of file + self.connect_row_pins(layer=self.wordline_layer, pins=poly_tap_pins) diff --git a/compiler/modules/rom_column_mux.py b/compiler/modules/rom_column_mux.py index 43d3bdab..e3d8a1d3 100644 --- a/compiler/modules/rom_column_mux.py +++ b/compiler/modules/rom_column_mux.py @@ -165,9 +165,9 @@ class rom_column_mux(pgate): # If there is a li layer, include it in the power stack self.add_via_stack_center(from_layer=self.active_stack[2], - to_layer=self.supply_stack[0], + to_layer=self.pin_layer, offset=active_pos) self.add_layout_pin_rect_center(text="gnd", - layer=self.supply_stack[0], + layer=self.pin_layer, offset=active_pos) \ No newline at end of file diff --git a/compiler/modules/rom_column_mux_array.py b/compiler/modules/rom_column_mux_array.py index 31f6bbee..e314596e 100644 --- a/compiler/modules/rom_column_mux_array.py +++ b/compiler/modules/rom_column_mux_array.py @@ -20,7 +20,7 @@ class rom_column_mux_array(design): Array of column mux to read the bitlines from ROM, based on the RAM column mux """ - def __init__(self, name, columns, word_size, tap_spacing=4, input_layer="m2", bitline_layer="m1", sel_layer="m2"): + def __init__(self, name, columns, word_size, tap_spacing=4, input_layer="m1", bitline_layer="m1", sel_layer="m2"): super().__init__(name) debug.info(1, "Creating {0}".format(self.name)) self.add_comment("cols: {0} word_size: {1} ".format(columns, word_size)) @@ -31,7 +31,7 @@ class rom_column_mux_array(design): self.input_layer = input_layer self.tap_spacing = tap_spacing self.sel_layer = sel_layer - + self.supply_layer = "m2" self.sel_pitch = getattr(self, self.sel_layer + "_pitch") self.bitline_layer = bitline_layer @@ -75,7 +75,7 @@ class rom_column_mux_array(design): def add_modules(self): self.mux = factory.create(module_type="rom_column_mux", input_layer=self.input_layer, output_layer=self.bitline_layer) - self.tap = factory.create(module_type="rom_poly_tap", add_tap=True) + self.tap = factory.create(module_type="rom_poly_tap", add_active_tap=True) self.cell = factory.create(module_type="rom_base_cell") def setup_layout_constants(self): @@ -123,7 +123,7 @@ class rom_column_mux_array(design): def route_supplies(self): - self.route_horizontal_pins("gnd", self.insts) + self.route_horizontal_pins("gnd", self.insts, layer=self.supply_layer) def add_routing(self): self.add_horizontal_input_rail() diff --git a/compiler/modules/rom_control_logic.py b/compiler/modules/rom_control_logic.py index a6dca49d..494c328d 100644 --- a/compiler/modules/rom_control_logic.py +++ b/compiler/modules/rom_control_logic.py @@ -101,10 +101,10 @@ class rom_control_logic(design): self.copy_layout_pin(self.buf_inst, "Z", "clk_out") self.copy_layout_pin(self.driver_inst, "Z", "prechrg") self.copy_layout_pin(self.nand_inst, "A", "CS") - self.copy_layout_pin(self.buf_inst, "gnd") - self.copy_layout_pin(self.driver_inst, "vdd") - self.copy_layout_pin(self.buf_inst, "vdd") + self.copy_power_pin(self.buf_inst.get_pin("gnd"), directions="nonpref") + self.copy_power_pin(self.driver_inst.get_pin("gnd"), directions="nonpref") + self.copy_power_pin(self.buf_inst.get_pin("vdd"), directions="nonpref") clk = self.buf_inst.get_pin("Z") nand_B = self.nand_inst.get_pin("B") diff --git a/compiler/modules/rom_poly_tap.py b/compiler/modules/rom_poly_tap.py index df698ca6..c16323b6 100644 --- a/compiler/modules/rom_poly_tap.py +++ b/compiler/modules/rom_poly_tap.py @@ -13,11 +13,15 @@ from openram.tech import drc class rom_poly_tap(design): - def __init__(self, name="", cell_name=None, tx_type="nmos", strap_layer="m2", add_tap=False): + def __init__(self, name="", cell_name=None, tx_type="nmos", strap_layer="m2", add_active_tap=False, place_poly=None): super().__init__(name, cell_name) self.strap_layer=strap_layer self.tx_type = tx_type - self.add_tap = add_tap + self.add_tap = add_active_tap + if place_poly is None: + self.place_poly = add_active_tap + else: + self.place_poly = place_poly self.pitch_offset = 0 self.create_netlist() self.create_layout() @@ -32,7 +36,7 @@ class rom_poly_tap(design): self.place_via() self.add_boundary() - if self.add_tap: + if self.add_tap or self.place_poly: self.place_active_tap() self.extend_poly() @@ -47,14 +51,6 @@ class rom_poly_tap(design): contact_width = self.poly_contact.width - # DRC rule here is hard coded since licon.9 isnt included in skywater130 tech file - - # poly contact spacing to P-diffusion < 0.235um (licon.9 + psdm.5a) - # if OPTS.tech_name == "sky130": - # self.contact_x_offset = 0.235 - (contact_width - self.pmos.contact_width) * 0.5 - self.poly_extend_active - # else: - # assert(False) - contact_y = self.dummy.cell_inst.width * 0.5 - 0.5 * self.contact_width - self.active_enclose_contact self.contact_x_offset = 0 @@ -91,13 +87,10 @@ class rom_poly_tap(design): tap_edge = tap_x + 0.5 * self.active_contact.height self.pitch_offset += (self.active_space * 2) - (tap_edge - active_edge) + self.contact_x_offset - if self.tx_type == "nmos": + if self.tx_type == "nmos" and self.add_tap: self.add_via_center(layers=self.active_stack, offset=contact_pos, implant_type="p", well_type="p", directions="nonpref") - self.add_power_pin(name="gnd", - loc=contact_pos, - start_layer=self.active_stack[2]) - self.add_layout_pin_rect_center("active_tap", self.supply_stack[0], contact_pos) \ No newline at end of file + self.add_layout_pin_rect_center("active_tap", self.active_stack[2], contact_pos) \ No newline at end of file diff --git a/compiler/modules/rom_precharge_array.py b/compiler/modules/rom_precharge_array.py index e034d402..a450c968 100644 --- a/compiler/modules/rom_precharge_array.py +++ b/compiler/modules/rom_precharge_array.py @@ -83,7 +83,7 @@ class rom_precharge_array(design): # For layout constants self.dummy = factory.create(module_type="rom_base_cell") - self.poly_tap = factory.create(module_type="rom_poly_tap", tx_type="pmos", add_tap=(self.tap_direction == "col")) + self.poly_tap = factory.create(module_type="rom_poly_tap", tx_type="pmos", add_active_tap=(self.tap_direction == "col")) def add_pins(self): for col in range(self.cols): diff --git a/compiler/modules/rom_wordline_driver_array.py b/compiler/modules/rom_wordline_driver_array.py index 7acdaf9c..44deac1c 100644 --- a/compiler/modules/rom_wordline_driver_array.py +++ b/compiler/modules/rom_wordline_driver_array.py @@ -49,11 +49,13 @@ class rom_wordline_driver_array(design): self.route_layer = "m1" self.place_drivers() self.route_layout() - self.route_supplies() + if self.tap_spacing != 0: self.place_taps() + self.route_supplies() self.add_boundary() + def add_pins(self): # inputs to wordline_driver. for i in range(self.rows): @@ -66,7 +68,7 @@ class rom_wordline_driver_array(design): def add_modules(self): b = factory.create(module_type="rom_base_cell") - self.tap = factory.create(module_type="rom_poly_tap", add_tap = True) + self.tap = factory.create(module_type="rom_poly_tap", add_active_tap = True) if self.invert_outputs: self.wl_driver = factory.create(module_type="pinv_dec", @@ -86,13 +88,41 @@ class rom_wordline_driver_array(design): Add a pin for each row of vdd/gnd which are must-connects next level up. """ - - if layer_props.wordline_driver.vertical_supply: - self.route_vertical_pins("vdd", [self], layer=self.supply_layer) - self.route_vertical_pins("gnd", [self], layer=self.supply_layer) + # self.route_vertical_pins("vdd", self.wld_inst, xside="cx", layer=self.supply_layer) + # self.route_vertical_pins("gnd", self.wld_inst, xside="cx", layer=self.supply_layer) + if not self.invert_outputs: + vdd_pins = [pin for inst in self.wld_inst for pin in inst.get_pins("vdd")] + gnd_pins = [pin for inst in self.wld_inst for pin in inst.get_pins("gnd")] else: - self.route_vertical_pins("vdd", self.wld_inst, xside="rx",) - self.route_vertical_pins("gnd", self.wld_inst, xside="lx",) + vdd_pins = [inst.get_pin("vdd") for inst in self.wld_inst] + gnd_pins = [inst.get_pin("gnd") for inst in self.wld_inst] + if self.tap_spacing != 0: + vdd_pins = vdd_pins + self.vdd_taps + gnd_pins = gnd_pins + self.gnd_taps + + supply_width = drc["minwidth_{}".format(self.supply_layer)] + + # Route together all internal supply pins + self.connect_col_pins(layer=self.supply_layer, pins=vdd_pins, name="vdd_tmp") + self.connect_col_pins(layer=self.supply_layer, pins=gnd_pins, name="gnd_tmp") + self.remove_layout_pin("gnd_tap") + self.remove_layout_pin("vdd_tap") + + # Place the top level supply pins on the edge of the module + for pin in self.get_pins("gnd_tmp"): + bottom = vector(pin.cx(), pin.by() - 0.5 * supply_width) + top = vector(pin.cx(), pin.uy() + 0.5 * supply_width) + self.add_layout_pin_rect_ends(layer=self.supply_layer, start=bottom, end=top, name="gnd") + + for pin in self.get_pins("vdd_tmp"): + bottom = vector(pin.cx(), pin.by() - 0.5 * supply_width) + top = vector(pin.cx(), pin.uy() + 0.5 * supply_width) + self.add_layout_pin_rect_ends(layer=self.supply_layer, start=bottom, end=top, name="vdd") + + + self.remove_layout_pin("gnd_tmp") + self.remove_layout_pin("vdd_tmp") + def create_drivers(self): self.wld_inst = [] @@ -125,8 +155,7 @@ class rom_wordline_driver_array(design): else: row_num = row inst = self.wld_inst[row_num] - self.copy_layout_pin(inst, "vdd") - self.copy_layout_pin(inst, "gnd") + self.copy_layout_pin(inst, "A", "in_{0}".format(row)) @@ -151,7 +180,8 @@ class rom_wordline_driver_array(design): self.add_layout_pin_rect_center(text="out_{}".format(row), layer=self.route_layer, offset=end - vector(0, 0.5 * route_width)) def place_taps(self): - + self.vdd_taps = [] + self.gnd_taps = [] for wl in range(0 , self.rows, self.tap_spacing): driver = self.wld_inst[wl] @@ -176,6 +206,7 @@ class rom_wordline_driver_array(design): self.place_tap(contact_pos, "p") def place_tap(self, offset, well_type): + self.add_via_center(layers=self.active_stack, offset=offset, implant_type=well_type, @@ -185,7 +216,8 @@ class rom_wordline_driver_array(design): from_layer=self.active_stack[2], to_layer=self.supply_layer) if well_type == "p": - pin = "gnd" + pin = "gnd_tap" + self.gnd_taps.append(self.add_layout_pin_rect_center(text=pin, layer=self.supply_layer, offset=offset)) else: - pin = "vdd" - self.add_layout_pin_rect_center(text=pin, layer=self.supply_layer, offset=offset) \ No newline at end of file + pin = "vdd_tap" + self.vdd_taps.append(self.add_layout_pin_rect_center(text=pin, layer=self.supply_layer, offset=offset)) diff --git a/macros/rom_configs/sky130_rom_common.py b/macros/rom_configs/sky130_rom_common.py index 81f4c756..d36887bf 100644 --- a/macros/rom_configs/sky130_rom_common.py +++ b/macros/rom_configs/sky130_rom_common.py @@ -2,7 +2,7 @@ tech_name = "sky130" nominal_corner_only = True -#route_supplies = "ring" -#check_lvsdrc = True -check_lvsdrc = False +route_supplies = "ring" +check_lvsdrc = True +# check_lvsdrc = False From 7805fcb21e344938d2ad1492c0f5d9b3d0485b79 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Mon, 20 Mar 2023 17:01:51 -0700 Subject: [PATCH 76/98] more top level routing cleanup --- compiler/modules/rom_address_control_array.py | 1 - compiler/modules/rom_base_array.py | 9 +++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/modules/rom_address_control_array.py b/compiler/modules/rom_address_control_array.py index 5fcb33e0..9f59ca71 100644 --- a/compiler/modules/rom_address_control_array.py +++ b/compiler/modules/rom_address_control_array.py @@ -117,6 +117,5 @@ class rom_address_control_array(design): self.remove_layout_pin("vdd") for pin in tmp_pins: - print("copying pin") self.copy_layout_pin(self, "vdd_edge", "vdd") self.remove_layout_pin("vdd_edge") \ No newline at end of file diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index d8c076bc..51ba8f07 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -204,11 +204,10 @@ class rom_base_array(bitcell_base_array): drain_r = self.cell_list[self.row_size][self.column_size - 1].get_pin("D") gnd_l = drain_l.center() + vector(-0.5 * self.route_width, pitch + via_width + self.route_pitch) gnd_r = drain_r.center() + vector(0.5 * self.route_width, pitch + via_width + self.route_pitch) - self.add_layout_pin_segment_center(text="gnd", layer=self.bitline_layer, start=gnd_l, end=gnd_r) + self.add_layout_pin_rect_ends(name="gnd", layer=self.bitline_layer, start=gnd_l, end=gnd_r) if self.tap_direction == "row": - self.route_horizontal_pins("gnd", insts=[self], yside="cy") self.connect_row_pins(layer=self.wordline_layer, pins=self.gnd_taps, name="gnd") self.remove_layout_pin("gnd_tap") @@ -217,13 +216,11 @@ class rom_base_array(bitcell_base_array): active_tap_pins = [self.active_tap_list[i].get_pin("active_tap") for i in range(len(self.active_tap_list))] self.connect_col_pins(layer=self.supply_stack[0], pins=active_tap_pins, name="gnd_tmp") for pin in self.get_pins("gnd_tmp"): - bottom = vector(pin.cx(), pin.by()) - top = vector(pin.cx(), pin.uy()) + bottom = vector(pin.cx(), pin.by() + 0.5 * drc("minwidth_{}".format(self.supply_stack[0]))) + top = vector(pin.cx(), pin.uy() - 0.5 * drc("minwidth_{}".format(self.supply_stack[0]))) self.add_layout_pin_rect_ends(layer=self.supply_stack[0], start=bottom, end=top, name="gnd") self.remove_layout_pin("gnd_tmp") - - self.copy_layout_pin(self.precharge_inst, "vdd") def place_array(self): From c1fb3cab6c79d2e056de80a61a63b81cf2f732a0 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Tue, 21 Mar 2023 14:46:05 -0700 Subject: [PATCH 77/98] 1kb rom DRC clean --- compiler/modules/rom_bank.py | 8 ++++---- compiler/modules/rom_base_array.py | 27 +++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 8 deletions(-) diff --git a/compiler/modules/rom_bank.py b/compiler/modules/rom_bank.py index b32e1cdf..0c7585ea 100644 --- a/compiler/modules/rom_bank.py +++ b/compiler/modules/rom_bank.py @@ -475,10 +475,10 @@ class rom_bank(design): for pin_name in ["vdd", "gnd"]: # Copy the pin shape(s) to rectangles for pin in self.get_pins(pin_name): - self.add_rect(pin.layer, - pin.ll(), - pin.width(), - pin.height()) + self.add_rect(layer=pin.layer, + offset=pin.ll(), + width=pin.width(), + height=pin.height()) # Remove the pin shape(s) self.remove_layout_pin(pin_name) diff --git a/compiler/modules/rom_base_array.py b/compiler/modules/rom_base_array.py index 51ba8f07..9c380624 100644 --- a/compiler/modules/rom_base_array.py +++ b/compiler/modules/rom_base_array.py @@ -209,17 +209,36 @@ class rom_base_array(bitcell_base_array): if self.tap_direction == "row": self.connect_row_pins(layer=self.wordline_layer, pins=self.gnd_taps, name="gnd") - self.remove_layout_pin("gnd_tap") if self.tap_direction == "col": + self.remove_layout_pin("gnd") + active_tap_pins = [self.active_tap_list[i].get_pin("active_tap") for i in range(len(self.active_tap_list))] self.connect_col_pins(layer=self.supply_stack[0], pins=active_tap_pins, name="gnd_tmp") + + gnd_y = gnd_l.y + min_x = float('inf') + max_x = 0 for pin in self.get_pins("gnd_tmp"): - bottom = vector(pin.cx(), pin.by() + 0.5 * drc("minwidth_{}".format(self.supply_stack[0]))) - top = vector(pin.cx(), pin.uy() - 0.5 * drc("minwidth_{}".format(self.supply_stack[0]))) - self.add_layout_pin_rect_ends(layer=self.supply_stack[0], start=bottom, end=top, name="gnd") + + # find the pins on the edges + if pin.cx() < min_x: + min_x = pin.cx() + if pin.cx() > max_x: + max_x = pin.cx() + + bottom = vector(pin.cx(), pin.by()) + top = vector(pin.cx(), gnd_y) + self.add_via_stack_center(offset=top, from_layer=self.bitline_layer, to_layer=self.supply_stack[0]) + self.add_via_center(offset=bottom, layers=self.supply_stack) + + self.add_layout_pin_rect_ends(name="gnd", layer=self.supply_stack[0], start=bottom, end=top) + self.remove_layout_pin("gnd_tmp") + self.add_segment_center(layer=self.supply_stack[2], start=vector(min_x, bottom.y), end=vector(max_x, bottom.y)) + self.add_segment_center(layer=self.bitline_layer, start=gnd_l, end=vector(min_x, gnd_l.y)) + self.add_segment_center(layer=self.bitline_layer, start=gnd_r, end=vector(max_x, gnd_r.y)) self.copy_layout_pin(self.precharge_inst, "vdd") From 52791a27198de19314452934a68769eac59480e7 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Tue, 21 Mar 2023 14:47:41 -0700 Subject: [PATCH 78/98] a space --- compiler/modules/rom_bank.py | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/modules/rom_bank.py b/compiler/modules/rom_bank.py index 0c7585ea..f4940338 100644 --- a/compiler/modules/rom_bank.py +++ b/compiler/modules/rom_bank.py @@ -1,4 +1,3 @@ - # See LICENSE for licensing information. # # Copyright (c) 2016-2023 Regents of the University of California and The Board From 0b056dca54cb0b1203b16918ac549905625a3e56 Mon Sep 17 00:00:00 2001 From: Jacob Walker Date: Thu, 30 Mar 2023 18:44:55 -0700 Subject: [PATCH 79/98] fixed rom bank test name --- compiler/tests/Makefile | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 7baa5f1f..8b992341 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -17,7 +17,7 @@ RESULTS_DIR = $(OPENRAM_DIR)/results -# Use % for all techs: +# Use % for all techs: # %/test.py # or a specific tech: # freepdk45/test.py @@ -70,8 +70,7 @@ BROKEN_STAMPS = \ freepdk45/10_rom_wordline_driver_array_test.ok \ freepdk45/14_rom_array_test.ok \ freepdk45/16_rom_control_logic_test.ok \ - freepdk45/19_rom_bank_1kb_test.ok \ - freepdk45/19_rom_bank_4kb_test.ok \ + freepdk45/19_rom_bank_test.ok \ freepdk45/21_xyce_delay_test.ok \ scn4m_subm/06_rom_decoder_test.ok \ scn4m_subm/07_rom_column_mux_array_test.ok \ @@ -80,8 +79,7 @@ BROKEN_STAMPS = \ scn4m_subm/10_rom_wordline_driver_array_test.ok \ scn4m_subm/14_rom_array_test.ok \ scn4m_subm/16_rom_control_logic_test.ok \ - scn4m_subm/19_rom_bank_1kb_test.ok \ - scn4m_subm/19_rom_bank_4kb_test.ok \ + scn4m_subm/19_rom_bank_test.ok \ scn4m_subm/19_single_bank_global_bitline_test.ok \ scn4m_subm/21_xyce_delay_test.ok \ sky130/01_library_test.ok \ @@ -126,7 +124,7 @@ all: clean $(WORKING_TECH_TEST_STAMPS) # Run a given technology # e.g. make freepdk45 -$(TECHS): +$(TECHS): @$(MAKE) --no-print-directory $(filter-out $(BROKEN_STAMPS), $(addprefix $@/, $(TEST_STAMPS))) .PHONY: $(TECHS) @@ -137,7 +135,7 @@ $(TEST_BASES): .PHONY: $(TEST_BASES) # To run a test in a given technology -%.ok: +%.ok: # @echo "Running $(gettech) $(getfile) ... " @rm -rf results/$* @rm -rf results/$*.* From 85db2043b27f842f8b927fe1a49deb42b0b05b40 Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Fri, 31 Mar 2023 06:10:25 +0000 Subject: [PATCH 80/98] Bump version: 1.2.7 -> 1.2.8 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c04c650a..db6fb4a9 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.7 +1.2.8 From 86372bbeb76f04139e926eb842dda1bc17236c78 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Fri, 7 Apr 2023 12:27:58 -0700 Subject: [PATCH 81/98] Add meta path finder for custom modules --- __init__.py | 48 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/__init__.py b/__init__.py index dd5751d5..4eababb0 100644 --- a/__init__.py +++ b/__init__.py @@ -7,19 +7,17 @@ # import os -# Attempt to add the source code to the PYTHONPATH here before running globals.init_openram(). + +# Attempt to add the source code to the PYTHONPATH here before running globals.init_openram() try: OPENRAM_HOME = os.path.abspath(os.environ.get("OPENRAM_HOME")) except: OPENRAM_HOME = os.path.dirname(os.path.abspath(__file__)) + "/compiler" - if not os.path.isdir(OPENRAM_HOME): assert False - # Make sure that OPENRAM_HOME is an environment variable just in case if "OPENRAM_HOME" not in os.environ.keys(): os.environ["OPENRAM_HOME"] = OPENRAM_HOME - # Prepend $OPENRAM_HOME to __path__ so that openram will use those modules __path__.insert(0, OPENRAM_HOME) @@ -29,7 +27,6 @@ if os.path.exists(OPENRAM_HOME + "/install_conda.sh"): CONDA_HOME = OPENRAM_HOME + "/miniconda" elif os.path.exists(OPENRAM_HOME + "/../install_conda.sh"): CONDA_HOME = os.path.abspath(OPENRAM_HOME + "/../miniconda") - # Add CONDA_HOME to environment variables try: os.environ["CONDA_HOME"] = CONDA_HOME @@ -41,9 +38,46 @@ except: # Import everything in globals.py from .globals import * # Import classes in the "openram" namespace -# sram_config should be imported before sram from .sram_config import * from .sram import * - from .rom_config import * from .rom import * + + +# Add a meta path finder for custom modules +from importlib.abc import MetaPathFinder +class custom_module_finder(MetaPathFinder): + """ + This class is a 'hook' in Python's import system. If it encounters a module + that can be customized, it checks if there is a custom module specified in + the configuration file. If there is a custom module, it is imported instead + of the default one. + """ + def find_spec(self, fullname, path, target=None): + # Get package and module names + package_name = fullname.split(".")[0] + module_name = fullname.split(".")[-1] + # Skip if the package is not openram + if package_name != "openram": + return None + # Check if this module can be custom + from openram import OPTS + if module_name in OPTS.__dict__.keys(): + # Get custom name from OPTS + custom_name = OPTS.__dict__[module_name] + # Skip if the module is default, it will be handled by Python + if custom_name == module_name: + return None + import sys + from importlib.util import spec_from_file_location + # Try to find the module in sys.path + for path in sys.path: + for file in os.listdir(path): + # If there is a script matching the custom module name, + # import it with the default module name + if file == (custom_name + ".py"): + return spec_from_file_location(module_name, "{0}/{1}.py".format(path, custom_name)) + return None +# Python calls meta path finders and asks them to handle the module import if +# they can +sys.meta_path.insert(0, custom_module_finder()) From 095e0baddd0c917d081fbe8d0f8ec69c99f94ddf Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Fri, 7 Apr 2023 12:32:29 -0700 Subject: [PATCH 82/98] Remove CHECKPOINT_OPTS since it is not used --- compiler/globals.py | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/compiler/globals.py b/compiler/globals.py index 626b5d22..2adae59e 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -28,7 +28,6 @@ NAME = "OpenRAM v{}".format(VERSION) USAGE = "sram_compiler.py [options] \nUse -h for help.\n" OPTS = options.options() -CHECKPOINT_OPTS = None def parse_args(): @@ -209,17 +208,6 @@ def init_openram(config_file, is_unit_test=False): factory.reset() global OPTS - global CHECKPOINT_OPTS - - # This is a hack. If we are running a unit test and have checkpointed - # the options, load them rather than reading the config file. - # This way, the configuration is reloaded at the start of every unit test. - # If a unit test fails, - # we don't have to worry about restoring the old config values - # that may have been tested. - if is_unit_test and CHECKPOINT_OPTS: - OPTS.__dict__ = CHECKPOINT_OPTS.__dict__.copy() - return # Setup correct bitcell names setup_bitcell() @@ -227,10 +215,6 @@ def init_openram(config_file, is_unit_test=False): # Import these to find the executables for checkpointing from openram import characterizer from openram import verify - # Make a checkpoint of the options so we can restore - # after each unit test - if not CHECKPOINT_OPTS: - CHECKPOINT_OPTS = copy.copy(OPTS) def install_conda(): From 7af2badf31c00ef033d88a6e800dbe3358ddd4ff Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Mon, 10 Apr 2023 10:28:15 -0700 Subject: [PATCH 83/98] Fix path search in custom module finder --- __init__.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/__init__.py b/__init__.py index 4eababb0..94bb9c33 100644 --- a/__init__.py +++ b/__init__.py @@ -62,9 +62,9 @@ class custom_module_finder(MetaPathFinder): return None # Check if this module can be custom from openram import OPTS - if module_name in OPTS.__dict__.keys(): + if hasattr(OPTS, module_name): # Get custom name from OPTS - custom_name = OPTS.__dict__[module_name] + custom_name = getattr(OPTS, module_name) # Skip if the module is default, it will be handled by Python if custom_name == module_name: return None @@ -72,6 +72,9 @@ class custom_module_finder(MetaPathFinder): from importlib.util import spec_from_file_location # Try to find the module in sys.path for path in sys.path: + # Skip this path if not directory + if not os.path.isdir(path): + continue for file in os.listdir(path): # If there is a script matching the custom module name, # import it with the default module name From f7a24aafb78224960eb98ea890f6cf08ac7f530e Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Mon, 10 Apr 2023 10:29:21 -0700 Subject: [PATCH 84/98] Ignore coverage files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f79d6d85..a045c64a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .DS_Store +.coverage* *~ *.orig *.rej From 71a8394cf8b5afa92697f4341dda9259aa3656c7 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Mon, 10 Apr 2023 14:30:30 -0700 Subject: [PATCH 85/98] Add note on how to uninstall conda --- docs/source/basic_setup.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/basic_setup.md b/docs/source/basic_setup.md index 9b0d0517..ccac8cd3 100644 --- a/docs/source/basic_setup.md +++ b/docs/source/basic_setup.md @@ -40,6 +40,12 @@ have installed on your system. > ./install_conda.sh > ``` +> **Note**: You can uninstall OpenRAM's Anaconda installation by running this +> command: +> ``` +> rm -rf miniconda +> ``` + ## Docker (deprecated, use Anaconda instead) From fc8ea972540935f2fc40c0a15d3865c2593aca52 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Mon, 10 Apr 2023 18:52:13 -0700 Subject: [PATCH 86/98] Update documentation for clarity --- docs/source/python_library.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/source/python_library.md b/docs/source/python_library.md index a4b92c5c..d61a6a82 100644 --- a/docs/source/python_library.md +++ b/docs/source/python_library.md @@ -47,6 +47,13 @@ point to that OpenRAM installation directory. If you don't want to use this feature, you can simply unset these environment variables. +> **Note**: If you are a developer working on the source code on local clone of +> the repository and want to use the Python library at the same time, you should +> set both `OPENRAM_HOME` and `OPENRAM_TECH` to point to the local clone (follow +> [Basic Setup](./basic_setup.md#go-back)). This way, the library will use the +> source code located at these paths and you won't have to rebuild the library +> after every change. + ## Usage From 688069cded857efc149aecd4f7793de1d7e73344 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Tue, 11 Apr 2023 10:50:54 -0700 Subject: [PATCH 87/98] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0bee4049..4c00b2dc 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ OpenRAM is licensed under the [BSD 3-Clause License](./LICENSE). + [M. R. Guthaus, J. E. Stine, S. Ataei, B. Chen, B. Wu, M. Sarwar, "OpenRAM: An Open-Source Memory Compiler," Proceedings of the 35th International Conference on Computer-Aided Design (ICCAD), 2016.](https://escholarship.org/content/qt8x19c778/qt8x19c778_noSplash_b2b3fbbb57f1269f86d0de77865b0691.pdf) + [S. Ataei, J. Stine, M. Guthaus, “A 64 kb differential single-port 12T SRAM design with a bit-interleaving scheme for low-voltage operation in 32 nm SOI CMOS,” International Conference on Computer Design (ICCD), 2016, pp. 499-506.](https://escholarship.org/uc/item/99f6q9c9) -+ [E. Ebrahimi, M. Guthaus, J. Renau, “Timing Speculative SRAM”, IEEE In- ternational Symposium on Circuits and Systems (ISCAS), 2017.](https://escholarship.org/content/qt7nn0j5x3/qt7nn0j5x3_noSplash_172457455e1aceba20694c3d7aa489b4.pdf) ++ [E. Ebrahimi, M. Guthaus, J. Renau, “Timing Speculative SRAM”, IEEE International Symposium on Circuits and Systems (ISCAS), 2017.](https://escholarship.org/content/qt7nn0j5x3/qt7nn0j5x3_noSplash_172457455e1aceba20694c3d7aa489b4.pdf) + [B. Wu, J.E. Stine, M.R. Guthaus, "Fast and Area-Efficient Word-Line Optimization", IEEE International Symposium on Circuits and Systems (ISCAS), 2019.](https://escholarship.org/content/qt98s4c1hp/qt98s4c1hp_noSplash_753dcc3e218f60aafff98ef77fb56384.pdf) + [B. Wu, M. Guthaus, "Bottom Up Approach for High Speed SRAM Word-line Buffer Insertion Optimization", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://ieeexplore.ieee.org/document/8920325) + [H. Nichols, M. Grimes, J. Sowash, J. Cirimelli-Low, M. Guthaus "Automated Synthesis of Multi-Port Memories and Control", IFIP/IEEE International Conference on Very Large Scale Integration (VLSI-SoC), 2019.](https://escholarship.org/content/qt7047n3k0/qt7047n3k0.pdf?t=q4gcij) From ed8242daf84d3fc351eaeaac86fda4bf1b51627d Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Tue, 11 Apr 2023 11:13:15 -0700 Subject: [PATCH 88/98] Add OPENRAM_TECH to package namespace --- compiler/globals.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/globals.py b/compiler/globals.py index 2adae59e..60442e99 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -565,8 +565,9 @@ def import_tech(): debug.info(1, "Tech directory found in {}".format(OPENRAM_TECH)) - # Add this environment variable to os.environ + # Add this environment variable to os.environ and openram namespace os.environ["OPENRAM_TECH"] = OPENRAM_TECH + openram.OPENRAM_TECH = OPENRAM_TECH # Add all of the paths for tech_path in OPENRAM_TECH.split(":"): From f3f18022cdc5e84e56023ffbd21cd0e5d7437000 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Tue, 11 Apr 2023 11:13:38 -0700 Subject: [PATCH 89/98] Update conda documentation --- docs/source/basic_setup.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/source/basic_setup.md b/docs/source/basic_setup.md index ccac8cd3..b936937a 100644 --- a/docs/source/basic_setup.md +++ b/docs/source/basic_setup.md @@ -30,6 +30,9 @@ you don't have to worry about updating/installing these tools. OpenRAM installs Anaconda silently in the background (without affecting any existing Anaconda setup you have). +You don't have to manually activate/deactivate the Anaconda environment. OpenRAM +automatically manages this before and after running the tools. + OpenRAM uses Anaconda by default, but you can turn this feature off by setting `use_conda = False` in your config file. Then, OpenRAM will use the tools you have installed on your system. @@ -40,8 +43,8 @@ have installed on your system. > ./install_conda.sh > ``` -> **Note**: You can uninstall OpenRAM's Anaconda installation by running this -> command: +> **Note**: You can uninstall OpenRAM's Anaconda installation by simply deleting +> the folder Anaconda is installed to. You can run: > ``` > rm -rf miniconda > ``` From 441aff8e093e160165123f7d75eb4420bb7236f6 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Wed, 12 Apr 2023 12:06:30 -0700 Subject: [PATCH 90/98] Add instructions to update a tool on conda --- docs/source/basic_setup.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/source/basic_setup.md b/docs/source/basic_setup.md index b936937a..91905861 100644 --- a/docs/source/basic_setup.md +++ b/docs/source/basic_setup.md @@ -49,6 +49,13 @@ have installed on your system. > rm -rf miniconda > ``` +> **Note**: You can change a tool's version with the following commands: +> ``` +> source ./miniconda/bin/activate +> conda uninstall +> conda install -y -c vlsida-eda = +> ``` + ## Docker (deprecated, use Anaconda instead) From 79a10dc63bbd3af2e7f9d0d9fadfc9195dc32fa9 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Wed, 12 Apr 2023 18:15:09 -0700 Subject: [PATCH 91/98] Use custom module name in module finder --- __init__.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/__init__.py b/__init__.py index 94bb9c33..ccb1c2b0 100644 --- a/__init__.py +++ b/__init__.py @@ -60,16 +60,15 @@ class custom_module_finder(MetaPathFinder): # Skip if the package is not openram if package_name != "openram": return None - # Check if this module can be custom + customizable = False + # Search for the module name in customizable modules from openram import OPTS - if hasattr(OPTS, module_name): - # Get custom name from OPTS - custom_name = getattr(OPTS, module_name) - # Skip if the module is default, it will be handled by Python - if custom_name == module_name: - return None + for k, v in OPTS.__dict__.items(): + if module_name == v: + customizable = True + # Search for the custom module + if customizable: import sys - from importlib.util import spec_from_file_location # Try to find the module in sys.path for path in sys.path: # Skip this path if not directory @@ -78,8 +77,9 @@ class custom_module_finder(MetaPathFinder): for file in os.listdir(path): # If there is a script matching the custom module name, # import it with the default module name - if file == (custom_name + ".py"): - return spec_from_file_location(module_name, "{0}/{1}.py".format(path, custom_name)) + if file == (module_name + ".py"): + from importlib.util import spec_from_file_location + return spec_from_file_location(module_name, "{0}/{1}.py".format(path, module_name)) return None # Python calls meta path finders and asks them to handle the module import if # they can From 51ddb083850940d96d184b5b77919bed8b5096f7 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Thu, 13 Apr 2023 22:12:46 -0700 Subject: [PATCH 92/98] Enable sky130 regression but disable failing tests --- compiler/tests/Makefile | 59 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 56 insertions(+), 3 deletions(-) diff --git a/compiler/tests/Makefile b/compiler/tests/Makefile index 8b992341..3ea5d299 100644 --- a/compiler/tests/Makefile +++ b/compiler/tests/Makefile @@ -4,7 +4,6 @@ include $(TOP_DIR)/openram.mk .DEFAULT_GOAL := all ARGS ?= -TEST_TECHS ?= scn4m_subm freepdk45 TECHS ?= scn4m_subm freepdk45 sky130 TEST_DIR = $(TOP_DIR)/compiler/tests @@ -107,11 +106,65 @@ BROKEN_STAMPS = \ sky130/23_lib_sram_model_corners_test.ok \ sky130/23_lib_sram_model_test.ok \ sky130/23_lib_sram_prune_test.ok \ - sky131/23_lib_sram_test.ok + sky130/23_lib_sram_test.ok \ + sky130/03_wire_test.ok \ + sky130/04_dummy_pbitcell_1rw1r1w_test.ok \ + sky130/04_dummy_pbitcell_1rw_test.ok \ + sky130/04_replica_pbitcell_1rw1r1w_test.ok \ + sky130/04_replica_pbitcell_1rw_test.ok \ + sky130/06_hierarchical_decoder_132row_test.ok \ + sky130/06_hierarchical_decoder_512row_test.ok \ + sky130/06_hierarchical_decoder_64row_test.ok \ + sky130/06_hierarchical_decoder_pbitcell_test.ok \ + sky130/10_write_driver_array_spare_cols_test.ok \ + sky130/10_write_driver_array_wmask_spare_cols_test.ok \ + sky130/14_capped_replica_bitcell_array_leftrbl_1rw_test.ok \ + sky130/14_capped_replica_bitcell_array_norbl_1rw_test.ok \ + sky130/14_replica_bitcell_array_leftrbl_1rw_test.ok \ + sky130/14_replica_bitcell_array_norbl_1rw_test.ok \ + sky130/14_replica_column_1rw_1r_test.ok \ + sky130/14_replica_column_1rw_test.ok \ + sky130/14_replica_pbitcell_1rw1r_array_test.ok \ + sky130/14_replica_pbitcell_1rw_array_test.ok \ + sky130/15_global_bitcell_array_1rw_1r_test.ok \ + sky130/15_global_bitcell_array_test.ok \ + sky130/15_local_bitcell_array_test.ok \ + sky130/18_port_address_512rows_test.ok \ + sky130/18_port_data_spare_cols_test.ok \ + sky130/19_single_bank_2mux_test.ok \ + sky130/19_single_bank_4mux_test.ok \ + sky130/19_single_bank_8mux_test.ok \ + sky130/19_single_bank_global_bitline_test.ok \ + sky130/19_single_bank_nomux_test.ok \ + sky130/19_single_bank_spare_cols_test.ok \ + sky130/19_single_bank_wmask_test.ok \ + sky130/20_sram_1bank_2mux_1rw_1r_spare_cols_test.ok \ + sky130/20_sram_1bank_2mux_1w_1r_spare_cols_test.ok \ + sky130/20_sram_1bank_2mux_global_test.ok \ + sky130/20_sram_1bank_2mux_test.ok \ + sky130/20_sram_1bank_2mux_wmask_spare_cols_test.ok \ + sky130/20_sram_1bank_2mux_wmask_test.ok \ + sky130/20_sram_1bank_4mux_test.ok \ + sky130/20_sram_1bank_8mux_test.ok \ + sky130/20_sram_1bank_nomux_spare_cols_test.ok \ + sky130/20_sram_1bank_nomux_test.ok \ + sky130/20_sram_1bank_nomux_wmask_test.ok \ + sky130/20_sram_1bank_ring_test.ok \ + sky130/21_model_delay_test.ok \ + sky130/21_ngspice_delay_extra_rows_test.ok \ + sky130/21_ngspice_delay_test.ok \ + sky130/21_regression_delay_test.ok \ + sky130/21_xyce_delay_test.ok \ + sky130/25_verilog_multibank_test.ok \ + sky130/25_verilog_sram_test.ok \ + sky130/30_openram_back_end_library_test.ok \ + sky130/30_openram_back_end_test.ok \ + sky130/30_openram_front_end_library_test.ok \ + sky130/30_openram_front_end_test.ok \ gettech = $(word 1,$(subst /, ,$*)) getfile = $(word 2,$(subst /, ,$*)) -TECH_TEST_STAMPS=$(foreach T, $(TEST_TECHS), $(addprefix $T/, $(TEST_STAMPS))) +TECH_TEST_STAMPS=$(foreach T, $(TECHS), $(addprefix $T/, $(TEST_STAMPS))) # Filter out the tests after creating the tech stamps WORKING_TECH_TEST_STAMPS=$(shell shuf -e -- $(filter-out $(BROKEN_STAMPS), $(TECH_TEST_STAMPS))) From 503ec274f8d11fb718f8f6ed580baa75661d7834 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Fri, 14 Apr 2023 09:55:49 -0700 Subject: [PATCH 93/98] Use conda when installing pdk --- Makefile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Makefile b/Makefile index fb0e8e6c..4a09922c 100644 --- a/Makefile +++ b/Makefile @@ -49,6 +49,9 @@ INSTALL_BASE_DIRS := gds_lib mag_lib sp_lib lvs_lib calibre_lvs_lib klayout_lvs_ INSTALL_BASE := $(OPENRAM_HOME)/../technology/sky130 INSTALL_DIRS := $(addprefix $(INSTALL_BASE)/,$(INSTALL_BASE_DIRS)) +# Remove this if you don't want to use conda +USE_CONDA ?= 1 + check-pdk-root: ifndef PDK_ROOT $(error PDK_ROOT is undefined, please export it before running make) @@ -69,12 +72,23 @@ $(OPEN_PDKS_DIR): $(SKY130_PDKS_DIR) $(SKY130_PDK): $(OPEN_PDKS_DIR) $(SKY130_PDKS_DIR) @echo "Installing open_pdks..." +ifdef USE_CONDA + @source $(TOP_DIR)/miniconda/bin/activate && \ + cd $(PDK_ROOT)/open_pdks && \ + ./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) && \ + cd sky130 && \ + make veryclean && \ + make && \ + make SHARED_PDKS_PATH=$(PDK_ROOT) install && \ + conda deactivate +else @cd $(PDK_ROOT)/open_pdks && \ ./configure --enable-sky130-pdk=$(PDK_ROOT)/skywater-pdk/libraries --with-sky130-local-path=$(PDK_ROOT) && \ cd sky130 && \ make veryclean && \ make && \ make SHARED_PDKS_PATH=$(PDK_ROOT) install +endif $(SRAM_LIB_DIR): check-pdk-root @echo "Cloning SRAM library..." From c01a7915d7187886a217d147f432634289742850 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Fri, 14 Apr 2023 09:56:14 -0700 Subject: [PATCH 94/98] Enable pdk installation on before regression --- .github/workflows/regress.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/regress.yml b/.github/workflows/regress.yml index b98153ab..2526a136 100644 --- a/.github/workflows/regress.yml +++ b/.github/workflows/regress.yml @@ -23,10 +23,10 @@ jobs: run: | export OPENRAM_HOME="${{ github.workspace }}/compiler" export OPENRAM_TECH="${{ github.workspace }}/technology" - #cd $OPENRAM_HOME/tests - #export PDK_ROOT="${{ github.workspace }}/pdk" - #make pdk - #make install + cd $OPENRAM_HOME/tests + export PDK_ROOT="${{ github.workspace }}/pdk" + make pdk + make install - name: Regress run: | export OPENRAM_HOME="${{ github.workspace }}/compiler" From e972427e5f92a7ad87d79f39cabe745934c95f45 Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Fri, 14 Apr 2023 10:03:29 -0700 Subject: [PATCH 95/98] Stay at the root when installing pdk on regress --- .github/workflows/regress.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/regress.yml b/.github/workflows/regress.yml index 2526a136..7eefd28f 100644 --- a/.github/workflows/regress.yml +++ b/.github/workflows/regress.yml @@ -23,7 +23,6 @@ jobs: run: | export OPENRAM_HOME="${{ github.workspace }}/compiler" export OPENRAM_TECH="${{ github.workspace }}/technology" - cd $OPENRAM_HOME/tests export PDK_ROOT="${{ github.workspace }}/pdk" make pdk make install From 0e3fd80a0571b1900596ee59fcaa931299c77e9b Mon Sep 17 00:00:00 2001 From: Eren Dogan Date: Fri, 14 Apr 2023 15:54:22 -0700 Subject: [PATCH 96/98] Export $PDK_ROOT before running regression --- .github/workflows/regress.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/regress.yml b/.github/workflows/regress.yml index 7eefd28f..9a8291aa 100644 --- a/.github/workflows/regress.yml +++ b/.github/workflows/regress.yml @@ -30,6 +30,7 @@ jobs: run: | export OPENRAM_HOME="${{ github.workspace }}/compiler" export OPENRAM_TECH="${{ github.workspace }}/technology" + export PDK_ROOT="${{ github.workspace }}/pdk" export FREEPDK45="~/FreePDK45" # KLAYOUT_PATH breaks klayout installation. Unset it for now... unset KLAYOUT_PATH From cc39505ca97f9eda5b02b61d534810751f22b9d6 Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Sat, 15 Apr 2023 02:19:18 +0000 Subject: [PATCH 97/98] Bump version: 1.2.8 -> 1.2.9 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index db6fb4a9..9d4f8239 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.8 +1.2.9 From d6d7bc6ec569803595717044c0d77f3301d12d52 Mon Sep 17 00:00:00 2001 From: vlsida-bot Date: Wed, 26 Apr 2023 21:10:12 +0000 Subject: [PATCH 98/98] Bump version: 1.2.9 -> 1.2.10 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 9d4f8239..963ed7cf 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.2.9 +1.2.10